wav文件头损坏_Dex文件结构学习
目 錄
一、DexHeader
? ? ? ?1. 理解DexHeader
? ? ? ?2. 解析DexHeader
二、DexStringId
? ? ? ?1. 理解DexStringId
? ? ? ?2. 解析DexStringId
三、DexTypeId
? ? ? ?1. 理解DexTypeId
? ? ? ?2. 解析DexTypeId
四、DexFieldId
? ? ? ?1. 理解DexFieldId
? ? ? ?2. 解析DexFieldId
五、DexMethodId
? ? ? ?1. 理解DexMethodId
? ? ? ?2. 解析DexMethodId
六、DexProtoId
? ? ? ?1. 理解DexProtoId
? ? ? ?2. 解析DexProtoId
七、DexClassDef
? ? ? ?1. 理解DexClassDef
? ? ? ?2. 理解DexClassDef
八、DexLink
? ? ? ?待續(xù)....狗命要緊
最近在學(xué)習(xí)dex文件,把學(xué)習(xí)的過程記錄一下!有什么不對的地方還各位多多指點,感激不盡!
一、DexHeader>>>>1.?理解DexHeader
隨便拖入一個Dex文件到010,運行DEXTemplate.bt,就能看到下圖中的Dex的結(jié)果。接下開始逐個分析Dex文件結(jié)構(gòu),我用的是android-6.0.0_r1的源碼中DexFile.h:通過上面的源碼的注釋知道了各個結(jié)構(gòu)的大意與010的對應(yīng)的關(guān)系,但是還不清楚這些結(jié)構(gòu)的內(nèi)部是什么樣子的!那么開始解析第一個結(jié)構(gòu) DexHeader:/* * Direct-mapped "header_item" struct. */struct DexHeader { u1 magic[8]; //取值必須是字符串 "dex\n035\0" 或者字節(jié)byte數(shù)組 {0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00} u4 checksum; //文件內(nèi)容的校驗和,不包括magic和自己,主要用于檢查文件是否損壞 u1 signature[kSHA1DigestLen]; //簽名信息,不包括 magic\checksum和自己 u4 fileSize; //整個文件的長度,單位為字節(jié),包括所有的內(nèi)容 u4 headerSize; //默認(rèn)是0x70個字節(jié) u4 endianTag; //大小端標(biāo)簽,標(biāo)準(zhǔn).dex文件為小端,此項一般固定為0x12345678常量 u4 linkSize; //鏈接數(shù)據(jù)的大小 u4 linkOff; //鏈接數(shù)據(jù)的偏移值 u4 mapOff; //map item的偏移地址,該item屬于data區(qū)里的內(nèi)容,值要大于等于dataOff的大小 u4 stringIdsSize; //DEX中用到的所有字符串內(nèi)容的大小* u4 stringIdsOff; //DEX中用到的所有字符串內(nèi)容的偏移量 u4 typeIdsSize; //DEX中類型數(shù)據(jù)結(jié)構(gòu)的大小 u4 typeIdsOff; //DEX中類型數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 protoIdsSize; //DEX中的元數(shù)據(jù)信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 protoIdsOff; //DEX中的元數(shù)據(jù)信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 fieldIdsSize; //DEX中字段信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 fieldIdsOff; //DEX中字段信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 methodIdsSize; //DEX中方法信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 methodIdsOff; //DEX中方法信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 classDefsSize; //DEX中的類信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 classDefsOff; //DEX中的類信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 dataSize; //DEX中數(shù)據(jù)區(qū)域的結(jié)構(gòu)信息的大小 u4 dataOff; //DEX中數(shù)據(jù)區(qū)域的結(jié)構(gòu)信息的偏移值};看010中對應(yīng)的位置:??u1??magic[8];???????//取值必須是字符串?"dex\n035\0"?或者字節(jié)byte數(shù)組?{0x64?0x65?0x78?0x0a?0x30?0x33?0x35?0x00}下圖選中magic時 會選中前八個字節(jié)magic[8]? u1代表字節(jié) [8] 則是8個字節(jié)。可以把magic看做dex文件的標(biāo)識{0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00}通過這個字段知道是該文件dex文件:它是一個u4 代表4個字節(jié)的內(nèi)容。u4 checksum; //文件內(nèi)容的校驗和,不包括magic和自己,主要用于檢查文件是否損壞signature[kSHA1DigestLen]了,signature字段用于檢驗dex文件,其實就是把整個dex文件用SHA-1簽名得到的一個值。這里占用20個字節(jié)。u1 signature[kSHA1DigestLen]; //簽名信息,不包括 magic\checksum和自己kSHA1DigestLen:/* * 160-bit SHA-1 digest. */enum { kSHA1DigestLen = 20, kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };fileSize:文件長度:u4 fileSize; //整個文件的長度,單位為字節(jié),包括所有的內(nèi)容553820個字節(jié)大小。表示 DexHeader 頭結(jié)構(gòu)的大小,占用4個字節(jié)。這里可以看到它一共占用了112個字節(jié),112對應(yīng)的16進制數(shù)為70h:u4 headerSize; //默認(rèn)是0x70個字節(jié)?u4??endianTag;??????//大小端標(biāo)簽,標(biāo)準(zhǔn).dex文件為小端,此項一般固定為0x12345678常量當(dāng)多個class文件被編譯到一個dex文件是,他們會用到link_size和link_off,通常為0。 u4 linkSize; //鏈接數(shù)據(jù)的大小 u4 linkOff; //鏈接數(shù)據(jù)的偏移值mapOff字段了,它指定了 DexMapList 的文件偏移:u4 mapOff; //map item的偏移地址,該item屬于data區(qū)里的內(nèi)容,值要大于等于dataOff的大小stringIdsSize代表全dex文件的字符串的個數(shù)stringIdsOff?代表全dex文件的字符串的偏移 u4 stringIdsSize; //DEX中用到的所有字符串內(nèi)容的大小* u4 stringIdsOff; //DEX中用到的所有字符串內(nèi)容的偏移量有了這個知識 可以嘗試分析第一個字符串:已經(jīng)找到第一個字符串的偏移是6e72c:那么也就找到了第一個字符串的值,雖然看不明顯但確實如此,以上的2個問題會在解析中給出答案!這指出了type類型的偏移和type的個數(shù):??u4??typeIdsSize;????????//DEX中類型數(shù)據(jù)結(jié)構(gòu)的大小 u4 typeIdsOff; //DEX中類型數(shù)據(jù)結(jié)構(gòu)的偏移值略... u4 protoIdsSize; //DEX中的元數(shù)據(jù)信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 protoIdsOff; //DEX中的元數(shù)據(jù)信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 fieldIdsSize; //DEX中字段信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 fieldIdsOff; //DEX中字段信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 methodIdsSize; //DEX中方法信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 methodIdsOff; //DEX中方法信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 classDefsSize; //DEX中的類信息數(shù)據(jù)結(jié)構(gòu)的大小 u4 classDefsOff; //DEX中的類信息數(shù)據(jù)結(jié)構(gòu)的偏移值 u4 dataSize; //DEX中數(shù)據(jù)區(qū)域的結(jié)構(gòu)信息的大小 u4 dataOff; //DEX中數(shù)據(jù)區(qū)域的結(jié)構(gòu)信息的偏移值>>>>2.?解析DexHeader
那么就開始動手寫的代碼來解析吧~~用的Clion編譯器:首先 先寫個一個讀取文件的方法char* Read_File(string file_Path) { filebuf *pbuf; ifstream filestr; long size; char *buffer; // 要讀入整個文件,必須采用二進制打開 filestr.open(file_Path, ios::binary); // 獲取filestr對應(yīng)buffer對象的指針 pbuf = filestr.rdbuf(); // 調(diào)用buffer對象方法獲取文件大小 size = pbuf->pubseekoff(0, ios::end, ios::in); pbuf->pubseekpos(0, ios::in); // 分配內(nèi)存空間 buffer = new char[size]; // 獲取文件內(nèi)容 pbuf->sgetn(buffer, size); filestr.close(); // 輸出到標(biāo)準(zhǔn)輸出 //cout.write (buffer,size); // delete []buffer; return buffer;}main: //得到文件內(nèi)存地址指針 char* fp = Read_File("/home/zlq/baidunetdiskdownload/android/classes.dex"); //強轉(zhuǎn)為DexFile指針 DexFile *dex = (DexFile*)&fp; //解析struct header_item dex_header Read_DexHeader(dex->pHeader);寫的比較拙劣。/** * 實現(xiàn)方法 * @param dexHeader */void Read_DexHeader(DexHeader* dexHeader){ //struct header_item dex_header printf("struct header_item dex_header\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t0x0"); printf("\t\t\t\t0x%x", (unsigned int)sizeof(DexHeader)); printf("\t\tDEX 文件頭,記錄了一些當(dāng)前文件的信息以及其他數(shù)據(jù)結(jié)構(gòu)在文件中的偏移量"); printf("\n\tmagic\t\t\t\t\t\t\t\t"); char* magic = (char*)dexHeader->magic; while(*magic != '\0') { if(*magic != '\n') { printf("%c ",(*magic)); } magic++; } printf("\t\t\t\t\t\t\t\t\t\t0x0\t\t\t\t0x%x\t\t\t取值必須是字符串 \"dex\\n035\\0\" 或者字節(jié)byte數(shù)組 {0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00}", (unsigned int)sizeof(dexHeader->magic)); printf("\n\tchecksum\t\t\t\t\t\t\t0x%X\t\t\t\t\t\t\t\t\t\t\t0x%x\t\t\t\t0x%x\t\t\t文件內(nèi)容的校驗和,不包括magic和自己,主要用于檢查文件是否損壞" ,dexHeader->checksum ,(unsigned int)sizeof(dexHeader->magic) ,(unsigned int)sizeof(dexHeader->checksum)); .... 略輸出:通過對比分析是一樣的,這個比較簡單,用結(jié)構(gòu)指針接受一下就行了,只是輸出有點麻煩。二、DexStringId>>>>1.?理解DexStringId
DEX中所有的字符串存儲在這里:?DexStringId*??pStringIds;?????//數(shù)組,元素類型為string_id_item,存儲字符串相關(guān)的信息進去看看此結(jié)構(gòu)。它只有一個字段,那么它是如何解析dex字符串呢?/* * Direct-mapped "string_id_item". */struct DexStringId { //用于指明 string_data_item 位置文件的位置 u4 stringDataOff; /* file offset to string_data_item */};首先要知道的是它是一個數(shù)組類型,數(shù)組的大小取決于:??DexHeader->stringIdsSize那么就很好理解了,上面提示 一共 有3619個字符串,解析主要靠DexHeader中的stringIdsSize和stringIdsOff來解析。>>>>2.?解析DexStringId
又開始寫代碼了:void Read_DexStringId(char* fp) { DexFile *dex = (DexFile*)&fp; printf("\n\nstruct string_id_list dex_string_ids\t%d\t\t\t\t\t\t\t\t\t\t\t\t0x%x", dex->pHeader->stringIdsSize,(unsigned int) sizeof(DexHeader)); printf("\t\t\t0x%x", (unsigned int) sizeof(DexStringId)); printf("\t\t\t數(shù)組,元素類型為string_id_item,存儲字符串相關(guān)的信息"); //拿到字符串的偏移 int *p2 = (int*)(fp + dex->pHeader->stringIdsOff); stringIdsSize --> DEX中用到的所有字符串內(nèi)容的大小 for (int i = 0; i < dex->pHeader->stringIdsSize; ++i) { printf("\n\tstruct string_id_item string_id[%d]:",i); // 文件首地址+字符串偏移就是字符串存放的位置的第一個數(shù)組 const u1* stringdata = (u1*)fp+*p2; //解碼 /* * dex文件里采用了變長方式表示字符串長度。一個字符串的長度可能是一個字節(jié)(小于256)或者4個字節(jié)(1G大小以上)。字符串的長度大多數(shù)都是小于 256個字節(jié),因此需要使用一種編碼,既可以表示一個字節(jié)的長度,也可以表示4個字節(jié)的長度,并且1個字節(jié)的長度占絕大多數(shù)。能滿足這種表示的編碼方式有很多,但dex文件里采用的是uleb128方式。leb128編碼是一種變長編碼,每個字節(jié)采用7位來表達原來的數(shù)據(jù),最高位用來表示是否有后繼字節(jié)。若第一個 Byte 的最高位為 1 ,則表示還需要下一個 Byte 來描述 ,直至最后一個 Byte 的最高位為 0 。每個 Byte 的其余 Bit 用來表示數(shù)據(jù) */ readUnsignedLeb128(&stringdata); //轉(zhuǎn)碼后該字符串為 內(nèi)存數(shù)據(jù)為 \0 時 則結(jié)束 while(*stringdata != '\0') { //換行 if((*stringdata) != '\a' && (*stringdata) != '\b' &&(*stringdata) != '\t' && (*stringdata) != '\n' && (*stringdata) != '\v' && (*stringdata) != '\r' && (*stringdata) != '\f' ) { printf("%c",(*stringdata)); } //printf("%c",(*stringdata)); stringdata++; } p2++; }}其中一部分的輸出:010:總結(jié): * dex->pHeader->stringIdsOff 存儲了整個dex的字符串的偏移的首地址 是一個數(shù)組類型 * dex->pHeader->stringIdsSize 存儲字符串的個數(shù) * 字符串偏移指向的地址的內(nèi)容通過 readUnsignedLeb128 解碼 字符串的長度通過判斷'\0' 即可 編碼:LEB128即"Little-Endian Base 128",基于128的小印第安序編碼格式,是對任意有符號或者無符號整型數(shù)的可變長度的編碼。也即,用LEB128編碼的正數(shù),會根據(jù)數(shù)字的大小改變所占字節(jié)數(shù)。在android的.dex文件中,他只用來編碼32bits的整型數(shù)。格式:圖只是指示性的用兩個字節(jié)表示。編碼的每個字節(jié)有效部分只有低7bits,每個字節(jié)的最高bit用來指示是否是最后一個字節(jié)。非最高字節(jié)的bit7為0,最高字節(jié)的bit7為1。將leb128編碼的數(shù)字轉(zhuǎn)換為可讀數(shù)字的規(guī)則是:除去每個字節(jié)的bit7,將每個字節(jié)剩余的7個bits拼接在一起,即為數(shù)字。比如:LEB128編碼的0x02b0 ---> 轉(zhuǎn)換后的數(shù)字0x0130轉(zhuǎn)換過程:0x02b0 ---> 0000 0010 1011 0000 -->去除最高位--> 000 0010 011 0000 -->按4bits重排 --> 00 0001 0011 0000 --> 0x130引用?https://blog.csdn.net/Roland_Sun/article/details/46708061三、DexTypeId>>>>
1.?理解DexTypeId
type_ids 區(qū)索引了 .dex 文件里的所有數(shù)據(jù)類型 ,包括 class 類型 ,數(shù)組類型(array types)和基本類型(primitive types) 。本區(qū)域里的元素格式為type_ids_item。type_ids_item 里面 descriptor_idx 的值的意思 ,是 string_ids 里的 index 序號 ,是用來描述此type 的字符串。??DexTypeId*????pTypeIds;???????//數(shù)組,存儲類型相關(guān)的信息看結(jié)構(gòu),他也是一個字段,且看如何分析它。注意是一個數(shù)組的類型:/* * Direct-mapped "type_id_item". */struct DexTypeId { u4 descriptorIdx; /* 指向string_ids的索引 */};同時 還有2個很重要的字段在DexHeader中typeIdsSize和typeIdsOff 同樣代表類型的偏移和大小。先來分析第一個type:得知第一個type所在位置是 00 00 38 FC。010:得到的值是 0x19F根據(jù)描述 ? /* 指向string_ids的索引 */?? 知道這個值是字符串偏移的索引。0x19F = 415恰好是第一個類型的值 : B?byte如此就分析出第一個類型的位置和來源了。? ?
>>>>
2.?解析DexTypeId?
又開始寫代碼:void Read_DexTypeId(char* fp){ DexFile *dex = (DexFile*)&fp; printf("\n\nstruct struct type_id_list dex_type_ids\t%d\t\t\t\t\t\t\t\t\t\t\t\t0x%x", dex->pHeader->typeIdsSize,(unsigned int) sizeof(DexHeader)); printf("\t\t\t0x%x", (unsigned int) sizeof(DexTypeId)); printf("\t\t\t數(shù)組,存儲類型相關(guān)的信息\n"); //拿到類型的偏移 int *typeIdsOff = (int*)(fp + dex->pHeader->typeIdsOff); for (int i = 0; i < dex->pHeader->typeIdsSize; ++i) { printf("\n\tstruct type_id_list dex_type_ids[%d]:",i); //先拿到字符串的偏移 int *stringIdsOff = (int*)(fp + dex->pHeader->stringIdsOff); //再根據(jù)類型的偏移去尋找字符串 const u1* stringdata = (u1*)fp+stringIdsOff[(*typeIdsOff)]; //解碼 readUnsignedLeb128(&stringdata); while(*stringdata != '\0') { printf("%c",(*stringdata)); stringdata++; } //自加 獲取下一個指針 int型指針自加 base += 1 typeIdsOff++; }}輸出:010:總結(jié):descriptor_idx 的值的意思 ,是 string_ids 里的 index 序號 ,是用來描述此type 的字符串 字符串指針[descriptor_idx地址內(nèi)的值] = descriptor_idx值四、DexFieldId>>>>1.?理解DexFieldId
大意:?DexFieldId*???pFieldIds;??????//數(shù)組,存儲成員變量信息,包括變量名和類型等具體結(jié)構(gòu):struct DexFieldId { u2 classIdx; /* field所屬的class類型,class_idx的值時type_ids的一個index,指向所屬的類 */ u2 typeIdx; /* field的類型,值是type_ids的一個index */ u4 nameIdx; /* field的名稱,它的值是string_ids的一個index */};仍然從header看起 重要的數(shù)據(jù)還是保存在頭部。繼續(xù)從010中嘗試分析:那么來到 824C:之前分析過type 這次 分析結(jié)構(gòu)中的 type_idx,上圖可見 type_idx的地址的值內(nèi)容為 0x1D 也就是 29。可以看到他們的值是一致的!另外2個原理一直,可以自行分析。截圖截多了!不好意思!>>>>2.?解析DexFieldId
又開始寫代碼。比較麻煩的是取值的過程需要通過其他屬性來取值。void Read_DexFieldId(char* fp){ DexFile *dex = (DexFile*)&fp; printf("\n\nstruct field_id_list dex_field_ids\t%d\t\t\t\t\t\t\t\t\t\t\t\t0x%x", dex->pHeader->fieldIdsSize,(unsigned int) sizeof(DexHeader)); printf("\t\t\t0x%x", (unsigned int) sizeof(DexFieldId)); printf("\t\t\t數(shù)組,存儲類的相關(guān)的信息"); //轉(zhuǎn)為DexFieldId結(jié)構(gòu)體 DexFieldId *dexFieldId = (DexFieldId*)(fp + dex->pHeader->fieldIdsOff); for (int i = 0; i < dex->pHeader->fieldIdsSize; ++i) { printf("\n\tstruct field_id_item field_id[%d]",i); /** * 重點: * 要想找到field_id的typeIdx對應(yīng)位置的值 要先找到 typeIdsOff偏移地址+typeIdx等于string_ids的索引,再通過string_ids來尋找值 * * [類型偏移首地址+typeIdx索引] = 字符串所在的索引位置 * 字符串偏移首地址[字符串所在的索引位置] = [類型偏移首地址+typeIdx索引]的具體值 */ //拿到類型的偏移首地址 int *typeIdsOff = (int*)(fp + dex->pHeader->typeIdsOff); //拿到字符串的偏移首地址 int *stringIdsOff = (int*)(fp + dex->pHeader->stringIdsOff); //類型偏移地址+索引=字符串索引 //字符串偏移+字符串索引=typeIdx位置具體的值 const u1* typeIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexFieldId->typeIdx))]; //解碼 readUnsignedLeb128(&typeIdx_stringdata); printf("\n\t\ttypeIdx --> "); while(*typeIdx_stringdata != '\0') { printf("%c",(*typeIdx_stringdata)); typeIdx_stringdata++; } //u2 classIdx; /* field所屬的class類型,class_idx的值時type_ids的一個index,指向所屬的類 */ const u1* classIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexFieldId->classIdx))]; //解碼 readUnsignedLeb128(&classIdx_stringdata); printf("\n\t\tclassIdx--> "); while(*classIdx_stringdata != '\0') { printf("%c",(*classIdx_stringdata)); classIdx_stringdata++; } //u4 nameIdx; /* field的名稱,它的值是string_ids的一個index */ const u1* nameIdx_stringdata = (u1*)fp+stringIdsOff[(dexFieldId->nameIdx)]; //解碼 readUnsignedLeb128(&nameIdx_stringdata); printf("\n\t\tnameIdx --> "); while(*nameIdx_stringdata != '\0') { printf("%c",(*nameIdx_stringdata)); nameIdx_stringdata++; } dexFieldId++; }}輸出:010:五、DexMethodId?>>>>
1.?理解DexMethodId?
DexMethodId* pMethodIds; //數(shù)組,存儲成員函數(shù)信息包括函數(shù)名 參數(shù)和返回值類型查看具體結(jié)構(gòu)。描述的比較清晰:struct DexMethodId { u2 classIdx; /* method所屬的class類型,class_idx的值是type_ids的一個index,必須指向一個class類型 */ u2 protoIdx; /* method的原型,指向proto_ids的一個index */ u4 nameIdx; /* method的名稱,值為string_ids的一個index */};可以自己嘗試手動分析了,這里就不過多的演示了..之前演示很多次了。>>>>2.?解析DexMethodId
又開始寫代碼了:void Read_DexMethodId(char* fp){ DexFile *dex = (DexFile*)&fp; printf("\n\nstruct method_id_list dex_method_ids\t%d\t\t\t\t\t\t\t\t\t\t\t\t0x%x", dex->pHeader->methodIdsSize,(unsigned int) sizeof(DexHeader)); printf("\t\t\t0x%x", (unsigned int) sizeof(DexMethodId)); printf("\t\t\t數(shù)組,存儲成員函數(shù)信息包括函數(shù)名 參數(shù)和返回值類型"); //轉(zhuǎn)為DexMethodId結(jié)構(gòu)體 DexMethodId *dexMethodId = (DexMethodId*)(fp + dex->pHeader->methodIdsOff); for (int i = 0; i < dex->pHeader->methodIdsSize; ++i) { printf("\n\tstruct method_id_item method_id[%d]", i); int *typeIdsOff = (int*)(fp + dex->pHeader->typeIdsOff); int *protoIdsOff = (int*)(fp + dex->pHeader->protoIdsOff); int *stringIdsOff = (int*)(fp + dex->pHeader->stringIdsOff); const u1* classIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexMethodId->classIdx))]; //解碼 readUnsignedLeb128(&classIdx_stringdata); printf("\n\t\tclassIdx--> "); while(*classIdx_stringdata != '\0') { printf("%c",(*classIdx_stringdata)); classIdx_stringdata++; } //method的原型,指向proto_ids的一個index DexProtoId* dexProtoId = (DexProtoId*) protoIdsOff+dexMethodId->protoIdx; const u1* protoIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexProtoId->returnTypeIdx))]; readUnsignedLeb128(&protoIdx_stringdata); printf("\n\t\tprotoIdx--> "); while(*protoIdx_stringdata != '\0') { printf("%c",(*protoIdx_stringdata)); protoIdx_stringdata++; } const u1* nameIdx_stringdata = (u1*)fp+stringIdsOff[dexMethodId->nameIdx]; //解碼 readUnsignedLeb128(&nameIdx_stringdata); printf("\n\t\tnameIdx --> "); while(*nameIdx_stringdata != '\0') { printf("%c",(*nameIdx_stringdata)); nameIdx_stringdata++; } dexMethodId++; }}輸出:010:六、DexProtoId>>>>
1.?理解DexProtoId
??DexProtoId*???pProtoIds;??????//數(shù)組,函數(shù)原型數(shù)據(jù)索引,記錄了方法聲明的字符串,返回類型和參數(shù)列表具體結(jié)構(gòu):struct DexProtoId { u4 shortyIdx; /* 值為一個string_ids的index號,用來說明該method原型 */ u4 returnTypeIdx; /* 值為一個type_ids的index,表示該method原型的返回值類型 */ u4 parametersOff; /* 指定method原型的參數(shù)列表type_list,若method沒有參數(shù),則值為0. 參數(shù)的格式是type_list */};>>>>2.?解析DexProtoId
void Read_DexProtoId(char* fp){ DexFile *dex = (DexFile*)&fp; printf("\n\nstruct proto_id_list dex_proto_ids\t%d\t\t\t\t\t\t\t\t\t\t\t\t0x%x", dex->pHeader->protoIdsSize,(unsigned int) sizeof(DexHeader)); printf("\t\t\t0x%x", (unsigned int) sizeof(DexMethodId)); printf("\t\t\t數(shù)組,函數(shù)原型數(shù)據(jù)索引,記錄了方法聲明的字符串,返回類型和參數(shù)列表"); //轉(zhuǎn)為DexMethodId結(jié)構(gòu)體 DexProtoId *dexProtoId = (DexProtoId*)(fp + dex->pHeader->protoIdsOff); for (int i = 0; i < dex->pHeader->protoIdsSize; ++i) { printf("\n\tstruct proto_id_item proto_id[%d]", i); int *typeIdsOff = (int*)(fp + dex->pHeader->typeIdsOff); int *stringIdsOff = (int*)(fp + dex->pHeader->stringIdsOff); const u1* shortyIdx_stringdata = (u1*)fp+stringIdsOff[dexProtoId->shortyIdx]; //解碼 readUnsignedLeb128(&shortyIdx_stringdata); printf("\n\t\tshortyIdx--> "); while(*shortyIdx_stringdata != '\0') { printf("%c",(*shortyIdx_stringdata)); shortyIdx_stringdata++; } const u1* returnTypeIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexProtoId->returnTypeIdx))]; readUnsignedLeb128(&returnTypeIdx_stringdata); printf("\n\t\tprotoIdx--> "); while(*returnTypeIdx_stringdata != '\0') { printf("%c",(*returnTypeIdx_stringdata)); returnTypeIdx_stringdata++; } printf("\n\t\tparametersOff--> %d",dexProtoId->parametersOff); dexProtoId++; }}輸出:010:七、DexClassDef>>>>
1.?理解DexClassDef
??DexClassDef*??pClassDefs;?????//數(shù)組,存儲類的信息結(jié)構(gòu)體:struct DexClassDef { u4 classIdx; /* 描述具體的class類型,值是type_ids的一個index,值必須是一個class類型,不能是數(shù)組或者基本類型 */ u4 accessFlags; /* 描述class的訪問類型,如public,final,static等 */ u4 superclassIdx; /* 描述父類的類型,值必須是一個class類型,不能是數(shù)組雷興國或者基本類型 */ u4 interfacesOff; /* 值為偏移地址,被指向的數(shù)據(jù)結(jié)構(gòu)為type_list,class若沒有interfaces,值為0 */ u4 sourceFileIdx; /* 表示源代碼文件的信息,值為string_ids的一個index。若此項信息丟失,此項賦值為NO_INDEX=0xFFFFFFFF */ u4 annotationsOff; /* 值為偏移地址,指向的內(nèi)容是該class的注解,位置在data區(qū),格式為annotations_directory_item,若沒有此項,值為0 */ u4 classDataOff; /* 值為偏移地址,指向的內(nèi)容是該class的使用到的數(shù)據(jù),位置在data區(qū),格式為class_data_item。無偶沒有此項,則值為0 */ u4 staticValuesOff; /* 值為偏移地址,指向data區(qū)里的一個列表,格式為encoded_array_item。若沒有此項,值為0. */};解析:void Read_DexClassDef(char* fp){ //u4 classIdx; /* 描述具體的class類型,值是type_ids的一個index,值必須是一個class類型,不能是數(shù)組或者基本類型 */ //u4 accessFlags; /* 描述class的訪問類型,如public,final,static等 */ //u4 superclassIdx; /* 描述父類的類型,值必須是一個class類型,不能是數(shù)組或者基本類型 */ //u4 interfacesOff; /* 值為偏移地址,被指向的數(shù)據(jù)結(jié)構(gòu)為type_list,class若沒有interfaces,值為0 */ //u4 sourceFileIdx; /* 表示源代碼文件的信息,值為string_ids的一個index。若此項信息丟失,此項賦值為NO_INDEX=0xFFFFFFFF */ //u4 annotationsOff; /* 值為偏移地址,指向的內(nèi)容是該class的注解,位置在data區(qū),格式為annotations_directory_item,若沒有此項,值為0 */ //u4 classDataOff; /* 值為偏移地址,指向的內(nèi)容是該class的使用到的數(shù)據(jù),位置在data區(qū),格式為class_data_item。無偶沒有此項,則值為0 */ //u4 staticValuesOff; /* 值為偏移地址,指向data區(qū)里的一個列表,格式為encoded_array_item。若沒有此項,值為0. */ DexFile *dex = (DexFile*)&fp; printf("\n\nstruct class_def_item_list dex_class_defs\t%d\t\t\t\t\t\t\t\t\t\t\t\t0x%x", dex->pHeader->classDefsSize,(unsigned int) sizeof(DexHeader)); printf("\t\t\t0x%x", (unsigned int) sizeof(DexMethodId)); printf("\t\t\t數(shù)組,存儲類的信息"); //轉(zhuǎn)為DexMethodId結(jié)構(gòu)體 DexClassDef *dexClassDef = (DexClassDef*)(fp + dex->pHeader->classDefsOff); for (int i = 0; i < dex->pHeader->classDefsSize; ++i) { printf("\n\tstruct class_def_item class_def[%d]", i); int *typeIdsOff = (int*)(fp + dex->pHeader->typeIdsOff); int *stringIdsOff = (int*)(fp + dex->pHeader->stringIdsOff); const u1* classIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexClassDef->classIdx))]; //解碼 readUnsignedLeb128(&classIdx_stringdata); printf("\n\t\tclassIdx\t\t--> "); while(*classIdx_stringdata != '\0') { printf("%c",(*classIdx_stringdata)); classIdx_stringdata++; } printf("\n\t\taccessFlags\t\t-->\t%x",dexClassDef->accessFlags); //通過類型去尋找 const u1* superclassIdx_stringdata = (u1*)fp+stringIdsOff[(*(typeIdsOff+dexClassDef->superclassIdx))]; //解碼 readUnsignedLeb128(&superclassIdx_stringdata); printf("\n\t\tsuperclassIdx\t--> "); while(*superclassIdx_stringdata != '\0') { printf("%c",(*superclassIdx_stringdata)); superclassIdx_stringdata++; } printf("\n\t\tinterfacesOff\t-->\t%d",dexClassDef->interfacesOff); if (dexClassDef->sourceFileIdx == -1) { printf("\n\t\tsourceFileIdx\t-->\tNO_INDEX"); } printf("\n\t\tannotationsOff\t-->\t%d",dexClassDef->annotationsOff); printf("\n\t\tclassDataOff\t-->\t%d",dexClassDef->classDataOff); printf("\n\t\tstaticValuesOff\t-->\t%d",dexClassDef->staticValuesOff); dexClassDef++; }}輸出:010:代碼寫的比較亂,在這次學(xué)習(xí)中收獲挺多的..各位大神看完了有什么錯的那啥,輕點。- End -看雪ID:iio
https://bbs.pediy.com/user-816237.htm?
*本文由看雪論壇?iio?原創(chuàng),轉(zhuǎn)載請注明來自看雪社區(qū)。推薦文章++++
*?CVE-2017-11882理論以及實戰(zhàn)樣本分析
*?惡意代碼分析之 RC4 算法學(xué)習(xí)
*?CVE-2017-0101-Win32k提權(quán)分析筆記
*?ROPEmporium全解
*?實戰(zhàn)棧溢出漏洞
好書推薦﹀﹀﹀公眾號ID:ikanxue官方微博:看雪安全商務(wù)合作:wsc@kanxue.com戳 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的wav文件头损坏_Dex文件结构学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python自动爬取更新电影网站_pyt
- 下一篇: java gui 线程_如何在java中