3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
ApkChannelPackage是一種快速多渠道打包工具,同時支持基於V1簽名和V2簽名進行多渠道打包。插件本身會自動檢測Apk使用的簽名方法,並選擇合適的多渠道打包方式,對使用者來說完全透明。概述眾所周知,因為國內Android應用分發市場的現狀,我們在發布APP時,一般需要生成多個渠道包,上傳到不同的應用市場。這些渠道包需要包含不同的渠道信息,在APP和後台交互或者數據上報時,會帶上各自的渠道信息。這樣,我們就能統計到每個分發市場的下載數、用戶數等關鍵數據。普通的多渠道打包方案既然我們需要進行多渠道打包,那我們就看下最常見的多渠道打包方案。Android Gradle PluginGradle Plugin本身提供了多渠道的打包策略:首先,在AndroidManifest.xml中添加渠道信息佔位符:dataandroid:name="InstallChannel" android:value="${InstallChannel}" />productFlavors標籤,添加渠道信息:這樣,Gradle編譯生成多渠道包時,會用不同的渠道信息替換AndroidManifest.xml中的佔位符。我們在代碼中,也就可以直接讀取AndroidManifest.xml中的渠道信息了。但是,這種方式存在一些缺點:1)每生成一個渠道包,都要重新執行一遍構建流程,效率太低,只適用於渠道較少的場景。2)Gradle會為每個渠道包生成一個不同的BuildConfig.java類,記錄渠道信息,導致每個渠道包的DEX的CRC值都不同。一般情況下,這是沒有影響的。但是如果你使用了微信的Tinker熱補丁方案,那麼就需要為不同的渠道包打不同的補丁,這完全是不可以接受的。(因為Tinker是通過對比基礎包APK和新包APK生成差分補丁,然後再把補丁和基礎包APK一起合成新包APK。這就要求用於生成差分補丁的基礎包DEX和用於合成新包的基礎包DEX是完全一致的,即:每一個基礎渠道包的DEX文件是完全一致的,不然就會合成失敗)ApkToolApkTool是一個逆向分析工具,可以把APK解開,添加代碼后,重新打包成APK。因此,基於ApkTool的多渠道打包方案分為以下幾步:複製一份新的APK通過ApkTool工具,解壓APK(apktool d origin.apk)刪除已有簽名信息添加渠道信息(可以在APK的任何文件添加渠道信息)通過ApkTool工具,重新打包生成新APK(apktool b newApkDir)重新簽名經過測試,這種方案完全是可行的。優點:不需要重新構建新渠道包,僅需要複製修改就可以了。並且因為是重新簽名,所以同時支持V1和V2簽名。缺點:ApkTool工具不穩定,曾經遇到過升級Gradle Plugin版本后,低版本ApkTool解壓APK失敗的情況。生成新渠道包時,需要重新解包、打包和簽名,而這幾步操作又是相對比較耗時的。經過測試:生成企鵝電競10個渠道包需要16分鐘左右,雖然比Gradle Plugin方案減少很多耗時。但是若需要同時生成上百個渠道包,則需要幾個小時,顯然不適合渠道非常多的業務場景。那有沒有一種方案:可以在添加渠道信息后,不需要重新簽名那?首先我們要了解一下APK的簽名和校驗機制。數據摘要、數字簽名和數字證書在進一步學習V1和V2簽名之前,我們有必要學習一下籤名相關的基礎知識。數據摘要數據摘要演算法是一種能產生特定輸出格式的演算法,其原理是根據一定的運算規則對原始數據進行某種形式的信息提取,被提取出的信息就是原始數據的消息摘要,也稱為數據指紋。一般情況下,數據摘要演算法具有以下特點:無論輸入數據有多大(長),計算出來的數據摘要的長度總是固定的。例如:MD5演算法計算出的數據摘要有128Bit。一般情況下(不考慮碰撞的情況下),只要原始數據不同,那麼其對應的數據摘要就不會相同。同時,只要原始數據有任何改動,那麼其數據摘要也會完全不同。即:相同的原始數據必有相同的數據摘要,不同的原始數據,其數據摘要也必然不同。不可逆性,即只能正向提取原始數據的數據摘要,而無法從數據摘要中恢復出原始數據。著名的摘要演算法有RSA公司的MD5演算法和SHA系列演算法。數字簽名和數字證書數字簽名和數字證書是成對出現的,兩者不可分離(數字簽名主要用來校驗數據的完整性,數字證書主要用來確保公鑰的安全發放)。要明白數字簽名的概念,必須要了解數據的加密、傳輸和校驗流程。一般情況下,要實現數據的可靠通信,需要解決以下兩個問題:1.確定數據的來源是其真正的發送者。2.確保數據在傳輸過程中,沒有被篡改,或者若被篡改了,可以及時發現。而數字簽名,就是為了解決這兩個問題而誕生的。首先,數據的發送者需要先申請一對公私鑰對,並將公鑰交給數據接收者。然後,若數據發送者需要發送數據給接收者,則首先要根據原始數據,生成一份數字簽名,然後把原始數據和數字簽名一起發送給接收者。數字簽名由以下兩步計算得來:1.計算髮送數據的數據摘要2.用私鑰對提取的數據摘要進行加密這樣,數據接收者拿到的消息就包含了兩塊內容:1.原始數據內容2.附加的數字簽名接下來,接收者就會通過以下幾步,校驗數據的真實性:用相同的摘要演算法計算出原始數據的數據摘要。用預先得到的公鑰解密數字簽名。對比簽名得到的數據是否一致,如果一致,則說明數據沒有被篡改,否則數據就是臟數據了。因為私鑰只有發送者才有,所以其他人無法偽造數字簽名。這樣通過數字簽名就確保了數據的可靠傳輸。綜上所述,數字簽名就是只有發送者才能產生的別人無法偽造的一段數字串,這段數字串同時也是對發送者發送數據真實性的一個有效證明。想法雖好,但是上面的整個流程,有一個前提,就是數據接收者能夠正確拿到發送者的公鑰。如果接收者拿到的公鑰被篡改了,那麼壞人就會被當成好人,而真正的數據發送者發送的數據則會被視作臟數據。那怎麼才能保證公鑰的安全性那?這就要靠數字證書來解決了。數字證書是由有公信力的證書中心(CA)頒發給申請者的證書,主要包含了:證書的發布機構、證書的有效期、申請者的公鑰、申請者信息、數字簽名使用的演算法,以及證書內容的數字簽名。可見,數字證書也用到了數字簽名技術。只不過簽名的內容是數據發送方的公鑰,以及一些其它證書信息。這樣數據發送者發送的消息就包含了三部分內容:原始數據內容附加的數字簽名申請的數字證書。接收者拿到數據后,首先會根據CA的公鑰,解碼出發送者的公鑰。然後就與上面的校驗流程完全相同了。所以,數字證書主要解決了公鑰的安全發放問題。因此,包含數字證書的整個簽名和校驗流程如下圖所示:V1簽名和多渠道打包方案V1簽名機制默認情況下,APK使用的就是V1簽名。解壓APK后,在META-INF目錄下,可以看到三個文件:MANIFEST.MF、CERT.SF、CERT.RSA。它們都是V1簽名的產物。其中,MANIFEST.MF文件內容如下所示:它記錄了APK中所有原始文件的數據摘要的Base64編碼,而數據摘要演算法就是SHA1CERT.SF文件內容如下所示:SHA1-Digest-Manifest-Main-Attributes主屬性記錄了MANIFEST.MF文件所有主屬性的數據摘要的Base64編碼。SHA1-Digest-Manifest則記錄了整個MANIFEST.MF文件的數據摘要的Base64編碼。其餘的普通屬性則和MANIFEST.MF中的屬性一一對應,分別記錄了對應數據塊的數據摘要的Base64編碼。例如:CERT.SF文件中skin_drawable_btm_line.xml對應的SHA1-Digest,就是下面內容的數據摘要的Base64編碼。Name: res/drawable/skin_drawable_btm_line.xml SHA1-Digest: JqJbk6/AsWZMcGVehCXb33Cdtrk= \r\n這裡要注意的是:最後一行的換行符是必不可少,需要參與計算的。CERT.RSA文件包含了對CERT.SF文件的數字簽名和開發者的數字證書。RSA就是計算數字簽名使用的非對稱加密演算法。V1簽名的詳細流程可參考SignApk.java,整個簽名流程如下圖所示:整個簽名機制的最終產物就是MANIFEST.MF、CERT.SF、CERT.RSA三個文件。V1校驗流程在安裝APK時,Android系統會校驗簽名,檢查APK是否被篡改。代碼流程是:PackageManagerService.java,PackageParser類負責V1簽名的具體校驗。整個校驗流程如下圖所示:若中間任何一步校驗失敗,APK就不能安裝。OK,了解了V1的簽名和校驗流程。我們來看下,V1簽名是怎麼保證APK文件不被篡改的?首先,如果破壞者修改了APK中的任何文件,那麼被篡改文件的數據摘要的Base64編碼就和MANIFEST.MF文件的記錄值不一致,導致校驗失敗。其次,如果破壞者同時修改了對應文件在MANIFEST.MF文件中的Base64值,那麼MANIFEST.MF中對應數據塊的Base64值就和CERT.SF文件中的記錄值不一致,導致校驗失敗。最後,如果破壞者更進一步,同時修改了對應文件在CERT.SF文件中的Base64值,那麼CERT.SF的數字簽名就和CERT.RSA記錄的簽名不一致,也會校驗失敗。那有沒有可能繼續偽造CERT.SF的數字簽名那?理論上不可能,因為破壞者沒有開發者的私鑰。那破壞者是不是可以用自己的私鑰和數字證書重新簽名那,這倒是完全可以!綜上所述,任何對APK文件的修改,在安裝時都會失敗,除非對APK重新簽名。但是相同包名,不同簽名的APK也是不能同時安裝的。APK文件結構由上述V1簽名和校驗機制可知,修改APK中的任何文件都會導致安裝失敗!那怎麼添加渠道信息那?只能從APK的結構入手了。APK文件本質上是一個ZIP壓縮包,而ZIP格式是固定的,主要由三部分構成,如下圖所示:第一部分是內容塊,所有的壓縮文件都在這部分。每個壓縮文件都有一個local file header,主要記錄了文件名、壓縮演算法、壓縮前後的文件大小、修改時間、CRC32值等。第二部分稱為中央目錄,包含了多個central directory file header一一對應),每個中央目錄文件頭主要記錄了壓縮演算法、註釋信息、對應的偏移量等,方便快速定位數據。最後一部分是EOCD,主要記錄了中央目錄大小、偏移量和ZIP註釋信息等,其詳細結構如下圖所示:根據之前的V1簽名和校驗機制可知,V1簽名只會檢驗第一部分的所有壓縮文件,而不理會後兩部分內容。因此,只要把渠道信息寫入到后兩塊內容就可以通過V1校驗,而EOCD的註釋欄位無疑是最好的選擇。基於V1簽名的多渠道打包方案既然找到了突破口,那麼基於V1簽名的多渠道打包方案就應運而生:在APK文件的註釋欄位,添加渠道信息。添加渠道信息后的EOCD數據塊如下所示:這裡添加魔數的好處是方便從後向前讀取數據,定位渠道信息。因此,讀取渠道信息包括以下幾步:定位到魔數向前讀兩個位元組,確定渠道信息的長度LEN繼續向前讀LEN位元組,就是渠道信息了。通過16進位編輯器,可以查看到添加渠道信息后的APK(小端模式),如下所示:6C 74 6C 6F 76 75 7A 68是魔數,04 00表示渠道信息長度為4,6C 65 6F 6E就是渠道信息leon了。0E 00就是APK註釋長度了,正好是15。雖說整個方案很清晰,但是在找到EOCD數據塊這步遇到一個問題。如果APK本身沒有註釋,那最後22位元組就是EOCD。但是若APK本身已經包含了註釋欄位,那怎麼確定EOCD的起始位置那?這裡借鑒了系統V2簽名確定EOCD位置的方案。整個計算流程如下圖所示:整個方案介紹完了,該方案的最大優點就是:不需要解壓縮APK,不需要重新簽名,只需要複製APK,在註釋欄位添加渠道信息。每個渠道包僅需幾秒的耗時,非常適合渠道較多的APK。但是好景不長,Android7.0之後新增了V2簽名,該簽名會校驗整個APK的數據摘要,導致上述渠道打包方案失效。所以如果想繼續使用上述方案,需要關閉Gradle Plugin中的V2簽名選項,禁用V2簽名。V2簽名和多渠道打包方案為什麼需要V2簽名從前面的V1簽名介紹,可以知道V1存在兩個弊端:1)MANIFEST.MF中的數據摘要是基於原始未壓縮文件計算的。因此在校驗時,需要先解壓出原始文件,才能進行校驗。而解壓操作無疑是耗時的。2) V1簽名僅僅校驗APK第一部分中的文件,缺少對APK的完整性校驗。因此,在簽名后,我們還可以修改APK文件,例如:通過zipalign進行位元組對齊后,仍然可以正常安裝。正是基於這兩點,Google提出了V2簽名,解決了上述兩個問題:V2簽名是對APK本身進行數據摘要計算,不存在解壓APK的操作,減少了校驗時間。V2簽名是針對整個APK進行校驗(不包含簽名塊本身),因此對APK的任何修改(包括添加註釋、zipalign位元組對齊)都無法通過V2簽名的校驗。關於第一點的耗時問題,這裡有一份實驗室數據(Nexus 6P、Android 7.1.1)可供參考。

本文由yidianzixun提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦