forked from patois/abyss
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathabyss.py
194 lines (164 loc) · 6.49 KB
/
abyss.py
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import ida_kernwin as kw
import ida_hexrays as hr
import ida_diskio, ida_idaapi
import os, sys, configparser
__author__ = "https://github.com/patois"
PLUGIN_NAME = "abyss"
ACTION_NAME = "%s:" % PLUGIN_NAME
POPUP_ENTRY = "%s/" % PLUGIN_NAME
FILTER_DIR = "%s_filters" % PLUGIN_NAME
CFG_FILENAME = "%s.cfg" % PLUGIN_NAME
FILTERS = {}
# ----------------------------------------------------------------------------
class abyss_filter_t:
"""every filter should inherit from this class and
override respective handlers/methods"""
def __init__(self):
self.set_activated(False)
return
def process_printfunc(self, cfunc, printer):
return 0
def process_text(self, vu):
return 0
def process_curpos(self, vu):
return 0
def is_activated(self):
return self.activated
def set_activated(self, active):
self.activated = active
# ----------------------------------------------------------------------------
def get_cfg_filename():
"""returns full path for config file."""
return os.path.join(
ida_diskio.get_user_idadir(),
"plugins",
"%s" % CFG_FILENAME)
# ----------------------------------------------------------------------------
def apply_cfg(reload=False, filters={}):
"""loads abyss configuration."""
cfg_file = get_cfg_filename()
kw.msg("%s: %sloading %s...\n" % (PLUGIN_NAME,
"re" if reload else "",
cfg_file))
if not os.path.isfile(cfg_file):
kw.msg("%s: default configuration (%s) does not exist!\n" % (PLUGIN_NAME, cfg_file))
kw.msg("Creating default configuration\n")
try:
with open(cfg_file, "w") as f:
f.write("[init]\n")
for name, mod in filters.items():
f.write("%s=False\n" % name )
except:
kw.msg("failed!\n")
return False
return apply_cfg(reload=True)
config = configparser.RawConfigParser()
config.readfp(open(cfg_file))
# read all sections
for section in config.sections():
if section == "init":
for name, value in config.items(section):
try:
filters[name].set_activated(config[section].getboolean(name))
#print("%s -> %s" % (name, value))
except:
pass
kw.msg("done!\n")
return True
# ----------------------------------------------------------------------------
def load_filters(reload=False):
global FILTERS
print("%s: %sloading filters..." % (PLUGIN_NAME, "re" if reload else ""))
if reload:
FILTERS = {}
filterdir = os.path.join(os.path.dirname(__file__), FILTER_DIR)
if os.path.exists(filterdir):
for entry in os.listdir(filterdir):
if entry.lower().endswith(".py") and entry.lower() != "__init__.py":
mod, ext = os.path.splitext(entry)
if mod not in FILTERS:
try:
ida_idaapi.require("%s.%s" % (FILTER_DIR, mod), FILTER_DIR)
flt = sys.modules["%s.%s" % (FILTER_DIR, mod)].FILTER_INIT()
if flt:
print(" loaded: \"%s\"" % (mod))
FILTERS[mod] = flt
except ModuleNotFoundError:
print(" failed: \"%s\"" % (mod))
apply_cfg(reload, FILTERS)
return
# ----------------------------------------------------------------------------
class ui_event_t(kw.UI_Hooks):
def finish_populating_widget_popup(self, widget, popup_handle):
if kw.get_widget_type(widget) == kw.BWN_PSEUDOCODE:
class FilterHandler(kw.action_handler_t):
def __init__(self, name):
self.name = name
kw.action_handler_t.__init__(self)
def activate(self, ctx):
obj = FILTERS[self.name]
obj.set_activated(not obj.is_activated())
vu = hr.get_widget_vdui(ctx.widget)
if vu:
vu.refresh_view(not obj.is_activated())
return 1
def update(self, ctx):
return kw.AST_ENABLE_FOR_WIDGET
for name, obj in FILTERS.items():
action_desc = kw.action_desc_t(
'%s%s' % (ACTION_NAME, name),
name,
FilterHandler(name),
None,
None,
34 if obj.is_activated() else -1)
kw.attach_dynamic_action_to_popup(widget, popup_handle, action_desc, POPUP_ENTRY)
# ----------------------------------------------------------------------------
class hx_event_t(hr.Hexrays_Hooks):
def __init__(self):
hr.Hexrays_Hooks.__init__(self)
def print_func(self, cfunc, printer):
for name, obj in FILTERS.items():
if obj.is_activated():
obj.process_printfunc(cfunc, printer)
return 0
def text_ready(self, vu):
for name, obj in FILTERS.items():
if obj.is_activated():
obj.process_text(vu)
return 0
def curpos(self, vu):
for name, obj in FILTERS.items():
if obj.is_activated():
obj.process_curpos(vu)
return 0
# ----------------------------------------------------------------------------
class abyss_plugin_t(ida_idaapi.plugin_t):
flags = 0
comment = "Postprocess Hexrays Output"
help = comment
wanted_name = PLUGIN_NAME
# allows reloading filter scripts while developing them
wanted_hotkey = "Ctrl-Alt-R"
def init(self):
if hr.init_hexrays_plugin():
load_filters()
self.ui_hooks = ui_event_t()
self.ui_hooks.hook()
self.hr_hooks = hx_event_t()
self.hr_hooks.hook()
return ida_idaapi.PLUGIN_KEEP
else:
return ida_idaapi.PLUGIN_SKIP
def run(self, arg):
load_filters(reload=True)
return
def term(self):
try:
self.ui_hooks.unhook()
self.hr_hooks.unhook()
except:
pass
return
def PLUGIN_ENTRY():
return abyss_plugin_t()