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
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 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 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; //数组,存储成员函数信息包括函数名 参数和返回值类型
查看具体结构
描述的比较清晰
struct DexMethodId {
u2 classIdx; /* method所属的class类型,class_idx的值是type_ids的一个index,必须指向一个class类型 */
u2 protoIdx; /* method的原型,指向proto_ids的一个index */
u4 nameIdx; /* method的名称,值为string_ids的一个index */
};