APK文件解析AXML-層層深入APK文件解析之一

jopen 9年前發布 | 35K 次閱讀 APK Android開發 移動開發

APK解析是很久以前想完成的一件事,但是因為一些事情擱下了。

當時使用Iteedee的代碼在200多個APK文件中有將近四分之一的文件是無法成功解析AXML的。Iteedee下稱I

?因此,本文的代碼基于I的代碼修改,效果基本接近于APKTOOL(https://code.google.com/p/android-apktool/)

毋庸置疑的是,在解析的時候,會遇到各種奇葩的編碼問題,首先會遇到文件的壓縮解壓縮碼流問題,不得不說SharpZip的性能還是可以的,注意APK使用的Zip壓縮格式是非固實壓縮,雖然壓縮性能(Performance of Compression ,BenchMark)降低了,但是對于文件尋址來說還是很方便的。

常用的APK解析讀取APK信息的方法有很多種:

1、AAPT工具、2、apkTool工具、3、AXMLPrinter2工具、4、自帶ZIP解壓引擎純字節流解碼分析、5、其它...

這里要講的就是第四種,是基于開源庫SharpZipLib的。

??下面言歸正傳,談談個中遇到的一些問題:??

1、關于怎么解壓zip可以看這個問題的某層回答:

http://bbs.csdn.net/topics/390421494

注意GZip和Zip不一樣,Gzip在HTTP請求中比較常見

使用到的sharp庫到如下網站去找

http://icsharpcode.github.io/SharpZipLib/


2、zip版本問題(788):

大部分文件的解壓版本都是0x14,而個別文件出現0x0314,因此拋出了異常,具體原因無法考究,解決方案是在SharpZipLib源碼中加入代碼過濾掉,影響應該不大:

 if (extractVersion==788)
{
    extractVersion &= 0xff; 
}

記得備案,免得那天遇到問題了不知道這一茬。


3、文本編碼問題:

從I那兒下載的代碼經過測試后還是存在不少問題的,這里說的文本編碼就是一個典型的例子。

I使用的是UTF8編碼格式進行轉碼

通過 http://tool.chinaz.com/Tools/URLEncode.aspx  查了下"趕集"兩字的UTF8的碼流形式為:%e8%b5%b6%e9%9b%86 .

 然而,把Parser之前的AndroidManifest.xml在程序里dump出來發現實際上是這樣的:

APK文件解析AXML-層層深入APK文件解析之一

那么問題就來了,通過http://tool.chinaz.com/Tools/Unicode.aspx 查了一下unicode碼流(unicode的編碼據說沒有一個統一的標準,所以才出現了UTF8\16\32等編碼),給出的結果是:\u8d76\u96c6\u7b80\u6613\u5730\u56fe。

原因真的就找到了嗎,有時候人真的是聰明反被聰明誤啊,博主考慮了大小端的問題,于是字節換序、去00字節、重返UTF8(為什么再使用UTF8也是基于很多原因)各種方法試過皆無果之后,探究了下Unicode編碼在c#中實現的具體碼流:

            byte[] bytes = Encoding.Unicode.GetBytes(textBox1.Text);
            for (int ii = 0; ii < bytes.Length; ii++)
            {
                textBox2.Text += string.Format("{0:x2} ", bytes[ii]);
            }

結果如下:

APK文件解析AXML-層層深入APK文件解析之一

顯然字序跟AXML中的是一模一樣,注意00字節,可見AXML和c#中的unicode都使用了雙字節對齊的(這不廢話么),那么修復了編碼Bug之后的某個子函數是這樣的:

 private String compXmlStringAt(byte[] arr, int strOff)
        {
            int strLen = arr[strOff + 1] << 8 & 0xff00 | arr[strOff] & 0xff;
            byte[] chars = new byte[strLen<<=1 ];
            for (int ii = 0; ii < strLen ; ii++)
            {
                chars[ii] = arr[strOff + 2 + ii];
            }
            return Encoding.Unicode.GetString(chars);//Change to Unicode of Encoding by Parser7
        }

如此而來,就成功支持了中文/多語言了。然而讓我郁悶的是,通篇的注釋都在說Unicode,只字未提UTF8,代碼的原作者居然赫然在目地寫著錯誤的代碼,令人費解的注釋


4、TEXT事件類型的處理:

I寫的代碼,只對startTag之類的事件做了處理,然而XmlPullParser使用了五類事件,但是I對未知事件的處理是直接break了,這樣會造成manifest等element未關閉的問題,嚴重的致命/FATOL ERROR。

由于此處對TEXT內容并不關心,所以使用對offset簡單處理防止死循環的方法跳過。后面有空了再來細細研究這個東西。有需要的朋友可以一起交流下。

XmlPullParser的源碼我估計可能就在這個網站http://www.xmlpull.org/ ,找到的記得發我一份,先謝謝了。

相關資料:

http://blog.csdn.net/andyhuabing/article/details/8036340


5、size=0問題導致無法正確讀到androidmanifest.xml:

I使用了如下的方法遍歷每一個壓縮包中的文件

 while ((item = zip.GetNextEntry()) != null)
{...}

在某個APK的解析中發現出現size=0導致未能成功讀取androidmanifest.xml文件。

跟蹤了size讀寫器所有的過程后,發現在ZipFile構造函數中已經能夠獲得所有的ZipEntry,而I的代碼這里調用GetNextEntry方法顯然不僅是畫蛇添足而且還引入了Bug,廢話少說,使用迭代器輕松搞定:

PZipFile = new ZipFile(fsStream);
 foreach (ZipEntry entry in PZipFile )
 {    ...    }

小結:

至此,已經能成功解析1021個文件的AXML,但還有35個文件不能成功解析。

經檢驗,有21個文件已經損壞,但還有14個文件可以成功打開壓縮包,具體原因還在分析中。


6、XmlException拋出的EntityName解析錯誤:并指出在35行51列

I的代碼似乎沒有實現將decompressXML之后的result轉為XMLDocument,這里是我自己加的代碼,但是卻出現這樣的問題。

dump出解析的xml內容后發現在指定位置出現了xml非法字符'&',將非法字符轉義處理就行了。

下面就是很直接、赤裸裸的代碼了:

public static string HandleInvalidCharAtXMLDoc(string filename)
{
 return filename.Replace("<", "&lt;").Replace(">", "&gt;").Replace("&", "&amp;").Replace("'", "&apos;").Replace("\"", "&quot;");
}


7、壓縮包簽名頭問題:

apktool解不開,winrar能看到目錄結構,從檔中拖拽文件貌似可以解壓AXML,但是會提示文件損壞,將解壓出來的AXML文件放入成功解析的APK后能正確解析出AXML明文內容。

經過一些實驗后,發現dump出來的字節流跟能解析出來的字節流不一樣,說明可能是entry索引出了問題,或者內容被破壞了。根據上文描述,明顯問題出在entry索引問題,或者是其它問題(不是788等版本問題)


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!