-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy patheject_plugin.cpp
More file actions
136 lines (120 loc) · 4.15 KB
/
Copy patheject_plugin.cpp
File metadata and controls
136 lines (120 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (c) 2019-2026 Elias Bachaalany
// SPDX-License-Identifier: LicenseRef-Human-Origin-Source-1.0
//
// This file is licensed under the Human-Origin Source License v1.0.
// See LICENSE.
// Eject IDB by Elias Bachaalany(c) AllThingsIDA
#include <memory>
#include <string>
#ifdef __NT__
#include <windows.h>
#else
#include <unistd.h>
#endif
// Include BEFORE the IDA headers: pro.h poisons identifiers (e.g. `wait` in
// SDK 9.2) that C++20 std headers pulled in here (<atomic>, <thread>) use.
#include <libidacpp/ipc/named_semaphore.hpp>
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include "utils.hpp"
// TODO:
// - use on_event/modern mechanism
// - delay event handler installation with a timer. give time to other plugins to install their handlers; come in last
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
libidacpp::ipc::semaphore_waiter_t waiter;
bool disable_ui = false;
static ssize_t idaapi ui_callback(void* ud, int notification_code, va_list va)
{
plugin_ctx_t* ctx = (plugin_ctx_t*)ud;
return ctx->disable_ui ? 1 : 0;
}
void do_eject()
{
qstring p = get_idb_path();
auto new_name = derive_ejected_path(p.c_str());
if (!new_name)
return;
// unfortunately, `save_database` calls the main thread/UI to display success/failure messages
// thus, before 'ejecting', let's disable/disallow all UI messages from being processed.
disable_ui = true;
flush_buffers();
save_database(new_name->c_str(), DBFL_BAK);
// Now it is safe to kill IDA.
#ifdef __NT__
if (MessageBoxW(NULL, L"IDB has been ejected. Do you want to forcefully exit IDA?", L"eject_idb", MB_YESNO | MB_ICONINFORMATION) == IDYES)
ExitProcess(0);
#else
// IDA's UI is presumed hung, so no dialogs: print to the IDA console
// (may not repaint) and to the terminal IDA was launched from.
// (qeprintf = the SDK's stderr printf; CRT fprintf/stderr are poisoned.)
msg("eject_idb: IDB ejected to %s\n", new_name->c_str());
qeprintf("eject_idb: IDB ejected to %s\n"
"IDA may be hung -- you may now kill it: kill -9 %d\n",
new_name->c_str(), (int)getpid());
#endif
disable_ui = false;
}
plugin_ctx_t()
{
std::string sem_name = make_semaphore_name(get_idb_path().c_str());
if (waiter.start(sem_name.c_str(), [this]() { do_eject(); }))
{
msg("eject_idb installed. call the 'eject_idb \"%s\"' command line tool to eject this database!\n",
get_idb_path().c_str());
}
else
{
// e.g. sandboxed macOS denying sem_open: stay loaded but inert.
msg("eject_idb: could not create the eject semaphore; plugin is inactive.\n");
}
hook_to_notification_point(HT_UI, ui_callback, this);
}
// This hanging mode (only if poll is true) can be 'ejected'
static bool hang_with_loop(bool poll=false)
{
while (true)
{
if (poll)
user_cancelled();
qsleep(1000);
}
return true;
}
bool idaapi run(size_t arg) override
{
switch (arg)
{
case 0:
if (ask_yn(1, "HIDECANCEL\nDo you want to simulate a non-responsive UI hang?") == ASKBTN_YES)
hang_with_loop(false);
break;
case 1:
if (ask_yn(1, "HIDECANCEL\nDo you want to simulate a responsive UI hang?") == ASKBTN_YES)
hang_with_loop(true);
break;
}
return true;
}
~plugin_ctx_t() override
{
waiter.stop();
unhook_from_notification_point(HT_UI, ui_callback, this);
}
};
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI,
[]()->plugmod_t* { return new plugin_ctx_t; },
nullptr,
nullptr,
nullptr,
nullptr,
"eject_idb: simulate an infinite loop",
nullptr
};