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:
110
reverse/scripts/dump_tng_nativelib_methods.py
Normal file
110
reverse/scripts/dump_tng_nativelib_methods.py
Normal file
@@ -0,0 +1,110 @@
|
||||
"""Minimal DEX parser: dump methods for target classes."""
|
||||
import struct
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
TARGET = {
|
||||
"Lcom/tngd/networksdk/common/NativeLib;",
|
||||
"Lcom/tngd/networksdk/common/ApiSixSecretKeys;",
|
||||
"Lmy/com/tngdigital/common/internal/libs/RetrieveFromNativeLibs;",
|
||||
}
|
||||
|
||||
|
||||
def uleb(data, i):
|
||||
result = 0
|
||||
shift = 0
|
||||
while True:
|
||||
b = data[i]
|
||||
i += 1
|
||||
result |= (b & 0x7F) << shift
|
||||
if (b & 0x80) == 0:
|
||||
break
|
||||
shift += 7
|
||||
return result, i
|
||||
|
||||
|
||||
def parse_dex(data: bytes, label: str):
|
||||
if data[:4] != b"dex\n":
|
||||
return
|
||||
string_ids_size, string_ids_off = struct.unpack_from("<II", data, 56)
|
||||
type_ids_size, type_ids_off = struct.unpack_from("<II", data, 64)
|
||||
proto_ids_size, proto_ids_off = struct.unpack_from("<II", data, 72)
|
||||
field_ids_size, field_ids_off = struct.unpack_from("<II", data, 80)
|
||||
method_ids_size, method_ids_off = struct.unpack_from("<II", data, 88)
|
||||
class_defs_size, class_defs_off = struct.unpack_from("<II", data, 96)
|
||||
|
||||
def string_at(idx):
|
||||
off = struct.unpack_from("<I", data, string_ids_off + idx * 4)[0]
|
||||
size, p = uleb(data, off)
|
||||
return data[p : p + size].decode("utf-8", "replace")
|
||||
|
||||
def type_at(idx):
|
||||
return string_at(struct.unpack_from("<I", data, type_ids_off + idx * 4)[0])
|
||||
|
||||
def proto_at(idx):
|
||||
shorty_idx, return_type_idx, parameters_off = struct.unpack_from(
|
||||
"<III", data, proto_ids_off + idx * 12
|
||||
)
|
||||
ret = type_at(return_type_idx)
|
||||
params = []
|
||||
if parameters_off:
|
||||
size = struct.unpack_from("<I", data, parameters_off)[0]
|
||||
for i in range(size):
|
||||
tidx = struct.unpack_from("<H", data, parameters_off + 4 + i * 2)[0]
|
||||
params.append(type_at(tidx))
|
||||
return ret, params
|
||||
|
||||
def method_at(idx):
|
||||
class_idx, proto_idx, name_idx = struct.unpack_from(
|
||||
"<HHI", data, method_ids_off + idx * 8
|
||||
)
|
||||
ret, params = proto_at(proto_idx)
|
||||
return type_at(class_idx), string_at(name_idx), ret, params
|
||||
|
||||
print(f"\n===== {label} =====")
|
||||
for c in range(class_defs_size):
|
||||
class_idx, access_flags, superclass_idx, interfaces_off, source_file_idx, annotations_off, class_data_off, static_values_off = struct.unpack_from(
|
||||
"<IIIIIIII", data, class_defs_off + c * 32
|
||||
)
|
||||
cname = type_at(class_idx)
|
||||
if cname not in TARGET:
|
||||
continue
|
||||
print(f"\nCLASS {cname} access=0x{access_flags:x}")
|
||||
if not class_data_off:
|
||||
print(" (no class_data)")
|
||||
continue
|
||||
p = class_data_off
|
||||
static_fields_size, p = uleb(data, p)
|
||||
instance_fields_size, p = uleb(data, p)
|
||||
direct_methods_size, p = uleb(data, p)
|
||||
virtual_methods_size, p = uleb(data, p)
|
||||
# skip fields
|
||||
for _ in range(static_fields_size + instance_fields_size):
|
||||
_, p = uleb(data, p)
|
||||
_, p = uleb(data, p)
|
||||
mid = 0
|
||||
for kind, count in (("direct", direct_methods_size), ("virtual", virtual_methods_size)):
|
||||
mid = 0
|
||||
for _ in range(count):
|
||||
diff, p = uleb(data, p)
|
||||
access, p = uleb(data, p)
|
||||
code_off, p = uleb(data, p)
|
||||
mid += diff
|
||||
cls, name, ret, params = method_at(mid)
|
||||
flags = []
|
||||
if access & 0x100:
|
||||
flags.append("native")
|
||||
if access & 0x8:
|
||||
flags.append("static")
|
||||
if access & 0x10000:
|
||||
flags.append("constructor")
|
||||
print(f" [{kind}] {' '.join(flags)} {name}({', '.join(params)}){ret} code=0x{code_off:x}")
|
||||
|
||||
|
||||
apk = Path(r"C:\Users\Administrator\Desktop\notiMessage\reverse\apks\tng\base.apk")
|
||||
with zipfile.ZipFile(apk) as z:
|
||||
for n in z.namelist():
|
||||
if n.endswith(".dex"):
|
||||
data = z.read(n)
|
||||
if any(t.encode() in data for t in ("NativeLib;", "ApiSixSecretKeys;", "RetrieveFromNativeLibs;")):
|
||||
parse_dex(data, n)
|
||||
Reference in New Issue
Block a user