#!/usr/bin/env python3 """T2: 拦截 msaoaidsec 的退出动作 (找到检测点 + 让App活下来). spawn -> attach(挂起) -> 加载【exit拦截脚本】: - Interceptor.replace libc _exit/exit/exit_group/_Exit/abort - 若调用者 backtrace 含 libmsaoaidsec.so → 吞掉该退出(不真正退出), 记录 backtrace - 其他来源(Java System.exit等) → 放行原函数 resume 后观察 App 是否存活 (若存活并能看到 msaoaidsec backtrace = 检测点找到+绕过成功) """ from pathlib import Path import frida, time, json, subprocess, sys REMOTE = "127.0.0.1:31878" ADB = ["adb", "-s", "127.0.0.1:5555"] PACKAGE = "com.duowan.kiwi" OUT = Path("/tmp/t2_exit_block.json") INTERCEPT_JS = r""" 'use strict'; const PACK = 'libmsaoaidsec.so'; let swallowed = 0, passthrough = 0; const log = []; function bt() { const src = []; try { for (const a of Thread.backtrace(this.context, Backtracer.ACCURATE)) { const m = Process.findModuleByAddress(a); src.push(m ? (m.name === PACK ? a.sub(m.base).toString() : m.name) : a.toString()); } } catch (_) {} return src; } function make(name, retType, argTypes) { try { const addr = Module.findExportByName('libc.so', name); if (addr === null) return; const orig = new NativeFunction(addr, retType, argTypes); Interceptor.replace(addr, new NativeCallback(function () { const src = bt(); const fromMsao = src.some(s => typeof s === 'string' && s.startsWith('0x')); if (fromMsao) { swallowed++; log.push({ fn: name, msao: true, src: src.slice(0, 8) }); send({ sw: name, n: swallowed }); return; // 吞掉 msaoaidsec 的退出 } passthrough++; send({ pass: name, src: src.slice(0, 6) }); return orig.apply(null, arguments); }, retType, argTypes)); send({ installed: name }); } catch (e) { send({ err: name, e: String(e) }); } } make('_exit', 'void', ['int']); make('_Exit', 'void', ['int']); make('exit', 'void', ['int']); make('exit_group', 'void', ['int']); make('abort', 'void', []); // 线程退出也要看 (pthread_exit 常用于静默死) try { const pe = Module.findExportByName('libc.so', 'pthread_exit'); const origPe = new NativeFunction(pe, 'void', ['pointer']); Interceptor.replace(pe, new NativeCallback(function (retval) { const src = bt(); if (src.some(s => typeof s === 'string' && s.startsWith('0x'))) { swallowed++; log.push({ fn: 'pthread_exit', msao: true, src: src.slice(0, 8) }); send({ sw: 'pthread_exit', n: swallowed }); return; // 吞掉 } return origPe(retval); }, 'void', ['pointer'])); send({ installed: 'pthread_exit' }); } catch (e) { send({ err: 'pthread_exit', e: String(e) }); } send({ ready: true }); """ 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 main(): d = frida.get_device_manager().add_remote_device(REMOTE) for rnd in (1, 2, 3): adb("shell", "am", "force-stop", PACKAGE) time.sleep(1.5) 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 {} p['elapsed'] = round(time.time() - t0, 2) events.append(p) if 'sw' in p: print(f" [+{p['elapsed']}s] 吞掉 msaoaidsec {p['sw']} (#{p['n']})", flush=True) elif 'pass' in p: print(f" [+{p['elapsed']}s] 放行 {p['pass']} src={p['src'][:4]}", flush=True) elif 'installed' in p: print(f" [+{p['elapsed']}s] hook {p['installed']}", flush=True) sc = session.create_script(INTERCEPT_JS) sc.on('message', on) sc.load() d.resume(pid) print(f"[T2.r{rnd}] spawn pid={pid} + exit拦截, resume +{(time.time()-t0)*1000:.0f}ms", flush=True) died = None while time.time() - t0 < 20: time.sleep(1.5) mp = main_pid() if mp is None or mp != pid: died = time.time() - t0 break # 抓 backtrace 详情 swallows = [e for e in events if 'sw' in e] print(f"[T2.r{rnd}] 结果: {'死@+'+str(round(died,1))+'s' if died else '存活20s'} 吞掉={len(swallows)} 放行={sum(1 for e in events if 'pass' in e)}", flush=True) # 打印最后几次吞掉的 backtrace (从 py 侧拿不到 log, 用 events 里的 sw 计数即可) try: session.detach() except Exception: pass try: d.kill(pid) except Exception: pass time.sleep(1) OUT.write_text(json.dumps(events, ensure_ascii=False, indent=1)) print(f"[*] -> {OUT}", flush=True) if __name__ == "__main__": main()