Files
notiMessage/reverse/scripts/scan_tng.py
mars 609635aba1 chore: 备份 TNG 注册/captcha 逆向与 MariBank SG bypass 进展
TngRootBypassHook 增强 captcha 诊断、TigerTally/JNIC 分层与 HWUI 策略;新增逆向脚本、Frida 工具与 UI dump;同步 MariBank SG hook 与 tng_exit_guard 更新。
2026-08-03 15:23:02 +08:00

95 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
"""Scan TNG eWallet APK for AppProtect / root detection artifacts."""
import re
import sys
import zipfile
KEYS = [
b"AppProtect", b"appprotect", b"vkey", b"V-Key", b"VKey", b"VGuard",
b"jailbroken", b"Jailbroken", b"Rooted Device", b"rooted device",
b"Close app", b"tngdigital", b"TNG eWallet", b"How to keep device safe",
b"enhanced our security", b"RootBeer", b"SafetyNet", b"PlayIntegrity",
b"detectRoot", b"isRooted", b"checkRoot", b"magisk", b"xposed", b"lsposed",
b"frida", b"emulator", b"su binary", b"/system/xbin/su",
]
CLASS_KEYS = [
b"safemode", b"SafeMode", b"appprotect", b"AppProtect", b"vkey", b"VKey",
b"vguard", b"VGuard", b"rooted", b"RootBeer", b"integrity", b"jailbreak",
b"security", b"RiskDevice", b"tamper", b"hook", b"frida",
]
def scan_strings(apk_path):
print("=== STRING SCAN: %s ===" % apk_path)
with zipfile.ZipFile(apk_path) as zf:
for name in sorted(zf.namelist()):
if not name.endswith(".dex"):
continue
data = zf.read(name)
hits = []
for key in KEYS:
start = 0
while True:
idx = data.find(key, start)
if idx < 0:
break
s = max(0, idx - 60)
e = min(len(data), idx + len(key) + 100)
chunk = re.sub(rb"[^\x20-\x7e]+", b" ", data[s:e])
chunk = chunk.decode("ascii", "ignore").strip()
if chunk and chunk not in hits:
hits.append(chunk)
start = idx + 1
if hits:
print("\n--- %s (%d hits) ---" % (name, len(hits)))
for h in sorted(set(hits))[:40]:
print(" ", h)
if len(hits) > 40:
print(" ... +%d more" % (len(hits) - 40))
def scan_classes(apk_path):
print("\n=== CLASS SCAN: %s ===" % apk_path)
with zipfile.ZipFile(apk_path) as zf:
for name in sorted(zf.namelist()):
if not name.endswith(".dex"):
continue
data = zf.read(name)
classes = set(re.findall(rb"L[a-zA-Z0-9_$/]+;", data))
hits = []
for raw in classes:
low = raw.lower()
if any(k.lower() in low for k in CLASS_KEYS):
s = raw.decode("ascii", "ignore")[1:-1].replace("/", ".")
hits.append(s)
if hits:
print("\n--- %s (%d classes) ---" % (name, len(hits)))
for h in sorted(set(hits))[:60]:
print(" ", h)
if len(hits) > 60:
print(" ... +%d more" % (len(hits) - 60))
def scan_native(apk_path):
print("\n=== NATIVE LIB SCAN: %s ===" % apk_path)
with zipfile.ZipFile(apk_path) as zf:
for name in sorted(zf.namelist()):
if not name.endswith(".so"):
continue
data = zf.read(name)
lib = name.split("/")[-1]
found = []
for key in KEYS + [b"libvos", b"libvkey", b"libvguard", b"libappprotect"]:
if key.lower() in data.lower():
found.append(key.decode("ascii", "ignore"))
if found:
print(" %s: %s" % (lib, ", ".join(sorted(set(found)))))
if __name__ == "__main__":
path = sys.argv[1] if len(sys.argv) > 1 else "reverse/apks/tng/base.apk"
scan_strings(path)
scan_classes(path)
scan_native(path)