15
15
16
16
BINDIFF_BINARY = None
17
17
BINDIFF_PATH_ENV = "BINDIFF_PATH"
18
- BIN_NAMES = [' bindiff' , ' bindiff.exe' , ' differ' ]
18
+ BIN_NAMES = [" bindiff" , " bindiff.exe" , " differ" ]
19
19
20
20
21
21
def _check_bin_names (path : Path ) -> bool :
@@ -48,7 +48,7 @@ def _check_environ() -> bool:
48
48
def _check_default_path () -> bool :
49
49
"""
50
50
Check if BinDiff is installed at its default location
51
-
51
+
52
52
:return: bool
53
53
"""
54
54
return _check_bin_names (Path ("/opt/zynamics/BinDiff/bin" ))
@@ -78,7 +78,12 @@ class BinDiff(BindiffFile):
78
78
additional attributes and method to the class.
79
79
"""
80
80
81
- def __init__ (self , primary : Union [ProgramBinExport , str ], secondary : Union [ProgramBinExport , str ], diff_file : str ):
81
+ def __init__ (
82
+ self ,
83
+ primary : Union [ProgramBinExport , str ],
84
+ secondary : Union [ProgramBinExport , str ],
85
+ diff_file : str ,
86
+ ):
82
87
"""
83
88
:param primary: first program diffed
84
89
:param secondary: second program diffed
@@ -94,7 +99,7 @@ def __init__(self, primary: Union[ProgramBinExport, str], secondary: Union[Progr
94
99
def primary_unmatched_function (self ) -> list [FunctionBinExport ]:
95
100
"""
96
101
Return a list of the unmatched functions in the primary program.
97
-
102
+
98
103
:return: list of unmatched functions in primary
99
104
"""
100
105
funs = []
@@ -106,7 +111,7 @@ def primary_unmatched_function(self) -> list[FunctionBinExport]:
106
111
def secondary_unmatched_function (self ) -> list [FunctionBinExport ]:
107
112
"""
108
113
Return a list of the unmatched functions in the secondary program.
109
-
114
+
110
115
:return: list of unmatched functions in secondary
111
116
"""
112
117
funs = []
@@ -115,7 +120,9 @@ def secondary_unmatched_function(self) -> list[FunctionBinExport]:
115
120
funs .append (fun )
116
121
return funs
117
122
118
- def iter_function_matches (self ) -> list [tuple [FunctionBinExport , FunctionBinExport , FunctionMatch ]]:
123
+ def iter_function_matches (
124
+ self ,
125
+ ) -> list [tuple [FunctionBinExport , FunctionBinExport , FunctionMatch ]]:
119
126
"""
120
127
Return a list of all the matched functions. Each element of the list is a tuple containing
121
128
the function in the primary program, the matched function in the secondary program and the
@@ -124,50 +131,58 @@ def iter_function_matches(self) -> list[tuple[FunctionBinExport, FunctionBinExpo
124
131
:return: list of tuple, each containing the primary function, the secondary function and
125
132
the FunctionMatch object
126
133
"""
127
- return [(self .primary [match .address1 ], self .secondary [match .address2 ], match ) \
128
- for match in self .primary_functions_match .values ()]
134
+ return [
135
+ (self .primary [match .address1 ], self .secondary [match .address2 ], match )
136
+ for match in self .primary_functions_match .values ()
137
+ ]
129
138
130
- def _unmatched_bbs (self , function : FunctionBinExport , map : dict [int , dict [int , BasicBlockMatch ]]) -> list [BasicBlockBinExport ]:
139
+ def _unmatched_bbs (
140
+ self , function : FunctionBinExport , map : dict [int , dict [int , BasicBlockMatch ]]
141
+ ) -> list [BasicBlockBinExport ]:
131
142
bbs = []
132
143
for bb_addr , bb in function .items ():
133
144
if maps := map .get (bb_addr ):
134
- if function .addr not in maps : # The block has been match but in another function thus unmatched here
145
+ # The block has been match but in another function thus unmatched here
146
+ if function .addr not in maps :
135
147
bbs .append (bb )
136
148
else :
137
149
bbs .append (bb )
138
150
return bbs
139
151
140
- def primary_unmatched_basic_block (self , function : FunctionBinExport ) -> list [BasicBlockBinExport ]:
152
+ def primary_unmatched_basic_block (
153
+ self , function : FunctionBinExport
154
+ ) -> list [BasicBlockBinExport ]:
141
155
"""
142
156
Return a list of the unmatched basic blocks in the provided function.
143
157
The function must be part of the primary program.
144
-
158
+
145
159
:param function: A function of the primary program
146
160
:return: list of unmatched basic blocks
147
161
"""
148
162
return self ._unmatched_bbs (function , self .primary_basicblock_match )
149
163
150
- def secondary_unmatched_basic_block (self , function : FunctionBinExport ) -> list [BasicBlockBinExport ]:
164
+ def secondary_unmatched_basic_block (
165
+ self , function : FunctionBinExport
166
+ ) -> list [BasicBlockBinExport ]:
151
167
"""
152
168
Return a list of the unmatched basic blocks in the provided function.
153
169
The function must be part of the secondary program.
154
-
170
+
155
171
:param function: A function of the secondary program
156
172
:return: list of unmatched basic blocks
157
173
"""
158
174
return self ._unmatched_bbs (function , self .secondary_basicblock_match )
159
175
160
- def iter_basicblock_matches (self ,
161
- function1 : FunctionBinExport ,
162
- function2 : FunctionBinExport
176
+ def iter_basicblock_matches (
177
+ self , function1 : FunctionBinExport , function2 : FunctionBinExport
163
178
) -> list [tuple [BasicBlockBinExport , BasicBlockBinExport , BasicBlockMatch ]]:
164
179
"""
165
180
Return a list of all the matched basic blocks between the two provided functions.
166
181
Each element of the list is a tuple containing the basic blocks of the primary and secondary
167
182
functions and the BasicBlockMatch object describing the match.
168
183
The first function must be part of the primary program while the second function must be
169
184
part of the secondary program.
170
-
185
+
171
186
:param function1: A function of the primary program
172
187
:param function2: A function of the secondary program
173
188
:return: list of tuple, each containing the primary basic block, the secondary basic block
@@ -180,7 +195,9 @@ def iter_basicblock_matches(self,
180
195
items .append ((bb , function2 [match .address2 ], match ))
181
196
return items
182
197
183
- def _unmatched_instrs (self , bb : BasicBlockBinExport , map : dict [int , dict [int , int ]]) -> list [InstructionBinExport ]:
198
+ def _unmatched_instrs (
199
+ self , bb : BasicBlockBinExport , map : dict [int , dict [int , int ]]
200
+ ) -> list [InstructionBinExport ]:
184
201
instrs = []
185
202
for addr , instr in bb .instructions .items ():
186
203
if addr not in map :
@@ -191,31 +208,34 @@ def primary_unmatched_instruction(self, bb: BasicBlockBinExport) -> list[Instruc
191
208
"""
192
209
Return a list of the unmatched instructions in the provided basic block.
193
210
The basic block must be part of the primary program.
194
-
211
+
195
212
:param bb: A basic block belonging to the primary program
196
213
:return: list of unmatched instructions
197
214
"""
198
215
return self ._unmatched_instrs (bb , self .primary_instruction_match )
199
216
200
- def secondary_unmatched_instruction (self , bb : BasicBlockBinExport ) -> list [InstructionBinExport ]:
217
+ def secondary_unmatched_instruction (
218
+ self , bb : BasicBlockBinExport
219
+ ) -> list [InstructionBinExport ]:
201
220
"""
202
221
Return a list of the unmatched instructions in the provided basic block.
203
222
The basic block must be part of the secondary program.
204
-
223
+
205
224
:param bb: A basic block belonging to the secondary program
206
225
:return: list of unmatched instructions
207
226
"""
208
227
return self ._unmatched_instrs (bb , self .secondary_instruction_match )
209
228
210
- def iter_instruction_matches (self , block1 : BasicBlockBinExport ,
211
- block2 : BasicBlockBinExport ) -> list [tuple [InstructionBinExport , InstructionBinExport ]]:
229
+ def iter_instruction_matches (
230
+ self , block1 : BasicBlockBinExport , block2 : BasicBlockBinExport
231
+ ) -> list [tuple [InstructionBinExport , InstructionBinExport ]]:
212
232
"""
213
233
Return a list of all the matched instructions between the two provided basic blocks.
214
234
Each element of the list is a tuple containing the instructions of the primary and secondary
215
235
basic blocks.
216
236
The first basic block must belong to the primary program while the second one must be
217
237
part of the secondary program.
218
-
238
+
219
239
:param block1: A basic block belonging to the primary program
220
240
:param block2: A basic block belonging to the secondary program
221
241
:return: list of tuple, each containing the primary instruction and the secondary instruction
@@ -226,10 +246,12 @@ def iter_instruction_matches(self, block1: BasicBlockBinExport,
226
246
insts .append ((instr , block2 .instructions [addr2 ]))
227
247
return insts
228
248
229
- def get_match (self , function : FunctionBinExport ) -> tuple [FunctionBinExport , FunctionMatch ] | None :
249
+ def get_match (
250
+ self , function : FunctionBinExport
251
+ ) -> tuple [FunctionBinExport , FunctionMatch ] | None :
230
252
"""
231
253
Get the function that matches the provided one.
232
-
254
+
233
255
:param function: A function that belongs either to primary or secondary
234
256
:return: A tuple with the matched function and the match object if there is a match for
235
257
the provided function, otherwise None
@@ -268,10 +290,12 @@ def raw_diffing(p1_path: Union[Path, str], p2_path: Union[Path, str], out_diff:
268
290
f1 = Path (p1_path )
269
291
f2 = Path (p2_path )
270
292
271
- cmd_line = [BINDIFF_BINARY .as_posix (),
272
- f"--primary={ p1_path } " ,
273
- f"--secondary={ p2_path } " ,
274
- f"--output_dir={ tmp_dir .as_posix ()} " ]
293
+ cmd_line = [
294
+ BINDIFF_BINARY .as_posix (),
295
+ f"--primary={ p1_path } " ,
296
+ f"--secondary={ p2_path } " ,
297
+ f"--output_dir={ tmp_dir .as_posix ()} " ,
298
+ ]
275
299
276
300
logging .debug (f"run diffing: { ' ' .join (cmd_line )} " )
277
301
process = subprocess .Popen (cmd_line , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
@@ -301,7 +325,7 @@ def raw_diffing(p1_path: Union[Path, str], p2_path: Union[Path, str], out_diff:
301
325
return True
302
326
303
327
@staticmethod
304
- def from_binary_files (p1_path : str , p2_path : str , diff_out : str ) -> Optional [' BinDiff' ]:
328
+ def from_binary_files (p1_path : str , p2_path : str , diff_out : str ) -> Optional [" BinDiff" ]:
305
329
"""
306
330
Diff two executable files. Thus it export .BinExport files from IDA
307
331
and then diff the two resulting files in BinDiff.
@@ -324,7 +348,9 @@ def from_binary_files(p1_path: str, p2_path: str, diff_out: str) -> Optional['Bi
324
348
return None
325
349
326
350
@staticmethod
327
- def from_binexport_files (p1_binexport : str , p2_binexport : str , diff_out : str ) -> Optional ['BinDiff' ]:
351
+ def from_binexport_files (
352
+ p1_binexport : str , p2_binexport : str , diff_out : str
353
+ ) -> Optional ["BinDiff" ]:
328
354
"""
329
355
Diff two binexport files. Diff the two binexport files with bindiff
330
356
and then load a BinDiff instance.
@@ -346,8 +372,10 @@ def _configure_bindiff_path() -> None:
346
372
if not _check_environ ():
347
373
if not _check_default_path ():
348
374
if not _check_path ():
349
- logging .warning (f"Can't find a valid bindiff executable. (should be available in PATH or"
350
- f"as ${ BINDIFF_PATH_ENV } env variable" )
375
+ logging .warning (
376
+ f"Can't find a valid bindiff executable. (should be available in PATH or"
377
+ f"as ${ BINDIFF_PATH_ENV } env variable"
378
+ )
351
379
352
380
@staticmethod
353
381
def assert_installation_ok () -> None :
0 commit comments