Android 7.0中新簽名對多渠道打包的影響詳解
老簽名多渠道打包原理
前言
由于Android7.0發(fā)布了新的簽名機制,加強了簽名的加固,導致在新的簽名機制下無法通過美團式的方式再繼續(xù)打多渠道包了。不過在說新的簽名機制對打包方案的
影響和為什么會影響我們原有的打包機制之前,需要先簡單理解下打包原理和簽名在整個打包過程中的作用。
Android打包流程
Android打包過程大致如圖所示,整個流程就是將Java代碼,資源文件以及第三方庫整合成一個Apk文件,并對整合后的文件進行簽名和優(yōu)化對齊。整個過程可以簡
單分為以下幾個步驟:
- 資源預編譯 為每一個非assert資源生成一個ID并保存在一個R文件中。
- Java文件編譯 把手動編寫的Java文件和前面步驟生成的Java文件一起編譯成.class文件
- Dex文件生成 把前面生成的class文件和第三方庫的class文件一起整合成.dex文件,相當于所有.class文件的索引表,可以通過這個文件找到每一個.class文件
- 資源文件打包 對資源進行大小進行優(yōu)化,并把所有有ID的資源對應的配置信息收錄生成resource.arsc文件中,相當于資源的索引表。
- APK文件生成 把之前生成的.dex文件和resource.arsc文件以及資源文件(res文件,里面包含一些已編譯成二進制的文件如布局文件等和一些未編譯成二進制的文件如圖片等)和未分配ID的文件(assert文件)等整合成一個APk文件(特殊的.zip文件)。
- 簽名 對生成的APK進行簽名,添加唯一標識,從而保證能夠正常安裝和覆蓋安裝,不會被惡意覆蓋,以及說明APK的來源和擁有者。
- 對齊處理 對APK中一些資源的二進制上的位置進行調整,從而加快APk運行時的速度。
APK生成的步驟大概就是這個樣子,我們不需要糾結一些細節(jié)上的實現(xiàn),只要大概了解這些流程就能理解后面我們打包方案的原理了。當然,這么看會覺得APK
是一個很神奇的文件,能夠安裝并且運行。其實,APK只是一中比較特別的.zip文件而已,只是它可以被我們的Android機器識別并且安裝成一個應用,我們可以把APK文件解壓出來看一下里面的內容。
可以看到文件內容和我們前面說的基本一致,接下來再看看最重要的一個文件夾,就是第三章圖里的文件,這些文件都在META-INF文件夾里,這就是我們在簽名過程中加入的文件來作為APK的唯一標識。那么這對我們打包優(yōu)化來說有什么意義呢,這里先保留下懸念,待會兒來說。在了解這個之前必須先把簽名這件事情說清楚。
簽名的作用和原理
簽名的作用
Android App在開發(fā)時都有一個唯一的標識,我們把它叫做包名,比如大客戶端的包名是com.Quanr,包名就像身份證號一樣,是和每一個人一一對應的,在把App安裝時機器也是通過包名來識別應用的,一個機器中不能存在兩個包名一樣的應用,這就是App在機器中的唯一性。我們在給App升級的時候,比如覆蓋安裝,就是通過包名來進行識別和對應的覆蓋,這樣才能保證App可以順利升級而不會覆蓋了其他的App,同樣,別的App包名不同也無法覆蓋我們的App。雖然Android提供了一套包名識別機制,但僅有包名就可以了嗎。試想一下,如果別人用我們的包名新建一個App想要覆蓋我們的App亦或是不法分子破解我們的
App往里面添加一些自己的內容,比如內嵌廣告來牟利,把篡改過的App再發(fā)出去讓用戶覆蓋安裝,我們可能會受到巨大的損失。當然這種事情是不會發(fā)生的,Google為每一個App增加了一個簽名機制,就像我們去銀行辦理業(yè)務,不但要提供身份證,還要簽字畫押,身份證號大家都可以看到,但簽字畫押只有自己才能做,別人是無法模仿的,App正是通過這種機制保證了自身的唯一性和安全性。
那么,簽名是如何做到這些的呢。
簽名的原理
對Apk簽名有好幾種工具,但原理都是大同小異的,這里拿signapk這個工具來說,對apk簽名只要用這個工具附帶一些參數(shù)以及我們的唯一的簽名文件就可以完成了,直接使用工具簽名是很簡單的,我們更需要關注的是它的原理和具體是怎么實現(xiàn)的,這樣才能幫助我們從中找出打渠道包的秘密。在使用簽名工具之前我們必須準備好簽名要用的私鑰和公鑰(a–(私鑰)–>b–(公鑰)–>a,最好用圖片展示),然后再用簽名工具對apk簽名,之后簽名流程會在apk里新建META-INF文件夾并在里面生成三個文件,這三個文件就是簽名的關鍵和驗證的依據。
從圖中可以看到三個文件分別是:
- MANIFEST.MF
- CERT.RSA
- CERT.SF
接下來說說這三個文件是怎么生成的。
MANIFEST.MF
先看看它的內容,可以看到是一些Name對應的SHA1的值,很容易就能知道這個文件保存的是每一個文件對應的一個唯一的值。MANIIFEST.MF文件的功能就如剛才說的一樣,在對APK簽名的時候,首先會對每一個文件進行數(shù)字編碼,生成一個唯一的SHA1的值,不同的文件內容不一樣所對應的SHA1的值也是不同的,所以如果有人篡改了文件內容,那么相應的SHA1的值也會發(fā)生變化。在對APK進行簽名的時候檢查自己的每一個文件,并生成對應的SHA1值,把這些內容都保存在一個新建的MANIFEST.MF文件中,并把這個文件放到META-INF目錄下,就完成了第一個簽名文件的生成。
CERT.SF
在生成了一個MANIFEST.MF文件之后,就能記錄下我們每一個文件的唯一值,從而保證文件不被篡改,這樣雖然保證了MANIFEST中記錄文件的安全,但卻無法保證自身的安全,別人照樣可以修改原有文件之后生成對應的SHA1值然后再修改MANIFEST文件,所以我們還要對MANIFEST進行加固,從而保證安全性。在進行完第一個文件生成后,簽名工具開始生成第二個文件了,這個文件就是CERT.RSA。在這個步驟里,對上一步生成的文件繼續(xù)進行一次數(shù)字編碼,把結果保存在這個新生成了CERT.RSA文件的頭部,在繼續(xù)對MANIFEST.MF文件中各個屬性塊做一次數(shù)字編碼,存到到CERT.SF文件的一個屬性塊中。
CERT.RSA
這個文件都是二進制的,生成完CERT.SF文件之后,我們用私鑰對CERT.SF進行加密計算得出簽名,將得到的簽名和公鑰的數(shù)字證書的信息一起保存到CERT.RSA中,整個簽名過程就結束了。
下面再簡單敘述一下Apk安裝過程中的驗證步驟,其實就是和生成簽名文件的步驟類似:
- 首先檢驗Apk中的所有文件的數(shù)字編碼和MANIFEST.MF中的數(shù)字編碼一致
- 驗證CERT.SF文件的簽名信息和CERT.RSA中的內容是否一致
- MANIFEST.MF整個文件簽名在CERT.SF文件中頭屬性中的值是否匹配以及驗證MANIFEST.MF文件中的各個屬性塊的簽名在CERT.SF文件中是否匹配
從上面的過程中,可以很明顯的發(fā)現(xiàn)一個問題,在這個過程中從來就沒有對META-INF里的任何文件進行數(shù)字編碼和加密,因為這個文件夾是簽名時生成的,在生成第一個文件MANIFEST.MF時并沒有對這個文件夾里的任何文件進行數(shù)字編碼,因為這個文件夾一定是空的,第二個文件是基于第一個文件生成的,第三個文件又是基于第二個生成的,所以整個過程中,這個META-INF文件夾幾乎是在控制范圍之外的。我們可以在里面添加一些文件從而躲過簽名這個過程。這就是美團多渠道包方案的突破口。
美團通過利用簽名原理來完成多渠道打包
通過前面打包過程的了解,可以知道想快速打多渠道包,就得跳過打包的階段直接想辦法對Apk文件進行修改,但這得挑戰(zhàn)Android的簽名校驗規(guī)則了,不過正好,通過剛才我們對簽名過程的分析,我們發(fā)現(xiàn)可以在META-INF文件夾里隨意添加文件從而躲過簽名規(guī)則的檢查,這時候新方案就孕育而生了,在打包生成了一個沒有渠道的Apk文件后,我們copy這個Apk并在在META-INF里添加一個文件,然后通過文件名來確定渠道號,不同的Apk里就在META-INF里添加不同的渠道名文件,即可確定不同的渠道了,之后要做的就是在我們需要渠道參數(shù)的時候直接去這個文件里拿就行了,完美的跳過了打包這個過程。那么這種方案的耗時呢?僅僅就是基于一個Apk文件的基礎上復制并插入一個文件而已,這樣的動作在高配的電腦里一分鐘可以做900次。所以,這時候打一個渠道包要4分鐘,打100個渠道包也只要四分鐘加一個小零頭,當然,這還不是極限,如果有900個渠道的話,一個個渠道包打包需要900x4分鐘,美團方案只要5分鐘,提高了好幾百倍的效率,可以說美團方案在老簽名下是非常完美的。
新簽名方式對現(xiàn)有方案的影響
在Android 7.0 之后,Google為了增強簽名的安全性,采用了新的簽名驗證規(guī)則,不是針對每個文件來進行數(shù)字編碼了,如圖所示:
新的簽名方式是根據zip文件結構來進行簽名的,Apk文件本質上就是一個.zip文件,如圖所示,在被簽名前可以分為三塊內容。
- 壓縮文件實體數(shù)據 包含所有的元素具體數(shù)據
- 核心目錄數(shù)據 包含所有元數(shù)據的相對偏移量
- 目錄結束標志 包含目錄數(shù)據的偏移位置和相關目錄詳情記錄
下圖中藍色的部分代表Contents of ZIP entries,粉色的部分代表Central Directory。
File Entry表示一個文件實體,一個壓縮文件中有多個文件實體。
文件實體由一個頭部和文件數(shù)據組成(壓縮后的,壓縮算法在頭部有說明)
Central Directory由多個File header組成,每個File header都保存一個文件實體的偏移
文件最后由一個叫End of central directory的結構結束。
再看看End of Central Directory的作用,它記錄了Central Directory相對于頭部的偏移位置,再看看我們的新簽名數(shù)據Apk Signing Block是放在Contents of ZIP entries和Central Directory之間的,它是根據未簽名的ZIP文件三個模塊的所有內容進行編碼簽名后產生的一個唯一的數(shù)據,可以按照前面說的數(shù)字編碼來理解,這三塊任何內容發(fā)生改變后所產生的這塊的數(shù)據都是不一致的,所以在簽名之后無法對Apk的任何內容進行修改,不過我們前面也沒修改過Apk簽名之外的內容,所以這個時候是不是可以考慮修改Apk Signing Block這塊內容呢,我們在后面再追加一個小尾巴。顯然這個方法也不行了,前面說過最后有一個叫End of Central Direcotry的部分,記錄著Central Direcotry相對與ZIP文件起始位置的偏移,正好APK Signing Block位于Central Direcotry前面,如果改變APK Signing Block的長度那么Central Direcotry相對于頭部的偏移就改變了,內容就會和Endof Central Directory里記錄的不一樣,整個Apk包就被破壞了。那么是不是可以修改這個偏移呢,顯然不行,修改過這個偏移之后Apk Signing Block也會變,然后只有擁有簽名文件的開發(fā)者才能得到對的APK Signing Block數(shù)據,想要篡改這個的人只能望洋興嘆了。這就是新簽名機制的作用原理。在這套新的機制下,我們老的簽名可能就要進行適當?shù)男薷牧恕?/p>
改進方案的思路
前面說過了,我們新的打包方案在新的簽名機制下又要捉襟見肘了(當然,如果你還采用老簽名的話那么就不需要考慮這個問題了),不過,Google有張良計,我們還有過墻梯~
之前說過添加渠道包有好幾種方式:
- 直接修改代碼,一個渠道包改一次代碼,然后再打包
- 不直接修改代碼,放出一個渠道參數(shù)在打包之前動態(tài)改變然后再打包
- 修改打包完成后的文件通過跳過簽名校驗加入渠道號
- 現(xiàn)在這三種方式都不行了,沒關系,我們還有第四中。
之前分析過,如果修改了zip文件的任何模塊內容,APK Signing Block都會發(fā)生改變,從而無法再繞過簽名機制。
不過這個不要緊,簽名機制只是為了保障我們Apk的安全,我們顯然不是想惡意篡改App,我們可是開發(fā)者,手握著簽名文件的私鑰和公鑰,既然簽名機制繞不過去,那么我們就直接修改Apk包然后重新進行簽名就行了。雖然這樣的效率沒有繞過簽名機制效率高,但相比于好幾分鐘的打包過程,這些時間也是可以接受的。一般重新簽名大概需要三四秒的時間,相對與我們四分鐘的打包流程,顯然還是可以接受和繼續(xù)使用的。
當然,這只是基于我們簽名機制想出來的一個方案,之前和大家分析了打包和簽名的整個流程和機制,也許還有更好的方式可以從中挖掘出來,這就需要我們集思廣益了,仔細分析和思考這些流程和原理,也許你就能找出更好的解決方案來繼續(xù)優(yōu)化我們的打包方案~
總結
以上就是關于Android7.0新簽名對多渠道打包影響的全部內容棩䍖,希望本文的內容對給我Android開發(fā)者們能帶來一定的幫助,如果有疑問大家可以留言交流
相關文章
Android開發(fā)手冊TextView屬性實現(xiàn)效果盤點
這篇文章主要為大家介紹了Android開發(fā)手冊TextView屬性實現(xiàn)的效果盤點及使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06RecyclerView使用payload實現(xiàn)局部刷新
這篇文章主要為大家詳細介紹了RecyclerView使用payload實現(xiàn)局部刷新,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10Android編程實現(xiàn)webview將網頁打包成apk的方法
這篇文章主要介紹了Android編程實現(xiàn)webview將網頁打包成apk的方法,以打包HTML5為例分析了webview打包apk的相關方法、屬性與事件操作技巧,需要的朋友可以參考下2017-08-08android開發(fā)教程之使用listview顯示qq聯(lián)系人列表
這篇文章主要介紹了android使用listview顯示qq聯(lián)系人列表的示例,需要的朋友可以參考下2014-02-02Android自定義View實現(xiàn)BMI指數(shù)條
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)BMI指數(shù)條,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-06-06