#!/usr/bin/env python3 """Deeper TNG reverse: Exiting/Report, TigerTally API, kill-SVC in SO.""" from pathlib import Path import re import struct ROOT = Path(__file__).resolve().parents[2] APK_DIR = ROOT / "reverse" / "apks" / "tng" SO = APK_DIR / "libtngdigital_ewallet.so" def load_dexes(): files = sorted(APK_DIR.glob("classes*.dex")) if not files: # try extracted under other layouts files = sorted((ROOT / "reverse" / "apks").rglob("tng*/classes*.dex")) return files def near(data, needle, before=40, after=80): out = [] for m in re.finditer(re.escape(needle), data): s = max(0, m.start() - before) e = min(len(data), m.end() + after) chunk = data[s:e] printable = "".join(chr(b) if 32 <= b < 127 else "." for b in chunk) out.append(printable) return out def main(): dexes = load_dexes() print(f"dex count={len(dexes)}") all_data = b"" for d in dexes: data = d.read_bytes() all_data += data hits = [] for k in [b"Exiting:", b"Exiting", b"Report", b"W: 16", b"W:16", b"TigerTallyAPI", b"ttInit", b"collect", b"killProcess", b"SIGABRT", b"abort(", b"tgkill"]: c = data.count(k) if c: hits.append(f"{k.decode('latin1')}x{c}") if hits: print(f"{d.name}: {', '.join(hits)}") print("\n=== near Exiting ===") for s in near(all_data, b"Exiting")[:15]: print(" ", s) print("\n=== TigerTallyAPI method refs ===") for m in sorted(set(re.findall(rb"Lcom/aliyun/TigerTally/TigerTallyAPI;->[A-Za-z0-9_<>$]+", all_data))): print(" ", m.decode()) print("\n=== TigerTally t/ classes ===") for m in sorted(set(re.findall(rb"Lcom/aliyun/TigerTally/[a-z]/[A-Za-z0-9_/$]*;", all_data))): print(" ", m.decode()) print("\n=== xwwqazamx/bl method refs ===") for m in sorted(set(re.findall(rb"Lxwwqazamx/bl;->[A-Za-z0-9_<>$]+", all_data)))[:40]: print(" ", m.decode()) print("\n=== Process.killProcess / Runtime.exit refs near Promon ===") for pat in [rb"Landroid/os/Process;->killProcess", rb"Ljava/lang/System;->exit", rb"Ljava/lang/Runtime;->exit", rb"Ljava/lang/Runtime;->halt"]: print(pat.decode(), "count=", len(re.findall(pat, all_data))) if SO.exists(): so = SO.read_bytes() print(f"\n=== SO {SO.name} size={len(so)} ===") # movz x8,#129 = D2801028 LE patterns = { "movz_x8_129": bytes.fromhex("281080d2"), "movz_w8_129": bytes.fromhex("28108052"), "movz_x8_130": bytes.fromhex("481080d2"), "movz_x8_131": bytes.fromhex("681080d2"), "svc0": bytes.fromhex("010000d4"), "brk0": bytes.fromhex("000020d4"), } for name, pat in patterns.items(): print(f" {name}: {so.count(pat)}") # find movz kill + nearby svc within 32 bytes kill_imm = [bytes.fromhex(x) for x in ("281080d2", "28108052", "481080d2", "681080d2")] svc = bytes.fromhex("010000d4") found = 0 for imm in kill_imm: start = 0 while True: i = so.find(imm, start) if i < 0: break window = so[i:i+36] if svc in window: found += 1 if found <= 20: off = window.find(svc) print(f" kill+svc @ file+0x{i:x} svc_delta={off}") start = i + 4 print(f" kill+svc pairs (packed): {found}") else: print(f"\nSO missing: {SO}") if __name__ == "__main__": main()