- 诊断报告: attach 主进程静默退出/EGL 崩溃, 仅约 4s 窗口可抓帧 - scripts: attach/spawn/hook/emu 系列 Frida 脚本与抓帧/验证工具 - evidence: identity/reqchain/frame/inputbuf/magic_buf/propedge 抓取样本, emu_* 存活对比, diag_* 策略实验, baseline 裸测基准
86 lines
3.4 KiB
Python
86 lines
3.4 KiB
Python
#!/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() |