docs(huya): 模拟器存活闪退诊断报告与 Frida 探测脚本证据
- 诊断报告: attach 主进程静默退出/EGL 崩溃, 仅约 4s 窗口可抓帧 - scripts: attach/spawn/hook/emu 系列 Frida 脚本与抓帧/验证工具 - evidence: identity/reqchain/frame/inputbuf/magic_buf/propedge 抓取样本, emu_* 存活对比, diag_* 策略实验, baseline 裸测基准
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user