'use strict'; function emit(row) { try { send(row); } catch (e) {} } const seen = {}; setTimeout(() => { let addr = null; try { for (const m of Process.enumerateModules()) { if (m.name !== 'libart.so') continue; const syms = m.enumerateSymbols(); for (const sm of syms) { if (sm.name.indexOf('RegisterNatives') >= 0) { addr = sm.address; break; } } } } catch (e) {} if (addr === null) { emit({ event: 'rn-err', msg: 'no sym' }); return; } emit({ event: 'rn-hooked', at: addr }); Interceptor.attach(addr, { onEnter(args) { try { const cls = args[1]; const methods = args[2]; const n = args[3].toInt32(); if (n <= 0 || n > 500) return; // 读 class 名 (jclass -> 从 vtable 附近读太复杂, 只读方法表) const rows = []; for (let i = 0; i < n; i++) { const off = methods.add(i * 24); const namePtr = off.readPointer(); const sigPtr = off.add(8).readPointer(); const fnPtr = off.add(16).readPointer(); const mod = Process.findModuleByAddress(fnPtr); const name = namePtr.readUtf8String(80) || '?'; const sig = sigPtr.readUtf8String(80) || '?'; rows.push({ name: name.length > 60 ? name.slice(0, 60) : name, sig: sig.length > 50 ? sig.slice(0, 50) : sig, impl: (mod ? mod.name + '!' + fnPtr.sub(mod.base) : fnPtr.toString()), }); } const key = rows.map(r => r.name + r.impl).join('|'); if (!seen[key]) { seen[key] = true; emit({ event: 'rn-table', n, rows: rows.slice(0, 60) }); } } catch (e) { emit({ event: 'rn-err', msg: String(e).slice(0, 120) }); } }, }); }, 1500);