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