最近有業務需求,須要向已經打包的APK裏面注入渠道(channel)信息,方便APK下載安裝以後進行渠道歸因。向APK裏面注入渠道信息已經有比較成熟的方案美團walle。walle的強大和實現原理本文再也不贅述。爲了理解walle的代碼,而且在出現異常case的時候,可以本身解決。必需要對APK文件的結構瞭如指掌。html
所以,本文的目的就是以一個簡單的利用walle向APK裏面注入渠道號爲例。帶你瞭解APK裏面的各類細節,相信讀者在看完此篇文章以後,再閱讀walle的代碼的時候必定豁然開朗。java
APK文件本質上是一個ZIP文件,所以在瞭解APK的格式以前必須先了解ZIP文件的格式。詳情參見zip文件格式詳解 。android
ZIP文件的總體格式以下圖所示,主要由三部分組成git
其中,中央目錄結尾記錄對於理解本文最爲重要。最好看完zip文件格式詳解 再繼續往下閱讀。此區域裏面有一個值核心目錄偏移地址
很是的重要,如下圖爲例的話,核心目錄的起始地址就是0x2D(注意:是地址,不是數值)github
APK在簽名(V2/V3簽名)以後,會在數據區和中央目錄區之間插入APK簽名區(APK Signing Block)工具
APK簽名區的組成結構以下圖所示google
用表格表示以下圖所示,其由4部分組成.net
ID-Value序列裏面存儲了ID-Value列表,ID-Value序列的結構以下圖所示。3d
列表的每個Item裏面由3個元素組成(8字節長度+4字節ID+內容)。其中APK的簽名信息就是其中一項item,ID爲0x7109871a。序列裏面的每個Item的結構以下圖所示:code
至於APK是如何計算簽名簽名信息保存在Item裏面,以及Android系統是如何校驗APK完整性的,詳情參考APK簽名機制之——V2簽名機制詳解。walle的實現原理就是向ID-Value列表裏面插入一個Item,因爲APK安裝的時候並不對插入的Item作校驗,所以可以保證APK能校驗成功的同時還能帶上插入的信息
至此,咱們對APK文件的基本結構有了一個總體的認識。下面,我將以上述的實例APK爲例子,經過二進制分析如何一步一步提取出walle注入的ID=0x71777777的渠道信息
基於wall,向APK裏面注入渠道號信息。在APK打包的時候,向APK裏面注入一下信息。
0x71777777
{"channel":"meituan"}
APK運行的時候,能夠成功提取出渠道號信息
實例分析前,咱們再回顧一下APK的總體格式(這張圖對後面步驟的理解很重要)
從APK裏面尋找存ID=0x71777777的渠道信息的總體過程以下:
注意,在閱讀二進制文件的時候都要把實際的數字轉成小端來看
ZIP文件是按照小端存儲的(除特殊部分,好比說magic部分),好比說0x7109871A,實際存儲16進制存儲爲:1A 87 09 71。關於大端和小端的區別能夠參考大端和小端
中央目錄結構以下所示,zip文件格式詳解 裏面詳細介紹了中央目錄結尾記錄的結構
(1)咱們首先根據ECDR的魔數0x06054b50(hex:50 4b 05 06)肯定ECDR部分的起始地址爲0xBD396
(2)日後偏移16個地址(參考上圖),便可計算出中央目錄起始地址爲0x0b4f18
咱們再簡單回顧一下APK簽名塊的格式
(1)咱們首先跳轉到0x0b4f18地址所在位置
APK Sig Block 42
(3)往前16個地址(魔數長度)取8個字節(block長度佔8字節)既爲APK簽名塊的長度
(4)所以從APK Sig Block 42的尾地址(0xb4f17)往前0x0584個地址,就是ID-Value部分的起始地址
再複習一下ID-Value序列Item每個Item的結構
根據步驟二咱們能夠得知ID-Value部分是從(43 05 00 到6E 22 7D,上圖的兩個紅框之間)。理論上,咱們根據上述Item的結構,順序從ID-Value序列的首地址解析到尾地址便可找出咱們的注入的信息。爲了方便起見,咱們直接在這部分搜索Id=0x71777777(hex: 77 77 77 71)的內容。能夠看出
至此,咱們就成功的經過分析APK的二進制數據,獲得了walle注入的數據。固然,walle注入的過程也是相似的,很是的簡單。除此以外walle還考慮了V3對齊的問題
當你通過上述步驟分析以後,再去看walle的代碼,你會發現,媽的!原來這麼簡單!!