Skip to content

Commit 4bd65d2

Browse files
committed
Enforce black code formatting
1 parent f0b8020 commit 4bd65d2

File tree

4 files changed

+210
-100
lines changed

4 files changed

+210
-100
lines changed

bin/bindiffer

+41-22
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,39 @@ import sys
1111
from bindiff import BinDiff
1212
from binexport import ProgramBinExport
1313

14-
BINARY_FORMAT = {'application/x-dosexec',
15-
'application/x-sharedlib',
16-
'application/x-mach-binary',
17-
'application/x-executable',
18-
'application/x-object',
19-
'application/x-pie-executable'}
14+
BINARY_FORMAT = {
15+
"application/x-dosexec",
16+
"application/x-sharedlib",
17+
"application/x-mach-binary",
18+
"application/x-executable",
19+
"application/x-object",
20+
"application/x-pie-executable",
21+
}
2022

21-
EXTENSIONS_WHITELIST = {'application/octet-stream': ['.dex']}
23+
EXTENSIONS_WHITELIST = {"application/octet-stream": [".dex"]}
2224

2325

24-
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'],
25-
max_content_width=300)
26+
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"], max_content_width=300)
2627

2728

2829
@click.command(context_settings=CONTEXT_SETTINGS)
29-
@click.option('-i', '--ida-path', type=click.Path(exists=True), default=None, help="IDA Pro installation directory")
30-
@click.option('-b', '--bindiff-path', type=click.Path(exists=True), default=None, help="BinDiff differ directory")
31-
@click.option('-o', '--output', type=click.Path(), default=None, help="Output file matching")
30+
@click.option(
31+
"-i",
32+
"--ida-path",
33+
type=click.Path(exists=True),
34+
default=None,
35+
help="IDA Pro installation directory",
36+
)
37+
@click.option(
38+
"-b",
39+
"--bindiff-path",
40+
type=click.Path(exists=True),
41+
default=None,
42+
help="BinDiff differ directory",
43+
)
44+
@click.option("-o", "--output", type=click.Path(), default=None, help="Output file matching")
3245
@click.argument("primary", type=click.Path(exists=True), metavar="<primary file>")
33-
@click.argument('secondary', type=click.Path(exists=True), metavar="<secondary file>")
46+
@click.argument("secondary", type=click.Path(exists=True), metavar="<secondary file>")
3447
def main(ida_path: str, bindiff_path: str, output: str, primary: str, secondary: str) -> None:
3548
"""
3649
bindiffer is a very simple utility to diff two binary files using BinDiff
@@ -44,20 +57,22 @@ def main(ida_path: str, bindiff_path: str, output: str, primary: str, secondary:
4457
:param secondary: Path to the secondary file
4558
"""
4659

47-
logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.INFO)
60+
logging.basicConfig(format="[%(levelname)s] %(message)s", level=logging.INFO)
4861

4962
if ida_path:
50-
os.environ['IDA_PATH'] = Path(ida_path).resolve().as_posix()
63+
os.environ["IDA_PATH"] = Path(ida_path).resolve().as_posix()
5164

5265
if bindiff_path:
53-
os.environ['BINDIFF_PATH'] = Path(bindiff_path).resolve().as_posix()
66+
os.environ["BINDIFF_PATH"] = Path(bindiff_path).resolve().as_posix()
5467

5568
if not BinDiff.is_installation_ok():
56-
logging.error("can't find bindiff executable (make sure its available in $PATH or via --bindiff-path")
69+
logging.error(
70+
"can't find bindiff executable (make sure its available in $PATH or via --bindiff-path"
71+
)
5772
sys.exit(1)
5873

5974
if output is None:
60-
output = '{}_vs_{}.BinDiff'.format(Path(primary).stem, Path(secondary).stem)
75+
output = "{}_vs_{}.BinDiff".format(Path(primary).stem, Path(secondary).stem)
6176

6277
# Check that the output name is not too long
6378
if len(output) > 255:
@@ -70,14 +85,18 @@ def main(ida_path: str, bindiff_path: str, output: str, primary: str, secondary:
7085
if not (primary.suffix == ".BinExport" and secondary.suffix == ".BinExport"):
7186
for file in [primary, secondary]:
7287
mime_type = magic.from_file(file, mime=True)
73-
if mime_type not in BINARY_FORMAT and Path(file).suffix not in EXTENSIONS_WHITELIST.get(mime_type, []):
74-
logging.error(f"file {file} mimetype ({mime_type}) not supported (not an executable file)")
88+
if mime_type not in BINARY_FORMAT and Path(file).suffix not in EXTENSIONS_WHITELIST.get(
89+
mime_type, []
90+
):
91+
logging.error(
92+
f"file {file} mimetype ({mime_type}) not supported (not an executable file)"
93+
)
7594
exit(1)
7695

7796
# Export each binary separately (and then diff to be able to print it)
7897
logging.info(f"export primary: {primary}.BinExport")
7998
ProgramBinExport.from_binary_file(primary, open_export=False, override=True)
80-
primary = Path(str(primary)+".BinExport")
99+
primary = Path(str(primary) + ".BinExport")
81100

82101
logging.info(f"export secondary: {secondary}.BinExport")
83102
ProgramBinExport.from_binary_file(secondary, open_export=False, override=True)
@@ -92,5 +111,5 @@ def main(ida_path: str, bindiff_path: str, output: str, primary: str, secondary:
92111
sys.exit(1)
93112

94113

95-
if __name__ == '__main__':
114+
if __name__ == "__main__":
96115
main()

src/bindiff/bindiff.py

+63-35
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
BINDIFF_BINARY = None
1717
BINDIFF_PATH_ENV = "BINDIFF_PATH"
18-
BIN_NAMES = ['bindiff', 'bindiff.exe', 'differ']
18+
BIN_NAMES = ["bindiff", "bindiff.exe", "differ"]
1919

2020

2121
def _check_bin_names(path: Path) -> bool:
@@ -48,7 +48,7 @@ def _check_environ() -> bool:
4848
def _check_default_path() -> bool:
4949
"""
5050
Check if BinDiff is installed at its default location
51-
51+
5252
:return: bool
5353
"""
5454
return _check_bin_names(Path("/opt/zynamics/BinDiff/bin"))
@@ -78,7 +78,12 @@ class BinDiff(BindiffFile):
7878
additional attributes and method to the class.
7979
"""
8080

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+
):
8287
"""
8388
:param primary: first program diffed
8489
:param secondary: second program diffed
@@ -94,7 +99,7 @@ def __init__(self, primary: Union[ProgramBinExport, str], secondary: Union[Progr
9499
def primary_unmatched_function(self) -> list[FunctionBinExport]:
95100
"""
96101
Return a list of the unmatched functions in the primary program.
97-
102+
98103
:return: list of unmatched functions in primary
99104
"""
100105
funs = []
@@ -106,7 +111,7 @@ def primary_unmatched_function(self) -> list[FunctionBinExport]:
106111
def secondary_unmatched_function(self) -> list[FunctionBinExport]:
107112
"""
108113
Return a list of the unmatched functions in the secondary program.
109-
114+
110115
:return: list of unmatched functions in secondary
111116
"""
112117
funs = []
@@ -115,7 +120,9 @@ def secondary_unmatched_function(self) -> list[FunctionBinExport]:
115120
funs.append(fun)
116121
return funs
117122

118-
def iter_function_matches(self) -> list[tuple[FunctionBinExport, FunctionBinExport, FunctionMatch]]:
123+
def iter_function_matches(
124+
self,
125+
) -> list[tuple[FunctionBinExport, FunctionBinExport, FunctionMatch]]:
119126
"""
120127
Return a list of all the matched functions. Each element of the list is a tuple containing
121128
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
124131
:return: list of tuple, each containing the primary function, the secondary function and
125132
the FunctionMatch object
126133
"""
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+
]
129138

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]:
131142
bbs = []
132143
for bb_addr, bb in function.items():
133144
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:
135147
bbs.append(bb)
136148
else:
137149
bbs.append(bb)
138150
return bbs
139151

140-
def primary_unmatched_basic_block(self, function: FunctionBinExport) -> list[BasicBlockBinExport]:
152+
def primary_unmatched_basic_block(
153+
self, function: FunctionBinExport
154+
) -> list[BasicBlockBinExport]:
141155
"""
142156
Return a list of the unmatched basic blocks in the provided function.
143157
The function must be part of the primary program.
144-
158+
145159
:param function: A function of the primary program
146160
:return: list of unmatched basic blocks
147161
"""
148162
return self._unmatched_bbs(function, self.primary_basicblock_match)
149163

150-
def secondary_unmatched_basic_block(self, function: FunctionBinExport) -> list[BasicBlockBinExport]:
164+
def secondary_unmatched_basic_block(
165+
self, function: FunctionBinExport
166+
) -> list[BasicBlockBinExport]:
151167
"""
152168
Return a list of the unmatched basic blocks in the provided function.
153169
The function must be part of the secondary program.
154-
170+
155171
:param function: A function of the secondary program
156172
:return: list of unmatched basic blocks
157173
"""
158174
return self._unmatched_bbs(function, self.secondary_basicblock_match)
159175

160-
def iter_basicblock_matches(self,
161-
function1: FunctionBinExport,
162-
function2: FunctionBinExport
176+
def iter_basicblock_matches(
177+
self, function1: FunctionBinExport, function2: FunctionBinExport
163178
) -> list[tuple[BasicBlockBinExport, BasicBlockBinExport, BasicBlockMatch]]:
164179
"""
165180
Return a list of all the matched basic blocks between the two provided functions.
166181
Each element of the list is a tuple containing the basic blocks of the primary and secondary
167182
functions and the BasicBlockMatch object describing the match.
168183
The first function must be part of the primary program while the second function must be
169184
part of the secondary program.
170-
185+
171186
:param function1: A function of the primary program
172187
:param function2: A function of the secondary program
173188
:return: list of tuple, each containing the primary basic block, the secondary basic block
@@ -180,7 +195,9 @@ def iter_basicblock_matches(self,
180195
items.append((bb, function2[match.address2], match))
181196
return items
182197

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]:
184201
instrs = []
185202
for addr, instr in bb.instructions.items():
186203
if addr not in map:
@@ -191,31 +208,34 @@ def primary_unmatched_instruction(self, bb: BasicBlockBinExport) -> list[Instruc
191208
"""
192209
Return a list of the unmatched instructions in the provided basic block.
193210
The basic block must be part of the primary program.
194-
211+
195212
:param bb: A basic block belonging to the primary program
196213
:return: list of unmatched instructions
197214
"""
198215
return self._unmatched_instrs(bb, self.primary_instruction_match)
199216

200-
def secondary_unmatched_instruction(self, bb: BasicBlockBinExport) -> list[InstructionBinExport]:
217+
def secondary_unmatched_instruction(
218+
self, bb: BasicBlockBinExport
219+
) -> list[InstructionBinExport]:
201220
"""
202221
Return a list of the unmatched instructions in the provided basic block.
203222
The basic block must be part of the secondary program.
204-
223+
205224
:param bb: A basic block belonging to the secondary program
206225
:return: list of unmatched instructions
207226
"""
208227
return self._unmatched_instrs(bb, self.secondary_instruction_match)
209228

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]]:
212232
"""
213233
Return a list of all the matched instructions between the two provided basic blocks.
214234
Each element of the list is a tuple containing the instructions of the primary and secondary
215235
basic blocks.
216236
The first basic block must belong to the primary program while the second one must be
217237
part of the secondary program.
218-
238+
219239
:param block1: A basic block belonging to the primary program
220240
:param block2: A basic block belonging to the secondary program
221241
:return: list of tuple, each containing the primary instruction and the secondary instruction
@@ -226,10 +246,12 @@ def iter_instruction_matches(self, block1: BasicBlockBinExport,
226246
insts.append((instr, block2.instructions[addr2]))
227247
return insts
228248

229-
def get_match(self, function: FunctionBinExport) -> tuple[FunctionBinExport, FunctionMatch] | None:
249+
def get_match(
250+
self, function: FunctionBinExport
251+
) -> tuple[FunctionBinExport, FunctionMatch] | None:
230252
"""
231253
Get the function that matches the provided one.
232-
254+
233255
:param function: A function that belongs either to primary or secondary
234256
:return: A tuple with the matched function and the match object if there is a match for
235257
the provided function, otherwise None
@@ -268,10 +290,12 @@ def raw_diffing(p1_path: Union[Path, str], p2_path: Union[Path, str], out_diff:
268290
f1 = Path(p1_path)
269291
f2 = Path(p2_path)
270292

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+
]
275299

276300
logging.debug(f"run diffing: {' '.join(cmd_line)}")
277301
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:
301325
return True
302326

303327
@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"]:
305329
"""
306330
Diff two executable files. Thus it export .BinExport files from IDA
307331
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
324348
return None
325349

326350
@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"]:
328354
"""
329355
Diff two binexport files. Diff the two binexport files with bindiff
330356
and then load a BinDiff instance.
@@ -346,8 +372,10 @@ def _configure_bindiff_path() -> None:
346372
if not _check_environ():
347373
if not _check_default_path():
348374
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+
)
351379

352380
@staticmethod
353381
def assert_installation_ok() -> None:

0 commit comments

Comments
 (0)