#!/usr/bin/env python3 """T0: 基础对照实验 (2026-08-27 重做, 不用旧结论). T1: spawn + attach(空session) + resume → 观察 15s, 死因=完整logcat T2: spawn + resume (不attach) → 对照 每轮输出: pid 时间线 + 死亡时 logcat(main/crash/events + kernel) 关键行。 判定死亡: 主进程不存在 或 pid 变化 (KeepAlive 重启也算死)。 """ 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" OUT = Path("/tmp/t0_basic.json") 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_case(d, kind, rnd): adb("shell", "am", "force-stop", PACKAGE) time.sleep(1.5) adb("shell", "logcat", "-c") adb("shell", "logcat", "-c", "-b", "crash") pid = d.spawn([PACKAGE]) t0 = time.time() session = None if kind == "attach": session = d.attach(pid) d.resume(pid) print(f"[T1.r{rnd}] spawn pid={pid} {'attach+resume' if kind=='attach' else '纯resume'} +{(time.time()-t0)*1000:.0f}ms", flush=True) # 观察 15s timeline = [] died_at = None while time.time() - t0 < 15: time.sleep(1.5) mp = main_pid() now = round(time.time() - t0, 1) if mp is None: died_at = now timeline.append({"t": now, "main": None}) print(f" +{now}s 主进程消失 (死)", flush=True) break if mp != pid: died_at = now timeline.append({"t": now, "main": mp, "note": "pid变化"}) print(f" +{now}s pid变化 {pid}->{mp} (主进程死/重启)", flush=True) break timeline.append({"t": now, "main": mp}) # 抓日志 main_log = adb("shell", "logcat", "-d", "-t", "300").stdout crash_log = adb("shell", "logcat", "-d", "-b", "crash", "-t", "100").stdout # 关键筛选 keys = [] for line in (main_log.splitlines() + crash_log.splitlines()): if re.search(r"msaoaid|nsdt|kist|guard|exit|kill|died|died|FATAL|Fatal|signal|Abort|SIGSEGV|SIGABRT|frida|avc:|SELinux|scudo|Suspicious|property|magisk|denied", line, re.I): keys.append(line[:220]) print(f" 死亡={'是@'+str(died_at) if died_at else '否(存活)'} 关键日志行数={len(keys)}", flush=True) for l in keys[-18:]: print(f" L: {l}", flush=True) try: if session: session.detach() except Exception: pass try: d.kill(pid) except Exception: pass time.sleep(1) return {"kind": kind, "round": rnd, "died_at": died_at, "timeline": timeline, "log_lines": keys[-40:]} def main(): d = frida.get_device_manager().add_remote_device(REMOTE) results = [] for rnd in (1, 2): results.append(run_case(d, "attach", rnd)) results.append(run_case(d, "pure", 1)) OUT.write_text(json.dumps(results, ensure_ascii=False, indent=1)) print(f"[*] -> {OUT}", flush=True) if __name__ == "__main__": main()