#!/usr/bin/env python3 """复现实验: attach + 只读 Interceptor 是否让 msaoaidsec 检测失效 (App 存活). 假设: 空 attach (E0) 2s 静默死; attach+trace的只读 Interceptor 装到 msaoaidsec 内 (+0x1bfac 线程名检测器入口 / +0x1c0e4,0x1c0f8 strstr callsite) 后 App 存活. 实验设计 (每轮): 1. spawn → attach → 加载 trace_msaoaid_thread_strstr_plt.js (只读, 不patch不mask) 2. resume → 用 /proc 精确监控主进程 20s 3. 记录: 存活? 死亡时刻? 是否EGL崩? 收到的strstr事件? 控制组: 相同流程但不加载任何脚本 (= E0 复现) """ from pathlib import Path import frida, time, json, subprocess, sys, re REMOTE = "127.0.0.1:31878" ADB = ["adb", "-s", "127.0.0.1:5555"] PACKAGE = "com.duowan.kiwi" RE = Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0") def sh(*a): return subprocess.run(a, capture_output=True, text=True) def adb(*a): return sh(*ADB, *a) def main_pid(): r = adb("shell", "pidof", PACKAGE) for p in r.stdout.strip().split(): rr = adb("shell", "cat", f"/proc/{p}/cmdline") if rr.stdout.strip("\x00").strip() == PACKAGE: return int(p) return None def run_round(d, rnd, script_name=None, observe=20): adb("shell", "am", "force-stop", PACKAGE) time.sleep(1.2) adb("shell", "logcat", "-c") pid = d.spawn([PACKAGE]) session = d.attach(pid) t0 = time.time() events = [] def on(m, dta): if m.get('type') != 'send': return p = m.get('payload') or {} events.append(p) ev = p.get('event', '?') if ev in ('msaoaid-thread-strstr',): print(f"[r{rnd} +{time.time()-t0:5.2f}s] STRSTR needle={p.get('needle')} haystack={p.get('haystack','')[:30]!r}", flush=True) elif ev == 'msaoaid-thread-strstr-return': print(f"[r{rnd} +{time.time()-t0:5.2f}s] STRSTR-RET needle={p.get('needle')} hit={p.get('returnedNonNull')}", flush=True) if script_name: sc = session.create_script((RE / "evidence/scripts" / script_name).read_text()) sc.on('message', on) sc.load() d.resume(pid) print(f"[r{rnd}] resume at +{(time.time()-t0)*1000:.0f}ms script={script_name}", flush=True) # 监控 died_at = None while time.time() - t0 < observe: time.sleep(2) if main_pid() is None: died_at = time.time() - t0 break cr = adb("shell", "logcat", "-d", "-b", "crash", "-t", "8").stdout status = "存活" if died_at is None else f"死@+{died_at:.1f}s" egl = "EGL" in cr or "libEGL" in cr print(f"[r{rnd}] 结果: {status} EGL崩={egl} events={len(events)}", flush=True) try: session.detach() except Exception: pass try: d.kill(pid) except Exception: pass time.sleep(1) return {"round": rnd, "script": script_name, "died_at": died_at, "egl": egl, "n_events": len(events)} def main(): scripts = sys.argv[1:] or ["None", "trace_msaoaid_thread_strstr_plt.js"] d = frida.get_device_manager().add_remote_device(REMOTE) results = [] for script in scripts: for rnd in (1, 2): r = run_round(d, rnd, None if script == "None" else script) results.append(r) print(f" → {r}", flush=True) out = Path("/tmp/attach_trace_survival.json") out.write_text(json.dumps(results, indent=1, ensure_ascii=False)) print(f"[*] -> {out}", flush=True) if __name__ == "__main__": main()