用 AndResGuard 做资源混淆:它到底买到了什么
重命名 res/ 路径是性价比最高的加固层——但如果漏了白名单,它也是最容易搞崩构建的一层。
AndResGuard 是 VALLUM 加固管线的第一层,也是整条管线里性价比最高的一步。它把 res/ 的路径与资源表条目改写成无意义的短名,并用 7za 重新深度压缩。它不改变运行时行为、不依赖 native、不与 ART 打交道——正因如此,它的兼容性记录也是所有层里最好的。多数构建跑完它之后体积是变小而不是变大。
它真正防的是「侦察」而不是「窃取」。攻击者定位业务逻辑,往往靠 grep 资源名:一个叫 activity_payment 的布局、一张叫 ic_premium 的图,在读到第一行 Smali 之前就告诉你该往哪看。把所有名字改写成 r/a、r/b,等于毁掉这份索引。它同时抬高了资源爬取、以及依赖固定资源 ID 的重打包流程的成本。但它不加密资源——如果你把密钥放在 raw/ 里,混淆不是解药。
失效模式来自「必须保留原名」的部分:启动图标、被应用外部引用的资源(部分 OEM 的通知图标、桌面小部件布局、快捷方式)、被反射按名字取用的资源 ID,以及那些用字符串名字而非编译期 ID 解析资源的第三方 SDK,改名即崩。AndResGuard 的白名单就是为此存在的,VALLUM 默认把 ic_launcher 一类放进去。如果加固后应用崩溃并抛 Resources.NotFoundException,第一排查点是白名单,而不是壳。
还有一个常被忽略的附加收益:因为 AndResGuard 用 7za 以最高等级重压、并把成千上万条路径字符串变短,即使构建已经过 R8 压缩,体积下降依然可测。资源密集型的 App 上,单这一层省下的体积有时足以抵消后续所有层加上的体积。这在加固里很罕见——多数步骤都是「加体积换安全」。
顺序很重要。资源重命名必须跑在任何改写 DEX 的步骤之前,因为 DEX 以编译期 ID 引用资源,资源表与 DEX 必须一致。正确位置是:在 R8 之后(这样混淆的是最终资源集)、dpt-shell 之前。放到最后跑,产出的 APK 资源表与代码请求对不上——这类 bug 的表现是首次布局加载时崩溃,离真正的原因很远。
一定要留好 mapping 文件。AndResGuard 会输出一份,而在生产崩溃栈里出现一个你解不开的资源名那天,你会需要它。把它和 ProGuard mapping 一起存进你们既有的制品库——一份没人找得到的 mapping,等于没有 mapping。