#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Diff two dex files at the class_defs level: class names + access_flags. The interesting flag is ACC_INTERFACE (0x200). Use it to prove that a disassemble -> reassemble round-trip did not damage the dex's interface/class relationships. The classic symptom of that damage is IncompatibleClassChangeError ("Found interface X, but class was expected") at runtime. Important limitation: this check compares tables only. It cannot see code-item damage — see references/patch-audit.md for the checks that can. """ import argparse import struct import sys ACC_INTERFACE = 0x200 def uleb128(data, off): result = 0 shift = 0 while True: b = data[off] off += 1 result |= (b & 0x7F) << shift if not (b & 0x80): break shift += 7 return result, off def read_strings(data): strings_size = struct.unpack('= args.max_flags: print(' ... (%d more suppressed)' % (len(diff_flags) - shown)) break print(' %-70s A=%s B=%s' % (name, hex(fa), hex(fb))) shown += 1 # Exit non-zero when a structural difference exists, so a caller can gate on it. verdict = (len(only_a) == 0 and len(only_b) == 0 and len(diff_iface) == 0) print('\nverdict: %s' % ('class tables identical' if verdict else 'STRUCTURAL DIFFERENCE — inspect above')) return 0 if verdict else 1 if __name__ == '__main__': sys.exit(main())