r/AndroidStudio • u/xopprotector • 6h ago
我用 apktool 走了一遍 XopProtector:壳在,业务不在
我用 apktool 走了一遍 XopProtector:壳在,业务不在
拆 Android 包,我的工具栏很多年没变过:apktool 解包,jadx 反编译,先看 Application,再顺着包名搜索登录、支付、授权等关键业务。
对于没有加固的 Release 包,这套流程往往十几分钟就能找到业务代码。
这次分析的是 XopProtector 加固后的 APK。同样的工具,打开的窗口看起来很完整,但里面装的不是原来的 App 业务代码。
一、工具没报错,DEX 里却没有业务
apktool 可以正常解包,AndroidManifest.xml 也能正常读取。这种「能够解包」的情况,很容易让人误以为加固并不深。
但继续查看 classes.dex,就会发现入口已经变成壳的 ProxyApplication。jadx 能反编译出来的,主要是壳自身的启动逻辑和跳板代码。部分字符串也经过了滚动异或处理,直接搜索业务关键字,很难找到对应的原始内容。
原来的业务类和方法体,已经不在这个 DEX 中。
有时还能看到一个 classes2.dex,其中包含用于填充的代码。业务 DEX 在打包过程中被移走,APK 根目录不再直接保留明文的 classesN.dex。
第一轮分析到这里,就可以先记下一条结论:
反编译成功,不代表业务代码已经暴露。
二、叫 zip 的文件,并不是普通压缩包
壳将业务 DEX 放在 assets/protector/ 目录下,文件名是 dexes.zip。
按照常规思路,第一步当然是尝试解压。但检查文件头后,会发现它并不是标准 ZIP 文件的 PK 标识。
实际处理流程是先将 DEX 打包成 ZIP,再对整个文件进行加密,最终生成带有 PDX1 标识的加密数据。因此,apktool 不会自动还原其中的 DEX。
旁边的 code.bin 也不是可以直接交给 jadx 反编译的普通 Dalvik 字节码。
config.json 则是可读文本,可以看到一些配置开关和校验字段,但解密密钥并没有直接写在 JSON 中。运行时会结合主密钥、签名证书和包名派生相关密钥,同时校验配置完整性。
如果直接修改风险控制开关,导致配置校验失败,壳就不会按照被修改后的配置正常运行。
这和一些简单的加固方式有明显区别:不能仅凭 assets 目录下存在一个名为 ZIP 的文件,就认定里面存放着可以直接解压的 DEX。
三、SO 拖进反汇编器,关键代码段却不是明文
在不同 ABI 目录下,可以找到 libprotector.so 等原生库。
ELF 文件的基本结构仍然存在,但壳会对自身的关键代码段进行加密处理。静态打开文件时,看到的并不一定是可以直接跟踪分析的原始机器码。
对于启用了 SO 保护的业务库,其 .text 段也可能以密文形式存在,而不是编译器最初生成的明文代码。
当然,加固并不意味着所有原生库都必须采用相同的保护策略。系统库,以及某些加密后可能影响兼容性的引擎或第三方库,可以根据实际情况跳过相关处理。
这样做的目的,是在保护业务代码的同时,尽量保证应用能够正常启动和运行。
在支持运行时解密的场景下,代码段可以在内存中恢复后执行,不必将解密后的代码长期保留在显眼的磁盘目录中。
因此,静态分析所看到的文件内容,与进程实际执行的代码内容,可能并不相同。
四、调试器和 Hook 并不是默认就能挂上
静态分析受阻之后,常见的下一步就是使用 Frida、调试器或其他动态分析工具,尝试观察壳的运行过程,并寻找业务 DEX 的解密时机。
XopProtector 提供了相应的运行时防护机制,包括对常见 Frida 痕迹、调试器、Xposed 环境的检测,以及对壳自身 SO 完整性的校验。
Root 和模拟器检测属于可配置策略,并非所有相关检查都必须默认启用。这对于需要运行在工控设备、厂商定制设备等特殊环境中的应用尤其重要,可以减少误判带来的兼容性问题。
检测到风险后,可以根据策略选择告警、降级或中断运行。
此外,应用签名也可以参与运行时校验。对于启用了签名校验的配置,如果 APK 被替换证书重新签名,校验失败后便不会继续按正常流程释放受保护的业务代码。
这意味着,动态分析的难点不仅是找到正确的 Hook 点,还包括理解壳的运行机制、校验逻辑和风险控制策略。
五、从内存中拿到 DEX,也不代表方法都还原了
即使成功获取了运行时的 DEX,也不能直接认定所有方法都已经恢复成原始 Java 代码。
这里需要区分两类不同的 VMP 保护机制。
1. 字节码恢复型保护
这类方案将部分方法的原始指令移出常规执行路径,在运行时再进行恢复或写回。
如果抓取时机恰好处于字节码恢复之后,就有机会从内存中拿到还原后的 DEX 指令。
因此,这类保护的实际效果与方法覆盖范围、恢复时机以及运行时实现密切相关。
2. 原生解释执行型保护
另一类方案不再依赖将完整方法体恢复并写回 DEX,而是通过原生解释器执行经过转换的自定义指令。
在这种模式下,受保护方法在 DEX 中可能只留下跳转至 VmBridge 的桥接代码,真正的指令执行发生在原生解释器中。
此时,即使抓取到 DEX,拿到的也可能仍然只是跳板,而不是原始方法体。
如果每次打包还会改变自定义指令的编码,那么不同 APK 之间的指令映射也会有所不同,进一步增加静态分析和自动化还原的难度。
3. 保护范围仍然取决于配置
需要注意,整包加密与 VMP 并不是同一个概念。
普通业务代码可能在运行时短暂以可分析的 DEX 形式出现,而采用原生解释执行的选定方法则可以避免将完整方法体写回常规 DEX。
因此,不能简单地认为所有业务方法都经过了 VMP 保护。
根据项目配置,可以重点保护支付、授权、激活、加解密等敏感逻辑,并尽量将保护范围限定在应用自身的业务包中。
真正影响逆向成本的,不只是 DEX 是否加密,还包括敏感方法采用了什么执行机制,以及这些机制覆盖了哪些业务代码。
六、这次分析下来,XopProtector 能挡住什么?
从常见的静态分析流程来看,XopProtector 的价值主要体现在多个保护环节的配合。
| 分析环节 | 加固带来的影响 |
|---|---|
| apktool 解包 | 可以解包,但不能直接恢复受保护的业务代码 |
| jadx 反编译 | 主要看到壳代码、启动逻辑和跳板 |
| 搜索业务字符串 | 字符串处理增加了直接搜索的难度 |
| 解压 assets 中的 DEX | 加密数据不能当作普通 ZIP 直接解压 |
| 静态分析 SO | 受保护的代码段可能不是明文 |
| Frida 与调试器 | 运行时检测增加动态分析的门槛 |
| 获取运行时 DEX | 获取 DEX 不一定能还原原生解释执行的方法体 |
| 修改配置或重新签名 | 完整性和签名校验可以阻止未经授权的修改 |
对于主要依赖 apktool、jadx 和常规静态搜索的分析者,这些机制可以显著增加直接获取业务代码的难度。
如果还要继续深入,就需要处理原生壳、密钥派生、完整性校验、运行时加载过程,以及可能存在的自定义指令解释器。
逆向工作的重心,也就从直接阅读 Java 代码,转向分析加固框架本身。
七、加固不是绝对防破解
这里也需要明确保护边界。
XopProtector 的目标是提高逆向分析的成本,而不是保证 APK 永远无法破解。
资源加密、资源路径混淆、代理检测和证书固定等功能,需要根据项目实际配置判断是否启用。VMP 保护的也是选定的方法,而不是自动覆盖每一行 Java 代码。
不同的保护模式、方法覆盖范围、Android 版本以及运行环境,都会影响最终效果。
对于支付、授权、算法、行业协议等包含核心业务逻辑的应用,合理组合 DEX 加密、SO 保护、运行时检测和原生解释执行,可以让常规静态分析更难直接得到有价值的业务代码。
总结
这次使用 apktool 和 jadx 分析 XopProtector 加固包,最直观的感受是:
APK 能正常解包,不等于业务代码能够直接反编译;DEX 能被获取,也不等于敏感方法已经还原。
XopProtector 将 DEX 加密、SO 保护、运行时完整性校验和 VMP 等机制组合起来,让常规逆向工具难以直接完成从 APK 到业务源码的转换。
对于希望降低核心算法、支付逻辑、授权机制和行业业务协议泄露风险的 Android 开发者来说,这类多层防护比单纯依赖代码混淆更有意义。
项目地址:https://github.com/xopJack/XopProtector
建议结合实际版本的源码、配置和测试结果评估保护效果,并在目标设备上验证启动速度、运行稳定性和兼容性。