当小程序使用了字节码保护(V8/QuickJS bytecode)、多层wrapper、自校验、花指令后,常规解包工具基本失效。这时需要转向内存级逆向。
| 防护类型 | 特征关键词 | 难度 | 主流绕过成功率 |
|---|---|---|---|
| V8/QuickJS字节码 | V8Snapshot、BytecodeArray | ★★★★★ | 70–85% |
| 多层wrapper + 自校验 | wrapper、checksum、setInterval校验 | ★★★★ | 80–90% |
| 行为/环境指纹检测 | canvas、WebGL、touch、navigator | ★★★★ | 75–95% |
核心原则:“无论多少层加密,最终明文都会在内存中组装好发出去——找到那块内存就赢了。”
| 工具/技术 | 用途 | 难度 | 成功率 |
|---|---|---|---|
| Frida Memory.scan | 搜索明文特征(手机号、token) | ★★★★ | ★★★★★ |
| r0capture | 自动抓取所有网络明文流量 | ★★★ | ★★★★★ |
| Frida Hook fetch / XMLHttpRequest | 拦截最终请求体 | ★★★★ | ★★★★☆ |
| bytenode / v8-decompile | 字节码 → JS 尝试还原 | ★★★★★ | ★★★☆ |
| Ghidra / IDA Pro | 分析小程序壳native层 | ★★★★★ | ★★☆ |
var pattern = Memory.scanSync(
Process.getModuleByName("libwechat.so"),
'13812345678',
{ json: true }
);
console.log("找到地址: " + pattern[0].address);
Hook 最终网络发送点
Hook wx.request、XMLHttpRequest.send、fetch
Interceptor.attach(Module.findExportByName(null, "send"), {
onEnter: function(args) {
console.log(
"准备发送的数据缓冲区:",
args[1].readByteArray(512)
);
}
});
20260125高手进阶方向:熟练 r0capture + frida-trace + 自定义内存搜索脚本。
这一节是整个五篇的“终点”
看到这里,你应该彻底放弃“靠加密本身防逆向”的幻想
✅ VM 防住的是:
❌ VM 永远防不住:
JS Bytecode
→ VM 执行
→ 构造明文对象
→ AES.encrypt()
→ ArrayBuffer
→ HTTPS send
Java.perform(function () {
var JSONObject = Java.use("org.json.JSONObject");
JSONObject.toString.implementation = function () {
var ret = this.toString();
console.log("[VM 明文]", ret);
return ret;
};
});
Memory.scan(
Process.getModuleByName("libwechat.so"),
"13800000000",
{
onMatch(addr) {
console.log(addr.readByteArray(512));
}
}
);
你无法做到:
HTTPS 解决网络问题
加密解决静态分析
VM 解决批量逆向
内存,解决一切防护
至此,小程序 HTTPS 加解密攻防体系完整闭环。