新手上路
- 資源幣
- 19
- 積分
- 16
- 貢獻(xiàn)
- 0
- 在線時(shí)間
- 2 小時(shí)
- 注冊時(shí)間
- 2020-2-20
- 最后登錄
- 2020-5-2
|
零基礎(chǔ)安卓逆向?qū)W習(xí)之旅(六-上)
1,將java源碼編譯成DEX文件
(1)創(chuàng)建一個(gè)Example.java文件,并編寫下邊代碼
公共類示例{
公共靜態(tài)void main(String [] args){
System.out.printf(“ HelloWorld!\ n”);
}
}
(2)將java源碼編譯為.class文件
javac–source 1.6 –target 1.6 Example.java
(3)確定dx工具的位置
較早版本的SDK將dx工具放置于[SDK路徑] / sdk / platform-tools / dx,而較新版本則將其放置與/ sdk / built-tools / android- [version] / dx。
1.jpg (38.78 KB, 下載次數(shù): 93)
下載附件
保存到相冊
2020-2-23 23:47 上傳
(4)執(zhí)行下邊命令生成DEX文件
[SDKpath] / sdk / platform-tools / dx --dex --output = Example.dex Example.class
2.jpg (26.05 KB, 下載次數(shù): 98)
下載附件
保存到相冊
2020-2-23 23:48 上傳
2,解析DEX文件格式
(1)DEX文件結(jié)構(gòu)
struct DexFile {
/ *直接映射的“ opt”標(biāo)頭* /
const DexOptHeader * pOptHeader;
/ *指向基本DEX中直接映射的結(jié)構(gòu)和數(shù)組的指針* /
const DexHeader * pHeader;
const DexStringId * pStringIds;
const DexTypeId * pTypeIds;
const DexFieldId * pFieldIds;
const DexMethodId * pMethodIds;
const DexProtoId * pProtoIds;
const DexClassDef * pClassDefs;
const DexLink * pLinkData;
/ *
*這些是在“輔助”部分之外映射的,可能不是
*包含在文件中。
* /
const DexClassLookup * pClassLookup;
const void * pRegisterMapPool; // RegisterMapClassPool
/ *指向DEX文件數(shù)據(jù)的開始* /
const u1 * baseAddr;
/ *跟蹤輔助結(jié)構(gòu)的內(nèi)存開銷* /
int開銷;
/ *與DEX相關(guān)的其他特定于應(yīng)用的數(shù)據(jù)結(jié)構(gòu)* /
// void * auxData;
};
DEX文件的第一個(gè)片段為DEX文件頭,下邊為DEX文件頭的定義
struct DexHeader {
u1魔法[8]; / * dex版本標(biāo)識* /
u4校驗(yàn)和;/ * adler32檢驗(yàn)* /
u1簽名[kSHA1DigestLen]; / * SHA-1哈希* /
u4 fileSize; / *整個(gè)dex文件大小* /
u4 headerSize; / * DexHeader結(jié)構(gòu)大小* /
u4 endianTag; / *字節(jié)序標(biāo)記* /
u4 linkSize; / *鏈接段大小* /
u4 linkOff; / *鏈接段偏移* /
u4 mapOff; / * DexMapList的文件替換* /
u4 stringIdsSize; / * DexStringId的個(gè)數(shù)* /
u4 stringIdsOff; / * DexStringId的文件替換* /
u4 typeIdsSize; / * DexTypeId的個(gè)數(shù)* /
u4 typeIdsOff; / * DexTypeId的文件替換* /
u4 protoIdsSize; / * DexProtoId的個(gè)數(shù)* /
u4 protoIdsOff; / * DexProtoId的文件替換* /
u4 fieldIdsSize; / * DexFieldId的個(gè)數(shù)* /
u4 fieldIdsOff; / * DexFieldId的文件替換* /
u4 methodIdsSize; / * DexMethodId的個(gè)數(shù)* /
u4 methodIdsOff; / * DexMethodId的文件替換* /
u4 classDefsSize; / * DexClassDef的個(gè)數(shù)* /
u4 classDefsOff; / * DexClassDef的文件替換* /
u4 dataSize; / *數(shù)據(jù)段的大小* /
u4 dataOff; / *數(shù)據(jù)段的文件替換* /
};
其中數(shù)據(jù)類型u1,u4為無符號整型數(shù)的別名
typedef uint8_t u1; / * 8字節(jié)無符號整數(shù)* /
typedef uint32_t u4; / * 32字節(jié)無符號整數(shù)* /
typedef int8_t s1; / * 8字節(jié)有符號整數(shù)* /
typedef int32_t s4; / * 32字節(jié)有符號整數(shù)* /
查看Example.dex文件,以十六進(jìn)制顯示
hexdump -C Example.dex
3.jpg (26.62 KB, 下載次數(shù): 86)
下載附件
保存到相冊
2020-2-23 23:48 上傳
DEX文件的第一個(gè)細(xì)分
u1魔法[8]; / *包括版本號* /
magic [8]是一個(gè)標(biāo)記,通常稱為magicnumber
u4校驗(yàn)和;/ * adler32校驗(yàn)和* /這是DEX文件的Adler32校正和。
4.jpg (28.14 KB, 下載次數(shù): 88)
下載附件
保存到相冊
2020-2-23 23:49 上傳
這個(gè)4個(gè)字節(jié)的校驗(yàn)和是對構(gòu)成標(biāo)題的各個(gè)位(bit)執(zhí)行一系列異或(XOR)和加法操作的結(jié)果,驗(yàn)證DEX文件頭部的各個(gè)數(shù)據(jù)沒有被破壞,確保文件頭的常量,因?yàn)樵贒alvik中,是使用DexHeader這個(gè)結(jié)構(gòu)體來確定DEX文件其他部分的存儲位置的。
u1簽名[kSHA1DigestLen]; / * SHA-1哈希長度= 20 * /這是長度為20個(gè)字節(jié)的SHA1哈希。
5.jpg (30.19 KB, 下載次數(shù): 88)
下載附件
保存到相冊
2020-2-23 23:49 上傳
u4 fileSize; / *整個(gè)文件的長度* /保存整個(gè)DEX文件的長度,用于幫助計(jì)算分段以及方便定位某些段。
6.jpg (28.47 KB, 下載次數(shù): 88)
下載附件
保存到相冊
2020-2-23 23:50 上傳
u4 headerSize; / *從下一部分開始的偏移量* /存放整個(gè)DexHeader結(jié)構(gòu)體的長度,可利用計(jì)算下一個(gè)分段在文件的起始位置。
7.jpg (28.94 KB, 下載次數(shù): 88)
下載附件
保存到相冊
2020-2-23 23:50 上傳
u4 endianTag; 這是endianness標(biāo)記,如下圖標(biāo)出文件中的endianness域。
8.jpg (29.32 KB, 下載次數(shù): 89)
下載附件
保存到相冊
2020-2-23 23:51 上傳
endianTag放置存放的是一個(gè)固定值,在所有DEX文件中都一樣,其值是:12345678。因?yàn)槟承┨幚砥魇钦J(rèn)為最高有效位應(yīng)該放在左邊,而另一些處理器卻認(rèn)為最高有效位應(yīng)該放在右邊,Dalvik虛擬機(jī)通過讀取該值,檢查此分段數(shù)字的放置順序,從而確定是內(nèi)置處理器。
接下來是linkSize和linkOff細(xì)分,當(dāng)多個(gè).class文件被編譯到一個(gè)DEX文件時(shí),會被用到。
u4 linkSize;
u4 linkOff;
指定鏈接段的大小及文件偏移,大多數(shù)情況下變量0
之后是地圖部分的偏移量,指定了DexMapList結(jié)構(gòu)的文件對齊
u4 mapOff;
19.jpg (28.42 KB, 下載次數(shù): 90)
下載附件
保存到相冊
2020-2-23 23:52 上傳
下邊是螺桿stringIdsSize的定義
u4 stringIdsSize;
20.jpg (26.6 KB, 下載次數(shù): 92)
下載附件
保存到相冊
2020-2-23 23:52 上傳
這個(gè)細(xì)分存放的是StringIds段的大小,和其他大小相同,用來計(jì)算StringIds段的起始位置。
字符串stringsIdsOff
u4 stringIdsOff;
21.jpg (29.46 KB, 下載次數(shù): 93)
下載附件
保存到相冊
2020-2-23 23:52 上傳
這個(gè)分區(qū)存放的是stringIds段的實(shí)際替換量,幫助Dalvik編譯器和虛擬機(jī)直接插入到該段。在這之后,分別是表示類型,原型,方法,類和數(shù)據(jù)ID區(qū)段的大小和Dalvik不必重復(fù)讀取文件內(nèi)容,或者是做很多加/減操作來獲得分段的起始地址,而是通過實(shí)際移位量訪問。
DexMapList分段
在DexHeader結(jié)構(gòu)的mapOff分區(qū)指定了DexMapList結(jié)構(gòu)在dex文件中的替換,由上邊可知為0x0270,DexMapList結(jié)構(gòu)的聲明如下:
struct DexMapList {
u4大小;/ * DexMapItem的個(gè)數(shù)* /
DexMapItem列表[1]; / * DexMapItem結(jié)構(gòu)* /
};
22.jpg (32.06 KB, 下載次數(shù): 93)
下載附件
保存到相冊
2020-2-23 23:53 上傳
由該分段數(shù)據(jù)的前4個(gè)字節(jié)可知,大小為0x0d,即DexMapItem的個(gè)數(shù)為13。
DexMapItem結(jié)構(gòu)的聲明如下:
struct DexMapItem {
u2類型;/ * kEexType開頭的類型* /
u2未使用;/ *未使用,用于字節(jié)對齊* /
u4大。/ *指定類型的個(gè)數(shù)* /
u4偏移量;/ *指定類型數(shù)據(jù)的文件替換* /
};
結(jié)構(gòu)中的類型類型為一個(gè)枚舉常量:
枚舉{
kDexTypeHeaderItem = 0x0000,
kDexTypeStringIdItem = 0x0001,
kDexTypeTypeIdItem = 0x0002,
kDexTypeProtoIdItem = 0x0003,
kDexTypeFieldIdItem = 0x0004,
kDexTypeMethodIdItem = 0x0005,
kDexTypeClassDefItem = 0x0006,
kDexTypeMapList = 0x1000,
kDexTypeTypeList = 0x1001,
kDexTypeAnnotationSetRefList = 0x1002,
kDexTypeAnnotationSetItem = 0x1003,
kDexTypeClassDataItem = 0x2000,
kDexTypeCodeItem = 0x2001,
kDexTypeStringDataItem = 0x2002,
kDexTypeDebugInfoItem = 0x2003,
kDexTypeAnnotationItem = 0x2004,
kDexTypeEncodeArrayItem = 0x2005,
kDexTypeAnnotationsDirectoryItem = 0x2006,
};
由上圖的數(shù)據(jù)可整理出13個(gè)DexMapItem結(jié)構(gòu)如下:
23.jpg (44.92 KB, 下載次數(shù): 99)
下載附件
保存到相冊
2020-2-23 23:54 上傳
StringIds段
該段純粹是由多個(gè)地址構(gòu)成的,這些地址是相對DEX文件的加載基地址的轉(zhuǎn)換量,用于計(jì)算定義在數(shù)據(jù)段中的各個(gè)靜態(tài)串行的起始位置
struct DexStringId {
u4 stringDataOff; / *文件到string_data_item的偏移量* /
};
該段從0x70偏移處開始,有連續(xù)0x10個(gè)DexStringId對象,以4個(gè)字節(jié)來放置這些移位量,下圖是Example.dex中的StringIds段
24.jpg (10.62 KB, 下載次數(shù): 87)
下載附件
保存到相冊
2020-2-23 23:55 上傳
如讀取下圖偏移量中的同軸:
25.jpg (12.55 KB, 下載次數(shù): 94)
下載附件
保存到相冊
2020-2-23 23:55 上傳
由字節(jié)重新順序可重新對齊預(yù)定00 00 01 8a,下圖則是DEX文件中轉(zhuǎn)換0x018a上的內(nèi)容。
26.jpg (9.98 KB, 下載次數(shù): 86)
下載附件
保存到相冊
2020-2-23 23:56 上傳
0x018a位置上的內(nèi)容是06 3c 69 6e 69 74 3e,是字符串<init>。
DexStringId結(jié)構(gòu)列表
27.jpg (47.16 KB, 下載次數(shù): 89)
下載附件
保存到相冊
2020-2-23 23:56 上傳
上邊中的串行非普通的ascii字符串,是由MUTF-8編碼來表示的,MUTF-8即是已修改的UTF-8,修改后的UTF-8編碼,其表示方式如下:
MUTF-8字符串右側(cè)放置該字符串的個(gè)數(shù)。
MUTF-8使用1〜3字節(jié)編碼長度。
大于16位的Unicode編碼U + 10000〜U + 10ffff使用3字節(jié)來編碼。
U + 0000采用2字節(jié)來編碼。
與C語言類似用空字符null作為字符串開頭。
如上邊在0x01a0偏移處的字符串編碼為0d48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0a00,其中0d表示有13個(gè)字符,代表的字符串為“ Hello World!\ n”
像02 e4 bd a0 e5 a5 bd 00頭部02表示有兩個(gè)字符,e4bd a0是UTF-8編碼字符“你”,e5 a5 bd是UTF-8編碼字符“好”。
Typelds分段
該細(xì)分市場收集尋找各種類型的各自類別是所需的信息
struct DexTypeId {
u4描述符Idx; /類型索引在stringIds列表中的索引號
};
28.jpg (14.58 KB, 下載次數(shù): 89)
下載附件
保存到相冊
2020-2-23 23:57 上傳
圖中為TypeIds分段中的第一個(gè)值,其值是03,由于是StringIds分段中某個(gè)值的索引號,則應(yīng)指StringIds分段的第4個(gè)值,如圖:
29.jpg (8 KB, 下載次數(shù): 96)
下載附件
保存到相冊
2020-2-23 23:57 上傳
第4個(gè)值是0x01af,則在數(shù)據(jù)段中對應(yīng)的字符串為L示例,這是Dalvik類型描述語言的類型變量,在Example類前加多字母L,實(shí)際上也是代表一個(gè)類或描述對象的名稱。
30.jpg (9.54 KB, 下載次數(shù): 97)
下載附件
保存到相冊
2020-2-23 23:58 上傳
DexTypeId結(jié)構(gòu)列表
31.jpg (24.33 KB, 下載次數(shù): 91)
下載附件
保存到相冊
2020-2-23 23:58 上傳
協(xié)議段
放置用作描述方法的原型ID(描述原型),方法的返回類型和參數(shù)信息。
struct DexProtoId {
u4 shortyIdx;
u4 returnTypeIdx;
u4 parametersOff;
};
DexProtoId是一個(gè)方法聲明結(jié)構(gòu)體。
shortyIdx:StringIds部分局部字符串的索引,使用了重復(fù)描述原型(原型)。
returnTypeIdx:TypeIds段中某個(gè)數(shù)據(jù)的索引號,用于描述返回值類型。
parametersOff:存放方法的參數(shù)列表的地址替換,指向DexTypeList結(jié)構(gòu)體。
struct DexTypeList {
u4大;
DexTypeItem列表[1];
};
struct DexTypeItem {
u2 typeIdx;
};
Example.dex文件中的ProtoIds部分:
32.jpg (11.67 KB, 下載次數(shù): 92)
下載附件
保存到相冊
2020-2-23 23:59 上傳
DexProtoId結(jié)構(gòu)列表
33.jpg (17.53 KB, 下載次數(shù): 96)
下載附件
保存到相冊
2020-2-23 23:59 上傳
FieldIds段
struct DexFieldId {
u2 classIdx; / *索引到typeIds列表中以定義類* /
u2 typeIdx; / *索引字段類型的typeIds * /
u4 nameIdx; / *索引字段名稱的stringIds * /
};
classIdx:存放 TypeId段的索引,所屬的類
typeIdx:存放TypeId段的索引,表示該成員的類型
nameIdx:存放stringId段的索引,成員的名字
34.jpg (6.84 KB, 下載次數(shù): 91)
下載附件
保存到相冊
2020-2-23 23:59 上傳
DexFieldId結(jié)構(gòu)列表
35.jpg (8.19 KB, 下載次數(shù): 89)
下載附件
保存到相冊
2020-2-24 00:00 上傳
MethodIds段
每個(gè)方法ID中各個(gè)分區(qū)的定義:
struct DexMethodId {
u2 classIdx; / *索引到typeIds列表中以定義類* /
u2 protoIdx; / *索引到方法原型的protoIds中* /
u4 nameIdx; / *索引到方法名稱的stringIds中* /
};
classIdx:該方法所屬的類
protoIdx:方法對應(yīng)的原型
nameIdx:方法名
36.jpg (13.14 KB, 下載次數(shù): 91)
下載附件
保存到相冊
2020-2-24 00:00 上傳
DexMethodId結(jié)構(gòu)列表
37.jpg (14.09 KB, 下載次數(shù): 92)
下載附件
保存到相冊
2020-2-24 00:01 上傳
下邊是Example.dex文件中一個(gè)方法的定義:
([Ljava / lang / String;)V
V:表示避免類型,方法的返回類型。
():方法接收的參數(shù)的類型。
java / lang / String;:String類的標(biāo)識符。
L:表示其后邊跟著的是一個(gè)類名。
[:表示其后邊跟著的是指定類型的數(shù)組。
所以該方法返回值是void類型,接收一個(gè)字符串類的數(shù)組作為參數(shù)。
ClassDefs段
其定義如下:
struct DexClassDef {
u4 classIdx; / *此類的typeIds索引* /
u4 accessFlags;
u4 superclassIdx; / *索引到超類的typeIds中* /
u4接口關(guān)閉; / *文件偏移到DexTypeList * /
u4 sourceFileIdx; / *索引到源文件名的stringIds中* /
u4注釋關(guān)閉; / *文件到注釋_directory_item的偏移量* /
u4 classDataOff; / *文件偏移到class_data_item * /
u4 staticValuesOff; / *文件偏移到DexEncodedArray * /
};
classIdx:存放的是TypeIds部分的一個(gè)索引,表示類的類型。
AccessFlags:存儲一個(gè)數(shù)字,表示其他對象可以怎樣訪問這個(gè)類。
superclassIdx:存放TypeIds部分的一個(gè)索引,表示父類的類型。
interfacesOff:接口,指向DexTypeList的替換。
sourceFileIdx:存放StringIds段的索引,使Dalvik可以找到類的源文件。
commentssOff:注解,指向DexAnnotationsDirectoryItem結(jié)構(gòu)。
classdataOff:Dalvik文件內(nèi)部的替換量,此位置存放類的重要屬性,即代碼在哪,有多少代碼。如classdataOff指向保存這些的DexClassData結(jié)構(gòu)體。
staticValuesOff:指向DexEncodedArray結(jié)構(gòu)的替換,記錄類的靜態(tài)數(shù)據(jù)。
DexClassData結(jié)構(gòu)的聲明。
/ * class_data_item的擴(kuò)展形式。注意:如果特定項(xiàng)目是
*不存在(例如,沒有靜態(tài)字段),然后是相應(yīng)的指針
*設(shè)置為NULL。* /
struct DexClassData {
DexClassDataHeader標(biāo)頭;/ *指定預(yù)設(shè)與方法的個(gè)數(shù)* /
DexField * staticFields; / *靜態(tài)靜態(tài),DexField結(jié)構(gòu)* /
DexField * instanceFields; / *實(shí)例基線,DexField結(jié)構(gòu)* /
DexMethod *直接方法; / *直接方法,DexMethod結(jié)構(gòu)* /
DexMethod * virtualMethods; / *虛方法,DexMethod結(jié)構(gòu)* /
};
DexClassDataHeader局部存放類的元數(shù)據(jù),即靜態(tài)字段,實(shí)例字段,直接方法和虛擬方法的大小,Dalvik使用這一信息計(jì)算重要參數(shù),可以確定訪問每個(gè)方法時(shí)所需的內(nèi)存大小
struct DexClassDataHeader {
u4 staticFieldsSize; / *靜態(tài)靜態(tài)個(gè)數(shù)* /
u4 instanceFieldsSize; / *實(shí)例基線個(gè)數(shù)* /
u4 directMethodsSize; / *直接方法個(gè)數(shù)* /
u4 virtualMethodsSize; / *虛方法個(gè)數(shù)* /
};
結(jié)構(gòu)DexField {
u4 fieldIdx; / *指向DexFieldId的索引* /
u4 accessFlags; / *訪問標(biāo)志* /
};
其中DexMethod左側(cè)的定義如下
struct DexMethod {
u4 methodIdx; / *指向DexMethodId的索引* /
u4 accessFlags; / *訪問標(biāo)志* /
u4 codeOff; / *指向DeCode結(jié)構(gòu)的替換* /
};
這個(gè)結(jié)構(gòu)體記錄了組成類的代碼的指針,代碼的位移量放置在codeOff細(xì)分中。
結(jié)構(gòu)DexCode {
u2寄存器 / *使用的寄存器的個(gè)數(shù)* /
u2 insSize; / *參數(shù)個(gè)數(shù)* /
u2 outsSize; / *調(diào)用其他方法時(shí)使用的寄存器個(gè)數(shù)* /
u2 trysSize; / *嘗試/捕捉個(gè)數(shù)* /
u4 debugInfoOff; / *指向調(diào)試信息的替換* /
u4 insnsSize; / *指令集個(gè)數(shù),以2字節(jié)為單位* /
u2 insns [1]; / *指令集,真正的代碼部分* /
…。
};
通過解析,更加直白地了解DEX文件的格式和結(jié)構(gòu)。
1.使用dexdump工具解析.dex文件
dexdump是Android SDK的一個(gè)工具,存放路徑為
[SDK路徑] / build-tools / android- [version] / dexdump
執(zhí)行下邊命令解析示例.dex文件
[SDK路徑] / build-tools / android- [version] /dexdumpExample.dex
38.jpg (26.35 KB, 下載次數(shù): 83)
下載附件
保存到相冊
2020-2-24 00:01 上傳
2.使用dx工具,更接近DEX文件格式的方式詳細(xì)解析DEX文件
dx--dex --verbose-dump --dump-to = [輸出文件] .txt [輸入文件] .class
由于dx工具只能對.class文件進(jìn)行操作,將其編譯成DEX文件,轉(zhuǎn)換為解析結(jié)果輸出到指定文件中。cat [輸出文件] .txt //查看解析結(jié)果。
39.jpg (35.77 KB, 下載次數(shù): 79)
下載附件
保存到相冊
2020-2-24 00:02 上傳
|
|