android6.0 dex文件,[原创]Dex文件结构学习,顺便还写了一个解析Dex文件的小程序.

本文详细介绍了 Android .dex 文件中的 LEB128 编码方式,它是用于表示变长整型数据的格式。接着,解释了如何从 Dex 文件中解析 TypeId、FieldId 和 MethodId,涉及类型描述符、字段名和方法信息的提取。通过示例代码展示了如何从 DexHeader 中获取相关偏移和大小信息,并解码字符串以获取实际的类型、字段和方法信息。
摘要由CSDN通过智能技术生成

LEB128即"Little-Endian Base 128",基于128的小印第安序编码格式,是对任意有符号或者无符号整型数的可变长度的编码。

也即,用LEB128编码的正数,会根据数字的大小改变所占字节数。在android的.dex文件中,他只用来编码32bits的整型数。

格式:

f94cb34bfdb460fcab2bdecf5e3fc01b.png

图只是指示性的用两个字节表示。编码的每个字节有效部分只有低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:

50cc7b2e54357990eadb29e86822ec5e.png

得知第一个type所在位置是 00 00 38 FC

010

8b80d0960684e7af5722413e8b551051.png

得到的值是 0x19F

根据描述   /* 指向string_ids的索引 */   知道这个值是字符串偏移的索引

0x19F = 415

dcf7e13e5e036b8ed684f587971b02c2.png

恰好是第一个类型的值 : 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++;

}

}

输出:

d3f42c96ef9d50c768a3905c48403aef.png

010:

cf61e3028a182af1a3404a93a15df4c5.png

总结: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中尝试分析:

86fc1f6026d1ffb93d6c530453092329.png

那么来到 824C

0ded618c020fcfd94388624b37b086c0.png

之前分析过type 这次 分析结构中的 type_idx

上图可见 type_idx的地址的值内容为 0x1D 也就是 29

可以看到 他们的值是一致的!

另外2个原理一直,可以自行分析

aa973011e27897355921ded002c237a4.png

截图截多了!不好意思!

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++;

}

}

输出

90bfa545c8d73230340fde4d651ebe8c.png

010

af84bb45746e41eb05fe411f7b727a48.png

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 */

};

《APK+Dex文件反编译及回编译工具》 简称:APKDB 是一款,针对Android OS系统的APK程序,直接反编译修改的工具。 APKDB集合了当今最强悍,最犀利的APK及Dex文件编译工具; 正常安装后,它直接在【鼠标右键】创建快捷菜单; 非常方便汉化工作者,对APK或Dex文件进行简易的反编译回编译操作 1.本工具必须先安装JAVA7; 2.如需显示APK自身图标必须先安装.NET Framework4 · 对*.Apk 文件 反编译 及 回编译 用于汉化修改 · 对*.Dex 文件 反编译 及 回编译 或查看详细源代码 · 对*.Apk 文件 批量反编译 及 回编译 · 对*.Apk、*.Zip 文件执行签名 · Windows下直示Apk件自身图标 v2.0.2 正式版 2016.06.05 *.更新,ShakaApktool v2.0.0(2016.06.01) *.更新,Apktool v2.1.1正式版(2016.05.07) *.更新,7-zip压缩工具版本到16.02 *.更新,smali、baksmali v2.1.2(2016.03.28) *.更新,ADB工具 (25.1 rc1版) *.更新,Zipalign优化工具 (23.0.3版) *.更新,合并Odex文件 *.更新,XML编辑器(提升速度,修复bug) *.更新,显示APK自身图标(Apkshellext v2.0.1.5780.2290) *.更新,刷机精灵APK安装器 *.新增,自定义默认签名,可用自己制作的签名包签名 *.新增,Keytool签名包制作工具,推荐使用JAVA8 *.新增,极限压缩优化APK内图片功能 *.新增,PNG图片优化工具OptiPNG v0.7.6 *.新增,设定默认Apktool版本(回车键直接执行) *.新增,ShakaApktool自定义操作 *.新增,选项,不反编译Resources、Classes文件 选择后(可同时使用),再选择使用Apktool工具。 *.新增,反编译jar文件时,自动识别是否含多个dex文件,并使用ShakaApktool反编译 *.新增,反编译JAR文件后,回编译时自动合并并转移到反编译目录内 右键[APK文件]、[RSA文件]、[original]目录、[META-INF]目录 可直接查看签名信息。 *.新增,创建[开始菜单-所有程序-APKDB]目录 *.新增,精简APK语言包功能(仅保留英文、简体中文、繁体中文) *.增强,对繁体系统的兼容 *.增强,右键菜单判别准确率 *.增强,重新调整右键菜单,强制关联所有文件 *.增強,针对不同系統的兼容性 *.修复,XP签名优化出错问题 *.修复,选项按键滞留问题 *.修复,文件名含空格优化失败问题 *.修复,签名遗留旧文件,删除框架文件… *.修复,卸载出错问题 *.修复,APK安装器不关联问题 *.修复,个别APK文件反编译时停顿问题 *.修复,修改AndroidManifest.xml回编译没变化问题 *.修复,各种小问题 *.优化,整体兼容性,增加选项状态提示 *.优化,界面调整 *.优化,安装过程 *.优化,对JAVA路径的判别 *.优化,对64位系统的支持 *.优化,执行脚本 *.优化,编译过程 *.优化,DEX文件夹的的判别 *.删减,旧版APKTOOL(2.0.0以下版本) *.其他,一些微调整
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值