Appearance
加密与加固逆向:AES-GCM、代码混淆、Root 检测与 Frida
回到总览:00 基础知识(Foundations)相关模块:TLS 1.2、ECDHE 密钥协商与 CA 信任链 · 09. 现代移动端网络底座:HTTP/1.1、HTTP/2、HTTP/3(QUIC) 与弱网治理
一句话定义
「加密与加固逆向」是语言无关的安全基础:用 AES-GCM 等认证加密保护数据机密与完整性,用代码混淆/加固提高逆向成本,用 Root/越狱检测与 Frida 等动态注入检测识别被篡改的运行环境——它和 TLS 同属「安全底座」,但 TLS 守通信、这一页守客户端自身的代码与数据。
代码索引
对应 Lab:aes-gcm-and-frida-detect —— AES-GCM 加解密 + Root/Frida 特征检测(源码内联于 README)
为什么需要
- 为什么不能直接把接口密钥/令牌明文写进客户端代码?
- 一句话答:客户端包体(APK/IPA/JS bundle)终会被反编译或解包提取,硬编码的密钥等于「公开」;密钥必须来自服务端下发或经安全协商,客户端只持有短期凭据。
- 为什么 AES 要用 GCM 而不是更老的 CBC 模式?
- 一句话答:CBC 只保证机密性、不防篡改(还怕 Padding Oracle 攻击),GCM 是 AEAD(带认证的加密),一次运算同时产出密文和 Tag,能同时验证完整性,省掉单独的 MAC。
- 为什么做了代码混淆,安全团队还说「混淆不是加密」?
- 一句话答:混淆只是重命名/控制流打乱,提高阅读成本,并不隐藏密钥或阻止运行;它拖延逆向,但配合动态注入(Frida)仍可在运行时提取内存中的明文,所以只能当第一道门槛,不能作为机密保护手段。
底层机制
1. AES-GCM 的「密钥 + Nonce + AAD → 密文 + Tag」
GCM 是带关联数据的认证加密:除明文外,还可以把不需加密但要参与完整性校验的 AAD(如报文头)一起算进 Tag。
- 关键约束(最容易踩的坑)
- Nonce 绝不能复用:同一个 Key 下两次加密用了相同 Nonce,攻击者可反推出明文异或关系,直接破坏保密性——这是 GCM 头号事故源。
- Tag 必须校验:解密端先验证 Tag 再使用明文;跳过校验等于退回「只加密不防篡改」。
- 可能输出(Android
javax.crypto片段示意)javaCipher c = Cipher.getInstance("AES/GCM/NoPadding"); // 12 字节 IV 推荐的 GCM 参数 c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv)); // 128 = Tag 长度 bit byte[] cipher = c.doFinal(plaintext); - 预期现象:
doFinal返回的字节里,前 12 字节是 IV(若未单独传)、其后为密文与末尾 16 字节 Tag,按协议约定拆分存储/传输即可。
2. 代码混淆与加固(提高逆向成本的层层手段)
- 可能输出(R8 规则片段)
-obfuscate -keep class com.example.sdk.public.** { *; } // 公开 API 不混淆,避免反射断裂 -printmapping mapping.txt // 保留映射,用于崩溃还原 - 预期现象:混淆后类名变
a.b.c,但-keep保留的公开边界不变;mapping.txt是还原混淆堆栈的钥匙,必须像 TLS 的symbols一样归档。
3. Root 检测与 Frida 动态注入检测
- 常见检测点
- Root:是否存在
/system/bin/su、/system/xbin/su;Magisk 的magisk挂载点;Build.TAGS含test-keys;SafetyNet/ Play Integrity 远端证明。 - Frida:进程
maps中出现frida-agent、frida-gadget;默认 TCP27042;尝试dlopen("libfrida")。
- Root:是否存在
- 预期现象:这些检测本质是「提高门槛」,不是绝对防线——越狱/Root 环境和 Frida 都能针对性绕过,所以检测到后业务侧应降权或要求二次验证,而不是当作铁证阻断。
Android / Flutter / Web / Backend 对照
| 维度 | Android | Flutter | Web(前端) | Backend |
|---|---|---|---|---|
| 对称加密 | javax.crypto (AES-GCM) | encrypt / pointycastle 包 | WebCrypto AES-GCM | OpenSSL / 各类语言 crypto 库 |
| 混淆/加固 | R8 / 加固 SDK | Dart 编译产物本身难读 + 混淆 | 代码本就下发,靠压缩/混淆 | 服务端代码不落地,天然更可控 |
| 运行环境校验 | Root/越狱 + Frida 检测 | 同宿主(走 MethodChannel 调原生检测) | 无可信环境,只能风控 | 服务器可信,无需自证 |
| 密钥保护 | Keystore / KeyChain 硬件级 | 同宿主 Keystore | 无安全存储,密钥不下发前端 | KMS / Vault 托管 |
常见场景
- 本地敏感缓存加密:把登录态 Token 之外的隐私数据落盘前用 AES-GCM 加密,Key 存进 Android Keystore(硬件级,不可导出),即使设备被 root 提取数据分区也解不开。
- 接口应答防篡改:把报文头作为
AAD参与 GCM 运算,服务端校验 Tag,防止中间人改包体或包头。 - 风控识别作弊环境:游戏/营销活动检测到 Frida 注入或 Root,标记设备、限制领券或要求短信二次验证。
常见误配、事故后果与排障
1. 事故:硬编码密钥 + Nonce 固定 → 数据可被批量解密
- 误配原因:为「方便」把 AES Key 写进代码,并用固定 IV(如全 0)。
- 后果:攻击者在客户端提取密钥后,对同一 IV 下所有密文可做已知明文攻击,批量还原历史数据。
- 排障与修法:密钥经安全协商/下发且不落客户端;每次加密用随机且唯一的 12 字节 Nonce,并随密文一起传出。
2. 误配:只做混淆,把混淆当加密防机密
- 现象:以为 R8 混淆后密钥就安全了,仍把密钥明文留在某字符串常量里。
- 排障与修法:混淆不改变「字符串常量在包体可被搜到」的事实;机密必须走 Keystore/下发/协商,混淆只用于提高逆向阅读成本。
3. 误配:只在启动一次性检测 Root/Frida,被动态绕过
- 后果:攻击者先启动干净进程、绕过启动检测,再注入 Frida 运行时篡改逻辑。
- 排障与修法:在敏感操作(支付、领券、校验)** 前置**做周期性/即时检测,并将结果上报风控,而非只在
Application.onCreate验一次。
相近概念对比
| 概念 | 它是什么 | 易混点 |
|---|---|---|
| 加密(AES-GCM) | 保护数据机密+完整性 | 不等于「藏住密钥」,密钥管理才是难点 |
| 混淆(Obfuscation) | 提高代码阅读成本 | 不是加密,运行时数据仍可提取 |
| 加固(Hardening) | 壳/反调试/反注入 | 提高门槛,非绝对防线 |
| Root/越狱检测 | 识别被篡改环境 | 可被绕过,应降权而非硬阻断 |
| Frida 检测 | 识别动态注入 | 同样可被反检测,属攻防博弈 |
对应实验
| 实验 | 说明 | 关键源码 |
|---|---|---|
| aes-gcm-and-frida-detect | AES-GCM 加解密链路 + 一组 Root/Frida 特征检测,观察检测命中时的行为 | 代码内联于 README |
复习检查题
为什么说「AES-GCM 的 Nonce 复用」是整个模式最致命的误用? 答:GCM 的安全证明依赖「同一把 Key 下每个 Nonce 只用一次」。一旦两个明文用相同 Key+Nonce 加密,攻击者把两段密文异或,就能消去密钥流得到两段明文的异或值,结合已知明文即可还原另一段;等价于把一次性密钥流直接暴露。所以 Nonce 必须随机且全局唯一。
代码混淆能防住「客户端密钥被提取」吗?为什么安全团队坚持它只是第一道门槛? 答:不能。混淆只是把类名/方法名打乱、控制流复杂化,包体里该有的字符串常量、算法逻辑仍在,反编译或动态注入(Frida 在运行时 dump 内存)照样能拿到明文密钥。所以它只提高逆向时间与成本,真正的机密保护要靠 Keystore 硬件存储与密钥协商下发。
Root 检测和 Frida 检测做到「检测到就阻断」是否足够安全? 答:不够。两者都属于客户端自证,运行在被攻击者控制的设备上,越狱/Root 隐藏与 Frida 反检测都能绕过「启动一次」式的检测。正确做法是把检测结果作为风控信号:在敏感操作前即时复检、上报服务端做设备画像与降权(如要求二次验证),而不是当作不可绕过的硬阻断。
速记
- AES-GCM:密钥+Nonce+AAD → 密文+Tag;Nonce 复用=灾难;Tag 必校验。
- 混淆≠加密:只拖慢阅读,不改「常量可被搜、内存可被 dump」。
- 密钥管理 > 算法:硬编码密钥再强的算法也白搭;用 Keystore/下发/协商。
- 检测是信号不是铁证:Root/Frida 可绕过,应降权+上报风控。