Files
live-hub-py/scripts/phone_probe_rn_all.py
T
yml2213 70621cff8f feat(huya): unidbg 金测试打通 - 采集器加密可复现(androidId=PDSuHx..)/GUID=0a7dfa..一致
- 输入图定案: 库内零硬件文件读, 种子=ANDROID_ID+服务端hydeviceid_config+MID, 属性层无关(X1/X2)
- 真机全段解密 dump(phone_dump_hydev_full) + merge_decrypted 合入原文件 → unidbg 可直接加载
- unidbg(JDK21+patch) harness: JNI 桩(SharedPreferences日志化/Settings.Secure/NativeBridge)
  金测试: androidId 加密态与 getGUID 全部与真机一致
- 遗留: NativeBridge.b(100) 原生归属库未定(非hydeviceid/udb/device-util), 当前桩替顶
- 修正结论: '单机不可铸造'判断错误, GUID=b(100)=f(androidId密, config, MID) 输入全可控
2026-08-28 16:06:25 +08:00

126 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""真机: dlopen 拦截所有目标库, JNI_OnLoad 入口挂 RegisterNatives 钩子,
抓 NativeBridge.klog/b 等全部 native 注册归属(库+偏移).
用法: python3 scripts/phone_probe_rn_all.py [serial] [remote]
"""
from __future__ import annotations
import json, subprocess, sys, time
from pathlib import Path
import frida
SERIAL = sys.argv[1] if len(sys.argv) > 1 else "5dd8c93f"
REMOTE = sys.argv[2] if len(sys.argv) > 2 else "127.0.0.1:31878"
PACKAGE = "com.duowan.kiwi"
RE = Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
ART_CALLSITE = RE / "evidence" / "scripts" / "bypass_msaoaid_maps_art_callsite.js"
JS = r"""
'use strict';
function jmod(a){
try{ var m = Process.findModuleByAddress(a); return m ? {n:m.name, off:'0x'+a.sub(m.base).toString(16)} : {n:'?',off:'?'}; }catch(e){ return {n:'?',off:'?'}; }
}
var rnHooked = false;
function hookRN(){
if(rnHooked) return;
try{
var env = Java.vm.tryGetEnv();
if(!env) return;
var fns = env.handle.readPointer();
var rn = fns.add(215 * Process.pointerSize).readPointer();
if(rn.isNull()) return;
Interceptor.attach(rn, {
onEnter: function(args){
var methods = args[3];
var count = args[4].toInt32();
var mm=[];
for(var i=0;i<count;i++){
var m = methods.add(i * Process.pointerSize * 3);
try{
var name = m.readPointer().readCString();
var sig = m.add(Process.pointerSize).readPointer().readCString();
var fnp = m.add(Process.pointerSize*2).readPointer();
var jm = jmod(fnp);
mm.push({name:name, sig:sig, mod:jm.n, off:jm.off});
}catch(e){}
}
send({type:'rn', methods:mm, tid:Process.getCurrentThreadId()});
}
});
rnHooked = true;
send({type:'rn-hooked'});
}catch(e){ send({type:'err', e:String(e).slice(0,120)}); }
}
setInterval(hookRN, 100);
// 目标库加载即挂 JNI_OnLoad
var TARGETS = ['libhydeviceid', 'libudbauthunify', 'libudb'];
var loaded = {};
function hookLib(md){
if(loaded[''+md.base]) return;
loaded[''+md.base] = true;
var jni = md.findExportByName('JNI_OnLoad');
if(!jni) return;
var name = md.name;
send({type:'lib', name:name, base:''+md.base});
Interceptor.attach(jni, {
onEnter: function(){ send({type:'ol-enter', lib:name}); hookRN(); },
onLeave: function(ret){ send({type:'ol-leave', lib:name, ret:ret.toString()}); }
});
}
setInterval(function(){
Process.enumerateModules().forEach(function(md){
for(var i=0;i<TARGETS.length;i++){
if(md.name.indexOf(TARGETS[i]) >= 0){ hookLib(md); break; }
}
});
}, 100);
"""
def adb(*a):
return subprocess.run(["adb", "-s", SERIAL, *a], capture_output=True, text=True)
def main():
adb("shell", "am", "force-stop", PACKAGE)
time.sleep(1.5)
d = frida.get_device_manager().add_remote_device(REMOTE)
pid = d.spawn([PACKAGE])
print(f"[*] spawn {pid}", flush=True)
s = d.attach(pid)
s.create_script(ART_CALLSITE.read_text()).load()
seen = set()
regs = []
def on_m(m, data):
p = m.get("payload") or {}
t = p.get("type")
if t == "rn":
for mm in p.get("methods", []):
k = (mm["name"], mm["sig"], mm["mod"], mm["off"])
if k not in seen:
seen.add(k)
regs.append(mm)
print(f"[RN] {mm['name']} {mm['sig']} @ {mm['mod']} {mm['off']}", flush=True)
elif t in ("rn-hooked",):
print("[*] rn-hooked", flush=True)
elif t == "lib":
print(f"[*] lib {p['name']} base={p['base']}", flush=True)
elif t in ("ol-enter", "ol-leave"):
print(f"[*] {t} {p.get('lib')} {p.get('ret','')}", flush=True)
elif t == "err":
print("[!]", p, flush=True)
elif m.get("type") == "error":
print("[JS-ERR]", m.get("description")[:120], flush=True)
sc = s.create_script(JS)
sc.on("message", on_m)
sc.load()
d.resume(pid)
time.sleep(20)
print(f"[*] total unique: {len(regs)}")
if __name__ == "__main__":
main()