summaryrefslogtreecommitdiff
path: root/python/diffing_dex.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/diffing_dex.py')
-rw-r--r--python/diffing_dex.py226
1 files changed, 226 insertions, 0 deletions
diff --git a/python/diffing_dex.py b/python/diffing_dex.py
new file mode 100644
index 0000000..8eba15d
--- /dev/null
+++ b/python/diffing_dex.py
@@ -0,0 +1,226 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+import argparse
+import sys
+import pychrysalide
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.analysis import LoadedBinary
+from pychrysalide.analysis.diffing import BinDiff, FingerprintList
+from pychrysalide.format.dex import DexFormat
+
+
+def display_matches(matches, methods):
+ """Show the matching routines."""
+
+ routine_a_name_len = len('Routine A')
+ routine_a_addr_len = len('Phys addr.')
+ routine_b_name_len = len('Routine B')
+ routine_b_addr_len = len('Phys addr.')
+
+ # Length computing
+
+ for match in matches:
+
+ routine_name = match['routine'].label
+
+ if len(routine_name) > routine_a_name_len:
+ routine_a_name_len = len(routine_name)
+
+ phys = '0x%x' % match['routine'].range.addr.phys
+
+ if len(phys) > routine_a_addr_len:
+ routine_a_addr_len = len(phys)
+
+ matching = match['matching']
+
+ for i in range(len(matching)):
+
+ routine_name = matching[i]['other'].label
+
+ if len(routine_name) > routine_b_name_len:
+ routine_b_name_len = len(routine_name)
+
+ phys = '0x%x' % matching[i]['other'].range.addr.phys
+
+ if len(phys) > routine_b_addr_len:
+ routine_b_addr_len = len(phys)
+
+ line = ' {:<%u} | {:>%u} | {:<%u} | {:>%u} | {:^%u}' \
+ % (routine_a_name_len, routine_a_addr_len, routine_b_name_len, routine_b_addr_len, len('Similarity'))
+
+ for meth in methods:
+
+ length = len(meth.name)
+
+ line += ' | {:^%u}' % length
+
+ # Columns display
+
+ names = []
+
+ for meth in methods:
+ names.append(meth.name)
+
+ header = line.format('Routine A', 'Phys addr.', 'Routine B', 'Phys addr.', 'Similarity', *names)
+
+ print(header)
+
+ print('-' * (len(header) + 2))
+
+ # Matches display
+
+ for match in matches:
+
+ matching = match['matching']
+
+ for i in range(len(matching)):
+
+ routine_a_name = match['routine'].label if i == 0 else ''
+
+ if i == 0:
+ phys_a = '0x%x' % match['routine'].range.addr.phys
+ else:
+ phys_a = ''
+
+ routine_b_name = matching[i]['other'].label
+
+ if i == 0:
+ phys_b = '0x%x' % matching[i]['other'].range.addr.phys
+ else:
+ phys_b = ''
+
+ similarity = '%.2f' % matching[i]['similarity']
+
+ values = [ 'X' if v else '' for v in list(matching[i]['values']) ]
+
+ print(line.format(routine_a_name, phys_a, routine_b_name, phys_b, similarity, *values))
+
+
+def display_unmatches(routines):
+ """Show the unmatching routines."""
+
+ name_len = len('Routine')
+ addr_len = len('Phys addr.')
+
+ # Length computing
+
+ for r in routines:
+
+ name = r.label
+
+ if len(name) > name_len:
+ name_len = len(name)
+
+ phys = '0x%x' % r.range.addr.phys
+
+ if len(phys) > addr_len:
+ addr_len = len(phys)
+
+ line = ' {:<%u} | {:>%u}' % (name_len, addr_len)
+
+ # Columns display
+
+ header = line.format('Routine', 'Phys addr.')
+
+ print(header)
+
+ print('-' * (len(header) + 2))
+
+ # Matches display
+
+ for r in routines:
+
+ phys = '0x%x' % r.range.addr.phys
+
+ print(line.format(r.label, phys))
+
+
+if __name__ == '__main__':
+ """Entry point."""
+
+ parser = argparse.ArgumentParser(description='readdex - Displays information about DEX files.', add_help=False)
+
+ parser.add_argument('-h', '--help', action='store_true', help='Display the command line options.')
+
+ parser.add_argument('dexfile1', type=str, help='The first object file to be examined')
+ parser.add_argument('dexfile2', type=str, help='The second object file to be examined')
+
+ args = parser.parse_args()
+
+ if args.help:
+ parser.print_help()
+ sys.exit(1)
+
+ cnt = FileContent(args.dexfile1)
+ fmt = DexFormat(cnt)
+ binary1 = LoadedBinary(fmt)
+
+ binary1.analyze_and_wait()
+
+ cnt = FileContent(args.dexfile2)
+ fmt = DexFormat(cnt)
+ binary2 = LoadedBinary(fmt)
+
+ binary2.analyze_and_wait()
+
+ fingerlist1 = FingerprintList(None, binary1, True)
+ print("list 1 ok")
+ fingerlist2 = FingerprintList(None, binary2, True)
+ print("list 1 ok")
+
+ diff = BinDiff(fingerlist1, fingerlist2)
+
+ print("analyzing...")
+
+ diff.analyze_and_wait()
+
+ print()
+
+ matches = diff.single_matches
+
+ if len(matches) > 0:
+
+ print('Single match routines')
+ print('=====================')
+ print()
+
+ display_matches(matches, fingerlist1.methods)
+
+ print()
+
+ matches = diff.multi_matches
+
+ if len(matches) > 0:
+
+ print('Multi match routines')
+ print('====================')
+ print()
+
+ display_matches(matches, fingerlist1.methods)
+
+ print()
+
+ unmatched = diff.first_unmatches
+
+ if len(unmatched) > 0:
+
+ print('First binary unmatched routines')
+ print('===============================')
+ print()
+
+ display_unmatches(unmatched)
+
+ print()
+
+ unmatched = diff.second_unmatches
+
+ if len(unmatched) > 0:
+
+ print('Second binary unmatched routines')
+ print('================================')
+ print()
+
+ display_unmatches(unmatched)
+
+ print()