#!/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()