docs: 绕过配方状态更正 (bypass_all 未验证, 以原版三脚本为准) + 三层健康检查工具
This commit is contained in:
@@ -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 });
|
||||
Reference in New Issue
Block a user