#!/usr/bin/env python3 """守护式抓取模拟器 32hex hdid: 持续 attach kiwi 主进程, hook getHdid/setSafeDeviceId. App 闪退/重启也不怕 —— 循环枚举进程, 遇新主进程立即 hook。 找到 hdid(≠ed0db8 或任意32hex)后写入 /tmp/emu_hdid_found.txt 并退出。 """ import time, json, sys import frida REMOTE = "127.0.0.1:31878" FOUND = "/tmp/emu_hdid_found.txt" JS = r""" 'use strict'; function readStdString(p){ if (p.isNull()) return null; try{ var first = p.readU8(); if ((first & 1) === 0) { var len = first >> 1; return (len>0 && len<256) ? p.add(1).readUtf8String(len) : ''; } else { var data = p.readPointer(); var len = p.add(8).readU64(); return (len>0 && len<1024) ? data.readUtf8String(len) : null; } }catch(e){ return null; } } function emit(t,m){ send({t:t,m:m}); } function hex32(s){ return /^[0-9a-fA-F]{32}$/.test(s||''); } var hooked=false; function tryHook(){ if(hooked) return true; var md = Process.findModuleByName('libudbauthunify.so'); if(!md) return false; emit('mod','base='+md.base); try{ Interceptor.attach(md.base.add(0x26A2E0), { onEnter:function(a){ this.sd=readStdString(a[1]); this.hd=readStdString(a[2]); }, onLeave:function(){ var hd=(this.hd||''); var sd=(this.sd||''); emit('SETSD', 'hdid='+hd+' sd='+sd.slice(0,32)); if(hex32(hd)) emit('FOUND_HDID', hd); } }); }catch(e){ emit('warn','setSd hook fail: '+e); } try{ Interceptor.attach(md.base.add(0x26A484), { onEnter:function(a){ this.thiz=a[0]; }, onLeave:function(){ try{ var s=readStdString(this.thiz.add(1088)); if(s) emit('GETHDID', ''+s); if(hex32(s)) emit('FOUND_HDID', ''+s); }catch(e){} } }); }catch(e){ emit('warn','getHdid hook fail: '+e); } emit('ready','hooked'); hooked=true; return true; } var tries=0; function poll(){ tries++; tryHook(); if(!hooked && tries<200){ setTimeout(poll, 250); } } poll(); """ def main(): dev = frida.get_device_manager().add_remote_device(REMOTE) seen = set() found_hdid = None start = time.time() while time.time() - start < 600: procs = [] try: procs = dev.enumerate_processes() except Exception: time.sleep(2); continue for p in procs: if not p.name or 'kiwi' not in p.name: continue if ':cloudpatch' in p.name or ':logcat' in p.name: continue if p.pid in seen: continue seen.add(p.pid) print(f"[{time.strftime('%H:%M:%S')}] 新主进程 pid={p.pid} {p.name},attach中...", flush=True) try: session = dev.attach(p.pid) except Exception as e: print(f" attach失败: {e}", flush=True) continue def on_msg(msg, data, pid=p.pid): global found_hdid if msg.get('type') == 'send': pl = msg['payload'] t, m = pl['t'], pl['m'] if t == 'FOUND_HDID': print(f"\n★★★★★★ 模拟器 hdid = {m} ★★★★★★", flush=True) with open(FOUND, 'w') as f: f.write(m) return print(f"[pid {pid}][{t}] {m}", flush=True) elif msg.get('type') == 'error': print(f"[pid {pid}] JSErr: {str(msg)[:150]}", flush=True) try: sc = session.create_script(JS) sc.on('message', on_msg) sc.load() print(f" hook 已装 (pid {pid})", flush=True) except Exception as e: print(f" script失败: {e}", flush=True) time.sleep(1.5) print("10分钟超时结束", flush=True) if __name__ == "__main__": main()