#!/usr/bin/env python3 import argparse import colorama import difflib import subprocess import os import sys parser = argparse.ArgumentParser(allow_abbrev=False, description='Verify Exports: Compare the exports of two DLLs.') parser.add_argument('original', metavar='original-binary', help='The original binary') parser.add_argument('recompiled', metavar='recompiled-binary', help='The recompiled binary') parser.add_argument('--no-color', '-n', action='store_true', help='Do not color the output') args = parser.parse_args() if not os.path.isfile(args.original): parser.error('Original binary does not exist') if not os.path.isfile(args.recompiled): parser.error('Recompiled binary does not exist') def get_file_in_script_dir(fn): return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn) def get_exports(file): call = [get_file_in_script_dir('DUMPBIN.EXE'), '/EXPORTS'] if os.name != 'nt': call.insert(0, 'wine') file = subprocess.check_output(['winepath', '-w', file]).decode('utf-8').strip() call.append(file) raw = subprocess.check_output(call).decode('utf-8').split('\r\n') exports = [] start = False for line in raw: if not start: if line == ' ordinal hint name': start = True else: if line: exports.append(line[27:line.rindex(' (')]) elif exports: break return exports og_exp = get_exports(args.original) re_exp = get_exports(args.recompiled) udiff = difflib.unified_diff(og_exp, re_exp) has_diff = False for line in udiff: has_diff = True if line.startswith("++") or line.startswith("@@") or line.startswith("--"): # Skip unneeded parts of the diff for the brief view pass elif line.startswith("+"): if args.no_color: print(line) else: print(colorama.Fore.GREEN + line) elif line.startswith("-"): if args.no_color: print(line) else: print(colorama.Fore.RED + line) else: print(line) if not args.no_color: print(colorama.Style.RESET_ALL, end='') if has_diff: sys.exit(1) else: sys.exit(0)