在Android开发与逆向对抗中,加密(Encryption) 和**混淆(Obfuscation)**是保护APP核心逻辑和数据安全的两大支柱。
简单来说:混淆是为了让人看不懂代码逻辑,加密是为了让人拿不到原始数据。
以下是Android中主流的加密与混淆技术总结:
一、 代码混淆技术 (Code Obfuscation)
混淆的主要目的是增加逆向分析的成本,使反编译出来的代码难以阅读。
-
名称混淆 (Name Obfuscation)
- 工具:ProGuard, R8 (Android Studio 默认)。
- 原理 :将类名、方法名、变量名改为无意义的短字符(如
a,b,c)。 - 效果:虽然逻辑还在,但失去了语义,增加了阅读难度。
-
字符串混淆 (String Obfuscation)
- 原理:默认情况下,ProGuard 不混淆字符串。硬编码的 API 地址、Key 会直接暴露。字符串混淆会将这些常量加密,在运行时动态解密。
- 工具:DexGuard (付费), 某些自研脚本。
-
控制流平坦化 (Control Flow Flattening)
- 原理 :将原本清晰的
if-else或switch逻辑打乱,改写为一个由switch和while循环组成的巨大"分发器"。 - 效果:F5(反汇编)出来的代码逻辑像"面条"一样杂乱,极难分析业务流程。
- 原理 :将原本清晰的
-
算术运算混淆
- 原理 :将简单的算术运算(如
a = b + 1)替换为极其复杂的等效数学公式。
- 原理 :将简单的算术运算(如
二、 加密技术 (Data Encryption)
加密侧重于保护敏感数据在存储和传输过程中的安全。
-
存储加密
- 数据库加密 :使用 SQLCipher 对 SQLite 数据库进行全盘加密。
- SP 加密 :使用 EncryptedSharedPreferences(Jetpack Security 库)加密本地配置。
- 文件加密:对 Assets 或资源文件进行 AES 加密,运行时解密。
-
传输加密 (网络层)
- HTTPS/TLS:基础物理层加密。
- 双向认证 (Mutual TLS):客户端也带证书,防止中间人攻击。
- SSL Pinning (证书固定):在 APP 内硬编码服务器证书指纹,防止 Charles/Fiddler 抓包。
-
核心密钥管理
- Android Keystore 系统:将密钥存储在硬件隔离区域(TEE),程序只能使用密钥,无法导出原始密钥。
三、 Native 层保护 (C/C++ 层)
由于 Java 容易被反编译,开发者常将核心逻辑写在 C/C++ 中(NDK),并进行更深层的保护。
- OLLVM (Obfuscator-LLVM)
- 基于 LLVM 编译器的后端混淆,可以对 C/C++ 代码进行指令替换、虚假控制流、控制流平坦化。
- SO 文件加密
- 对生成的
.so文件进行加壳或段加密,只有在 APP 启动加载时才在内存中解密。
- 对生成的
四、 加固/加壳技术 (App Hardening)
这是目前国内 Android 安全的主战场,通常由第三方厂商(如腾讯、网易、加固宝等)提供。
- 第一代:DEX 整体加密
- 将整个
classes.dex加密存放在 Assets,启动时由壳代码(Stub)解密后加载到内存。
- 将整个
- 第二代:函数抽取/动态加载
- 将 DEX 中的方法体(CodeItem)清空,在运行时动态将代码填充回内存。这让内存 Dump 变得困难。
- 第三代:VMP (虚拟机保护)
- 原理:最强形态。将原始 Java 指令转换为自定义的私有指令集,并在 APP 内内置一个自定义的解释器执行。
- 效果:逆向者即使反编译,看到的也是一堆无法识别的自定义指令,彻底封死反编译之路。
五、 环境监测与反调试 (Environmental Detection)
虽然不属于加密和混淆,但它们是逆向对抗的关键。
- 反调试 (Anti-Debug) :检测
ptrace、isDebuggerConnected,一旦被调试则崩溃。 - 反 Root/反模拟器 :检测是否存在
su文件,检测硬件特征,拒绝在不安全环境下运行。 - 签名校验:在运行时检测当前签名的 Hash。如果逆向者篡改代码并重新打包,签名改变,APP 停止运行。
- 反 Hook 监测:检测内存中是否存在 Xposed、Frida 等框架的残留特征。
总结对比
| 技术项 | 解决的问题 | 常用手段 | 难度等级 |
|---|---|---|---|
| 代码混淆 | 逻辑阅读难度 | R8/ProGuard, 控制流平坦化 | 中等 |
| 数据加密 | 数据被窃取 | AES, RSA, Keystore, SQLCipher | 中等 |
| Native 保护 | 底层逻辑泄露 | OLLVM, JNI 隐藏 | 高 |
| 加壳加固 | 整体反编译 | DEX 加密, 方法抽取, VMP | 极高 |
逆向学习者的视角 :看到混淆要学会耐心调试 ;看到加密要找Hook 点(参数拦截) ;看到加壳要学会脱壳(内存镜像拉取) ;看到 VMP 建议换个简单的 APP 练手。
了解常见加密算法的实现有助于快速进行源码分析和参数定位,具体的代码实现就不再贴出来了,笔者总结了一些可作为关键词检索的特征词:
1. MD5 (Message Digest Algorithm 5)
- 算法简介 :哈希(散列)算法,不可逆。将任意长度的数据映射为固定长度(128位,通常显示为 32位十六进制字符串)。
- 核心特点 :
- 结果长度固定:32位(如
5d41402abc4b2a76b9719d911017c592)。 - 雪崩效应:输入微调,结果全变。
- 结果长度固定:32位(如
- 逆向检索关键词 :
- 代码层 :
MD5,MessageDigest,hash,hex_md5. - 特征常量(魔数) :
0x67452301,0xefcdab89,0x98badcfe,0x10325476(这些是 MD5 初始化的核心幻数)。 - 库名 :
crypto-js,blueimp-md5,hash.js.
- 代码层 :
2. AES (Advanced Encryption Standard)
- 算法简介:对称加密算法(加密和解密用同一把钥匙),是目前最流行的加密标准。
- 核心特点 :
- 要素:Key(密钥)、IV(偏移量)、Mode(模式:ECB/CBC/CFB/OFB)、Padding(填充:PKCS5/PKCS7)。
- Key 长度通常为 16, 24, 32 字节。
- 逆向检索关键词 :
- 模式名 :
AES,CBC,ECB,CFB,CTR. - 填充名 :
PKCS5Padding,PKCS7Padding,ZeroPadding. - 代码层 :
Cipher.getInstance,SecretKeySpec,IvParameterSpec,enc.Utf8.parse. - 库名 :
CryptoJS,pycryptodome(Python),Crypto.
- 模式名 :
3. RSA (Rivest-Shamir-Adleman)
- 算法简介 :非对称加密算法。有公钥 和私钥之分,公钥加密的数据只能用私钥解。
- 核心特点 :
- 通常用于加密"对称加密的密钥",或者用于数字签名。
- 速度慢,但安全性高。
- 标识:常见以
-----BEGIN PUBLIC KEY-----开头的长字符串。
- 逆向检索关键词 :
- 关键术语 :
RSA,PublicKey,PrivateKey,Modulus(模数),Exponent(指数, 常见010001或65537)。 - 文件格式 :
.pem,.der,.crt,.key. - 代码层 :
setPublicKey,setPrivateKey,X509EncodedKeySpec,RSASSAPKCS1v15. - 库名 :
jsencrypt,node-rsa,BigInt.
- 关键术语 :
4. HMAC (Hash-based Message Authentication Code)
- 算法简介 :利用哈希算法(如 MD5, SHA1, SHA256),结合一个密钥生成的摘要。
- 核心特点 :
- 相比普通哈希,多了一个
SecretKey(盐值)。 - 常用于 API 的
signature(签名)校验。
- 相比普通哈希,多了一个
- 逆向检索关键词 :
- 算法组合 :
HmacMD5,HmacSHA1,HmacSHA256. - 代码层 :
Mac.getInstance,Hmac,sig,signature,sign. - 特征 :通常在代码中会看到两个输入:
Message和Key。
- 算法组合 :
5. DES (Data Encryption Standard)
- 算法简介:较早的对称加密算法。由于 Key 较短(56位有效位),目前已被 AES 取代,但在老旧系统或某些 APP 协议中仍可见。
- 核心特点 :
- 块大小为 64 位。
- 3DES (Triple DES):DES 的增强版,应用更广,对数据进行三次 DES 加密。
- 逆向检索关键词 :
- 名称 :
DES,DESede(即 3DES),TripleDES. - 代码层 :
DES/CBC/PKCS5Padding,DESKeySpec. - 库名:同 AES,通常都在 Crypto 库中。
- 名称 :
当你在开发者工具(F12)或 Jadx 中搜索时,建议按以下优先级操作:
- 搜"参数名" :先搜请求里的加密参数名(如
sign、token、_signature)。 - 搜"特征单词" :
- 搜
JSON.stringify:这是加密前的最后一步,看数据是在哪被序列化的。 - 搜
encrypt(、decrypt(:寻找加密函数入口。 - 搜
setPublicKey:基本就是 RSA。 - 搜
iv:、mode::基本就是 AES 或 DES。
- 搜
- 搜"常数/魔数" :
- 遇到大量位运算逻辑,搜索 MD5 的初始化常量(如
0x67452301)。 - 搜索 Base64 码表:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=。
- 遇到大量位运算逻辑,搜索 MD5 的初始化常量(如
- 打断点(XHR Breakpoints) :
- 如果你知道请求的 URL,直接在 Network 面板右键该请求,选择 "XHR Breakpoints" ,当程序再次发送该请求时会自动停在加密完成的那一刻,然后通过 Call Stack(调用栈) 向上回溯。