docs: 绕过配方状态更正 (bypass_all 未验证, 以原版三脚本为准) + 三层健康检查工具

This commit is contained in:
yml2213
2026-08-29 11:44:54 +08:00
parent 5fa1f6d082
commit 1a6711c180
11 changed files with 504 additions and 24 deletions
+224
View File
@@ -0,0 +1,224 @@
'use strict';
// ============================================================================
// bypass_all.js — 虎牙 com.duowan.kiwi (13.4.22) 反 frida 绕过 · 一体化脚本
// ============================================================================
// 合并自 RE 仓库三脚本 (实测配方, R31-R39 全程验证):
// 1. bypass_msaoaid_maps_art_callsite.js — libmsaoaidsec 线程名/fd 掩盖 + maps 清理分支跳转 + ART 完整性 callsite NOP
// 2. mask_frida_maps_only.js — libc 层 /proc/self/maps 内容 'frida-agent' 掩写
// 3. patch_guard_block_termination.js — kill/tgkill/exit/abort 自终止拦截 + msaoaid crash-guard 补丁
//
// 用法 (必须 spawn 挂起中、resume 之前加载!):
// const opts = { patchGuardDelayMs: 3000 }; // B 层延迟, 传参可调
// const src = 'globalThis.BYPASS_OPTS=' + JSON.stringify(opts) + ';\n' + bypassSrc;
// s.create_script(src).load(); // 然后 d.resume(pid)
//
// 时序语义:
// A 层 (立即): maps 线索掩盖 — 必须 resume 前就位, 否则启动检测线程先读到 frida 痕迹
// B 层 (延迟): 终止拦截会无差别吞掉 exit/abort, 过早加载会卡死启动期合法退出
// → 默认 3000ms 后安装; 若 App 秒死调小, 若启动期被杀调大
// ============================================================================
var OPTS = { patchGuardDelayMs: 3000, persist: false };
try { if (globalThis.BYPASS_OPTS) OPTS = Object.assign(OPTS, globalThis.BYPASS_OPTS); } catch (_) {}
function emit(o) {
// 关键: 钩子上下文 (dlopen/拦截器 onEnter, 主线程启动期) 内直接 send() 会死锁主线程
// (R40 ANR trace: main 阻塞在 frida-agent) — 一律入队, setImmediate 刷出
try { pendingEmits.push(Object.assign({ src: 'bypass_all' }, o)); setImmediate(flushEmits); } catch (_) {}
}
var pendingEmits = [];
function flushEmits() {
while (pendingEmits.length) { try { send(pendingEmits.shift()); } catch (_) {} }
}
// ---------- 持久化调试日志 (默认关) ----------
var logFile = null;
function persist(row) {
if (!OPTS.persist) return;
try {
if (logFile === null) logFile = new File('/data/user/0/com.duowan.kiwi/cache/bypass-all-' + Process.id + '.jsonl', 'a');
row.tid = Process.getCurrentThreadId();
logFile.write(JSON.stringify(row) + '\n');
logFile.flush();
} catch (_) {}
}
function exportOf(name) {
try { if (typeof Module.getGlobalExportByName === 'function') return Module.getGlobalExportByName(name); } catch (_) {}
try { if (typeof Module.findGlobalExportByName === 'function') return Module.findGlobalExportByName(null, name); } catch (_) {}
try { return Module.findExportByName(null, name); } catch (_) { return null; }
}
// ============================================================================
// A1) libmsaoaidsec.so: 线程名/fd 掩盖 + predicate 分支跳转 + ART callsite NOP
// (原 bypass_msaoaid_maps_art_callsite.js, offsets 对应 13.4.22 arm64)
// ============================================================================
var msaoaid = { installed: false };
function readStr(pointer, length) { try { return pointer.readCString(length) || ''; } catch (_) { return ''; } }
function installMsaoaid(source) {
if (msaoaid.installed) return;
var module = Process.findModuleByName('libmsaoaidsec.so');
if (module === null) return;
msaoaid.installed = true;
var branch = module.base.add(0x1c4a0);
var continuePath = module.base.add(0x1c4b4);
var artCallsite = module.base.add(0x1ceec);
persist({ event: 'installed', source: source, base: module.base.toString() });
emit({ event: 'A-msaoaid-patched', base: module.base.toString() });
// 线程名掩盖: /proc/<tid>/cmdline 读取处的 gmain/gum-js-loop/linjector → pool-worker
[0x1c0e4, 0x1c0f4].forEach(function (offset) {
Interceptor.attach(module.base.add(offset), {
onEnter() {
var buffer = this.context.sp.add(0x18);
var value = readStr(buffer, 96);
if (!value.startsWith('Name:\tgmain') && !value.startsWith('Name:\tgum-js-loop') && !value.startsWith('Name:\tlinjector')) return;
buffer.writeUtf8String('Name:\tpool-worker');
persist({ event: 'name-masked', offset: '0x' + offset.toString(16) });
},
});
});
// fd 扫描掩盖: 'linjector' → 'xxxxxxxxx'
Interceptor.attach(module.base.add(0x1c214), {
onEnter() {
var buffer = this.context.sp.add(0x288);
var value = readStr(buffer, 512);
var index = value.indexOf('linjector');
if (index < 0) return;
buffer.add(index).writeUtf8String('xxxxxxxxx');
persist({ event: 'fd-masked' });
},
});
// predicate 分支: 检出 frida 线索后的清理分支 → 直接跳继续路径; ART 完整性周期 callsite → NOP
try {
Memory.patchCode(branch, 4, function (code) {
var w = new Arm64Writer(code, { pc: branch });
w.putBranchAddress(continuePath);
w.flush();
});
Memory.patchCode(artCallsite, 4, function (code) {
var w = new Arm64Writer(code, { pc: artCallsite });
w.putNop();
w.flush();
});
persist({ event: 'branches-patched' });
} catch (error) {
emit({ event: 'A-patch-error', error: String(error) });
}
}
// msaoaid 可能在 spawn 时已加载, 也可能稍后 dlopen — 双路触发
['dlopen', 'android_dlopen_ext'].forEach(function (name) {
var address = exportOf(name);
if (address !== null) Interceptor.attach(address, {
onEnter() { installMsaoaid(name + ':enter'); },
onLeave() { installMsaoaid(name + ':leave'); },
});
});
installMsaoaid('initial');
// ============================================================================
// A2) libc 层 maps 内容掩盖: open*/fopen 记录 maps fd → read/pread64 时掩写 frida-agent
// (原 mask_frida_maps_only.js)
// ============================================================================
var trackedFds = {};
function trackOpen(pathPointer, fd) {
var path = '';
try { path = pathPointer.isNull() ? '' : pathPointer.readCString(); } catch (_) { return; }
if (fd >= 0 && /(?:^|\/)maps$/.test(path)) trackedFds[fd] = path;
}
['open', 'open64', 'fopen'].forEach(function (name) {
var address = exportOf(name);
if (address === null) return;
Interceptor.attach(address, {
onEnter(args) { this.path = args[0]; },
onLeave(retval) { trackOpen(this.path, retval.toInt32()); },
});
});
var openat = exportOf('openat');
if (openat !== null) Interceptor.attach(openat, {
onEnter(args) { this.path = args[1]; },
onLeave(retval) { trackOpen(this.path, retval.toInt32()); },
});
var closeFn = exportOf('close');
if (closeFn !== null) Interceptor.attach(closeFn, {
onEnter(args) { delete trackedFds[args[0].toInt32()]; },
});
function maskMapsRead(buffer, length, path) {
if (!path || length <= 0) return;
try {
var bytes = new Uint8Array(buffer.readByteArray(length));
var value = '';
for (var i = 0; i < bytes.length; i++) value += String.fromCharCode(bytes[i]);
if (value.indexOf('frida-agent') < 0 && value.indexOf('gum-js-loop') < 0 && value.indexOf('linjector') < 0) return;
value = value.replace(/frida-agent/gi, 'xxxxxxxxxxx')
.replace(/gum-js-loop/g, 'pool-worker')
.replace(/linjector/g, 'xxxxxxxxx');
for (var j = 0; j < length; j++) buffer.add(j).writeU8(value.charCodeAt(j) || 0);
} catch (_) {}
}
['read', 'pread64'].forEach(function (name) {
var address = exportOf(name);
if (address === null) return;
Interceptor.attach(address, {
onEnter(args) { this.buffer = args[1]; this.path = trackedFds[args[0].toInt32()] || ''; },
onLeave(retval) { maskMapsRead(this.buffer, retval.toInt32(), this.path); },
});
});
emit({ event: 'A-maps-mask-installed' });
// ============================================================================
// B 层 (延迟 OPTS.patchGuardDelayMs): 自终止拦截 + msaoaid crash-guard 补丁
// (原 patch_guard_block_termination.js)
// ============================================================================
function installPatchGuard() {
var keep = [];
var ownPid = Process.id;
function replaceFn(name, returnType, argumentTypes, callback) {
var address = exportOf(name);
if (address === null) return;
try {
var native = new NativeCallback(callback, returnType, argumentTypes);
keep.push(native);
Interceptor.replace(address, native);
} catch (_) {}
}
replaceFn('kill', 'int', ['int', 'int'], function (pid) { return Number(pid) === ownPid ? 0 : -1; });
replaceFn('tgkill', 'int', ['int', 'int', 'int'], function (tgid, tid) { return (Number(tgid) === ownPid || Number(tid) === ownPid) ? 0 : -1; });
replaceFn('exit', 'void', ['int'], function () {});
replaceFn('_exit', 'void', ['int'], function () {});
replaceFn('_Exit', 'void', ['int'], function () {});
replaceFn('abort', 'void', [], function () {});
replaceFn('raise', 'int', ['int'], function () { return 0; });
// msaoaid crash-guard: 属性读取触发点后补丁 0x20ca8 (x0 → 0)
var guardPatched = false;
function patchGuard(module) {
if (guardPatched) return;
var address = module.base.add(0x20ca8);
try {
Memory.protect(address, 4, 'rwx');
var writer = new Arm64Writer(address);
writer.putMovRegReg('x0', 'xzr');
writer.flush(); writer.dispose();
guardPatched = true;
emit({ event: 'B-guard-patched' });
} catch (error) { emit({ event: 'B-guard-error', error: String(error) }); }
}
var prop = exportOf('__system_property_get');
if (prop !== null) Interceptor.attach(prop, {
onEnter(args) {
var name = ''; try { name = args[0].readCString(); } catch (_) { return; }
if (name !== 'ro.build.version.sdk') return;
var module = Process.findModuleByName('libmsaoaidsec.so');
if (module !== null) patchGuard(module);
},
});
emit({ event: 'B-patch-guard-installed', delayMs: OPTS.patchGuardDelayMs });
}
setTimeout(installPatchGuard, OPTS.patchGuardDelayMs);
emit({ event: 'armed', pid: Process.id, patchGuardDelayMs: OPTS.patchGuardDelayMs });