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++;
}
}
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
3、DexTypeId
3.0、理解DexTypeId
* 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
如此就分析出第一个类型的位置和来源了
3.0、解析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数组,存储类型相关的信息\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值
4、DexFieldId
4.0、理解DexFieldId
大意:
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个原理一直,可以自行分析
截图截多了!不好意思!
4.1、解析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数组,存储类的相关的信息");
//转为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
5、DexMethodId
5.0、理解DexMethodId
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
6、DexProtoId
6.0、理解DexProtoId
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 */
};
6.0、解析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数组,函数原型数据索引,记录了方法声明的字符串,返回类型和参数列表");
//转为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:
7、DexClassDef
7.0、理解DexClassDef
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:
代码写的比较乱,在这次学习中收获挺多的..
各位大神看完了有什么错的那啥,,轻点,,