下面以Android4.4.2源码为例,来分析Dex文件的结构,这里分析的方式是将结构定义与实际的Hex字节码进行对照分析。
Dex文件结构图
1、查看/dalvik/libdex/DexFile.h,它里面包含了所有结构体定义。
2、我们将一个dex文件使用010Editor打开,并且使用Dex Template进行查看,可以看到Hex字节码和结构的对应关系
一、Dex文件整体结构
1、DexFile结构体定义
/*
* Structure representing a DEX file.
*
* Code should regard DexFile as opaque, using the API calls provided here
* to access specific structures.
*/
struct DexFile {
/* directly-mapped "opt" header */
const DexOptHeader* pOptHeader;
/* pointers to directly-mapped structs and arrays in base DEX */
// 下面就是各个结构和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; // 链接数据区
/*
* These are mapped out of the "auxillary" section, and may not be
* included in the file.
*/
const DexClassLookup* pClassLookup;
const void* pRegisterMapPool; // RegisterMapClassPool
/* points to start of DEX file data */
const u1* baseAddr;
/* track memory overhead for auxillary structures */
int overhead;
/* additional app-specific data structures associated with the DEX */
//void* auxData;
};
对应关系如下:
DexHeader* pHeader ---->struct header_item dex_header
DexStringId* pStringIds---->struct string_id_list dex_string_ids
DexTypeId* pTypeIds ---->struct type_id_list dex_type_ids
DexFieldId* pFieldIds ---->struct field_id_list dex_field_ids
DexMethodId* pMethodIds---->struct method_id_list dex_method_ids
DexProtoId* pProtoIds ---->struct proto_id_list dex_proto_ids
DexClassDef* pClassDefs---->struct class_def_item_list dex_class_defs
DexLink* pLinkData ---->struct map_list_type dex_map_list
二、DexHeader结构分析
1、DexHeader结构体定义
/*
* Direct-mapped "header_item" struct.
*/
struct DexHeader {
u1 magic[8]; // dex版本标志
u4 checksum; // alder32校验
u1 signature[kSHA1DigestLen]; // SHA-1哈希值
u4 fileSize; // 整个文件大小
u4 headerSize; // DexHeader结构大小
u4 endianTag; // 字符序标记
u4 linkSize; // 链接段大小
u4 linkOff; // 链接段偏移
u4 mapOff; // DexMapList的文件偏移
u4 stringIdsSize; // DexStringid的个数
u4 stringIdsOff; // DexString的文件偏移
u4 typeIdsSize; // DexTypeid的个数
u4 typeIdsOff; // DexTypeid的文件偏移
u4 protoIdsSize; // DexProtoid的个数
u4 protoIdsOff; // DexProtoid的文件偏移
u4 fieldIdsSize; // DexFieldid的个数
u4 fieldIdsOff; // DexFieldid的文件偏移
u4 methodIdsSize; // DexMethodid的个数
u4 methodIdsOff; // DexMethodid的文件偏移
u4 classDefsSize; // DexClassDef的个数
u4 classDefsOff; // DexClassDef的文件偏移
u4 dataSize; // 数据段的大小
u4 dataOff; // 数据段的文件偏移
};
2、DexHeader Hex字节码
三、DexStringId结构分析
1、DexStringId结构体定义
/*
* Direct-mapped "string_id_item".
*/
struct DexStringId {
u4 stringDataOff; // string_data_item的偏移地址
};
struct string_data_item {
uleb128 utf16_size; // 字符串大小
ubyte data; // 字符串的值
}
2、DexStringId Hex字节码
四、DexTypeId结构分析
1、DexTypeId结构体定义
/*
* Direct-mapped "type_id_item".
*/
struct DexTypeId {
u4 descriptorIdx; // 表示这个类型描述符在string_ids中的索引值
};
五、DexFieldId结构分析
1、DexFieldId结构体定义
/*
* Direct-mapped "field_id_item".
*/
struct DexFieldId {
u2 classIdx; // 字段所属所属的 class 类型在type_ids中的索引
u2 typeIdx; // 字段本身类型在type_ids中的索引
u4 nameIdx; // 字段名称在stringIds中的索引
};
六、DexMethodId结构分析
1、DexMethodId结构体定义
/*
* Direct-mapped "method_id_item".
*/
struct DexMethodId {
u2 classIdx; // 方法所属所属的 class 类型在type_ids中的索引
u2 protoIdx; // 方法prototype在protoIds中的索引
u4 nameIdx; // 方法名称在stringIds中的索引
};
2、DexMethodId Hex字节码
七、DexProtoId结构分析
1、DexProtoId结构体定义
/*
* Direct-mapped "proto_id_item".
*/
struct DexProtoId {
u4 shortyIdx; // 表示这个短描述符在string_ids中的索引值
u4 returnTypeIdx; // 返回类型在type_ids中的索引
u4 parametersOff; // 参数类型列表在文件中的偏移,参数列表结构为DexTypeList
};
/*
* Direct-mapped "type_list".
*/
struct DexTypeList {
u4 size; // DexTypeItem的个数
DexTypeItem list[1]; // DexTypeItem结构
};
/*
* Direct-mapped "type_item".
*/
struct DexTypeItem {
u2 typeIdx; // 类型在type_ids中的索引
};
八、DexClassDef结构分析
1、DexClassDef结构体定义
/*
* Direct-mapped "class_def_item".
*/
struct DexClassDef {
u4 classIdx; // class 类型在type_ids中的索引
u4 accessFlags; // class 的访问类型 ,诸如 public , final , static 等
u4 superclassIdx; // class父类类型在type_ids中的索引
u4 interfacesOff; // class的interfaces在文件中的偏移,interfaces的数据结构为DexTypeList
u4 sourceFileIdx; // 源文件名称在stringIds中的索引
u4 annotationsOff; // class注释的偏移地址,注释数据结构为DexAnnotationsDirectoryItem
u4 classDataOff; // class类信息的偏移地址,数据结构DexClassData
u4 staticValuesOff; // class静态数据的偏移地址,数据结构DexEncodedArray
};
struct DexClassData {
DexClassDataHeader header; // 指定字段与方法的个数
DexField* staticFields; // 静态字段,DexField结构
DexField* instanceFields; // 实例字段,DexField结构
DexMethod* directMethods; // 直接方法,DexMethod结构
DexMethod* virtualMethods; // 虚方法,DexMethod结构
}
struct DexClassDataHeader {
u4 staticFieldsSize; // 静态字段个数
u4 instanceFieldsSize; // 实例字段个数
u4 directMethodsSize; // 直接方法个数
u4 virtualMethodsSize; // 虚方法个数
}
struct DexField {
u4 fieldIdx; // 指向DexFieldId的索引
u4 accessFlags; // 访问标志
}
struct DexMethod {
u4 methodIdx; // 指向DexMethodId的索引
u4 accessFlags; // 访问标志
u4 codeOff; //指向DexCode结构的偏移
}
struct DexCode {
u2 registersSize; //使用寄存器个数
u2 insSize; //参数个数
u2 outsSize; //调用其他方法时使用的寄存器个数
u2 triesSize; //try/catch个数
u4 debugInfoOff; //指向调试信息的偏移
u4 insnsSize; //指令集个数,以2字节为单位
u2 insns[1]; //指令集
/* followed by optional u2 padding */
/* followed by try_item[triesSize] */
/* followed by uleb handlersSize */
/* followed by catch_handler_item[handlersSize] */
};
/*
* Direct-mapped "encoded_array".
*
* NOTE: this structure is byte-aligned.
*/
struct DexEncodedArray {
u1 array[1]; /* data in encoded_array format */
};
九、DexLink结构分析
1、DexLink结构体定义
/*
* Link table. Currently undefined.
*/
struct DexLink {
u1 bleargh;
};
2、DexLink Hex字节码
整体对照图如下:
参考文章:
分析一个简单的 .dex 文件 —— Hello.dex
dex文件格式分析