summaryrefslogtreecommitdiff
path: root/python/diffing_elf.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/diffing_elf.py')
-rw-r--r--python/diffing_elf.py222
1 files changed, 222 insertions, 0 deletions
diff --git a/python/diffing_elf.py b/python/diffing_elf.py
new file mode 100644
index 0000000..ccaaaa1
--- /dev/null
+++ b/python/diffing_elf.py
@@ -0,0 +1,222 @@
+#!/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.elf import ElfFormat
+
+
+def display_matches(matches, methods):
+ """Show the matching routines."""
+
+ routine_a_name_len = len('Routine A')
+ routine_a_addr_len = len('Virt addr.')
+ routine_b_name_len = len('Routine B')
+ routine_b_addr_len = len('Virt 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)
+
+ virt = '0x%x' % match['routine'].range.addr.virt
+
+ if len(virt) > routine_a_addr_len:
+ routine_a_addr_len = len(virt)
+
+ 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)
+
+ virt = '0x%x' % matching[i]['other'].range.addr.virt
+
+ if len(virt) > routine_b_addr_len:
+ routine_b_addr_len = len(virt)
+
+ 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', 'Virt addr.', 'Routine B', 'Virt 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:
+ virt_a = '0x%x' % match['routine'].range.addr.virt
+ else:
+ virt_a = ''
+
+ routine_b_name = matching[i]['other'].label
+
+ if i == 0:
+ virt_b = '0x%x' % matching[i]['other'].range.addr.virt
+ else:
+ virt_b = ''
+
+ similarity = '%.2f' % matching[i]['similarity']
+
+ values = [ 'X' if v else '' for v in list(matching[i]['values']) ]
+
+ print(line.format(routine_a_name, virt_a, routine_b_name, virt_b, similarity, *values))
+
+
+def display_unmatches(routines):
+ """Show the unmatching routines."""
+
+ name_len = len('Routine')
+ addr_len = len('Virt addr.')
+
+ # Length computing
+
+ for r in routines:
+
+ name = r.label
+
+ if len(name) > name_len:
+ name_len = len(name)
+
+ virt = '0x%x' % r.range.addr.virt
+
+ if len(virt) > addr_len:
+ addr_len = len(virt)
+
+ line = ' {:<%u} | {:>%u}' % (name_len, addr_len)
+
+ # Columns display
+
+ header = line.format('Routine', 'Virt addr.')
+
+ print(header)
+
+ print('-' * (len(header) + 2))
+
+ # Matches display
+
+ for r in routines:
+
+ virt = '0x%x' % r.range.addr.virt
+
+ print(line.format(r.label, virt))
+
+
+if __name__ == '__main__':
+ """Entry point."""
+
+ parser = argparse.ArgumentParser(description='readelf - Displays information about ELF files.', add_help=False)
+
+ parser.add_argument('-h', '--help', action='store_true', help='Display the command line options.')
+
+ parser.add_argument('elffile1', type=str, help='The first object file to be examined')
+ parser.add_argument('elffile2', 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.elffile1)
+ fmt = ElfFormat(cnt)
+ binary1 = LoadedBinary(fmt)
+
+ binary1.analyze_and_wait()
+
+ cnt = FileContent(args.elffile2)
+ fmt = ElfFormat(cnt)
+ binary2 = LoadedBinary(fmt)
+
+ binary2.analyze_and_wait()
+
+ fingerlist1 = FingerprintList(None, binary1, True)
+ fingerlist2 = FingerprintList(None, binary2, True)
+
+ diff = BinDiff(fingerlist1, fingerlist2)
+
+ 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()