首页 / 新闻资讯 / 用Frida和IDA验证加固效果,这套安卓加固自测流程我们跑...
去年Q2,我们给一款金融App上加固,选了市面上某头部平台的企业版。上线第三天,安全群里炸了——某逆向论坛有人贴出了我们App的核心算法伪代码。去查原因,对方用Frida绕过反调试后dump内存,直接把解密后的dex抠了出来。

老板问:“不是说加固防得住吗?”我答不上来。
之后三个月,我跑通了四个加固平台的测试流程,踩了无数坑,最终沉淀出一套用Frida+IDA自测加固效果的标准化SOP。今天把这套流程完整公开,目标只有一个:加固效果好不好,自己测了才算。
| 设备类型 | 推荐型号 | 用途 | 关键点 |
|---|---|---|---|
| 低端真机 | 小米8 (Android 9) | 兼容性/性能测试 | 最易暴露闪退问题 |
| 中端真机 | 荣耀9X (Android 10) | 主测机型 | 市占率高 |
| 高端真机 | Pixel 4/5 (Android 13-14) | 动态调试环境 | 原厂系统兼容性好 |
| 模拟器 | 夜神/Nox Android 9 | 快速验证 | 部分加固会检测模拟器 |
关键配置:所有测试机需要root,因为后续要push frida-server到/data/local/tmp并赋予执行权限。
# 1. 安装frida-toolspip install frida-tools frida-dexdump# 2. 下载对应架构的frida-server# 查看设备架构: adb shell getprop ro.product.cpu.abi# 下载地址: https://github.com/frida/frida/releases# 3. push并运行adb push frida-server /data/local/tmp/adb shell chmod 755 /data/local/tmp/frida-serveradb shell su -c /data/local/tmp/frida-server 4. 端口转发adb forward tcp:27042 tcp:27042# 5. 验证连接frida-ps -U坑点预警:部分加固会检测默认端口27042和frida-server字符串特征。实战中建议改端口:frida-server -l 0.0.0.0:12345,并重命名二进制文件。

IDA的android_server需要和加固壳做对抗。核心配置:
# 推送调试服务adb push android_server /data/local/tmp/adb shell chmod 755 /data/local/tmp/android_serveradb shell su -c /data/local/tmp/android_server -p12345 端口转发adb forward tcp:23946 tcp:12345adb forward tcp:8700 jdwp:$(pid)调试前在IDA中设置:Debugger → Debugger options → 勾选Suspend on process entry point和Suspend on library load/unload。这样能在壳加载so的瞬间断下,抢在反调试启动前attach。
我们维护了一套内部脚本库,以下是经实战检验的核心脚本。
针对加固壳对/proc/self/status中TracerPid字段的检测:
// bypass_anti_debug.jsvar openPtr = Module.findExportByName(null, "open");var readPtr = Module.findExportByName(null, "read");var fakeStatus = "Name: app\nTracerPid: 0\nState: S\n"; // 干净的statusInterceptor.attach(openPtr, { onEnter: function(args) { var path = args[0].readCString(); if (path && path.indexOf("/proc/self/status") !== -1) { this.isTarget = true; console.log("[*] 拦截open: " + path); } }, onLeave: function(retval) { if (this.isTarget) { // 返回伪造的文件描述符 this.isTarget = false; } }});更高级的反调试绕过需要Hook ptrace:
var ptracePtr = Module.findExportByName(null, "ptrace");Interceptor.attach(ptracePtr, { onEnter: function(args) { var request = args[0].toInt32(); if (request === 0) { // PTRACE_TRACEME console.log("[*] 拦截ptrace(PTRACE_TRACEME)"); this.pc = Process.getCurrentThread().context.pc; } }, onLeave: function(retval) { if (this.pc) { retval.replace(ptr(0)); // 返回成功 } }});使用frida-dexdump可以快速验证加固是否防得住基础dump:
# 深度搜索模式frida-dexdump -U -a --deep-search -o ./dumped/# 指定进程frida-dexdump -U -n com.example.app --deep-search一年测试下来,一代/二代壳在deep-search模式下基本必破,脱出的dex可直接jadx打开看源码。
针对三代函数抽取壳,需要更精确的hook:
// dex_dumper.js - hook类加载时机var DexFile = Java.use("com.android.dex.DexFile");DexFile.openDexFile.overload('java.nio.ByteBuffer', 'java.lang.String', 'int').implementation = function(bb, str, i) { console.log("[*] openDexFile called"); var result = this.openDexFile(bb, str, i); // 尝试从ByteBuffer中读取dex var bytes = Java.array('byte', new Array(bb.remaining())); bb.get(bytes); console.log("[+] Dex size: " + bytes.length); return result;};对于Native层加固,需要用IDA脚本或Frida批量dump:
# dump_so.pyimport fridadef on_message(message, data): if message['type'] == 'send': if 'so_dump' in message['payload']: with open(message['payload']['name'], 'wb') as f: f.write(data) print(f"[+] Saved: {message['payload']['name']}")js_code = """var soName = "libcore.so";var base = Module.findBaseAddress(soName);if (base) { var exports = Module.enumerateExports(soName); var end = base.add(Module.getExportByName(soName, "JNI_OnLoad")); // 扫描整个so send({type: "so_dump", name: soName + ".dump"}, base.readByteArray(end.sub(base).add(0x10000)));}"""四、结果评级标准
经过一年实测和多轮迭代,我们建立了四级评分体系:
| 等级 | 评分 | 判定标准 | 加固强度 |
|---|---|---|---|
| A级 | 90-100 | frida-dexdump无法脱壳,IDA动态调试无法断下,内存扫描无完整dex | 企业级 |
| B级 | 70-85 | 可dump但代码被混淆/虚拟化,分析成本高 | 商用级 |
| C级 | 50-65 | 可直接dump出可读dex,但有基础反调试 | 基础级 |
| D级 | 0-40 | 加固后和未加固无区别,jadx直接看代码 | 无效加固 |
每个加固方案跑完这套用例才算通过:
[ ] 反编译测试:jadx查看是否直接显示源码[ ] frida-dexdump测试:能否自动脱出dex[ ] 自定义脚本脱壳:能否通过hook关键函数拿到明文[ ] IDA动态attach:能否在反调试启动前断下[ ] 内存搜索dex:扫描进程内存是否发现dex魔数(64 65 78 0a)[ ] so加固测试:IDA打开so是否能看到完整导出表[ ] 性能测试:启动耗时增幅<30%,无新增闪退测试结果:frida-dexdump直接脱出完整dex,降级为C级。
问题复盘:该平台未对openDexFile做hook防护,dump时机在壳解密后、类加载前。教训:验证过的东西也要定期重测,加固方案会迭代,安全团队懒不得。
测试结果:frida-dexdump失败,内存扫描无dex魔数,评分A-。
分析:采用LLVM-based代码虚拟化,原始dex从未完整落内存,而是逐方法解释执行。这种方案对抗dump效果好,但性能损耗需要评估。
测试结果:IDA直接attach成功,评分D。
问题:免费版只做了dex加壳,连ptrace反调试都没有。上线一周就被论坛破解,**再次验证"免费加固=心理安慰"**。
1. 加固后必须自测,别信厂商话术
我们测试过6个平台,实际防护强度和销售描述的偏差平均在40%以上。用frida-dexdump跑10秒,比看100页产品手册管用。
2. 深度搜索模式跑不通才是及格线
如果frida-dexdump -U -a --deep-search能直接跑出dex,说明连基础防护都没有。一线加固平台至少要做到deep-search无效。
3. 动态和静态要结合测
只测静态反编译不够,很多壳dex加密做得不错但so层裸奔。我们见过jadx打不开但IDA里导出表完整的案例。

4. 关注测试时机
壳的解密时机一般在Application.onCreate和MainActivity.onCreate之间。Frida脚本最好在这两个阶段都做内存扫描。
5. 持续跟进对抗技术
2026年Frida GUM API升级后,部分老绕过脚本已失效。建议每季度更新测试脚本,关注Xposed模块论坛的新姿势。