AndroidManifest Ambiguity方案原理及代碼

1簡述

前段時間在bluebox的一份android安全pdf中看到一個AndroidManifest Ambiguity方案。該方案基於android系統解析AXML的一個特色:android在解析AXML的屬性的時候,是經過該屬性的res id號而非屬性名定位的。所謂的AXML就是AndroidManifest.xml對應的二進制文件,APK包中存儲的就是AXML。好比屬性:linux

<public type="attr" name="name" id="0x01010003" />android

它的屬性名爲name,id號爲0x01010003。git

該方案的大體原理以下圖所示:github

 

我簡要歸納一下:安全

咱們在axml(注意是axml不是AndroidManifest.xml)中添加一個屬性,該屬性的屬性名是name,屬性的值是some.class,屬性的ID號爲0。根據前文所述,android系統對於非法的res ID號是不會解析的。因此咱們添加這個無用的屬性後,並不影響該APK的正常工做(上圖左下角所示),可是對於apktool之類的逆向工具而言,他們卻會對這個無用的屬性進行解析(上圖右下角所示)。因此,若是咱們進行重打包的話,apktool就會將該屬性變動爲一個ID號0x01010003的能夠被系統解析的屬性。這樣形成的後果就是:因爲咱們的APK中並無實現trap.class類,因此APK啓動時會報錯「there is no trap.class~~」。app

2 實現方案

該PDF雖然提出了這個方案,但並無給出實現的代碼(其實它就給了上面那張圖~其它什麼都木有了~),google也是空白。因此當我看懂原理以後,就想本身將它實現出來。哪知事情並無我想的那麼簡單~~工具

2.1 AXML文件格式

遇到的第一個挑戰就是:網上居然搜不到AXML文件的格式!!!當時差點就放棄了,不事後來一想,既然apktool能解析AXML那就說明它是瞭解AXML的文件格式的,因此就上網搜索了一下解析AXML的各類解析代碼,綜合事後以爲Claud大大的AXML Parser代碼比較利於總結AXML的文件格式。因此就以該代碼問藍本總結了一下文件格式,以下表所示:性能

0x0~0x3    magic: 0x03000800固定值ui

0x4~0x7    filesize: 文件總體大小google

0x8~0xb     StringTag: 字符串塊開始標誌,0x01001c00固定值

0xc~0xf      StringChunkSize:字符串塊大小

0x10~0x13   count of strings:字符串個數,

0x14~0x17   count of styles: 類型個數

0x18~0x1b   reserve field: 保留的,爲0

0x1c~0x1f    string的起始偏移值:注意,這個偏移值是相對於stringChunk而言的!

0x20~0x23    styles的起始偏移值:同上

下面存儲的就是n個連續的string的偏移值,每一個偏移值佔4字節,須要注意的是,這個偏移值加上string的起始偏移值和0x8纔是真正的偏移值!n的大小就是0x10~0x13的大小

而後就是n個連續的style的偏移值,同上~

String數據塊

........

Style數據塊

........

注意:到這裏,stringchunk就算是結束了

下面就是ResourceChunk了,裏面保存的就是資源ID號

ResourceTag: 0x80010800  

ResourceChunkSize: 資源ID塊的大小

連續 ResourceChunkSize/4 -2個res id值。-2主要是除去上面的8字節resourceChunkHeader。

每一個res id佔4字節

                           ResourceChunk結束

下面就是一些連續的chunk塊了:

CHUNK_STARTNS:  doc開始標誌,0x00011000

CHUNK SIZE:

line number

unknown, 0xffffffff

下面就是一個namespace record結構體,簡稱NsRecord

NsRecord->prefix

NsRecord->uri,

而後就是遞歸地進行chunk操做,由於一個命名空間裏面每每含有不少子chunk

CHUNK_TYPE:0x02011000->0x00100102爲CHUNK_STARTTAG

CHUNK_SIZE 

line number

unknown, 0xffffffff 

current tag's namespace's uri

當前tag的名字 所一個string索引值

flags, unknown usage

當前標籤含有的attr個數,注意最後結果要&0x0000ffff

classAttribute, unknown usage

下面就是連續的n個attribution chunk,attribution的結構體以下:

/* attribute structure within tag */

typedef struct{

      uint32_t uri;        /* uri of its namespace  index  of strings*/

      uint32_t name;   /*屬性名,索引值 index  of strings */

      uint32_t string;   /* attribute value if type == ATTR_STRING ,索引值*/

      uint32_t type;             /* attribute type, == ATTR_* * / 注意該值須要右移24位

      uint32_t data;            /* attribute value, encoded on type */

} Attribute_t;

依次類推

........

 

2.2修改AXML的注意事項

瞭解了AXML的文件格式,咱們就能夠想法進行屬性插入了。不過在屬性插入以前,咱們必須規劃好具體地實施方案,由於它涉及到的東西並不算少。

1)首先,須要對屬性結構體作進一步分析。它的格式以下:

/* attribute structure within tag */

typedef struct{

         uint32_t uri;               /* uri of its namespace  index  of strings*/

         uint32_t name;      /*屬性名,索引值 index  of strings */

         uint32_t string;     /* attribute value if type == ATTR_STRING ,索引值*/

         uint32_t type;            /* attribute type, == ATTR_* * / 注意該值須要右移24位

         uint32_t data;           /* attribute value, encoded on type */

} Attribute_t;

重點是name, string, data。我提取出了一個AXML中屬性片斷,以下所示:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

0C 00 00 00  05 00 00 00   FF FF FF FF   08 00 00 01   01 00 06 7F 

0C 00 00 00  06 00 00 00   FF FF FF FF   08 00 00 01   00 00 05 7F

0C 00 00 00[w1]   04 00 00 00[w2]    17 00 00 00[w3]   08 00 00 03 [w4]   17 00 00 00[w5] 

 [w1]uri:命名空間的URI,是string的索引值

 [w2]name:屬性名,也是一個string的索引值

 [w3]string:若是屬性type爲ATTR_STRING的話,此值就是屬性android:name="xxx",xxx在string的索引值。其他狀況均爲0xffffffff

 [w4]type:屬性的類型,對於android:name,類型值爲0x03000008

 [w5]data:屬性的數據值,對於ATTR_STRING而言,它的值就是string的值。

能夠發現,結構體裏面並無一個叫作res ID的成員,那麼系統又是如何獲取某個屬性的ID號的呢?原來這裏的name成員是身兼兩職,即做爲屬性名的一個string索引,又做爲res ID的索引。好比這裏name = 4,它對應StringChunk中的字符串爲"name",對應ResourceChunk中的res ID 0x01010003。因此要插入一個屬性名爲name,ID號又爲0的屬性,咱們就必須新建一個string,該string的值爲name,再新建一個res ID,值爲0,且二者在各自Chunk區域的索引值是相等的(這是重點)

2)其次,就是在StringChunk中string的對齊問題(最初被弄得腦洞大開~)。

AXML中幾乎全部的成員都是uint32型的,除了使用UTF-16編碼的string數據塊以外。因此在加入string後必須對string數據塊進行4字節對齊。而若是原AXML的string數據塊已經進行過4字節對齊(即人爲地填充了幾個0x00)的話,咱們就須要注意UTF-16編碼的最後一個string的第一個字節的大小並不包含這幾個填充的0x00(這個字節表示該string所佔用的字節數,詳情可查閱UTF-16編碼相關資料)。爲了繞過煩人的對齊問題,咱們使用取巧的方式獲取字符串的長度:

stringLen = stringChunkSize - stringOffset; //此時的stringLen確定是4字節對齊的

固然,這是在沒有style的狀況下,若是有的話,還得采起額外的操做(實現代碼中有~)。爲了簡便,我是直接將添加的string加在這個對齊後的字符串以後的,這樣就只須要考慮添加的字符串是否須要對齊了~

3)而後,就是ResourceChunk的擴充。

在1)中已經提到插入的屬性的name的值同時充當res ID索引值。而一般ResourceChunk中的res ID個數是遠少於string 的個數的,那麼這就須要咱們將ResourceChunk進行擴充。擴充很簡單,所有賦值爲0便可。

4)最後,除了須要添加數據外,還須要修改原文件的某些「計量值」,這些計量值都是與數據塊大小或偏移值有關的,總結以下:

①fileSize

②StringChunkSize

③count of string

④styles的起始偏移值(若是有style的話就須要修改)

⑤ResourceChunkSize

⑥application所屬chunk的chunksize

⑦applicationh含有的屬性個數

 

2.3 修改AXML步驟

1)修改StringChunk,添加UTF-16表示的字符串chouchou.class和name,併爲這兩個字符串添加偏移值條目。同時對StringChunkSize、count of string、styles的起始偏移值進行修復;

2)修改ResourceChunk,主要是進行res ID擴充和對ResourceChunkSize的修復

3)修改application所在的chunk,插入屬性,同時對chunksize和applicationh含有的屬性個數進行修復;

4)將不須要修改的部分copy到合適的位置;

5)修復fileSize

固然,具體地實現確定比上訴步驟複雜一些,不過實現源碼中有較爲詳細的註釋,你們可參照源碼閱讀~

3 代碼說明

AxmlParser.h/.c是Claud大大解析axml的源碼,出於對做者的感謝以及讓你們更詳細地瞭解AXML的解析過程(其實,是我實在是不想本身寫解析代碼o(╯□╰)o),我將實現代碼跟它合併到一塊了。AxmlModify.c就是我寫的實現AXML修改功能。

4 使用方法

當前代碼還不完善,只是初步實現了插入application.attr("name", "chouchou.class",0x0)的功能。因此並不是最終版。

代碼只能在linux下運行,下載代碼後make便可生成可執行文件manifestAmbiguity。而後直接運行./manifestAmbiguity能夠獲得完整的使用說明。

修改前:

 

修改後:

 

將修改後的xml覆蓋原APK中的xml,而後刪掉原來的簽名文件夾再進行簽名便可。這時候若是對按照此方案修改後的APK進行重打包,就會發現重打包的APK已經沒法啓動了。

5 下一步工做

因爲目前的apk軟件保護主要是基於dex代碼加密和so庫文件加密,對AndroidManifest.xml並無進行任何操做,而AndroidManifest.xml做爲apk的入口文件,其重要性是不言而喻的。因此我想能不能在此文件中作些「手腳」,而後結合相應的處理代碼實現另外一角度的軟件保護。

好比,咱們徹底能夠實現那個陷阱類trap.class,且這個類繼承自application等等,以便被重打包的apk也可運行。只是,從一開始,該apk就運行在一個錯誤的環境中,至於以後的操做,那就能夠盡情發揮了。

或者,咱們能夠在其餘tag中插入一些不會影響apk運行的屬性(即新添加的屬性不可被系統識別,重打包後該屬性能被系統識別但又不會影響apk的運行),而後在代碼中檢查AndroidManifest.xml是否含有該屬性,若是有就說明軟件被重打包了。

等等~

若是你們有好的建議或方法,請必定不吝賜教~謝謝!

代碼地址:https://github.com/wanchouchou/ManifestAmbiguity

相關文章
相關標籤/搜索