chore: 备份 TNG 注册/captcha 逆向与 MariBank SG bypass 进展

TngRootBypassHook 增强 captcha 诊断、TigerTally/JNIC 分层与 HWUI 策略;新增逆向脚本、Frida 工具与 UI dump;同步 MariBank SG hook 与 tng_exit_guard 更新。
This commit is contained in:
mars
2026-08-03 15:23:02 +08:00
parent 193c04a24b
commit 609635aba1
185 changed files with 60843 additions and 231 deletions

View File

@@ -0,0 +1,167 @@
#!/usr/bin/env python3
"""Race-window: dump TNG executable maps and hunt kill+SVC after launch."""
import re
import subprocess
import sys
import time
from pathlib import Path
ADB = r"C:\Users\Administrator\AppData\Local\Android\Sdk\platform-tools\adb.exe"
PKG = "my.com.tngdigital.ewallet"
OUT = Path(__file__).resolve().parents[1] / "dumps" / "tng_runtime"
OUT.mkdir(parents=True, exist_ok=True)
# aarch64 movz x8/w8,#129/130/131 + svc #0
KILL_IMMS = [
bytes.fromhex("281080d2"),
bytes.fromhex("28108052"),
bytes.fromhex("481080d2"),
bytes.fromhex("48108052"),
bytes.fromhex("681080d2"),
bytes.fromhex("68108052"),
]
SVC0 = bytes.fromhex("010000d4")
EXIT_IMM = bytes.fromhex("c80b80d2") # movz x8,#94 exit_group
EXIT2 = bytes.fromhex("ba0b80d2") # movz x8,#93 exit
def adb(*args, check=False):
r = subprocess.run([ADB, *args], capture_output=True)
out = (r.stdout or b"") + (r.stderr or b"")
if check and r.returncode != 0:
raise RuntimeError(out.decode("utf-8", "ignore"))
return r.returncode, out.decode("utf-8", "replace")
def su(cmd):
return adb("shell", f"su -c '{cmd}'")
def main():
adb("shell", "am", "force-stop", PKG)
time.sleep(0.5)
adb("shell", "monkey", "-p", PKG, "-c", "android.intent.category.LAUNCHER", "1")
pid = None
for _ in range(40):
time.sleep(0.25)
_, out = adb("shell", "pidof", PKG)
toks = out.strip().split()
if toks:
pid = toks[0]
break
if not pid:
print("FAIL: no pid")
return 1
print(f"pid={pid}")
# pull maps
_, maps = su(f"cat /proc/{pid}/maps")
maps_path = OUT / f"maps_{pid}.txt"
maps_path.write_text(maps, encoding="utf-8", errors="replace")
print(f"maps -> {maps_path} lines={len(maps.splitlines())}")
targets = []
for line in maps.splitlines():
if "r-xp" not in line and "r-x" not in line:
# also rw-p with execute rarely; keep x
if "x" not in line.split()[1] if len(line.split()) > 1 else "":
continue
if "tngdigital" in line or "libnative" in line or "ewallet" in line.lower():
parts = line.split()
rng = parts[0]
start_s, end_s = rng.split("-")
start, end = int(start_s, 16), int(end_s, 16)
path = parts[-1] if len(parts) >= 6 else ""
targets.append((start, end, path, line))
print(f"target segments={len(targets)}")
for start, end, path, line in targets[:12]:
print(f" {hex(start)}-{hex(end)} {path}")
# dump via dd from /proc/pid/mem
remote = f"/data/local/tmp/tng_rt_{pid}.bin"
su(f"rm -f {remote}")
total = 0
for i, (start, end, path, _) in enumerate(targets):
size = end - start
if size <= 0 or size > 32 * 1024 * 1024:
continue
# append dump
cmd = (
f"dd if=/proc/{pid}/mem bs=4096 skip={start // 4096} "
f"count={(size + 4095) // 4096} 2>/dev/null >> {remote}"
)
# dd skip is in blocks from file start — wrong for /proc/pid/mem!
# Use busybox dd with seek on output and skip via python on device instead.
cmd = (
f"toybox dd if=/proc/{pid}/mem of={remote}.p{i} "
f"bs=1 skip={start} count={size} 2>/dev/null"
)
code, _ = su(cmd)
if code == 0:
total += size
print(f" dumped p{i} size={size} from {path}")
else:
# fallback: python on device
py = (
f"python3 -c \"import sys;f=open('/proc/{pid}/mem','rb');"
f"f.seek({start});d=f.read({size});open('{remote}.p{i}','wb').write(d)\""
)
code2, out2 = su(py)
if code2 == 0:
total += size
print(f" dumped p{i} via python size={size}")
else:
print(f" FAIL dump p{i}: {out2[:120]}")
# pull pieces and scan
local_dir = OUT / f"mem_{pid}"
local_dir.mkdir(exist_ok=True)
kill_hits = 0
exit_hits = 0
for i, (start, end, path, _) in enumerate(targets):
rem = f"{remote}.p{i}"
loc = local_dir / f"seg_{i}_{start:x}.bin"
code, _ = adb("shell", f"su -c 'test -f {rem} && echo OK'")
if "OK" not in _:
continue
adb("pull", rem, str(loc))
if not loc.exists():
continue
data = loc.read_bytes()
for imm in KILL_IMMS:
pos = 0
while True:
j = data.find(imm, pos)
if j < 0:
break
win = data[j : j + 36]
if SVC0 in win:
kill_hits += 1
delta = win.find(SVC0)
print(f"KILL+SVC seg{i} file+0x{j:x} va=0x{start+j:x} delta={delta} path={path}")
pos = j + 4
for imm in (EXIT_IMM, EXIT2):
pos = 0
while True:
j = data.find(imm, pos)
if j < 0:
break
win = data[j : j + 36]
if SVC0 in win:
exit_hits += 1
if exit_hits <= 15:
print(f"EXIT+SVC seg{i} file+0x{j:x} va=0x{start+j:x} path={path}")
pos = j + 4
# also count raw svc
print(f" seg{i} svc0={data.count(SVC0)} size={len(data)}")
print(f"DONE kill+svc={kill_hits} exit+svc={exit_hits} dumped_bytes~={total}")
_, alive = adb("shell", "pidof", PKG)
print(f"still alive? {alive.strip() or 'NO'}")
return 0
if __name__ == "__main__":
sys.exit(main())