#!/usr/bin/env python3 """R35: 清 turing 状态(保留登录) -> spawn -> bypass -> hook_memshot 内存快照. 产出 evidence/memshot_.json: - dfp wire 全量 + backtrace - 线上密文在进程内存中的全部拷贝 + ±2KB 邻域 - Perseus 会话密钥 + 静态密钥出现位置 + 16 字符候选密钥串 - zlib 流候选 (78 xx) 供主机 inflate 验证 """ from __future__ import annotations import json, subprocess, time from pathlib import Path import frida REMOTE = "127.0.0.1:31878" ADB = "5dd8c93f" PACKAGE = "com.duowan.kiwi" RE = Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0") HERE = Path(__file__).resolve().parent.parent OUT = HERE / "evidence" / ("memshot_" + time.strftime("%H%M%S") + ".json") def clear_turing(): """只清 turing 状态, 保留登录态 -> ~40s 内自动重注册上报.""" dirs = ["app_turingdfp", "app_turingfd"] for d in dirs: subprocess.run(["adb", "-s", ADB, "shell", "su", "-c", f"rm -rf /data/data/{PACKAGE}/{d}/*"], capture_output=True) # resinfo 清理 (配方 §11.55) subprocess.run(["adb", "-s", ADB, "shell", "su", "-c", f"find /data/data/{PACKAGE} -name 'resinfo*' -delete"], capture_output=True) def main(): print("[*] clearing turing state (login kept)", flush=True) clear_turing() d = frida.get_device_manager().add_remote_device(REMOTE) subprocess.run(["adb", "-s", ADB, "shell", "am", "force-stop", PACKAGE], capture_output=True) time.sleep(1.5) pid = d.spawn([PACKAGE]) print(f"[*] spawn pid={pid}", flush=True) s = d.attach(pid) from bypass_loader import load_bypass load_bypass(s) d.resume(pid) result: dict = {} got = {"post": False, "done": False} def on(m, _): if m.get("type") == "error": print(f"[JS] {str(m)[:200]}", flush=True) return p = m.get("payload") or {} ev = p.get("event") if ev in ("post", "scan-done"): got["post" if ev == "post" else "done"] = True if ev == "post": print(f"[+] dfpReport POST {p['num']}B", flush=True) elif ev == "ranges": print(f"[*] scanning {p['n']} rw- ranges ({p['bytes']//1024//1024}MB)", flush=True) elif ev == "cipher-copies": print(f"[+] cipher copies in memory: {p['n']}", flush=True) elif ev == "perseus": print(f"[+] Perseus key: {p.get('key')}", flush=True) elif ev == "key-cands": print(f"[+] key candidates: {p['n']}", flush=True) elif ev == "zcand": pass elif ev == "scan-done": print(f"[*] scan complete (zlib cands={p['zcands']})", flush=True) result.setdefault(ev or "misc", []).append(p) sc = s.create_script((HERE / "tools/frida/hook_memshot.js").read_text()) sc.on("message", on) sc.load() t0 = time.time() while time.time() - t0 < 120: time.sleep(2) if got["done"]: break if got["post"] and time.time() - t0 > 60: break json.dump(result, open(OUT, "w"), indent=2) print(f"[*] saved {OUT}", flush=True) try: s.detach() except Exception: pass if __name__ == "__main__": main()