第4章 dex文件格式 第三节
1、 环境配置
Ubuntu 15.10 系统 IP:192.168.153.130
理解dex文件整体结构
一、dex文件整体结构
1、 dex文件由7个部分组成。Dex header为dex文件头,它指定了dex文件的一些属性,并记录了其他6部分数据结构在dex文件中的物理偏移。String_ids到class_def结构可以理解为“索引结构区”,真实的数据存放在data数据区,最后link_data为静态链接数据区,对于目前生成dex文件而言,它始终为空。
Dex header |
String_ids |
Type_ids |
Proto_ids |
Field_ids |
Methon_ids |
Class_ids |
data |
Link_data |
2、 dex文件结构如下:
structDexFile {
/* directly-mapped "opt" header*/
const DexOptHeader* pOptHeader;
/* pointers to directly-mapped structs andarrays in base DEX */
const DexHeader* pHeader;
const DexStringId* pStringIds;
const DexTypeId* pTypeIds;
const DexFieldId* pFieldIds;
const DexMethodId* pMethodIds;
const DexProtoId* pProtoIds;
const DexClassDef* pClassDefs;
const DexLink* pLinkData;
3、 DexHeader结构占用0x70个字节如下:
structDexHeader {
u1 magic[8]; /* includesversion number */
u4 checksum; /* adler32checksum */
u1 signature[kSHA1DigestLen]; /* SHA-1 hash */
u4 fileSize; /* length ofentire file */
u4 headerSize; /* offset tostart of next section */
u4 endianTag;
u4 linkSize;
u4 linkOff;
u4 mapOff;
u4 stringIdsSize;
u4 stringIdsOff;
u4 typeIdsSize;
u4 typeIdsOff;
u4 protoIdsSize;
u4 protoIdsOff;
u4 fieldIdsSize;
u4 fieldIdsOff;
u4 methodIdsSize;
u4 methodIdsOff;
u4 classDefsSize;
u4 classDefsOff;
u4 dataSize;
u4 dataOff;
};
1)Magic字段标识了一个有效的dex文件,目前它的值固定为“64 65 78 0a 30 33 35 00”,转换为字符串为“dex.035”。
2)chencksum段为dex文件的校验和,通过它来判断dex文件是否被损坏或修改。
3)Signature字段用来识别最佳化之间的dex文件,checksum字段与signature字段将dexopt验证与优化。
4)FileSize字段记录了包括DexHeader在内的整个dex文件的大小。
5)HeaderSize字段记录了DexHeader结构本身占用的字节数,目前它的值为0x70。
6)endianTag字段指定了dex运行环境cpu字节序,预设值ENDIAN_CONSTANT等于0x12345678,表示默认采用Little-Endian字节序。
7)linkSize字段与stringldsOff字段指定链接段的大小与文件偏移,大多数情况下它们的值为0。
8)mapOff字段指定了DexMapList结构的文件偏移。
9)其他字段分别表示DexStringid、DexTypeid、DexProtoid、DexFieldid、DexMethonid、DexClassDef以及数据段的大小与文件偏移。
4、 DexHeader结构下面的数据为“索引结构区” 与“数据区”,“索引结构区”中各数据结构的偏移地址都是从DexHeader结构的stringIdsOff~classDefsOff字段的值指定的,它们并非真正的类数据,而是指向dex文件的data数据区的偏移或数据结构索引。(DexData字段,实际上是ubyte字节数组,包含了程序所有使用到的数据)
二、dex文件结构分析
1、 Dalvik虚拟机解析dex文件的内容,最终将其映射成DexMapList数据结构。DexHeader结构的mapOff字段指明了DexMaplist结构在dex文件中的偏移,声明如下。
Struct DexMapList{
U4 size; /*DexMapItem的个数*/
DexMapItemlist[1]; /*DexMapItem结构*/
};
2、Size 字段表示接下来有多少个DexMapItem结构,DexMapItem的结构声明如下。
Struct DexMapItem {
U2 type; /*kDexType开头的类型*/
U2 unused; /*未使用,用于字节对齐*/
U4 size; /*指定类型的个数*/
U4 offset; /*指定类型数据的文件偏移*/
};
2、 type字段为一个枚举常量,如下所示名称,通过类型很容易判断它的具体类型。
Enum{
kDexTypeHeaderItem = 0x0000,
kDexTypeStringIdItem = 0x0001,
kDexTypeTypeIdItem = 0x0002,
kDexTypeProtoIdItem = 0x0003,
kDexTypeFieldIdItem = 0x0004,
kDexTypeMethodIdItem = 0x0005,
……….
……….
kDexTypeAnnotationsDirectoryItem = 0x2006,
};
DexMapItem中的size字段指定了特定类型的个数,它们以特定的类型在dex文件中连续存放。Offset为该类型的文件起始偏移地址。以Hello.dex为例,DexHeader结构的mapOff字段为0x290,读取0x290处的一个双字值为0x0d,表明接下来会有13个DexMapItem结构。使用hexdump –C命令打开Hello.dex,如下图:
注意:通过DexMapItem定义可以发现:这个定义的像类、字符串、方法等资源和dex文件头里定义的类型有很多是一样的。其实这个map的数据,就是头里类型的重复,完全是为了检验作用而存在的。当andriod系统加载dex文件时,如果比较文件头类型个数与map里类型不一致时,就会停止使用这个dex文件。