Dex文件介绍
Dex文件是Dalvik的可执行文件,Dalvik是针对嵌入式设备设计的java虚拟机,所以Dex文件和Class文件的结构上有很大区别。为了更好的利用嵌入式你设备的资源,Dalvik在java程序编译后,还需要用dx工具将编译产生的数个Class文件整合成一个Dex文件。这样其中的各个类就可以共享数据,减少冗余,使文件结构更加紧凑。
一个设备在执行Dex文件之前,需要优化该Dex文件并生成对应的Odex文件,然后该Odex文件被Dalvik执行。Odex文件本质是个Dex文件,只是针对目标平台做了相关优化,包括对内部字节码进行一系列处理,主要为字节码验证,替换优化及空方法消除。
Dex文件结构解析
名称 | 含义 |
header | Dex文件头部,记录Dex文件的相关属性 |
string_ids | 字符串数据索引,记录了各个字符处在数据区的地址偏移量 |
type_ids | 类型数据索引,记录了各个类型的字符串索引 |
proto_ids | 原型数据索引,记录了方法声明的字符串、返回类型字符串、参数列表 |
field_ids | 字段数据索引,记录所属类、声明类型及方法名等信息 |
method_ids | 类方法索引,记录方法所属类名、方法声明及该方法名等信息 |
class_ids | 类定义数据,记录了指定类各类信息,包括接口、超类、类数据偏移量等 |
data | 数据区,保存着各个类的真实数据 |
link_data | 连接数据区 |
字节码各部分数据详解
- header
header是Dex文件的文件头,简单的记录了Dex文件的一些基本信息,及大致数据分布。header的总长度是固定的0x70,其中每一信息项所占的内存空间也是相对固定的,这样做的好处,虚拟机在处理目标Dex文件初期,可以不考虑Dex文件的多样性,根据规定读取文件头,就可以获取Dex文件的大致信息。
Dex文件头部信息:
字段名 | 偏移量 | 长度 | 描述 |
magic | 0x0 | 8 | “魔数”,格式如”/dex/n035/0” |
Cheaksum | 0x8 | 4 | 校验码 |
signature | 0xC | 20 | SHA-1签名 |
File_size | 0x20 | 4 | Dex文件的长度 |
Header_size | 0x24 | 4 | 文件头长度,009版本=0x5C,035版本=0x70 |
Endian_tag | 0x28 | 4 | 标示字节顺序的常量 |
Link_size | 0x2C | 4 | 链接桥的大小,若0则为静态链接 |
Link_off | 0x30 | 4 | 链接段的开始位置 |
Map_off | 0x34 | 4 | Map数据基址 |
String_ids_size | 0x38 | 4 | 字符串列表中的字符串个数 |
String_ids_off | 0x3C | 4 | 字符串列表基址 |
Type_ids_size | 0x40 | 4 | 类列表里的类型个数 |
Type_ids_off | 0x44 | 4 | 类列表基址 |
Proto_ids_size | 0x48 | 4 | 原型列表里的原型个数 |
Proto_ids_off | 0x4C | 4 | 原型列表里的字段个数 |
Field_ids_size | 0x50 | 4 | 字段列表里的字段个数 |
Field_ids_off | 0x54 | 4 | 字段列表的基址 |
Method_ids_size | 0x58 | 4 | 方法列表里的方法个数 |
Method_ids_off | 0x5C | 4 | 方法列表基址 |
Class_ids_size | 0x60 | 4 | 类定义表中的类的个数 |
Class_ids_off | 0x64 | 4 | 类定义表基址 |
Data_ids_size | 0x68 | 4 | 数据段大小,必须以4字节对其 |
Data_ids_off | 0x6C | 4 | 数据段基址 |
源码位于 /dalvik/libdex/DexFile.h:DexHeader
- string_ids
这一区域存储的是Dex文件字符串资源的索引信息,该索引信息是目标字符串在Dex文件数据区所在的真实物理偏移量。
源码位于/dalvik/libdex/DexFile.h:DexStringId
stringDataOff
记录了目标字符串在Dex文件中的实际偏移量,虚拟机想读取该字符串时,只需将Dex文件在内存中的起始地址加上stringDataOff
所指的偏移量,就是该字符串在内存中的实际物理地址。
在Dex文件中,每个每个字符串对应一个DexStringId
,大小4B。另外虚拟机通过DexHeader中的String_ids_size
获得当前Dex文件中的字符串的总数,通过乘法就可对该索引资源进行访问。
未完待续