-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFindStruct.py
170 lines (134 loc) · 5.28 KB
/
FindStruct.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
#Find structs by field type.
#@author Rena
#@category Struct
#@keybinding
#@menupath
#@toolbar
StringColumnDisplay = ghidra.app.tablechooser.StringColumnDisplay
AddressableRowObject = ghidra.app.tablechooser.AddressableRowObject
TableChooserExecutor = ghidra.app.tablechooser.TableChooserExecutor
DTM = state.tool.getService(ghidra.app.services.DataTypeManagerService)
AF = currentProgram.getAddressFactory()
DT = currentProgram.getDataTypeManager()
listing = currentProgram.getListing()
mem = currentProgram.getMemory()
def addrToInt(addr):
return int(str(addr), 16)
def intToAddr(addr):
return AF.getAddress("0x%08X" % addr)
class Executor(TableChooserExecutor):
def getButtonName(self):
return "Edit Structure"
def execute(self, row):
DTM.edit(row.struc) # show the structure editor
return False # do not remove row
class StructNameColumn(StringColumnDisplay):
def getColumnName(self):
return "Struct Name"
def getColumnValue(self, row):
return row.struc.displayName
class StructLengthColumn(StringColumnDisplay):
def getColumnName(self):
return "Struct Size"
def getColumnValue(self, row):
return row.struc.length
class StructListResult(AddressableRowObject):
def __init__(self, struc):
self.struc = struc
def getAddress(self):
return intToAddr(self.struc.length)
def run():
# XXX find a way to make this UI better.
# criteria is eg:
# B8=*int (a struct with an int* at 0xB8)
# B8=* (a struct with any pointer at 0xB8)
# B8=2 (a struct with any field at 0xB8 with length 2)
# B8=*2 (a struct with a pointer at 0xB8 to something with length 2)
# B8 (a struct with any field starting at 0xB8)
params = askString("Find Struct", "Enter search criteria")
params = params.split(';')
monitor.initialize(len(params))
candidates = list(DT.allStructures)
def showResults():
executor = Executor()
tbl = createTableChooserDialog("Matching Structs", executor)
tbl.addCustomColumn(StructNameColumn())
tbl.addCustomColumn(StructLengthColumn())
#printf("show %d results\n", len(candidates))
for res in candidates:
#printf("%s\n", res.displayName)
tbl.add(StructListResult(res))
tbl.show()
tbl.setMessage("%d results" % len(candidates))
def removeResult(struc):
candidates.remove(struc)
#print("remove", struc.name, "#res", len(candidates))
def checkComponent(struc, comp, offset, typ):
# return True if match, False if not.
# does component match given offset/type?
if comp.offset != offset: return False
if typ is None: return True # match any type at this offset
# if this is a pointer, walk the dataType chain
# to reach the base type
tp = typ
dt = comp.dataType
while tp.startswith('*'):
if (not hasattr(dt, 'dataType')) or dt.dataType is None:
#printf("[X] %s.%s @%X type is %s\n", struc.name,
# comp.fieldName, offset, str(getattr(dt, 'dataType')))
return False
dt = dt.dataType
tp = tp[1:]
# check the name
# remove spaces for simplicity
tp = tp.replace(' ', '')
nm = dt.name.replace(' ', '')
if tp.isnumeric():
#printf("[%s] %s.%s @%X size is %d\n",
# "O" if dt.length == int(tp) else "X",
# struc.name, comp.fieldName, offset, dt.length)
if dt.length == int(tp):
return True
else:
#printf("[%s] %s.%s @%X type is %d\n",
# "O" if nm == tp else "X",
# struc.name, comp.fieldName, offset, dt.length)
if nm == tp:
return True
#comp.dataType.name, numElements, elementLength, length, dataType
#comp.fieldName, comment, endOffset, bitFieldComponent, dataType, length, offset, ordinal
return False
def evaluateParam(param):
param = param.split('=')
offset = int(param[0], 16)
if len(param) < 2:
# no type given - find any struct which has a field
# beginning at this offset.
typ = None
else:
# user specified a type for the field
typ = param[1]
#printf("Evaluate '%s', #res=%d\n", param, len(candidates))
remove = []
for struc in candidates:
monitor.checkCanceled()
#monitor.incrementProgress(1)
#monitor.setMessage("Checking %s" % struc.displayName)
#print("check", struc.displayName)
match = False
for comp in struc.components:
if checkComponent(struc, comp, offset, typ):
match = True
break
if not match: remove.append(struc)
for struc in remove: removeResult(struc)
#printf("Evaluated '%s', #res=%d\n", param, len(candidates))
for param in params:
monitor.checkCanceled()
monitor.incrementProgress(1)
monitor.setMessage("Checking %s" % param)
evaluateParam(param)
if len(candidates) == 0: break
#popup("Found %d matches (see console)" % len(candidates))
showResults()
run()