-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathcvutils-cfs-importer.py
231 lines (180 loc) · 7.94 KB
/
cvutils-cfs-importer.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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#------------------------------------------------------------------------------
# IDA Plugin that imports CFS files
# Copy the 'cvutils-cfs-importer.py' into the plugins directory of IDA
#------------------------------------------------------------------------------
VERSION = '1.1.0'
__AUTHOR__ = 'cra0'
PLUGIN_NAME = "CFS Importer"
PLUGIN_HOTKEY = "Ctrl+Shift+I"
import os
import idc
import idaapi
import ida_bytes
import ida_funcs
import ida_name
major, minor = map(int, idaapi.get_kernel_version().split("."))
using_ida7api = (major > 6)
using_pyqt5 = using_ida7api or (major == 6 and minor >= 9)
idaver_74newer = (major == 7 and minor >= 4)
idaver_8newer = (major >= 8)
if idaver_74newer or idaver_8newer:
newer_version_compatible = True
else:
newer_version_compatible = False
if newer_version_compatible:
#IDA 7.4+
#https://hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml
import ida_ida
if using_pyqt5:
import PyQt5.QtGui as QtGui
import PyQt5.QtCore as QtCore
import PyQt5.QtWidgets as QtWidgets
from PyQt5.Qt import QApplication
else:
import PySide.QtGui as QtGui
import PySide.QtCore as QtCore
QtWidgets = QtGui
QtCore.pyqtSignal = QtCore.Signal
QtCore.pyqtSlot = QtCore.Slot
from PySide.QtGui import QApplication
class ImportFileMenuHandler(idaapi.action_handler_t):
def __init__(self):
idaapi.action_handler_t.__init__(self)
def get_directory_path(self, file_path):
"""
Get the directory path from a given file path.
"""
return os.path.dirname(file_path)
def get_file_name(self, file_path):
"""
Get the file name from a given file path.
"""
return os.path.basename(file_path)
def find_all_matches(self, min_ea, max_ea, signature, max_matches=-1):
matches = []
ea = idaapi.find_binary(min_ea, max_ea, signature, 16, idaapi.SEARCH_DOWN)
count = 0
while ea != idaapi.BADADDR:
matches.append(ea)
count += 1
if max_matches != -1 and count >= max_matches:
break
ea = idaapi.find_binary(ea + 1, max_ea, signature, 16, idaapi.SEARCH_DOWN)
return matches
def process_signatures(self, sig_file_path):
"""
Process the signatures and resolve function names in IDA.
"""
counter = 0
resolved_count = 0
error_count = 0
min_ea = idaapi.cvar.inf.min_ea
max_ea = idaapi.cvar.inf.max_ea
is_64bit = idc.__EA64__
print("Processing Signatures...")
with open(sig_file_path, "r") as sig_file:
for line in sig_file:
line = line.strip()
if not line or line.startswith("//"):
continue
# Index
index, line = line.split(",", 1)
index = int(index)
# Function Name
func_name, line = line.split(",", 1)
func_name = func_name.strip()
# Signature
signature = line.strip()[1:-1] # Remove surrounding quotes
# Find all matches
ea = idaapi.BADADDR
matches = self.find_all_matches(min_ea, max_ea, signature, 2)
matches_count = len(matches)
if matches_count > 1:
print("Multiple signature matches[%i] found for [%s] ignoring sig." % (matches_count, func_name))
continue
# Set EA if we have only 1 hit, change this if you wish.
if matches_count == 1:
ea = matches[0]
print(f"({resolved_count}/{counter}) [{ea:X}] [{func_name}] ==> ", end="")
if ea != idaapi.BADADDR:
if ida_bytes.get_full_flags(ea) != idaapi.BADADDR:
func_idb_name_str = ida_name.get_name(ea)
if idc.get_func_flags(ea) == -1:
ida_bytes.del_items(ea, ida_bytes.DELIT_SIMPLE, 1)
idc.create_insn(ea)
ida_funcs.add_func(ea)
ida_name.set_name(ea, func_name, ida_name.SN_FORCE)
idc.set_cmt(ea, "SIG-RESOLVED " + func_name, 1)
resolved_count += 1
print("[RESOLVED]")
elif func_idb_name_str and len(func_idb_name_str) >= 3:
if func_idb_name_str[:3] == "sub":
ida_name.set_name(ea, func_name, ida_name.SN_FORCE)
idc.set_cmt(ea, "SIG-RESOLVED " + func_name, 1)
resolved_count += 1
print("[RENAMED+RESOLVED]", func_idb_name_str, "TO", func_name)
else:
print("[IGNORED] Function @ 0x{:X} seems named.".format(ea))
else:
print("[UNKNOWN ERROR]")
else:
error_count += 1
print("[BAD!!!] Unable to resolve =>", func_name, "@ [0x{:X}]".format(ea))
else:
print("[NOT FOUND] Signature not found in the binary")
counter += 1
print("------------------------------------------")
print("Resolved ({}/{}) Functions!".format(resolved_count, counter))
if error_count > 0:
print("Errors ({})".format(error_count))
return False
return True
def main(self):
sig_file_path = idaapi.ask_file(0, "*.cfs", "Cra0 Signature Definition File")
if sig_file_path:
print("------------------------------------------")
print("IDA Signature Resolver - cra0 (cra0.net)")
print("Parsing:", sig_file_path)
# Show the "Please wait" dialog before starting the heavy sigfind operation
idaapi.show_wait_box("Processing... Please Wait (This may take a while chill)")
if not self.process_signatures(sig_file_path):
idaapi.warning("Some errors occurred while importing.")
# Hide the "Please wait" dialog
idaapi.hide_wait_box()
# Invoke the main
def activate(self, ctx):
self.main() # call the main function when the action is activated
return 1
# This action is always available.
def update(self, ctx):
return idaapi.AST_ENABLE_ALWAYS
class CFSImportPlugin(idaapi.plugin_t):
flags = 0
comment = "CFS Importer Plugin"
help = "Import a CFS File into your idb."
wanted_name = PLUGIN_NAME
wanted_hotkey = ""
ACTION_IMPORT_SIGNATURES = "cfs:import_action"
ACTION_TOOLTIP_ICON = 198
def init(self):
# Create a new action
action_desc = idaapi.action_desc_t(
self.ACTION_IMPORT_SIGNATURES, # The action name.
'CFS File...', # The action text.
ImportFileMenuHandler(), # The action handler.
PLUGIN_HOTKEY, # Optional: the action shortcut.
'Import a CFS File into the current idb.', # Optional: the action tooltip.
self.ACTION_TOOLTIP_ICON) # Icon.
# Register the action
idaapi.register_action(action_desc)
# Attach the action to a menu item in the File menu.
idaapi.attach_action_to_menu('File/Load file/', # The relative path of where to add the action.
self.ACTION_IMPORT_SIGNATURES, # The action ID (declared above).
idaapi.SETMENU_APP) # We want to append the action after.
return idaapi.PLUGIN_KEEP
def run(self, arg):
print("CFSImportPlugin is running")
def term(self):
idaapi.unregister_action(self.ACTION_IMPORT_SIGNATURES)
def PLUGIN_ENTRY():
return CFSImportPlugin()