點贊關注顿颅,不再迷路,你的支持對我意義重大足丢!
?? Hi粱腻,我是丑丑。本文 GitHub · Android-NoteBook 已收錄斩跌,這里有 Android 進階成長路線筆記 & 博客绍些,歡迎跟著彭丑丑一起成長。(聯(lián)系方式 & 入群方式在 GitHub)
前言
- 在打生產包時耀鸦,一定需要對 apk 簽名柬批,那么你知道為什么要給應用簽名嗎?
- 在這篇文章里袖订,我將分析 Android apk 的簽名機制氮帐,并介紹 v1、v2 和 v3 三種安裝包簽名方案的原理與演進洛姑。如果能幫上忙上沐,請務必點贊加關注,這真的對我非常重要楞艾。
目錄
前置知識
這篇文章的內容會涉及以下前置 / 相關知識参咙,貼心的我都幫你準備好了龄广,請享用~
1. 什么是應用簽名净宵?
1.1 數(shù)字簽名模型
數(shù)字簽名(Digital Signature)也叫作數(shù)字指紋(Digital Fingerprint)敲才,它是消息摘要算法和非對稱加密算法的結合體,能夠驗證數(shù)據的完整性塘娶,并且認證數(shù)據的來源归斤。
數(shù)據簽名算法的模型分為兩個主要階段:
- 1痊夭、簽名: 先計算數(shù)據的 [摘要]刁岸,再使用私鑰對 [摘要] 進行加密生成 [簽名],將 [數(shù)據 + 簽名] 一并發(fā)送給接收方她我;
- 2虹曙、驗證: 先使用相同的摘要算法計算接收數(shù)據的 [摘要],再使用預先得到的公鑰解密 [簽名]番舆,對比 [解密的簽名] 和 [計算的摘要] 是否一致酝碳。若一致,則說明數(shù)據沒有被篡改恨狈。
需要注意的是疏哗,Android 目前不對應用證書進行 CA 認證,應用可以由第三方(OEM禾怠、運營商返奉、其他應用市場)簽名,也可以自行簽名吗氏。
1.2 為什么要給應用簽名芽偏?
應用 APK 其實是一種特殊的 Zip 壓縮包,無法避免惡意破解者解壓 / 反編譯修改內容弦讽,針對這個問題有何解決方案呢污尉?他山之石,可以攻玉 ——數(shù)字簽名算法往产。應用簽名正是數(shù)字簽名算法的應用場景之一被碗,與其他應用場景類似,目的無非是:
- 認證
Android 平臺上運行的每個應用都必須有開發(fā)者的簽名仿村。在安裝應用時锐朴,軟件包管理器會驗證 APK 是否已經過適當簽名,安裝程序會拒絕沒有獲得簽名就嘗試安裝的應用奠宜。
- 驗證完整性
軟件包管理器在安裝應用前會驗證應用摘要包颁,如果破解者修改了 apk 里的內容瞻想,那么摘要就不再匹配,驗證失斆浣馈(驗證流程見下文方案)蘑险。
提示: 使用數(shù)字簽名的優(yōu)點是驗證過程無須復雜的接口和權限,只需要在本機驗證岳悟。
1.3 應用簽名方案演進
截止至 Android 11佃迄,Android 支持以下三種應用簽名方案:
- v1 簽名方案:基于 Jar 簽名;
- v2 簽名方案:提高驗證速度和覆蓋度(在 Android 7.0 Nougat 中引入)贵少;
- v3 簽名方案:實現(xiàn)密鑰輪轉(在 Android 9.0 Pie 中引入)呵俏。
為了提高兼容性,必須按照 v1滔灶、v2普碎、v3 的先后順序采用簽名方案,低版本平臺會忽略高版本的簽名方案在 APK 中添加的額外數(shù)據录平。
2. 簽名方案 v1
v1 簽名方案是基于 Jar 的簽名麻车。
2.1 簽名產物
首先,我們先來分析其簽名產物斗这。v1 簽名后會增加 META-INF 文件夾动猬,其中會有如下三個文件”砑考慮到使用不同的證書和簽名方式赁咙,得到的文件名可能不同,因此你只要留意文件的后綴即可:
META-INF
├── MANIFEST.MF
├── CERT.SF
├── CERT.RSA
文件 | 描述 |
---|---|
MANIFEST.MF | 記錄「apk 中每一個文件對應的摘要」(除了 META-INF 文件夾) |
*.SF | 記錄「MANIFEST.MF 文件的摘要」和「MANIFEST.MF 中每個數(shù)據塊的摘要」 |
*.RSA | 包含了「*.SF 文件的簽名」和「包含公鑰的開發(fā)者證書」 |
提示: 如果 apk 中文件數(shù)很多免钻,而且文件名很長彼水,那么 MANIFEST.MF 和 *.SF 兩個文件會變得很大。有沒有辦法優(yōu)化呢伯襟?見 第 5.1 節(jié) 優(yōu)化摘要記錄文件大小猿涨。
2.2 簽名流程
v1 簽名流程如下:
- 1、計算每個文件的 SHA-1 摘要姆怪,進行 BASE64 編碼后寫入 MANIFEST.MF 文件叛赚;
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= 【文件的摘要】
...
- 2稽揭、計算整個 MANIFEST.MF 文件的 SHA-1 摘要俺附,進行 BASE64 編碼后寫入 *.SF 文件;
- 3溪掀、計算 MANIFEST.MF 文件中每一塊摘要的 SHA-1 摘要事镣,進行 BASE64 編碼后寫入 *.SF 文件;
\*.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= 【摘要的摘要】
...
- 4璃哟、計算整個 *.SF 文件的數(shù)字簽名(先摘要再私鑰加密)氛琢;
- 5、將數(shù)字簽名和 X.509 開發(fā)者數(shù)字證書(公鑰)寫入 *.RSA 文件随闪。
提示:*.RSA 文件加密了阳似,需要使用 openssl 工具打開。
2.3 驗證流程
驗證流程可以分為驗證簽名和驗證完整性兩個步驟:
驗證簽名步驟:
- 1铐伴、取出 *.RSA 中包含的開發(fā)者證書撮奏;
- 2、【注意:這里不向 CA 認證開發(fā)者證書合法性】当宴;
- 3畜吊、用證書中的公鑰解密 *.RSA 中包含的簽名,得到摘要户矢;
- 4玲献、計算 *.SF 的摘要;
- 5逗嫡、對比 (3) 和 (4) 的摘要是否一致青自;
如果上述簽名驗證結果正確株依,才會驗證完整性:
- 1驱证、計算 MANIFEST.MF 的摘要;
- 2恋腕、對比 *.SF 記錄中的文件摘要和 (1) 的摘要是否一致抹锄;
- 3、如果一致荠藤,再用 MANIFEST.MF 中的每一塊數(shù)據去校驗每一個文件是否被修改伙单。
以上任何步驟驗證失敗,則整個 APK 驗證失敗哈肖。
2.4 存在的問題
- 完整性覆蓋范圍不足:Zip 文件中部分內容不在驗證范圍吻育,例如 META-INF 文件夾;
- 驗證速度較差:驗證程序必須解壓所有壓縮的條目淤井,這需要花費更多時間和內存布疼。
為了解決這些問題,Android 7.0 中引入了 APK 簽名方案 v2币狠。
3. 簽名方案 v2
v2 簽名方案是一種 全文件簽名方案游两,該方案能夠發(fā)現(xiàn)對 APK 的受保護部分進行的所有更改,相對于 v1 簽名方案驗證速度更快漩绵,完整性覆蓋范圍更廣贱案。
提示: 為了兼容低版本,使用 v2 簽名方案的同時止吐,還需要使用 v1 簽名方案宝踪。
3.1 Zip 文件簡介
在分析 v2 簽名方案之前侨糟,我們先簡單了解一下 Zip 文件格式:
Zip 文件主體結構分為三個部分:「條目內容區(qū)」&「中央目錄區(qū)」&「中央目錄結尾區(qū)(EoCD)」。
EoCD 中記錄了中央目錄的起始位置瘩燥,在「條目內容區(qū)」和「中央目錄區(qū)」之間插入了其他數(shù)據不會影響 Zip 解壓粟害。
3.2 簽名產物
首先,我們先來分析其簽名產物颤芬。v2 簽名后會在 「條目內容區(qū)」和「中央目錄區(qū)」之間插入「APK 簽名分塊(APK Signing Block)」悲幅。
從左到右邊,我們定義為區(qū)塊 1~4站蝠。
3.2 簽名流程
相對與 v1 簽名方案汰具,v2 簽名方案不再以文件為單位計算摘要了,而是以 1 MB 為單位將文件拆分為多個連續(xù)的塊(chunk)菱魔,每個分區(qū)的最后一個塊可能會小于 1 MB留荔。
v2 簽名流程如下:
- 1、對區(qū)塊 1澜倦、3聚蝶、4,按照 1MB 大小分割為多個塊(chunk)藻治;
- 2碘勉、計算每個塊的摘要;
- 3桩卵、計算 (2) 中所有摘要的簽名验靡。
- 4、添加 X.509 開發(fā)者數(shù)字證書(公鑰)
3.3 驗證流程
驗證流程可以分為驗證簽名和驗證完整性兩個步驟:
- 驗證簽名步驟:用公鑰驗證區(qū)塊 2 的簽名雏节;
- 驗證完整性步驟:用「APK數(shù)據摘要集」驗證每一塊數(shù)據的摘要胜嗓。
4. 簽名方案 v3
簽名方案 v3 支持密鑰輪換,應用能夠在 APK 更新過程中更改其簽名密鑰钩乍。
【累了辞州,后面先不寫了...】
5. 衍生應用場景
這一節(jié),我們介紹基于 Android 應用簽名機制的衍生應用場景寥粹。
5.1 優(yōu)化摘要記錄文件大小
在 v1 方案中变过,MANIFEST.MF 和 *.SF 這兩個文件會記錄大量的文件名和文件摘要。如果 apk 中文件數(shù)很多排作,而且文件名很長牵啦,那么這兩個文件會變得很大。使用 AndResGuard 工具妄痪,可以將文件名轉換為短路徑文件名哈雏,從而減少這兩個文件的大小。
5.2 多渠道打包方案
在實際生產中,往往需要生成多個渠道的 APK 包裳瘪,傳統(tǒng)的方法是使用 APKTool 逆向工具土浸、Flavor + BuildType 等方案,這一類多渠道打包方案的缺點是耗時嚴重彭羹。隨著 Android 應用簽名方案的演進黄伊,演變出了不同的多渠道打包方案:
v1 方案時代下的多渠道打包
- 添加空文件
在 v1 方案中,我們提到了完整性校驗不覆蓋到 META-INF 文件夾的問題派殷。有些多渠道打包方案就是利用了這個問題还最,在 META-INF 文件夾下添加空文件,用空文件的名稱來作為渠道的唯一標識毡惜,就可以節(jié)省打包的時間拓轻,提高打渠道包的速度。
- Zip Comment
除了添加空文件的方法经伙,還可以向 APK 添加 Zip Comment 來生成多渠道包(APK 本身就是特殊的 Zip 包)扶叉。
v2 方案時代下的多渠道打包
在 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 簽名分塊(區(qū)塊 2)不受保護 & 字段可擴展的特點垮刹,向區(qū)塊中添加多渠道信息(ID-Value)达吞,例如 美團多渠道打包方案 Walle。
6. 總結
簽名應用是處于兩個目的:認證 & 驗證完整性危纫,即:認證 APK 的開發(fā)者以及驗證 APK 內容是否被篡改宗挥。截止到 Android 11,一共有 v1种蝶、v2、v3 三種簽名方案瞒大。
v1 是基于 Jar 的簽名方案螃征,它存在完整性覆蓋范圍不足 & 驗證速度較差兩個問題。
Android 7.0 推出的 v2 簽名方案優(yōu)化了這兩個問題透敌,通過「條目內容區(qū)」和「中央目錄區(qū)」之間插入「APK 簽名分塊(APK Signing Block)」盯滚,優(yōu)化了 v1 方案的兩大問題。
Android 9.0 推出的 v3 方案是 v2 方案的優(yōu)化版本酗电,滿足了密鑰輪換的需求魄藕。
參考資料
- Signed_JAR_File —— Oracle 官方文檔
- 應用簽名 v1 、v2撵术、v3 —— Android 官方文檔
- 對應用進行簽名 —— Android 官方文檔
- Android 應用安全防護和逆向分析(第 12 章)—— 姜維 著
- Android 端 V1/V2/V3 簽名的原理 —— 木質的旋律(阿里)著
- 分析Android V2 新簽名打包機制 —— pisazzpan(騰訊音樂)著
- 新一代開源 Android 渠道包生成工具 Walle —— 建帥 陳潼(美團)著
- Android V1 及 V2 簽名原理簡析 —— 看書的蝸牛(網易) 著
- Android App 包瘦身優(yōu)化實踐 —— 建帥(美團)著
- Android 開發(fā)高手課 · 包體積優(yōu)化(下) —— 張紹文(微信)著
- 深入理解 Android 內核設計思想(第 20 章) —— 林學森 著
創(chuàng)作不易背率,你的「三連」是丑丑最大的動力,我們下次見!