点赞关注,再也不迷路,你的支持对我意义重大!html
🔥 Hi,我是丑丑。本文 GitHub · Android-NoteBook 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一块儿成长。(联系方式在 GitHub)java
应用 APK 实际上是一种特殊的 Zip 压缩包,没法避免恶意破解者解压 / 反编译修改内容,针对这个问题有何解决方案呢?他山之石,能够攻玉 ——数字签名算法。应用签名正是数字签名算法的应用场景之一,与其余应用场景相似,目的无非是:android
Android 平台上运行的每一个应用都必须有开发者的签名。在安装应用时,软件包管理器会验证 APK 是否已通过适当签名,安装程序会拒绝没有得到签名就尝试安装的应用。git
软件包管理器在安装应用前会验证应用摘要,若是破解者修改了 apk 里的内容,那么摘要就再也不匹配,验证失败(验证流程见下文方案)。github
提示: 使用数字签名的优势是验证过程无须复杂的接口和权限,只须要在本机验证。web
在以前我写过的一篇文章里,我曾经分析过数字签名 & 验证模型:《密码学 | 高屋建瓴!摘要、签名与数字证书都是什么?》。在这里我简单复述下:算法
Editting...安全
须要注意的是,Android 目前不对应用证书进行 CA 认证,应用能够由第三方(OEM、运营商、其余应用市场)签名,也能够自行签名。微信
截止至 Android 11,Android 支持如下三种应用签名方案:markdown
为了提升兼容性,必须按照 v一、v二、v3 的前后顺序采用签名方案,低版本平台会忽略高版本的签名方案在 APK 中添加的额外数据。
引用自 source.android.com/security/ap… —— Android Developers
v1 签名方案是基于 Jar 的签名。
首先,咱们先来分析其签名产物。v1 签名后会增长 META-INF 文件夹,其中会有以下三个文件。考虑到使用不一样的证书和签名方式,获得的文件名可能不一样,所以你只要留意文件的后缀便可:
META-INF
├── MANIFEST.MF
├── CERT.SF
├── CERT.RSA
复制代码
文件 | 描述 |
---|---|
MANIFEST.MF | 记录「apk 中每个文件对应的摘要」(除了 META-INF 文件夹) |
*.SF | 记录「MANIFEST.MF 文件的摘要」和「MANIFEST.MF 中每一个数据块的摘要」 |
*.RSA | 包含了「*.SF 文件的签名」和「包含公钥的开发者证书」 |
提示: 若是 apk 中文件数不少,并且文件名很长,那么 MANIFEST.MF 和 *.SF 两个文件会变得很大。有没有办法优化呢?见 第 5.1 节 优化摘要记录文件大小。
v1 签名流程以下:
MANIFEST.MF(Message Digest File,摘要文件)
Manifest-Version: 1.0
Built-By: Generated-by-ADT
Created-By: Android Gradle 3.1.0
Name: AndroidManifest.xml
SHA1-Digest: 9hTSmRfzHEeQc7V2wxBbTT3DmCY= 【文件的摘要】
...
复制代码
\*.SF(Signature File,签名文件)
Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA1-Digest-Manifest: MJQyZ0dc4dv7G9nlJPAMQLwEwbU= 【MANIFEST.MF 文件的摘要】
X-Android-APK-Signed: 2
Name: AndroidManifest.xml
SHA1-Digest: IJioMmfD693T4qnUJcPKhq9woHQ= 【摘要的摘要】
...
复制代码
提示:*.RSA 文件加密了,须要使用 openssl 工具打开。
引用自 zhuanlan.zhihu.com/p/108034286 —— 木质的旋律 著
验证流程能够分为验证签名和验证完整性两个步骤:
验证签名步骤:
若是上述签名验证结果正确,才会验证完整性:
以上任何步骤验证失败,则整个 APK 验证失败。
为了解决这些问题,Android 7.0 中引入了 APK 签名方案 v2。
v2 签名方案是一种 全文件签名方案,该方案可以发现对 APK 的受保护部分进行的全部更改,相对于 v1 签名方案验证速度更快,完整性覆盖范围更广。
提示: 为了兼容低版本,使用 v2 签名方案的同时,还须要使用 v1 签名方案。
在分析 v2 签名方案以前,咱们先简单了解一下 Zip 文件格式:
Zip 文件主体结构分为三个部分:「条目内容区」&「中央目录区」&「中央目录结尾区(EoCD)」。
EoCD 中记录了中央目录的起始位置,在「条目内容区」和「中央目录区」之间插入了其余数据不会影响 Zip 解压。
首先,咱们先来分析其签名产物。v2 签名后会在 「条目内容区」和「中央目录区」之间插入「APK 签名分块(APK Signing Block)」。
引用自 source.android.com/security/ap… —— Android Developers
从左到右边,咱们定义为区块 1~4。
相对与 v1 签名方案,v2 签名方案再也不以文件为单位计算摘要了,而是以 1 MB 为单位将文件拆分为多个连续的块(chunk),每一个分区的最后一个块可能会小于 1 MB。
v2 签名流程以下:
引用自 source.android.com/security/ap… —— Android Developers
验证流程能够分为验证签名和验证完整性两个步骤:
签名方案 v3 支持密钥轮换,应用可以在 APK 更新过程当中更改其签名密钥。
【累了,后面先不写了...】
这一节,咱们介绍基于 Android 应用签名机制的衍生应用场景。
在 v1 方案中,MANIFEST.MF 和 *.SF 这两个文件会记录大量的文件名和文件摘要。若是 apk 中文件数不少,并且文件名很长,那么这两个文件会变得很大。使用 AndResGuard 工具,能够将文件名转换为短路径文件名,从而减小这两个文件的大小。
引用自 time.geekbang.org/column/arti… —— 张绍文 著
在实际生产中,每每须要生成多个渠道的 APK 包,传统的方法是使用 APKTool 逆向工具、Flavor + BuildType 等方案,这一类多渠道打包方案的缺点是耗时严重。随着 Android 应用签名方案的演进,演变出了不一样的多渠道打包方案:
在 v1 方案中,咱们提到了完整性校验不覆盖到 META-INF 文件夹的问题。有些多渠道打包方案就是利用了这个问题,在 META-INF 文件夹下添加空文件,用空文件的名称来做为渠道的惟一标识,就能够节省打包的时间,提升打渠道包的速度。
除了添加空文件的方法,还能够向 APK 添加 Zip Comment 来生成多渠道包(APK 自己就是特殊的 Zip 包)。
在 v2 签名方案中,几乎整个 APK 都归入保护范围,若是向 APK 添加空文件或 Zip Comment 的话,在安装时会报如下错误:
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES:
Failed to collect certificates from base.apk: META-INF/CERT.SF indicates base.apk is signed using APK Signature Scheme v2,
but no such signature was found. Signature stripped?]
复制代码
新背景下的多渠道打包方案,则是利用了 APK 签名分块(区块 2)不受保护 & 字段可扩展的特色,向区块中添加多渠道信息(ID-Value),例如 美团多渠道打包方案 Walle。
签名应用是处于两个目的:认证 & 验证完整性,即:认证 APK 的开发者以及验证 APK 内容是否被篡改。截止到 Android 11,一共有 v一、v二、v3 三种签名方案。
v1 是基于 Jar 的签名方案,它存在完整性覆盖范围不足 & 验证速度较差两个问题。
Android 7.0 推出的 v2 签名方案优化了这两个问题,经过「条目内容区」和「中央目录区」之间插入「APK 签名分块(APK Signing Block)」,优化了 v1 方案的两大问题。
Android 9.0 推出的 v3 方案是 v2 方案的优化版本,知足了密钥轮换的需求。
创做不易,你的「三连」是丑丑最大的动力,咱们下次见!