最近在学习dex文件,把学习的过程记录一下!有什么不对的地方还各位多多指点,感激不尽!
目录:
1、DexHeader
1.0、理解DexHeader
1.1、解析DexHeader
2、 DexStringId
2.0、理解DexStringId
2.0、解析DexStringId
3、DexTypeId
3.0、理解DexTypeId
3.0、解析DexTypeId
4、DexFieldId
4.0、理解DexFieldId
4.0、解析DexFieldId
5、DexMethodId
5.0、理解DexMethodId
5.0、解析DexMethodId
6、DexProtoId
6.0、理解DexProtoId
6.0、解析DexProtoId
7、DexClassDef
7.0、理解DexClassDef
7.0、理解DexClassDef
8、DexLink
8.待续....狗命要紧
随便拖入一个Dex文件到010,运行DEXTemplate.bt,就能看到下图中的Dex的结果
接下开始逐个分析Dex文件结构
我用是的android-6.0.0_r1的源码中DexFile.h
/* * Structure representing a DEX file. * * Code should regard DexFile as opaque, using the API calls provided here * to access specific structures. */ struct DexFile { directly-mapped "opt" header */ //const DexOptHeader* pOptHeader; /* 对应关系如下 DexHeader* pHeader ---->struct header_item dex_header DexStringId* pStringIds---->struct string_id_list dex_string_ids DexTypeId* pTypeIds ---->struct type_id_list dex_type_ids DexFieldId* pFieldIds ---->struct field_id_list dex_field_ids DexMethodId* pMethodIds---->struct method_id_list dex_method_ids DexProtoId* pProtoIds ---->struct proto_id_list dex_proto_ids DexClassDef* pClassDefs---->struct class_def_item_list dex_class_defs DexLink* pLinkData ---->struct map_list_type dex_map_list */ /* pointers to directly-mapped structs and arrays in base DEX */ DexHeader* pHeader; //DEX 文件头,记录了一些当前文件的信息以及其他数据结构在文件中的偏移量 DexStringId* pStringIds; //数组,元素类型为string_id_item,存储字符串相关的信息 DexTypeId* pTypeIds; //数组,存储类型相关的信息 DexFieldId* pFieldIds; //数组,存储成员变量信息,包括变量名和类型等 DexMethodId* pMethodIds; //数组,存储成员函数信息包括函数名 参数和返回值类型 DexProtoId* pProtoIds; //数组,函数原型数据索引,记录了方法声明的字符串,返回类型和参数列表 DexClassDef* pClassDefs; //数组,存储类的信息 DexLink* pLinkData; //Dex文件重要的数据内容都存在data区域内,一些数据结构会通过如 xx_off这样的成员变量只想文件的某个位置,从该位置开始,存储了对应的数据结构的内容,而xx_off的位置一般落在data区域内 /* * These are mapped out of the "auxillary" section, and may not be * included in the file. */ const DexClassLookup* pClassLookup; const void* pRegisterMapPool; // RegisterMapClassPool /* points to start of DEX file data */ const u1* baseAddr; /* track memory overhead for auxillary structures */ int overhead; /* additional app-specific data structures associated with the DEX */ //void* auxData; };
通过上面的源码的注释知道了各个结构的大意与010的对应的关系,但是还不清楚这些结构的内部是什么样子的!
那么开始解析第一个结构 DexHeader:
/* * Direct-mapped "header_item" struct. */ struct DexHeader { u1 magic[8]; //取值必须是字符串 "dex\n035\0" 或者字节byte数组 {0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00} u4 checksum; //文件内容的校验和,不包括magic和自己,主要用于检查文件是否损坏 u1 signature[kSHA1DigestLen]; //签名信息,不包括 magic\checksum和自己 u4 fileSize; //整个文件的长度,单位为字节,包括所有的内容 u4 headerSize; //默认是0x70个字节 u4 endianTag; //大小端标签,标准.dex文件为小端,此项一般固定为0x12345678常量 u4 linkSize; //链接数据的大小 u4 linkOff; //链接数据的偏移值 u4 mapOff; //map item的偏移地址,该item属于data区里的内容,值要大于等于dataOff的大小 u4 stringIdsSize; //DEX中用到的所有字符串内容的大小* u4 stringIdsOff; //DEX中用到的所有字符串内容的偏移量 u4 typeIdsSize; //DEX中类型数据结构的大小 u4 typeIdsOff; //DEX中类型数据结构的偏移值 u4 protoIdsSize; //DEX中的元数据信息数据结构的大小 u4 protoIdsOff; //DEX中的元数据信息数据结构的偏移值 u4 fieldIdsSize; //DEX中字段信息数据结构的大小 u4 fieldIdsOff; //DEX中字段信息数据结构的偏移值 u4 methodIdsSize; //DEX中方法信息数据结构的大小 u4 methodIdsOff; //DEX中方法信息数据结构的偏移值 u4 classDefsSize; //DEX中的类信息数据结构的大小 u4 classDefsOff; //DEX中的类信息数据结构的偏移值 u4 dataSize; //DEX中数据区域的结构信息的大小 u4 dataOff; //DEX中数据区域的结构信息的偏移值 };
看010中对应的位置
u1 magic[8]; //取值必须是字符串 "dex\n035\0" 或者字节byte数组 {0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00}
下图选中magic时 会选中前八个字节magic[8] u1代表字节 [8] 则是8个字节
可以把magic看做dex文件的标识{0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00}
通过这个字段知道是该文件dex文件
它是一个u4 代表4个字节的内容,
u4 checksum; //文件内容的校验和,不包括magic和自己,主要用于检查文件是否损坏
signature[kSHA1DigestLen]了,signature字段用于检验dex文件,其实就是把整个dex文件用SHA-1签名得到的一个值。这里占用20个字节
u1 signature[kSHA1DigestLen]; //签名信息,不包括 magic\checksum和自己
kSHA1DigestLen:
/* * 160-bit SHA-1 digest. */ enum { kSHA1DigestLen = 20, kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };
fileSize:文件长度
u4 fileSize; //整个文件的长度,单位为字节,包括所有的内容
553820个字节大小
表示 DexHeader 头结构的大小,占用4个字节。这里可以看到它一共占用了112个字节,112对应的16进制数为70h
u4 headerSize; //默认是0x70个字节
u4 endianTag; //大小端标签,标准.dex文件为小端,此项一般固定为0x12345678常量
0
当多个class文件被编译到一个dex文件是,他们会用到link_size和link_off,通常为0
u4 linkSize; //链接数据的大小 u4 linkOff; //链接数据的偏移值
mapOff字段了,它指定了 DexMapList 的文件偏移
u4 mapOff; //map item的偏移地址,该item属于data区里的内容,值要大于等于dataOff的大小
stringIdsSize代表全dex文件的字符串的个数
stringIdsOff 代表全dex文件的字符串的偏移
u4 stringIdsSize; //DEX中用到的所有字符串内容的大小* u4 stringIdsOff; //DEX中用到的所有字符串内容的偏移量
有了这个知识 可以尝试分析第一个字符串
已经找到第一个字符串的偏移是6e72c
那么也就找到了 第一个字符串的值 虽然看不明显但确实如此
以上的2个问题会在解析中给出答案!
这指出了type类型的偏移和type的个数
u4 typeIdsSize; //DEX中类型数据结构的大小 u4 typeIdsOff; //DEX中类型数据结构的偏移值
略...
u4 protoIdsSize; //DEX中的元数据信息数据结构的大小 u4 protoIdsOff; //DEX中的元数据信息数据结构的偏移值 u4 fieldIdsSize; //DEX中字段信息数据结构的大小 u4 fieldIdsOff; //DEX中字段信息数据结构的偏移值 u4 methodIdsSize; //DEX中方法信息数据结构的大小 u4 methodIdsOff; //DEX中方法信息数据结构的偏移值 u4 classDefsSize; //DEX中的类信息数据结构的大小 u4 classDefsOff; //DEX中的类信息数据结构的偏移值 u4 dataSize; //DEX中数据区域的结构信息的大小 u4 dataOff; //DEX中数据区域的结构信息的偏移值
那么就开始动手写的代码来解析吧~~
用的Clion编译器
1.
首先 先写个一个读取文件的方法 char* Read_File(string file_Path) { filebuf *pbuf; ifstream filestr; long size; char *buffer; // 要读入整个文件,必须采用二进制打开 filestr.open(file_Path, ios::binary); // 获取filestr对应buffer对象的指针 pbuf = filestr.rdbuf(); // 调用buffer对象方法获取文件大小 size = pbuf->pubseekoff(0, ios::end, ios::in); pbuf->pubseekpos(0, ios::in); // 分配内存空间 buffer = new char[size]; // 获取文件内容 pbuf->sgetn(buffer, size); filestr.close(); // 输出到标准输出 //cout.write (buffer,size); // delete []buffer; return buffer; }
2.
main: //得到文件内存地址指针 char* fp = Read_File("/home/zlq/baidunetdiskdownload/android/classes.dex"); //强转为DexFile指针 DexFile *dex = (DexFile*)&fp; //解析struct header_item dex_header Read_DexHeader(dex->pHeader);
3.
写的比较拙劣,,,,
/** * 实现方法 * @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 文件头,记录了一些当前文件的信息以及其他数据结构在文件中的偏移量"); 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\" 或者字节byte数组 {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文件内容的校验和,不包括magic和自己,主要用于检查文件是否损坏" ,dexHeader->checksum ,(unsigned int)sizeof(dexHeader->magic) ,(unsigned int)sizeof(dexHeader->checksum)); .... 略
输出
通过对比分析是一样的
这个比较简单,用结构指针接受一下就行了 只是输出有点麻烦
DEX中所有的字符串存储在这里
DexStringId* pStringIds; //数组,元素类型为string_id_item,存储字符串相关的信息
进去看看此结构!
它只有一个字段,那么它是如何解析dex字符串呢?
/* * Direct-mapped "string_id_item". */ struct DexStringId { //用于指明 string_data_item 位置文件的位置 u4 stringDataOff; /* file offset to string_data_item */ };
首先要知道的是它是一个数组类型,数组的大小取决于
DexHeader->stringIdsSize
那么就很好理解了,上面提示 一共 有3619个 字符串
又开始写代码了
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数组,元素类型为string_id_item,存储字符串相关的信息"); //拿到字符串的偏移 int *p2 = (int*)(fp + dex->pHeader->stringIdsOff); ////stringIdsSize --> DEX中用到的所有字符串内容的大小 for (int i = 0; i < dex->pHeader->stringIdsSize; ++i) { printf("\n\tstruct string_id_item string_id[%d]:",i); // 文件首地址+字符串偏移就是字符串存放的位置的第一个数组 const u1* stringdata = (u1*)fp+*p2; //解码 /* * dex文件里采用了变长方式表示字符串长度。一个字符串的长度可能是一个字节(小于256)或者4个字节(1G大小以上)。字符串的长度大多数都是小于 256个字节,因此需要使用一种编码,既可以表示一个字节的长度,也可以表示4个字节的长度,并且1个字节的长度占绝大多数。能满足这种表示的编码方式有很多,但dex文件里采用的是uleb128方式。leb128编码是一种变长编码,每个字节采用7位来表达原来的数据,最高位用来表示是否有后继字节。若第一个 Byte 的最高位为 1 ,则表示还需要下一个 Byte 来描述 ,直至最后一个 Byte 的最高位为 0 。每个 Byte 的其余 Bit 用来表示数据 */ readUnsignedLeb128(&stringdata); //转码后该字符串为 内存数据为 \0 时 则结束 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:
总结:
* dex->pHeader->stringIdsOff 存储了整个dex的字符串的偏移的首地址 是一个数组类型 * dex->pHeader->stringIdsSize 存储字符串的个数 * 字符串偏移指向的地址的内容通过 readUnsignedLeb128 解码 字符串的长度通过判断'\0' 即可
编码:
LEB128即"Little-Endian Base 128",基于128的小印第安序编码格式,是对任意有符号或者无符号整型数的可变长度的编码。
也即,用LEB128编码的正数,会根据数字的大小改变所占字节数。在android的.dex文件中,他只用来编码32bits的整型数。
格式:
图只是指示性的用两个字节表示。编码的每个字节有效部分只有低7bits,每个字节的最高bit用来指示是否是最后一个字节。
非最高字节的bit7为0
最高字节的bit7为1
将leb128编码的数字转换为可读数字的规则是:除去每个字节的bit7,将每个字节剩余的7个bits拼接在一起,即为数字。
比如:
LEB128编码的0x02b0 ---> 转换后的数字0x0130
转换过程:
0x02b0 ---> 0000 0010 1011 0000 -->去除最高位--> 000 0010 011 0000 -->按4bits重排 --> 00 0001 0011 0000 --> 0x130
引用 https://blog.csdn.net/Roland_Sun/article/details/46708061
* type_ids 区索引了 .dex 文件里的所有数据类型 ,包括 class 类型 ,数组类型(array types)和基本类型(primitive types) 。 本区域里的元素格式为type_ids_item
* type_ids_item 里面 descriptor_idx 的值的意思 ,是 string_ids 里的 index 序号 ,是用来描述此type 的字符串 。
DexTypeId* pTypeIds; //数组,存储类型相关的信息
看结构
他也是一个字段,且看如何分析它
注意是一个数组的类型
/* * Direct-mapped "type_id_item". */ struct DexTypeId { u4 descriptorIdx; /* 指向string_ids的索引 */ };
同时 还有2个很重要的字段在DexHeader中typeIdsSize和typeIdsOff 同样代表类型的偏移和大小.
先来分析第一个type:
得知第一个type所在位置是 00 00 38 FC
010
得到的值是 0x19F
根据描述 /* 指向string_ids的索引 */ 知道这个值是字符串偏移的索引
0x19F = 415
恰好是第一个类型的值 : B byte
如此就分析出第一个类型的位置和来源了
又开始写代码:
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数组,存储类型相关的信息\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); //再根据类型的偏移去寻找字符串 const u1* stringdata = (u1*)fp+stringIdsOff[(*typeIdsOff)]; //解码 readUnsignedLeb128(&stringdata); while(*stringdata != '\0') { printf("%c",(*stringdata)); stringdata++; } //自加 获取下一个指针 int型指针自加 base += 1 typeIdsOff++; } }
输出:
010:
总结:
descriptor_idx 的值的意思 ,是 string_ids 里的 index 序号 ,是用来描述此type 的字符串 字符串指针[descriptor_idx地址内的值] = descriptor_idx值
大意:
DexFieldId* pFieldIds; //数组,存储成员变量信息,包括变量名和类型等
具体结构:
struct DexFieldId { u2 classIdx; /* field所属的class类型,class_idx的值时type_ids的一个index,指向所属的类 */ u2 typeIdx; /* field的类型,值是type_ids的一个index */ u4 nameIdx; /* field的名称,它的值是string_ids的一个index */ };
仍然从header看起 重要的数据还是保存在头部
继续从010中尝试分析:
那么来到 824C
之前分析过type 这次 分析结构中的 type_idx
上图可见 type_idx的地址的值内容为 0x1D 也就是 29
可以看到 他们的值是一致的!
另外2个原理一直,可以自行分析
截图截多了!不好意思!
又开始写代码
比较麻烦的是取值的过程需要通过其他属性来取值
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数组,存储类的相关的信息"); //转为DexFieldId结构体 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对应位置的值 要先找到 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* pMethodIds; //数组,存储成员函数信息包括函数名 参数和返回值类型<br>
查看具体结构
描述的比较清晰
struct DexMethodId { u2 classIdx; /* method所属的class类型,class_idx的值是type_ids的一个index,必须指向一个class类型 */ u2 protoIdx; /* method的原型,指向proto_ids的一个index */ u4 nameIdx; /* method的名称,值为string_ids的一个index */ };
可以自己尝试手动分析了,这里就不过多的演示了..之前演示很多次了
又开始写代码了
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数组,存储成员函数信息包括函数名 参数和返回值类型"); //转为DexMethodId结构体 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* pProtoIds; //数组,函数原型数据索引,记录了方法声明的字符串,返回类型和参数列表
具体结构
struct DexProtoId { u4 shortyIdx; /* 值为一个string_ids的index号,用来说明该method原型 */ u4 returnTypeIdx; /* 值为一个type_ids的index,表示该method原型的返回值类型 */ u4 parametersOff; /* 指定method原型的参数列表type_list,若method没有参数,则值为0. 参数的格式是type_list */ };
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数组,函数原型数据索引,记录了方法声明的字符串,返回类型和参数列表"); //转为DexMethodId结构体 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* pClassDefs; //数组,存储类的信息
结构体
struct DexClassDef { u4 classIdx; /* 描述具体的class类型,值是type_ids的一个index,值必须是一个class类型,不能是数组或者基本类型 */ u4 accessFlags; /* 描述class的访问类型,如public,final,static等 */ u4 superclassIdx; /* 描述父类的类型,值必须是一个class类型,不能是数组雷兴国或者基本类型 */ u4 interfacesOff; /* 值为偏移地址,被指向的数据结构为type_list,class若没有interfaces,值为0 */ u4 sourceFileIdx; /* 表示源代码文件的信息,值为string_ids的一个index。若此项信息丢失,此项赋值为NO_INDEX=0xFFFFFFFF */ u4 annotationsOff; /* 值为偏移地址,指向的内容是该class的注解,位置在data区,格式为annotations_directory_item,若没有此项,值为0 */ u4 classDataOff; /* 值为偏移地址,指向的内容是该class的使用到的数据,位置在data区,格式为class_data_item。无偶没有此项,则值为0 */ u4 staticValuesOff; /* 值为偏移地址,指向data区里的一个列表,格式为encoded_array_item。若没有此项,值为0. */ };
解析:
void Read_DexClassDef(char* fp) { //u4 classIdx; /* 描述具体的class类型,值是type_ids的一个index,值必须是一个class类型,不能是数组或者基本类型 */ //u4 accessFlags; /* 描述class的访问类型,如public,final,static等 */ //u4 superclassIdx; /* 描述父类的类型,值必须是一个class类型,不能是数组或者基本类型 */ //u4 interfacesOff; /* 值为偏移地址,被指向的数据结构为type_list,class若没有interfaces,值为0 */ //u4 sourceFileIdx; /* 表示源代码文件的信息,值为string_ids的一个index。若此项信息丢失,此项赋值为NO_INDEX=0xFFFFFFFF */ //u4 annotationsOff; /* 值为偏移地址,指向的内容是该class的注解,位置在data区,格式为annotations_directory_item,若没有此项,值为0 */ //u4 classDataOff; /* 值为偏移地址,指向的内容是该class的使用到的数据,位置在data区,格式为class_data_item。无偶没有此项,则值为0 */ //u4 staticValuesOff; /* 值为偏移地址,指向data区里的一个列表,格式为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数组,存储类的信息"); //转为DexMethodId结构体 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:
代码写的比较乱,在这次学习中收获挺多的..
各位大神看完了有什么错的那啥,,轻点,,
[公告][征集寄语] 看雪20周年年会 | 感恩有你,一路同行
最后于 2小时前 被iio编辑 ,原因: 代码排版问题