如何对热更DLL做AES白盒加密
解读
面试官问“如何对热更DLL做AES白盒加密”,表面看是加密方案,实则考察四条线:
- 国内手游过包体检测、渠道审包、反外挂合规的硬性合规经验;
- Unity热更(HybridCLR/ILRuntime/Addressables)链路里,DLL在内存中裸奔的真实攻击面;
- 白盒AES与常规AES的区别——密钥不落地、不完整的密钥分片、抗动态调试;
- 工程落地:C#层、Native层、SO加壳、性能损耗、崩溃率、热更包大小增量,能否在上线日活百万级项目跑稳。
答得太浅(“用AES加密再解密”)会被直接打断;答得太偏(“自己写白盒算法”)会被质疑可行性;必须给出国内上线验证过的分层方案,并主动说出灰度回滚策略。
知识点
-
国内热更主流路线:
- HybridCLR(AOT+Interpreter):DLL以Assembly.dll形式存在,更新时整包下发;
- ILRuntime:DLL作为纯数据,由ILRuntime解释执行;
- Addressables + Unity Code Stripping:脚本打包成AssetBundle,运行时反射加载。
三种路线DLL在内存中都有完整IL字节码,dump即得源码,是白盒加密刚需场景。
-
白盒AES核心指标:
- 密钥隐匿:算法内部把128-bit密钥扩展成 lookup-table,外部看不到原始key;
- 抗差分故障攻击(DFA):在Android ptrace/iOS lldb注入下,单步调试无法还原key;
- 性能预算:ARM64单核解密速度≥20 MB/s,热更DLL 1 MB 需在50 ms内完成;
- 包体增量:白盒lookup-table约占用48~64 KB,需合并到libEncrypt.so,不能每个DLL一份。
-
国内合规“双清单”要求:
加密算法需在国家密码管理局双清单内,AES-128/192/256属于通用算法,可直接使用;但若使用SM4白盒,需额外提供《商用密码产品认证证书》,否则渠道包会被卡。 -
上线踩坑点:
- iOS14+ 开始,JIT权限收紧,白盒SO必须走TestFlight与App Store双重签名,__TEXT段不能有可写权限;
- 部分华为/荣耀机型对mprotect()改RX→RW会触发内核告警,需用memfd_create + mmap匿名映射绕过;
- 腾讯MTP、网易易盾外挂样本已出现IL2CPP + frida脚本dump Assembly-CSharp.dll,白盒解密必须放在NativeInit()之前完成,且Java层不可暴露decrypt()符号。
答案
我去年在XX项目(月活600万)落地的方案,分四层:
-
生成白盒密钥:
用白盒AES-128生成工具(国内采购的江南科友WB-AES SDK,已过国密二级),把原始密钥k扩展成16组8-bit lookup表Tbox/Ty,输出whitebox_key.bin(48 KB)与whitebox_decrypt.so(内置表驱动)。 -
打包阶段:
CI里在Jenkins Pipeline新增stage“EncryptDLL”,把Assembly.dll先LZ4HC压缩→再白盒AES-128-CBC加密→IV每包随机→输出Assembly.dll.enc;同时把whitebox_key.bin作为raw资源打进libEncrypt.so,strip掉所有符号,用OLLVM -bcf -fla混淆。 -
运行时解密:
a. NativeInit()在JNI_OnLoad阶段完成,早于Unity的mono_jit_init_version,防止IL2CPP dump;
b. 在memfd_create匿名fd里mmap RWX,把whitebox_decrypt.so自解密到内存,mprotect成RX;
c. 从StreamingAssets读取Assembly.dll.enc,白盒解密到匿名映射区,返回byte*给HybridCLR的LoadImage回调;
d. 解密完成后memset_s清零临时buffer,**madvise(MADV_DONTDUMP)**防止coredump。 -
保障与回滚:
- 性能:小米13 Pro上1.2 MB DLL冷启解密耗时38 ms,内存峰值+2.1 MB,帧率掉0.3帧,低于策划容忍阈值;
- 崩溃率:灰度7天,SIGSEGV从0.04%升到0.05%,确认与白盒无关;
- 回滚:若解密失败,VersionManager回退到上一版本未加密DLL,玩家无感知;
- 合规:SDK提供**《商用密码产品认证证书》**扫描件,已上架华为、OPPO、应用宝无驳回。
一句话总结:“DLL在磁盘是密文,在内存是明文但生命周期仅50 ms,密钥以白盒表形式分散在SO,dump也还原不了原始AES key,上线半年零外挂脱壳。”
拓展思考
-
如果项目切到WebGL平台,无法使用SO,白盒AES怎么做?
答:用WebAssembly + Emscripten把白盒表编译成**.wasm**,通过Unity WebGL Plugin导入;密钥表拆成4段,分别藏在wasm code section、memory section、custom name section、JS字符串混淆里,运行时动态拼表。实测Chrome v113下解密1 MB DLL耗时120 ms,比SO慢3倍,但WebGL玩家占比<5%,可接受。 -
对抗Frida stalker + inline hook如何做?
答:在whitebox_decrypt.so里加入反调试链:- syscall(SYS_gettid) + /proc/self/status TracerPid轮询;
- **SIGTRAP + ptrace(PTRACE_TRACEME)**互斥;
- TLS回调里校验libc.so .text完整性;
一旦发现调试,不立即退出,而是返回伪造IL字节码(空方法体),让外挂以为解密成功,实则游戏逻辑无法进入,降低分析意愿。
-
未来升级到SM4白盒的价值?
国密趋势下,硬核渠道(央企、军工、教育版号)已要求SM4/SM2双算法;SM4白盒lookup-table体积比AES大1.6倍,但单轮次加密指令数更少,在HarmonyOS NEXT纯鸿蒙机型上性能反而提升8%。若项目有出海+国内双版本,可编译宏隔离:国内包走SM4白盒,海外包走AES白盒,共用同一套Native接口,维护成本仅+5%。