#!/usr/bin/env python3 # -*- coding: utf-8 -*- """对比两个 dex 的 class_defs:类名 + access_flags(重点看 ACC_INTERFACE 0x200)。 用途:验证 baksmali -> smali 整树往返是否损伤了 dex 的 interface/class 关系。 ICCE "Found interface X, but class was expected" 就是这类损伤的典型症状。 用法:python dex_classdiff.py [过滤子串] """ import struct import sys 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): off = struct.unpack(' 3 else None A = class_map(a) B = class_map(b) print('A classes=%d B classes=%d' % (len(A), len(B))) only_a = sorted(set(A) - set(B)) only_b = sorted(set(B) - set(A)) print('only_in_A=%d only_in_B=%d' % (len(only_a), len(only_b))) for n in only_a[:10]: print(' A-only:', n) for n in only_b[:10]: print(' B-only:', n) diff_iface = [] diff_flags = [] for name in sorted(set(A) & set(B)): fa, fb = A[name], B[name] ia, ib = bool(fa & 0x200), bool(fb & 0x200) if ia != ib: diff_iface.append((name, hex(fa), hex(fb))) elif fa != fb: diff_flags.append((name, hex(fa), hex(fb))) print('\n*** ACC_INTERFACE mismatch: %d ***' % len(diff_iface)) for name, fa, fb in (diff_iface if not filt else [x for x in diff_iface if filt in x[0]]): print(' %-70s A=%s B=%s' % (name, fa, fb)) print('\naccess_flags diff (same interface-ness): %d' % len(diff_flags)) shown = 0 for name, fa, fb in diff_flags: if filt and filt not in name: continue if shown < 25: print(' %-70s A=%s B=%s' % (name, fa, fb)) shown += 1 if __name__ == '__main__': main()