#!/usr/bin/env python3 """真机: 确认 getGUID 生成时是否 ioctl/openat 读底层硬件(而非属性/文件). hook libc ioctl + openat + __system_property_get, getGUID(0x20f8c8) onEnter/onLeave 设窗口, 窗口内记录调用的 ioctl(fd/request) / openat(path) / 属性读取。决定 32hex 硬件输入来源。 用法: /Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/.venv/bin/python \ scripts/phone_getguid_ioctl.py [serial] [remote] 输出: evidence/diag_phone/getguid_ioctl.json """ from __future__ import annotations import json import subprocess import sys import 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" REPO = Path("/Users/yml/codes/douyu_login_py") OUT = REPO / "evidence" / "diag_phone" / "getguid_init.json" RE = Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0") ART_CALLSITE = RE / "evidence" / "scripts" / "bypass_msaoaid_maps_art_callsite.js" GETGUID_OFF = 0x20E6E4 JS = r""" 'use strict'; var inGuid=false, hooked=false, iosHooked=false; function hookIo(){ if(iosHooked) return; try{ var ioctl = Module.findExportByName('libc.so','ioctl'); var openat = Module.findExportByName('libc.so','openat'); var open = Module.findExportByName('libc.so','open'); if(!ioctl && !openat && !open) return; iosHooked=true; if(ioctl) Interceptor.attach(ioctl,{onEnter:function(a){ if(inGuid){ try{ send({type:'ioctl', fd:a[0].toInt32(), req:a[1].toInt32()}); }catch(e){} } }}); if(openat) Interceptor.attach(openat,{onEnter:function(a){ if(inGuid){ try{ var p=a[1].readCString()||'?'; send({type:'openat', p:p}); }catch(e){} } }}); if(open) Interceptor.attach(open,{onEnter:function(a){ if(inGuid){ try{ send({type:'open', p:a[0].readCString()||'?'}); }catch(e){} } }}); send({type:'io-hooked'}); }catch(e){ send({type:'io-err', e:String(e)}); } } function hookGetGUID(){ if(hooked) return; var md=Process.findModuleByName('libhydeviceid.so'); if(!md) return; hooked=true; Interceptor.attach(md.base.add(0x20e6e4),{ // init() onEnter:function(){ inGuid=true; send({type:'g-enter'}); }, onLeave:function(){ inGuid=false; send({type:'g-leave'}); } }); send({type:'guid-hooked'}); } setInterval(hookGetGUID,200); setInterval(hookIo,200); setTimeout(function(){ Java.perform(function(){ try{ var NE=Java.use('com.huya.security.hydeviceid.NativeEntry'); send({type:'cls-ok'}); send({type:'call', v:NE['init']()}); // 主动 init }catch(e){ send({type:'java-err', e:String(e).slice(0,120)}); } }); }, 8000); """ def adb(*a): return subprocess.run(["adb", "-s", SERIAL, *a], capture_output=True, text=True) def main(): OUT.parent.mkdir(parents=True, exist_ok=True) 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={pid}", flush=True) session = d.attach(pid) det = [] session.on("detached", lambda r, dd: det.append({"reason": r, "detail": str(dd)}) or print(f"[*] detached {r} {dd}", flush=True)) session.create_script(ART_CALLSITE.read_text()).load() result = {"ioctl": [], "openat": [], "props": [], "detached": det} def on_message(m, data): if m.get("type") == "error": print("[JS-ERR]", str(m)[:200], flush=True); return p = m.get("payload") or {} t = p.get("type") if t == "ioctl": result["ioctl"].append(p); print(f"[ioctl] fd={p.get('fd')} req=0x{p.get('req'):x}", flush=True) elif t == "openat": result["openat"].append(p); print(f"[openat] {p.get('p')}", flush=True) elif t == "open": result["openat"].append(p); print(f"[open] {p.get('p')}", flush=True) elif t in ("g-enter","g-leave","guid-hooked","io-hooked","cls-ok","call"): print(f"[*] {t}", p if t=="call" else "", flush=True) elif t in ("io-err","java-err"): print(f"[!] {t}: {p.get('e')}", flush=True) sc = session.create_script(JS) sc.on("message", on_message) sc.load() d.resume(pid) print("[*] resumed", flush=True) time.sleep(9) result["detached"] = det OUT.write_text(json.dumps(result, indent=1, ensure_ascii=False), encoding="utf-8") print(f"[*] ioctl={len(result['ioctl'])} openat={len(result['openat'])} saved {OUT}") if __name__ == "__main__": main()