iOS 游戏加固 Checklist:一套方案至少覆盖这几层

68 阅读3分钟

平台回一句"加固完成",很多团队的加固验收就到此为止。但只打了勾、上线没几天就出事的包,见过不少:改了数值的破解版在群里传,查下来漏的不是"加没加固",是某几层没做到位,比如热更资源还是明文、越狱检测一处就能 patch 掉。验收不该停在平台回执,得把它拆成可勾选的几层,每层给一个当场能核对的点,最后附一张对照表。

分层清单

代码保护

  • 关键字符串(接口地址、开关字段、检测标记)编译期加密,成品包里搜不到明文
  • 控制流做了混淆,反编译出来不是一条直线读下去
  • 保护做在编译阶段,而不是给成品包套壳(套壳能在运行时从内存 dump 出原始代码)

IL2CPP(Unity)

  • 不只加密 global-metadata.dat,类名方法名在编译前就混淆过
  • 还原出来是 a1、b2,不是 PlayerController$$AddGold 这种可读名
  • 配了运行时反 dump(防止有人等内存里解开再整包捞走)

资源

  • 首包和热更资源用同一套保护,热更目录里没有明文 bundle
  • 按需分块解密,运行时内存里不出现整包完整明文
  • per-resource key,解出一块不等于开全套

运行时

  • 越狱检测不只探固定路径(rootless 越狱已把环境挪到别处)
  • 越狱、注入、hook、内存修改器、变速多信号组合判断,不靠单一特征
  • 检测不收敛成一个返回 bool 的总开关(否则 patch 一处就全关)

上报与服务端

  • 客户端不自己判 safe/unsafe,结果带签名和随机数报给服务端
  • "该报没报、安全模块缺失"本身也当风险信号
  • 关键结果最终由服务端定性,客户端只负责抬高伪造成本

三个最容易"假到位"的点

IL2CPP 只加密 metadata。 文件确实加密了,但游戏一跑它必然在内存里解成明文,现成工具按特征一搜就 dump 走,名字原样还原。真正拦住的是编译前把名字混掉。

资源整包解密。 加载时把整包解开再交给引擎:

byte[] plain = Decrypt(File.ReadAllBytes(path), key); // 整包明文
AssetBundle ab = AssetBundle.LoadFromMemory(plain);   // hook 这里就整包拿走

Decrypt 写得再复杂也没参与,因为攻击者截的是解完的 plain。按需分块能把这个明文窗口切碎。

检测收敛成一个 bool。

bool isSafeEnvironment() {
    return checkJailbreak() && checkDebugger() && checkSignature();
}

一条指令把返回值改成 true,前面查得再全一起失效。检测要分散、结果掺进后续逻辑,别汇成一个能被一处 patch 掉的开关。

验收对照表

检查项只做到这步 = 不够验收看什么
代码Strip 完符号变少明文字符串搜不到;保护在编译阶段
IL2CPP只加密 global-metadata还原出来是 a1/b2
资源只加密首包首包+热更统一、按需分块、内存无整包明文
运行时探几个越狱路径多信号组合、不收敛成单点 bool
上报本地判 safe/unsafe签名+随机数报服务端,缺报也算信号

一句建议

验收别数"做了哪些",看"绕过一层之后能不能直接进下一层"。这几层连成一条没有断点的线才算数;缺哪一层,就从哪一层被穿过去。

每层的完整实操和原理在字节暗面主站原文:bytehidden.com/ios-game-ha… ,也可搜「字节暗面 iOS 游戏加固」。