TngRootBypassHook 增强 captcha 诊断、TigerTally/JNIC 分层与 HWUI 策略;新增逆向脚本、Frida 工具与 UI dump;同步 MariBank SG hook 与 tng_exit_guard 更新。
104 lines
3.6 KiB
Python
104 lines
3.6 KiB
Python
#!/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()
|