Administrator
发布于 2026-08-25 / 30 阅读
0
0

系列文章《Android 工程师的 100 篇进阶笔记》第 14 篇:Android 安全:反编译、加固、签名与数据保护

Android 安全是一个常被低估的领域。很多团队直到被逆向、被爬虫、被薅羊毛,才开始补课。

这篇会讲 Android 安全的几个核心层面:

  1. APK 反编译有多容易。

  2. 代码混淆、加固、VMP 的基本原理。

  3. 本地数据、密钥、通信安全。

  4. 签名机制与 APK 完整性校验。


一、APK 反编译:你的代码其实是裸奔的

1.1 反编译三步走

# 1. 解压 APK
unzip app-release.apk -d app/

# 2. 把 classes.dex 转成 jar
d2j-dex2jar app/classes.dex -o app.jar

# 3. 用 JD-GUI 或 jadx 查看源码
jadx app-release.apk -d source/

不到一分钟,你的 Kotlin/Java 代码就差不多能看懂了。

1.2 资源文件也暴露

APK 里的 res/、assets/、AndroidManifest.xml 都是明文或容易还原的。图片、配置文件、密钥文件都能被直接拿走。

1.3 反编译能做什么?

  • 分析你的接口和加密逻辑。

  • 修改代码重新打包(如跳过登录、破解 VIP)。

  • 提取密钥、Token、业务规则。

结论:没有任何手段能 100% 防反编译,安全的目标是提高逆向成本。


二、代码混淆:第一道防线

2.1 ProGuard / R8 做了什么?

  • 缩短类名、方法名、字段名。

  • 删除未使用的代码。

  • 优化字节码。

  • 打乱控制流(R8 有限支持)。

-keep public class com.example.MyApi { *; }
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

2.2 混淆不是加固

混淆只是让代码难读,但逻辑结构还在。配合 jadx 的变量重命名和反编译优化,熟练的逆向工程师仍然能看懂。

2.3 哪些不能混淆?

  • 四大组件(Activity、Service、Receiver、Provider)。

  • JNI 方法名。

  • 反射调用的类。

  • 序列化/反序列化类。

  • 注解模型类。

-keep class com.example.model.** { *; }
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

三、加固与 VMP:提高逆向成本

3.1 加固基本原理

加固通常包括:

  1. 解压原始 dex。

  2. 对 dex 加密或压缩。

  3. 运行时通过壳代码动态解密并加载。

原始 APK
    │
    ▼
壳程序
    │
    ▼
启动时解密 → 加载原始 dex → 执行

3.2 VMP(虚拟机保护)

VMP 是把关键代码翻译成自定义指令集,运行时用自己的虚拟机解释执行。逆向者需要:

  • 还原自定义指令。

  • 还原虚拟机执行逻辑。

  • 才能理解原始代码。

成本远高于普通加固,但实现复杂、性能有损耗。

3.3 加固方案选型

方案

强度

性能影响

成本

仅 R8 混淆

低

小

低

第三方加固(腾讯乐固、阿里聚安全)

中

中

中

VMP 加固

高

中到高

高

建议:核心业务上 VMP,普通业务用加固 + 混淆。


四、本地数据安全

4.1 SharedPreferences 不安全

// 明文存储
val prefs = getSharedPreferences("config", Context.MODE_PRIVATE)
prefs.edit().putString("token", userToken).apply()

未 root 的设备上其他应用读不到,但 root 后可以轻松查看。

4.2 用 EncryptedSharedPreferences

val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val prefs = EncryptedSharedPreferences.create(
    context,
    "secret_prefs",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

4.3 数据库加密

用 SQLCipher:

val factory = SupportFactory(SQLiteDatabase.getBytes("password".toCharArray()))
val db = Room.databaseBuilder(context, AppDb::class.java, "app.db")
    .openHelperFactory(factory)
    .build()

4.4 密钥不要硬编码

// 错误
const val API_SECRET = "sk_1234567890abcdef"

硬编码密钥等于白送。正确做法:

  • 用 NDK 把密钥放 C/C++ 层。

  • 用 TEE / 硬件安全模块。

  • 用服务端动态下发 + 白盒加密。


五、通信安全

5.1 HTTPS 不是终点

  • 证书固定(Certificate Pinning)防止中间人攻击。

  • 防止代理抓包(但做不到 100%,只是提高门槛)。

val certificatePinner = CertificatePinner.Builder()
    .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
    .build()

val client = OkHttpClient.Builder()
    .certificatePinner(certificatePinner)
    .build()

5.2 请求签名

关键接口要做请求签名,防止重放攻击和参数篡改:

fun sign(params: Map<String, String>, secret: String): String {
    val sorted = params.toSortedMap()
    val base = sorted.entries.joinToString("&") { "${it.key}=${it.value}" }
    return HmacSHA256(base, secret)
}

服务端校验签名,不一致则拒绝。

5.3 Token 安全

  • Access Token 有效期短(15 分钟)。

  • Refresh Token 存 EncryptedSharedPreferences。

  • 关键操作二次验证(短信、指纹、人脸)。


六、签名与完整性校验

6.1 APK 签名机制

Android 要求 APK 必须签名。签名信息包括:

  • 证书公钥。

  • 每个文件摘要。

  • 签名算法。

6.2 校验 APK 签名

fun verifySignature(context: Context): Boolean {
    val info = context.packageManager.getPackageInfo(
        context.packageName,
        PackageManager.GET_SIGNATURES
    )
    val signature = info.signatures[0].toByteArray()
    val digest = MessageDigest.getInstance("SHA-256").digest(signature)
    return digest.toHex() == "EXPECTED_HASH"
}

6.3 运行时自检

加固方案通常会做运行时自检:

  • 检查是否被二次签名。

  • 检查是否运行在模拟器。

  • 检查是否被调试器附加。

  • 检查 Xposed / Frida 等 Hook 框架。


小结

Android 安全没有银弹,核心是分层防御 + 提高逆向成本:

  1. 混淆是底线,R8 必须开。

  2. 核心业务上 VMP 或第三方加固。

  3. 本地敏感数据用 EncryptedSharedPreferences / SQLCipher。

  4. 密钥不要硬编码,通信要 HTTPS + 签名 + 证书固定。

  5. 做运行时签名校验和反调试。


下篇预告

下一篇《第 15 篇:从 Android 工程师到移动端架构师》是这个阶段的收官:

  1. 技术广度与深度怎么平衡。

  2. 架构师的日常工作和核心能力。

  3. 如何规划从高级工程师到架构师的成长路径。


参考阅读

  • Android 官方安全文档

  • OWASP Mobile Security Testing Guide

  • R8 / ProGuard 官方文档

  • 上一篇文章:第 13 篇《性能监控框架:从埋点到线上 APM 的闭环》


评论