读完本文,你将获得:
- 分清 R8、代码混淆、DEX 加壳、函数抽取、DEX2C、VMP、SO 保护与 RASP 到底解决什么问题
- 看懂一个加固 APK 从 CI 构建、后处理、对齐、重签名,到壳启动、完整性校验和业务代码加载的完整链路
- 了解 360、阿里 mPaaS、爱加密、梆梆、腾讯乐固,以及 DexGuard、Promon、Appdome、AppSealing、Google Play 方案的公开能力与证据边界
- 理解为什么加固必须与 APK 签名、Play Integrity、设备注册、账号图谱和服务端风控组合,而不能独自承担“客户端可信”
- 获得一套可执行的 release 参数、性能基线、兼容性矩阵和加固验收方法
〇、摘要:壳不是保险柜,它是一套成本控制系统
Android APK 对逆向工程天然友好。
classes.dex 不是源码,却保留了大量类、方法、调用和数据流语义;resources.arsc、Manifest、Assets、字符串和 native SO 又把接口、功能开关、协议常量、JNI 边界与第三方 SDK 关系一并交给了终端用户。一个正常用户看到的是登录、支付和播放页面,分析者拿到的却是一份可以离线拆解、反复运行和任意修改的程序副本。
APK 加固由此产生。它要处理的不是一个问题,而是四类问题:
- 代码理解。 降低 Java/Kotlin、C/C++、Flutter、Unity 或脚本逻辑被快速恢复和复用的概率。
- 运行时观测。 增加调试、Hook、注入、内存读取和自动化批量控制的成本。
- 篡改与重打包。 发现签名、代码、资源、调用顺序或运行环境发生了不符合预期的变化。
- 业务滥用。 把客户端风险信号传给服务端,让登录、领券、支付、游戏结算、内容授权等动作得到分级处置。
但有一条物理事实绕不过去:代码要在用户控制的设备上执行,处理器最终就必须获得明文指令、解码后的类,或与原算法等价的 VM 语义。 加固可以缩短稳定观测窗口、打散结构、改变执行形态、提高自动化规模成本,却无法把白盒客户端变成服务端 HSM。
所以本文的主线不是“哪家的壳最硬”,而是:
| |
这条链也把前两篇文章接了起来:Chrome VMP讨论如何让关键语义难以稳定观测,设备指纹与设备注册讨论如何把端上证据放进服务端身份和业务图谱。APK 加固位于两者之间:它保护”客户端如何执行”,但不能独立回答”服务端为什么应该相信这次请求”。
研究证据与方法声明
本文是一篇横向分析综述,不是针对某一款 App 或某一家加固产品的逆向工程报告。核心方法是公开文档收集 + 厂商能力矩阵交叉验证 + 安全边界推理,辅以已有实战经验作为校准。以下声明帮助读者判断每条结论的可信度和适用边界。
方法论
| 项目 | 说明 |
|---|---|
| 研究方法 | 文献综述 + 厂商公开文档分析 + 安全边界推理 + 已有逆向经验校准 |
| 覆盖范围 | 国内 5 家加固厂商(360、阿里 mPaaS、爱加密、梆梆、腾讯乐固)+ 海外 6 类方案(R8、DexGuard、Promon、Appdome、AppSealing、Google Play)+ 6 类技术层次(混淆、加壳、抽取、DEX2C、VMP、RASP),共计 11 产品/平台 x 6 技术维度 |
| 技术维度 | 构建期变换、DEX/SO 载荷保护、运行时检测(RASP)、签名与 Attestation、设备注册、服务端风控 |
| 证据分级 | A(官方公开文档与平台规范)/ B(架构推理与工程共识)/ C(版本化逆向样本与社区观察)– 详见下表 |
证据来源与分级
| 等级 | 来源数 | 典型代表 |
|---|---|---|
| A:公开确认 | ~25 | Android 官方文档(R8 配置、APK 签名方案 v2/v3/v4、Code Transparency、Play Integrity、动态代码加载风险)、OWASP MASTG(混淆、RASP、Root 检测、编译器/壳识别)、360/阿里/爱加密/梆梆/乐固产品页与帮助文档、Guardsquare/Promon/Appdome/AppSealing 产品文档与白皮书 |
| B:架构推理 | ~8 | NDSS 2018 DroidUnpack 论文(壳双面性与安全影响)、PolyU 壳演化研究、APKiD/Obfuscapk 开源项目分析、通用 VMP/白盒密码学工程共识 |
| C:外部观察 | ~3 | 仓库内抖音 MetaSec 实验记录(native SDK 保护与设备注册观察)、Chrome VMP 文章(VMP 安全属性验证)、设备指纹文章(注册闭环与证据边界) |
范围限制
| 限制 | 说明 |
|---|---|
| 未做加固产品实测 | 本文未对任何加固产品进行采购、接入或红队测试;厂商能力来自公开文档声明,不代表默认策略、最新版本或实际防护效果 |
| 无防护强度排名 | 不采信厂商自述指标(”脱壳率为 0””全方位保护”),不对产品做安全强度排名 |
| 版本时效 | 厂商产品页和帮助文档以 2026 年 8 月可访问版本为准;部分厂商文档更新频率不一致,历史版本信息可能仍存在于公开页面 |
| 乐固当前状态不确定 | 腾讯乐固的当前服务形态、SLA 和能力矩阵无法从公开文档完整确认,相关结论仅基于历史公开材料 |
| 无服务端验证 | 所有关于”服务端应如何”的建议来自安全工程最佳实践和 OWASP 规范,非对任何平台后端的实测 |
| 未覆盖 iOS | 本文仅讨论 Android APK/AAB 加固,iOS App Shielding 不在范围内 |
AI 使用声明
| 用途 | 工具 | 边界 |
|---|---|---|
| 架构图与流程图绘制 | Cocoon AI architecture-diagram | 图形布局与渲染;数据内容、层次设计和标注由笔者决定 |
| 厂商能力矩阵初稿整理 | 通用 LLM | 按笔者设计的维度从公开文档提取能力声明;所有条目均经笔者逐项验证原始来源 |
| 文献检索辅助 | 通用 LLM | 初筛候选论文和项目;所有引用均经人工验证原文 |
一、先分清六个概念:很多“加固强度”争论从名词就错了
1.1 六类技术不是同义词
| 技术 | 发生位置 | 主要改变 | 主要目标 | 天然边界 |
|---|---|---|---|---|
| R8/ProGuard 类优化混淆 | Android 构建期 | 删除无用代码、优化、重命名类/方法/字段 | 缩小体积,降低直接可读性 | 不隐藏整体 DEX,不负责动态攻击 |
| 代码/数据保护 | 构建期或后处理 | 控制流、算术、字符串、资源、API 调用变换 | 减少静态锚点 | 运行时仍需恢复等价语义 |
| DEX/SO 加壳 | APK/AAB 后处理 + 启动时 | 加密载荷、替换入口、注入 loader | 阻断直接反编译和简单重打包 | loader 和加载边界成为新攻击面 |
| 函数抽取/DEX2C/Java2CPP | 构建期或后处理 | 移走方法体,改成 native 桥或自定义调度 | 破坏 JADX 中的自然调用图 | Java/JNI 边界和输入输出仍可观察 |
| VMP/代码虚拟化 | 构建期 + 运行时 | 把方法变成随机或自定义 VM 指令及解释器 | 抹除原始指令集和控制流语义 | 性能成本高,通常只能保护少量关键路径 |
| RASP | App 运行时 | 检测篡改、调试、Hook、Root、模拟器、覆盖层等 | 发现实时攻击并响应 | 本地检测可被修改,误报会直接影响用户 |
APK 签名、Play Integrity 也常被塞进“加固”这个词里,但两者属于另一层:
- APK v2/v3/v4 签名让 Android 在安装和更新时验证包内容及开发者身份连续性。它能发现签名后被修改的 APK,但不能阻止分析者读取一个合法 APK。
- Play Integrity让 Google Play 为具体请求返回 App、设备、许可和可选环境 Verdict。它增加了客户端外部的证据,却不保护你的业务算法,也不替服务端做授权。
1.2 一张图看清五层责任
这张图最重要的不是五层都要买,而是每层的证明对象不同:
| 层 | 能提高什么 | 不能证明什么 |
|---|---|---|
| 构建期加固 | 代码恢复、复制和修改成本 | 当前安装一定来自官方渠道 |
| 壳与 RASP | 动态观测、注入和批量自动化成本 | 检测结果没有被本地修改 |
| 签名与 Attestation | 包身份、版本、设备或请求属性 | 操作者是真人、账号无风险、交易意图正常 |
| 设备注册 | 安装、事件与账号历史连续性 | 句柄等于物理设备,或设备永久唯一 |
| 服务端风控 | 对具体业务动作做授权和分级处置 | 客户端从此不再需要更新防护 |
1.3 先做威胁模型,再勾功能复选框
🧑🔬 一款新闻客户端、一款离线游戏、一款银行 App 和一个广告归因 SDK,需要保护的资产完全不同。
| 资产 | 典型威胁 | 优先技术 | 不应放在客户端的东西 |
|---|---|---|---|
| API 调用资格 | 脚本化、重放、重打包调用 | 请求绑定、Attestation、设备注册、服务端限速 | 永久 API 主密钥、全局签名私钥 |
| 支付/权益逻辑 | 金额篡改、重复领券、账号接管 | 服务端权威状态、RASP、动作级完整性证明 | 最终价格、余额和权益判定 |
| 游戏规则 | 修改内存、速度、结算结果 | 服务端结算、关键逻辑 VMP、反调试/反注入 | 可由客户端单方面决定的排名和资产 |
| 算法与 SDK IP | 反编译、未授权集成、接口复制 | 选择性 VMP、native 保护、授权协议 | 可离线复用的厂商级秘密 |
| 媒体与模型资产 | 批量提取、替换、离线复用 | 资源加密、白盒密钥、DRM/服务端授权 | 无到期和设备约束的内容密钥 |
如果没有这张资产表,“全 VMP”“所有 Root 设备退出”“所有字符串都加密”只是在把稳定性预算换成一个模糊的安全感。
二、一个加固包是如何构建和启动的
2.1 从 release 产物到业务请求的十步链路
这是一张抽象图,不代表某个厂商的实现。主流方案在“载荷放在哪里、何时解密、如何接管 ClassLoader、是否抽取方法、VM 在 Java 还是 native 层”上差异很大,但生命周期大体一致:
- CI 先产出可运行、可测试的 release APK/AAB。
- R8 做 shrink、optimize、obfuscate,构建系统保存 mapping 和 native symbols。
- 加固工具改写 DEX、SO、资源或 Manifest,注入 stub、loader、完整性逻辑和 RASP。
- 对改写后的最终内容做 ABI、组件、资源、Split、热修复和框架兼容验证。
- APK 先
zipalign再用发布密钥签名;AAB 按加固厂商和 Play App Signing 流程使用 upload key。 - 安装时由 Package Manager 验证签名和更新关系。
- 启动时壳的
Application、ContentProvider或 native bootstrap 先于主要业务代码运行。 - 壳校验证书、载荷、内存、进程和环境,建立本次运行的保护状态。
- 业务语义通过内存类加载、函数抽取、native 桥或 VM 解释器被执行。
- 高价值动作携带安装句柄、动作摘要和 Attestation,由服务端决定放行、挑战、限速或拒绝。
2.2 壳启动时究竟做了什么
传统“整体 DEX 加密壳”的典型 APK 表面上只剩一个很小的 classes.dex 和若干壳 SO,原始 DEX 被放进 Assets、附加区或自定义容器。进程启动后,壳先执行:
| |
早期壳倾向把完整 DEX 解密到文件,再通过 DexClassLoader 加载;这种路径稳定,但明文落盘窗口明显。后续方案更多采用应用私有目录、匿名映射、内存加载、按类/方法恢复、函数抽取或 VM 调度,目的不是让明文“绝对不存在”,而是让它不再以一个完整、长期、标准格式的 DEX 出现。
Android 官方对动态代码加载的态度很明确:它会引入代码替换和完整性风险,从远程来源下载可执行代码还可能违反 Google Play 政策。加固壳即使只加载包内载荷,也需要做到来源固定、加载前校验、私有存储和最小化动态面;“因为是安全产品,所以动态加载天然安全”并不成立。
2.3 函数抽取、DEX2C 与 VMP 的差别
🔬 函数抽取把关键方法体从原 DEX 拿走,原位置只保留索引、桥接或异常形态,运行时再从保护容器恢复。它对付的是“解开整体 DEX 就得到全部逻辑”。
DEX2C/Java2CPP把部分 Java/Kotlin 字节码翻译为 native 代码,通过 JNI 或生成的桥接层调用。它把问题从 JADX 转到 ELF、ABI、对象封送和 JNI 边界,并没有把白盒环境变成黑盒。
VMP则把方法编译成自定义指令流,由随机化或定制解释器维护虚拟 PC、寄存器、状态和 handler。它与 Chrome VMP 文章里的核心思想相同:保护重点不是“没有代码”,而是让原控制流、数据流、常量和算法阶段失去稳定对应关系。
| 方案 | 静态恢复成本 | 运行成本 | 最适合 | 最大工程风险 |
|---|---|---|---|---|
| 名称/资源混淆 | 低到中 | 很低 | 全量代码基线 | keep 规则过宽导致效果有限 |
| 字符串/类加密 | 中 | 低到中 | URL、策略、少量敏感类 | 解密入口成为集中锚点 |
| 函数抽取 | 中到高 | 中 | 核心 Java/Kotlin 方法 | 反射、序列化、热修复兼容 |
| DEX2C/Java2CPP | 中到高 | 中 | 算法、协议、SDK IP | JNI 复杂度、崩溃定位和 ABI |
| 选择性 VMP | 高 | 中到高 | 短小、高价值、低频逻辑 | 启动、耗电、JIT/ART 和机型差异 |
| 全量 VMP | 表面很高 | 很高 | 极少数离线高价值目标 | 性能、包体、崩溃和可维护性失控 |
“全量”不是高级版的同义词。真正成熟的策略是把 VM 预算放在授权状态机、签名核心、结算校验、白盒密钥派生等少量方法上,把 UI、序列化、数据库、网络框架和高频循环留给正常编译器优化。
2.4 release 构建参数和正确顺序
加固前的包必须先是一份合格的 release 产物。一个保守的 Kotlin DSL 基线如下:
| |
这段配置只有三个安全含义:release 不暴露调试入口,R8 使用优化规则,CI 为 native 崩溃保留可归档符号。它不是“开启加固”的开关。
推荐把发布链固定为:
| |
几个容易踩中的顺序问题:
- 使用现代
apksigner时,APK 应在签名前完成zipalign;签名后再改任何 ZIP 字节都会让 v2/v3 校验失效。 - 很多云加固服务需要读取原包证书做防重打包绑定,但加固输出仍要重新签名。输入是否必须已签名以厂商文档为准,生产发布密钥不应上传给 SaaS 加固平台。
- AAB 不是“把
.apk后缀换掉”。加固必须理解 Bundle、dynamic feature、split、Play App Signing 和最终设备 APK 的关系。 - Code Transparency 要覆盖最终 DEX 和 native library;如果先生成透明度文件,再让加固工具改写代码,验证会失败。应确认加固、透明度生成和上传的明确顺序。
- mapping、native symbols、加固策略版本和原/加固产物哈希都要进入不可变构建记录,否则线上 crash 只剩一串被二次变换的地址。
三、主流方案对比:比较产品形态,不比较宣传词数量
🧑🔬 截至 2026 年 8 月,市面方案大致分成三类:构建工具、包后处理/应用 Shielding、平台完整性服务。下面的“公开能力”只证明厂商文档声明或产品支持过某项能力,不证明默认策略已经开启,不证明任意版本的防护强度,也不构成采购排名。
3.1 国内:以包后处理和一站式防护为主
| 产品/平台 | 公开形态 | 公开能力重点 | 适合的组织形态 | 必须追问的边界 |
|---|---|---|---|---|
| 360 加固保/天御 | SaaS 与本地部署,APK/AAB 后处理 | DEX 加壳、函数抽取、DEX2C、DEX/SO VMP、字符串/资源、白盒、反调试/Hook/dump、Root/Xposed/Frida 等 | 需要广覆盖能力和多渠道支持的团队 | 哪些能力默认启用;AAB/64 位/新 Android 版本矩阵;包体与冷启动实测 |
| 阿里云 mPaaS 应用加固 | 云端任务,支持 APK/AAB、核心类、SO、Assets | DEX 整体、篡改、白盒、调试/Hook/模拟器/dump;专业版增加 VMP、注入、劫持等 | 已使用 mPaaS、需要控制台和企业流程的团队 | “快速/兼容模式”差异;包名绑定;动态特性、热修复和三方 SDK 兼容 |
| 爱加密 | 云端与企业加固,App/SDK/SO 多产品 | DEX 整体/分离/混合/VMP、Java2CPP、SO Linker/SO VMP、签名和运行时防护 | 需要 SDK 独立保护或多种 VMP 形态的团队 | “双重 VMP”等名词对应的保护范围;策略可观测性;升级和故障回滚 |
| 梆梆安全 | 在线/桌面助手,标准与定制加固 | DEX/资源完整性、反调试、函数级保护、VM 指令集、SO/协议定制 | 需要批量、多渠道或定制交付的团队 | 官网帮助同时存在较老兼容信息;必须以当前合同版本和真机测试为准 |
| 腾讯乐固 | 历史上一键云加固、重签名与多渠道工具 | 官方历史资料覆盖 DEX、防篡改、防调试、内存和 SO 保护 | 维护既有接入或腾讯生态历史项目 | 当前公开文档较分散,不能用旧版功能表推断 2026 年服务、兼容和 SLA |
🤖 国内方案的共同优点是接近”拿包即加固”:不要求大规模改源码,能同时覆盖 DEX、SO、Assets、签名、运行环境和渠道包。共同风险也来自这里:它们会成为 release 供应链的一部分,并且在 App 最早启动阶段注入大量高权限逻辑。
采购时至少要回答:
- 原包是否离开企业网络,厂商是否保存样本,谁能访问,保留多久?
- 加固引擎、策略和壳运行时能否锁版本,能否重现半年前的同一构建?
- 是否支持 AAB、Play App Signing、dynamic feature、Baseline Profile、64 位和目标 Android 版本?
- 遇到 crash、ANR 或误报时,能否符号化、灰度关闭单项策略并快速回滚?
- RASP 事件能否带版本、置信度和证据类型上报,而不是只返回一个
isRisk=true?
3.2 海外:构建工具、Post-compile Shielding 与运行时平台分工更明显
| 产品/平台 | 集成位置 | 公开能力重点 | 与国内“一键壳”的主要差异 |
|---|---|---|---|
| R8 | Android Gradle 构建链 | shrink、optimize、obfuscate、resource shrink | 免费基线和性能工具,不是完整 App Shielding/RASP |
| Guardsquare DexGuard | 构建工具链,延续 R8/ProGuard 配置 | 名称/控制流/算术/API 混淆,类/字符串/资源/SO 加密,随机 VM 代码虚拟化,RASP | 更强调与源码构建、规则和可选择保护范围结合 |
| Promon Shield for Mobile | post-compile Shielding,可本地部署 | DEX 加密、白盒保护、反篡改/重打包、Root/Hook/调试/覆盖层、响应与 Attestation | 把运行时 Shielding、代码保护和 App Attestation 分成可组合模块 |
| Appdome | CI/CD 中的 no-code post-build 融合 | RASP、反篡改、混淆、数据加密、MitM、威胁遥测与构建证明 | 更像持续维护的移动防御平台,重点是策略编排和运行时可见性 |
| AppSealing | post-build sealing,游戏场景突出 | 内存/代码、Root/模拟器/调试/篡改检测,Assets/Data Sealing | 面向游戏和快速接入,需实测引擎、插件和商店兼容 |
| Google Play Automatic Protection + Play Integrity | 分发平台与动作级 API | 未授权再分发引导、App/设备/许可 Verdict、可选风险信号 | 不是通用混淆器或壳;优势是证据不完全由 App 自己生成 |
🧑🔬 Google 的方案尤其容易被误读。Automatic Protection 主要解决未知渠道再分发和盗版引导,Play Integrity 解决请求是否来自 Play 识别的 App/设备环境;它们不加密你的 DEX,也不会隐藏算法。反过来,一套很重的本地壳也不能生成与 Google 平台签发等价的硬件/生态证据。
3.3 一个更有用的“强度分级”
🧑🔬 与其按厂商排名,不如按业务投入分级:
| 级别 | 组合 | 适用场景 | 退出条件 |
|---|---|---|---|
| L0 发布完整性 | release 配置 + APK/AAB 签名 + 密钥治理 | 所有 App | 不允许省略 |
| L1 低成本基线 | R8 全模式 + 最小 keep + 移除日志/调试元数据 | 普通内容和工具 App | 静态恢复仍足以造成业务损失时升级 |
| L2 关键资产保护 | 字符串/资源/类加密 + 少量 native 化 | 有接口、算法、离线资产 | 性能和维护成本超过资产价值时停止扩张 |
| L3 运行时韧性 | 壳 + 完整性 + 选择性 RASP + 威胁遥测 | 金融、游戏、反作弊、高价值 SDK | 没有灰度、回滚和误报治理时不要强拦截 |
| L4 选择性 VMP | 关键状态机/算法 VMP + 白盒/会话材料 | 高价值且低频的核心路径 | 高频 UI、序列化、渲染和网络框架不应进入 VM |
| L5 服务端闭环 | 动作级 Attestation + 设备注册 + 风险图谱 + 分级授权 | 有在线后端的高价值业务 | 这是目标架构,不是可选豪华版 |
L5 不代表客户端保护越多越好。它代表系统终于承认:客户端防护的结果只是证据,授权权力应留在后端。
四、从分析者视角评估:主流加固为什么仍会失守
本节只讨论安全边界和防守验证,不给出针对具体产品、版本或 App 的脱壳与绕过步骤。
4.1 静态面:壳隐藏原 DEX,也暴露自己的形状
加固后的 APK 通常会出现结构变化:业务 DEX 缩小或熵升高、入口组件变化、新增 native loader、自定义 Assets、异常节区、反调试字符串和新的类加载逻辑。APKiD 之类工具正是通过 DEX/ELF 特征识别编译器、混淆器、壳和反分析机制。
“能识别是哪家壳”不等于“能自动脱壳”,但它会帮助分析者选择正确的观察层。更重要的是,固定壳版本在大量 App 间复用,攻击者一次理解 loader、协议和检查点,成本就可能被摊薄到整个客户群。因此成熟加固会做构建级随机化、策略差异化和版本轮换,而不是只更换 SO 文件名。
4.2 运行时面:CPU 必须执行等价语义
🔬 无论原始方法最终变成内存 DEX、native 基本块还是 VM opcode,运行时都要完成三件事:拿到输入、改变状态、产生输出。分析者不一定需要恢复一份漂亮的原 APK;在安全评估中,观察关键 API 边界、类加载事件、JNI 封送、文件/网络副作用和业务结果,往往已经足以回答“秘密是否可复用、校验是否仅在本地、请求是否可重放”。
这与 Chrome VMP 的结论一致:高级保护减少的是稳定锚点,而不是输入输出语义。防御设计应进一步做到:
- 密钥按设备、安装、账号、会话或动作派生,单次观测材料不能跨环境复用。
- 高价值输出带服务端 nonce、时效和业务摘要,不接受离线生成的万能结果。
- 把完整性检查分散到真实状态转换中,让“删掉一个 if”不能关闭整套保护。
- 后端识别异常调用顺序、速度、关系和结果,而不是只检查一个客户端 Header。
4.3 本地完整性:签名校验不是第二个信任根
App 自己读取证书、计算 DEX hash、检查 .text 或验证资源,能发现大量低成本篡改。但校验代码、期待值和失败分支也都在同一攻击者控制的进程里。
单点本地校验常见的失败模式是:
| |
它在工程上简单,在安全上也给出了稳定的单点。更合理的设计是让证书、包体、内存、加载来源和调用顺序共同参与会话状态派生,把结果连同版本和动作摘要送往后端;本地响应只负责保护正在处理的敏感数据,服务端响应负责业务授权。
4.4 Root、模拟器和 Hook 检测:证据相关,不是用户定罪
文件路径、包名、端口、线程名、内存映射和进程属性等 artifact 检测更新快、成本低,也最容易因工具改名、隐藏或系统差异失效。状态一致性、代码页完整性、调用来源、时序和平台 Attestation 通常更稳,但仍然没有任何单一检测能覆盖全部设备。
🔬 OWASP 对 Root/RASP 的建议很克制:多种、分散的检测能提高整体反篡改成本,但 RASP 可被有能力的攻击者绕过,并会带来性能和误报。企业设备、无障碍服务、投屏、调试 ROM、云手机和部分 OEM 行为都可能落入“看起来异常”的集合。
因此响应至少要分层:
| 风险 | 推荐响应 | 不推荐响应 |
|---|---|---|
| 低价值浏览 + 单一弱信号 | 记录、限频、增加后续抽样 | 立即退出并永久封设备 |
| 登录/注册 + 多个一致异常 | 二次验证、缩短会话、限制批量速度 | 只在客户端弹“检测到 Hook” |
| 支付/结算 + App 不识别或动作摘要不匹配 | 服务端拒绝本次动作并保留审计 | 让客户端自行决定交易成功 |
| 敏感密钥正在内存中 + 确定篡改 | 清理局部状态、终止敏感操作、上报 | 无差别清数据导致证据和用户数据丢失 |
4.5 VMP 的真实价值与上限
🧑🔬 VMP 对”必须恢复原算法”的攻击非常有效:原控制流被 VM dispatcher 吞掉,opcode/handler 可随机化,中间状态可编码,完整性检查又能与 VM 状态耦合。它会把线性的反编译任务变成指令集恢复、状态语义映射和动态差分工程。
但 VMP 不会修复业务协议:
- 如果服务端接受永久 Token,VM 只是在保护这个永久 Token 的生成器。
- 如果价格和结算由客户端决定,VM 只是让错误架构更难读。
- 如果所有设备共享同一把客户端密钥,一次有效恢复仍可能造成全局影响。
- 如果 VM 覆盖高频路径导致卡顿和崩溃,攻击者甚至不需要突破它,产品自己先损失用户。
加固的经济目标应该是:让攻击的单样本成本高于可获得收益,让批量复制难以摊薄,让泄露材料的复用范围足够小,并让服务端能及时发现和撤销。
4.6 加固本身也会扩大风险面
NDSS 2018 的 DroidUnpack 研究提醒了一个经常被忽略的事实:商业壳既被合法 App 使用,也会被恶意软件滥用;壳还可能给被保护应用引入新的安全漏洞和分析盲区。
对正常企业而言,风险集中在五处:
- 供应链。 生产包上传第三方后,源 DEX、证书信息、接口和资源进入新的信任域。
- 早期启动。 壳在业务代码前执行,任何兼容问题都会变成全量冷启动故障。
- 高权限 native 面。 自定义 loader、解压、解析和内存权限切换增加 native 攻击面。
- 可观测性。 二次混淆和虚拟化会让 crash、ANR、性能热点和安全事件更难归因。
- 审核与政策。 动态加载、下载代码、无障碍/覆盖层处置和数据采集都要满足商店及隐私要求。
这也是为什么“加固后能安装、能打开首页”远远不够。
五、结合设备注册:把加固结果变成可用证据
设备注册文章里已经拆分了四个对象:本地安装种子、服务端设备句柄、用户映射 ID、动作证明/风险 Token。APK 加固接入这条链时,最容易犯的错误是把壳生成的“设备 ID”或“环境安全”布尔值当成新的永久信任根。
5.1 推荐的请求闭环
| |
这里每个对象都有不同生命周期:
| 对象 | 建议生命周期 | 服务端用途 |
|---|---|---|
| 加固策略/壳版本 | 随 App 发布版本 | 解释检测能力和已知缺陷,不直接授权 |
| RASP 事件 | 单次运行或短窗口 | 作为带证据类型、置信度的环境信号 |
| 安装句柄 | 一次安装,可轮换/删除 | 连接激活、事件、配置和账号历史 |
| Attestation Token | 单动作或短时 | 验证 App/设备属性、摘要和新鲜度 |
| 登录会话 | 账号策略决定 | 认证用户并限制权限、设备数和时效 |
| 业务授权 | 单个对象/交易 | 决定这次领取、支付、结算或播放是否成立 |
5.2 抖音系样本给出的启示
🔬 抖音 MetaSec 实验记录展示了一种典型组合:native 安全 SDK 经过 OLLVM、VM、JIT、自毁和环境门保护;设备注册返回 device_id/install_id 后再回填安全与事件上下文;后续请求带签名和连续设备历史。
这套设计的价值不只是“某个 SO 很难逆”。它把四件事连在了一起:
- 加固保护签名和环境采集实现,降低直接复制成本。
- 设备注册把一次安装变成服务端可运营句柄。
- 请求签名把 URL、Body、时间、设备上下文和会话状态组合成短期证据。
- 服务端继续使用内容、账号、广告、电商、网络和行为图谱判断风险。
它同样说明了加固的边界:如果研究者能够在完整运行环境中调用保护后的实现,系统面对的是“实现被当作 Oracle 使用”,而不只是“算法被还原”。防守不能只检测 SO 是否被 dump,还要限制注册速率、会话转移、设备句柄复用、请求时序和业务结果异常。
5.3 Play Integrity 应放在动作附近
Play Integrity 的标准请求使用 requestHash 绑定业务摘要,Classic 请求使用 nonce。后端应先验证请求详情、App 识别、时间和摘要,再解释设备、许可和附加 Verdict;缓存一个长期“通过”的 Verdict 会增加代理和跨环境复用风险。
一个典型策略不是“不过强完整性就封号”,而是:
| |
这样即使某个本地检测被绕过,攻击者仍需同时解决动作绑定、平台证据、安装历史、账号关系和业务速度;而正常用户遇到设备兼容问题时,也不会被一个脆弱布尔值永久误伤。
六、如何选型和验收:用数据决定加固到哪一层
6.1 按业务选组合
| 场景 | 推荐基线 | 选择性增强 | 服务端必须保留 |
|---|---|---|---|
| 普通内容/工具 App | R8、签名、密钥治理、基础篡改检查 | 少量字符串/资源保护、Play Integrity 抽样 | 登录、权益、限速和远程配置 |
| 电商/本地生活 | R8 + RASP + 设备注册 + 动作级完整性 | 核心协议、风控 SDK、白盒材料保护 | 价格、库存、券、订单、支付与履约图谱 |
| 银行/支付 | 企业级 Shielding、选择性 VMP、Attestation、威胁遥测 | 输入输出保护、覆盖层/恶意 App 风险、硬件密钥 | 交易签名、限额、收款方、会话和实时风控 |
| 游戏/直播 | native/Unity 保护、反调试/注入、资源加密 | 结算/反作弊状态机 VMP、设备召回 | 权威结算、资产、匹配、速度和群体异常 |
| 对外 SDK | 最小可集成包、SDK 独立加固、授权和防盗用 | API/算法 VMP、调用方证书绑定 | 客户租户、配额、版本撤销和服务端结果 |
| 离线算法/模型 | 选择性 VMP、资源分片、白盒和设备密钥 | TEE/硬件能力、在线短租约 | 接受无法绝对保密,控制材料复用半径 |
6.2 一套可复现的验收矩阵
🧑🔬 加固验收应同时保留”未加固 release 基线”和”加固候选包”。每次更换 AGP、NDK、Kotlin、Flutter/Unity、壳版本或策略,都重新跑同一套矩阵。
构建与供应链。
- 记录源提交、依赖锁、AGP/NDK、加固引擎、策略 ID、输入输出 SHA-256、证书摘要和 SBOM。
- 确认 release key 只在企业 KMS/HSM 或受控签名任务中使用,加固平台只接触必要材料。
- 验证 mapping、native symbols、加固符号映射能在权限隔离的制品库中恢复。
静态保护。
- 对未加固/加固包分别检查 Manifest、DEX、SO、Assets、字符串、资源、导出组件和调试元数据。
- 用 APKiD、JADX、apktool、readelf 等合规工具测量“能看到什么”,不把“工具报错”当作安全通过。
- 选择 5 到 10 个真正高价值方法,验证它们是否被目标策略覆盖,而不是只看壳 SO 是否存在。
运行时与兼容。
- 覆盖最低/目标/最新 Android、主流 OEM、32/64 位、低内存、首装/升级/重装、冷/热启动和离线启动。
- 覆盖反射、序列化、WebView、ContentProvider、WorkManager、推送、动态特性、热修复和所有高风险三方 SDK。
- 测量安装大小、下载大小、冷启动 P50/P95/P99、首帧、峰值 RSS、CPU、耗电、ANR 和 crash 增量。
安全响应。
- 在企业授权测试设备上分别验证篡改包、调试环境、Root/模拟器、Hook/注入、覆盖层和屏幕捕获信号。
- 先以 shadow mode 上报,比较真实用户误报和攻击样本召回,再启用 challenge/limit/deny。
- 每个强制策略必须有远程降级、版本范围、审计日志、申诉/恢复和紧急回滚路径。
6.3 采购时最有价值的十二个问题
- 哪些能力是编译期变换,哪些只是运行时 artifact 检测?
- VMP 能否按方法选择,能否给出性能预算和不支持的字节码/ABI 清单?
- AAB、Split APK、dynamic feature、Baseline Profile 和 Play App Signing 如何兼容?
- 新 Android 版本和 OEM 适配的 SLA 是什么,壳是否可锁定和回滚?
- Flutter、React Native、Unity、Kotlin 协程、Jetpack Compose 和常用热修复框架覆盖到哪一层?
- 原始 APK/AAB 如何传输、存储、隔离和删除,能否完全本地部署?
- 是否需要上传 keystore,若需要,为什么不能在客户 CI 内完成签名?
- crash 如何映射到原始 Java/native 符号,供应商能否在不拿源代码时协助定位?
- RASP 事件是否有稳定 schema、版本、证据类型、置信度和服务端签名?
- 误报时能否单独关闭某项检测,而不是替换整个 APK?
- 能否提供经授权的红队测试,而不是只展示 JADX 打不开的截图?
- 加固引入的 native loader 和第三方组件如何做漏洞响应、SBOM 和 CVE 通知?
🧑🔬 如果供应商不能回答第 4、6、8、10、12 个问题,即使功能表上写满了 VMP、白盒和反 Hook,也不适合进入高价值 release 链。
七、结论:加固的终点不是“脱不下来”,而是“拿下来也难以复用”
主流 APK 加固已经从早期“整体 DEX 加密 + 启动释放”演化成一组可组合技术:
- R8 和代码变换减少静态语义;
- 类/函数抽取、DEX2C 和 SO 保护改变代码承载位置;
- VMP 用自定义状态机替代自然指令和控制流;
- RASP 检测运行时篡改、调试、Hook、Root、模拟器和恶意环境;
- APK 签名与 Play Integrity 增加 App 外部的身份和环境证据;
- 设备注册把安装、事件与账号历史连接起来;
- 服务端最终把证据绑定到一次登录、支付、领券、结算或播放动作。
国内 360、阿里、爱加密、梆梆、乐固更偏一站式包后处理和多渠道生态;DexGuard 更靠近构建工具链;Promon、Appdome、AppSealing 更强调 post-compile Shielding、RASP 和持续运营;Google Play 提供的是分发与平台 Attestation。它们不是一条单轴上的替代品。
🧑🔬 从安全角度看,最重要的五条结论是:
- 所有客户端保护都可被研究,差别是成本、时间、稳定性和规模。
- R8、壳、VMP、RASP、签名和 Attestation 保护的是不同对象。
- 秘密的价值取决于复用半径;设备/会话/动作绑定比“永不出现明文”更现实。
- 强度必须与兼容性、启动性能、崩溃可观测性、供应链和误报治理一起验收。
- 最终授权必须在服务端,且绑定具体业务语义。
真正成熟的加固,不追求让某个 APK 永远无法被拆开。它追求的是:即使一个版本被理解、一个检查被修改、一次运行被观察,得到的材料也难以跨设备、跨账号、跨会话和跨业务动作复用;与此同时,服务端能看见异常、限制影响、轮换材料并快速修复。
这才是 APK 加固从“壳技术”走向“安全体系”的分界线。
参考资料
Android 平台与 OWASP
- Android Developers, Configuration of R8
- Android Developers, Adopt app optimizations incrementally
- Android Open Source Project, App signing
- Android Open Source Project, APK signature scheme v3
- Android Open Source Project, APK signature scheme v4
- Android Developers, Code transparency for app bundles
- Android Developers, Dynamic code loading risks
- Android Developers, Play Integrity API overview
- Android Developers, Play Integrity, signing and automatic protection
- OWASP Mobile Application Security, Obfuscation
- OWASP Mobile Application Security, Runtime Application Self-Protection
- OWASP Mobile Application Security, Root Detection
- OWASP Mobile Application Security, Identifying Compilers, Obfuscators, and Packers
国内厂商公开资料
- 360 数字安全, 360 天御移动应用加固平台 Android 版
- 阿里云 mPaaS, Android 应用安全加固
- 阿里云 mPaaS, 创建安全加固任务与加固对象
- 阿里云 mPaaS, 移动应用安全加固产品矩阵公告
- 爱加密, Android 移动应用安全加固
- 爱加密, 移动应用 SDK 加固保护
- 梆梆安全, 应用加固介绍
- 梆梆安全, 应用加固操作流程
- 梆梆安全, 应用加固常见问题与 VM 保护说明
- 腾讯云开发者社区, 移动安全加固基础版操作指引
海外产品、项目与研究
- Guardsquare, Protecting Android applications and SDKs
- Guardsquare, DexGuard code virtualization for Android
- Guardsquare, DexGuard product factsheet
- Promon, Shield for Mobile
- Promon, App shielding for Android and iOS
- Appdome, Mobile App Security
- Appdome, Mobile Security Suite capabilities
- AppSealing, How Android AppSealing works
- RedNaga, APKiD
- Claudiu Georgiu, Obfuscapk
- Yue Duan et al., Things You May Not Know About Android (Un)Packers: A Systematic Study Based on Whole-System Emulation
- Luyi Yan, Characterizing the Evolving Android Packers