一句话结论:加固(代码保护、混淆)必须发生在签名之前,而且必须在提交给签名方之前做完。已经签好的包再去做任何形式的代码加固,出来的东西基本一定是废包——要么签不上,要么装上就闪退。
为什么顺序不能反
签名做的事,是给包里的可执行文件、动态库、资源打上一层校验信息,形成一道完整的信任链条。系统启动应用时会逐份比对:这个文件的哈希(根据文件内容算出的校验值)跟签名里记录的是不是一致,不一致就判定包被改过,直接拒绝启动。
而加固、混淆的本质,恰恰是改写可执行文件——变量名替换、控制流程打乱、插入垃圾指令、字符串加密。任何一个操作都会让文件内容变化,哈希随之变化。签名在前、加固在后,等于把签名当时的校验基准改掉了,系统一比对就失败。
所以逻辑很硬:先把代码改到最终状态,最后一步才盖章。盖章之后,包里的任何东西都不应该再被碰。
顺序对了,还有三处容易卡住
实际中会出问题的地方通常是这三类:
- 加固工具往包里注入了新的动态库或者可执行段,但导出的包里没有同步更新权限声明,导致签名方修改 entitlements(权限声明)时丢失部分内容。
- 加固对可执行文件做了压缩或者加壳,导致重签工具读不清内部结构,报”包体无法解析”。
- 加固时顺手改写了 Info.plist(应用配置清单,记录包名版本等信息的文件),把 Bundle ID(应用包名)或者版本号改掉了,后续设备统计、覆盖更新都会错位。
这三种都不是签名环节的问题,根源在加固的输出不规范。
哪些加固手段和签名直接冲突
按冲突概率从高到低排:
- 加壳类保护:把整个可执行文件包一层壳,运行时才还原。这种对签名最不友好,重签经常失败,多数签名服务会直接拒收。
- 运行时动态解密:本身可行,但要确保解密之后的产物仍然落在原本的路径上,否则签名覆盖不到。
- 资源混淆:资源改名、移动位置,风险中等,签名前确认资源完整即可。
- 纯编译期混淆:变量名、类名替换这一类只改符号、不改结构,对签名基本没有影响,是最安全的做法。
如果你的应用用了加壳类方案,务必在找签名之前跟加固方确认一句:”这个包能不能被第三方重新签名”。答不上来,就要先做一次测试签。
正确的协作顺序
给一个能直接照着走的流程:
-
应用功能开发完成,出发布版本。
-
在这一版上做加固、混淆,产出加固后的安装包。
-
自己先跑一遍冒烟测试:装上、打开、走一遍主流程,确认加固本身没把应用搞坏。这一步很多人跳过,代价是后面分不清问题出在加固还是出在签名。
-
把加固后的包提交给签名方。
-
签名产出的成品再验一遍:能装、能打开、主流程正常,就可以分发了。
什么时候该先做一次测试签
如果应用用了比较重的加固方案,建议第一次合作时先走一次小范围测试。花的时间不多,但能把”加固与签名是否兼容”这个最大的不确定性一次性打掉。比起整批用户装不上的损失,这点时间成本可以忽略不计。
小结
记住一句话就够了:加固在前,签名在后,签完别再动。加固完先自己测一遍再交出去,加壳类方案提前确认能不能被第三方重签,这两件事做到,这条链路基本不会出岔子。
我是本期作者小思,想解决苹果企业签名、超级签名、TF签名问题?可以在微信公众号对话框找到我哦~(QQ:822404920 微信:A-mk5888)