點贊關注,再也不迷路,你的支持對我意義重大!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 方案的優化版本,知足了密鑰輪換的需求。
創做不易,你的「三連」是醜醜最大的動力,咱們下次見!