您的位置:首页 > 其它

.dex文件结构学习笔记(1)

2013-05-13 11:02 316 查看
最近在搞ANDROID平台下的研究,ANDROID平台下最主要的文件格式就是DEX文件格式,这个格式相对于PE文件格式来说还是简单的多。一个DEX文件整体格式如下标所示。此表摘自dalvik虚拟机源代码目录的doc文档翻译而来。我翻译东西一直不怎么样。并且头一次研究Android上面的东西,加上我又不懂JAVA。难免有不正确的地方,本文只是我要学习Android开发的一些笔记,如果不小心有人看到此文的翻译,千万别喷。
以下这张表也是整个DEX文件的格式。首先是一个文件头,在文件头后随后是数据目录。有这样几项数据目录,字符串索引目录,类型索引目录,函数原型索引目录,区域索引目录,函数索引目录,类定义列表,数据段还有静态链接数据段。
名称
格式描述
headerheader_item文件头
string_idsstring_id_item[]字符串标识符列表。这里标志了当前DEX文件所有字符串使用的标志,也有一些内部名称(例如.,类型描述)或者代码段引用的一些常量对象。
这个表按照字符串常量进行排序,字符串使用UTF-16进行编码(不在本地敏感方式),并且这个表不包含任何复制项。
type_idstype_id_item[]类型标识项。这里是此文件中所有类型的标识(类,队列,或者主类型),无论在文件中是否定义。这个表按照字符串标识索引进行排序,它不包含任何复制项。
proto_idsproto_id_item[]函数原型标识表。这里定义了此文件中所用引用的原型标识。这个表按照类型标识索引进行排序,并且参数也是通过类型标识索引进行排序。
此表不包含复制项。
field_idsfield_id_item[]区域标识符列表。这里定义了在此文件中的所有区域定义,此表按照类型标识索引进行主排序,并且按照区域名称作为中排序,按照类型作为子排序。并不包含复制项。
method_idsmethod_id_item[]函数标识表。定义了此文件引用的方法标识。按照类型标识索引作为主排序,按照方法名作为辅排序,按照方法原型作为子排序。不包含复制项。
class_defsclass_def_item[]类标识表。引用这些类的父类以及接口前必须要经过排序。并且此列表中不能出现重复的类名。
dataubyte[]以上表列出的数据,在此进行保存。
link_dataubyte[]静态链接数据段。如果此节为空则没有静态链接文件。
以下是来自DexFile.h中的结构定义

/*
* Direct-mapped "header_item" struct.
* DEX文件头结构
*/
struct DexHeader {
u1  magic[8];           /* includes version number */
u4  checksum;           /* adler32 checksum */
u1  signature[kSHA1DigestLen]; /* SHA-1 hash */
u4  fileSize;           /* length of entire file */
u4  headerSize;         /* offset to start 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;
};
/*
* Direct-mapped "string_id_item".
* string identifiers list. These are identifiers for all the strings used by this file,
* either for internal naming (e.g., type descriptors) or as constant objects referred to by code.
* This list must be sorted by string contents, using UTF-16 code point values (not in a locale-sensitive manner),
* and it must not contain any duplicate entries.
*
* 字符串标识符列表。这里标志了当前DEX文件所有字符串使用的标志,也有一些内部名称(例如.,类型描述)或者代码段引用的一些常量对象。
* 这个表按照字符串常量进行排序,字符串使用UTF-16进行编码(不在本地敏感方式),并且这个表不包含任何复制项。
*/
struct DexStringId {
/* 字符串数据的的文件偏移 */
u4 stringDataOff;      /* file offset to string_data_item */
};
/*
* Direct-mapped "type_id_item".
* type identifiers list. These are identifiers for all types (classes, arrays, or primitive types) referred to by this file,
* whether defined in the file or not. This list must be sorted * by string_id index, and it must not contain any duplicate entries.
*
* 类型标识项。这里是此文件中所有类型的标识(类,队列,或者主类型),无论在文件中是否定义。这个表按照字符串标识索引进行排序,它不包含任何复制项。
*/
struct DexTypeId {
/* 在字符串列表的类型描述的索引 */
u4  descriptorIdx;      /* index into stringIds list for type descriptor */
};
/*
* Direct-mapped "field_id_item".
* field identifiers list. These are identifiers for all fields referred to by this file, whether defined in the file or not.
* This list must be sorted, where the defining type (by type_id index) is the major order, field name (by string_id index) is the intermediate order,
* and type (by type_id index) is the minor order. The list must not contain any duplicate entries.
*
* 区域标识符列表。这里定义了在此文件中的所有区域定义,此表按照类型标识索引进行主排序,并且按照区域名称作为中排序,按照类型作为子排序。并不包含复制项。
*/
struct DexFieldId {
/* 类定义在类型标识表的索引 */
u2  classIdx;           /* index into typeIds list for defining class */
/* 区域类型在类型标识表的索引 */
u2  typeIdx;            /* index into typeIds for field type */
/* 区域名称在字符串标识表的索引 */
u4  nameIdx;            /* index into stringIds for field name */
};
/*
* Direct-mapped "method_id_item".
* method identifiers list. These are identifiers for all methods referred to by this file, whether defined in the file or not.
* This list must be sorted, where the defining type (by type_id index) is the major order, method name (by string_id index) is the intermediate order,
* and method prototype (by proto_id index) is the minor order. The list must not contain any duplicate entries.
*
* 函数标识表。定义了此文件引用的方法标识。按照类型标识索引作为主排序,按照方法名作为辅排序,按照方法原型作为子排序。不包含复制项。
*/
struct DexMethodId {
u2  classIdx;           /* index into typeIds list for defining class */
u2  protoIdx;           /* index into protoIds for method prototype */
u4  nameIdx;            /* index into stringIds for method name */
};
/*
* Direct-mapped "proto_id_item".
* method prototype identifiers list. These are identifiers for all prototypes referred to by this file.
* This list must be sorted in return-type (by type_id index) major order, and * then by arguments (also by type_id index).
* The list must not contain any duplicate entries.
*
* 函数原型标识表。这里定义了此文件中所用引用的原型标识。
* 这个表按照类型标识索引进行排序,并且参数也是通过类型标识索引进行排序。
* 此表不包含复制项。
*
*/
struct DexProtoId {
/* 在字符串表的描述索引项 */
u4  shortyIdx;          /* index into stringIds for shorty descriptor */
/* 返回值的类型在类型表中的索引 */
u4  returnTypeIdx;      /* index into typeIds list for return type */
/* 参数在类型表中的文件偏移 */
u4  parametersOff;      /* file offset to type_list for parameter types */
};
/*
* Direct-mapped "class_def_item".
* class definitions list. The classes must be ordered such that a given class's superclass and implemented interfaces appear in the list earlier than the referring class.
* Furthermore, it is invalid for a definition for the same-named class to appear more than once in the list.
*
* 类标识表。引用这些类的父类以及接口前必须要经过排序。并且此列表中不能出现重复的类名。
*/
struct DexClassDef {
u4  classIdx;           /* index into typeIds for this class */
u4  accessFlags;
u4  superclassIdx;      /* index into typeIds for superclass */
u4  interfacesOff;      /* file offset to DexTypeList */
u4  sourceFileIdx;      /* index into stringIds for source file name */
u4  annotationsOff;     /* file offset to annotations_directory_item */
u4  classDataOff;       /* file offset to class_data_item */
u4  staticValuesOff;    /* file offset to DexEncodedArray */
};A

在DexFile.h中还有一个"映射目录项"结构,这个结构如果不出我意料的话,是dalvik将以上数据目录加载到内存时所用到的保存结构,现在只是分析文件信息而已,没必要去理会它。到后面分析DEX文件加载时在看它。
在android SDK中提供了一个名为dexdump的工具。可以打印DEX文件的信息。它的源代码在dalvik目录中。这里先熟悉一下它的使用。直接在命令行中输入它的名称会出现使用帮助
-c: 验证DEX文件的校验和
-d : 反汇编代码段
-f : 显示文件头摘要
-h : 显示文件头详细信息
-i : 忽略文件校验
-l : 输出格式,可以是'plain'或者'xml'格式
-m : 打印出寄存器图。(暂时还不知道这个什么玩意,等分析完源代码就清楚了)
-t : 临时文件名称。
随便新建一个android程序。其中工程目录中bin目录下的class.dex就是主dex文件了。
首先使用-c 参数 dexdump -c class.dex,屏幕显示如下:
Processing '/home/devilogic/workspace/tryme/bin/classes.dex'...
Checksum verified
这表示校验和验证通过。

使用 dexdump -d class.dex,这里输出一堆暂时我还看不懂的东西,如果没错的话就是传说中的smali代码。屏幕现实的太多。这里只截取了一部分
Class #0 -
Class descriptor : 'Landroid/support/v4/accessibilityservice/AccessibilitySer
viceInfoCompat$AccessibilityServiceInfoVersionImpl;'
Access flags : 0x0600 (INTERFACE ABSTRACT)
Superclass : 'Ljava/lang/Object;'
Interfaces -
Static fields -
Instance fields -
Direct methods -
Virtual methods -
#0 : (in Landroid/support/v4/accessibilityservice/Accessibility
ServiceInfoCompat$AccessibilityServiceInfoVersionImpl;)
name : 'getCanRetrieveWindowContent'
type : '(Landroid/accessibilityservice/AccessibilityServiceInfo;)
Z'
access : 0x0401 (PUBLIC ABSTRACT)
code : (none)

#1 : (in Landroid/support/v4/accessibilityservice/Accessibility
ServiceInfoCompat$AccessibilityServiceInfoVersionImpl;)
name : 'getDescription'

使用dexdump -f class.dex
显示文件头信息,说实话也非常多。这里仅打印一个文件头结构的内容。
Processing '/home/devilogic/workspace/tryme/bin/classes.dex'...
Opened '/home/devilogic/workspace/tryme/bin/classes.dex', DEX version '035'
DEX file header:
magic : 'dex\n035\0'
checksum : 7483dd9e
signature : ef45...c10f
file_size : 448704
header_size : 112
link_size : 0
link_off : 0 (0x000000)
string_ids_size : 4048
string_ids_off : 112 (0x000070)
type_ids_size : 572
type_ids_off : 16304 (0x003fb0)
field_ids_size : 837
field_ids_off : 27940 (0x006d24)
method_ids_size : 3561
method_ids_off : 34636 (0x00874c)
class_defs_size : 327
class_defs_off : 63124 (0x00f694)
data_size : 374848
data_off : 73856 (0x012080)
使用dexdump -h class.dex
显示部分如下:
Processing '/home/devilogic/workspace/tryme/bin/classes.dex'...
Opened '/home/devilogic/workspace/tryme/bin/classes.dex', DEX version '035'
Class #0 header:
class_idx : 64
access_flags : 1536 (0x0600)
superclass_idx : 508
interfaces_off : 0 (0x000000)
source_file_idx : 301
annotations_off : 442888 (0x06c208)
class_data_off : 82444 (0x01420c)
static_fields_size : 0
instance_fields_size: 0
direct_methods_size : 0
virtual_methods_size: 5

Class #0 -
Class descriptor : 'Landroid/support/v4/accessibilityservice/AccessibilitySer
viceInfoCompat$AccessibilityServiceInfoVersionImpl;'
Access flags : 0x0600 (INTERFACE ABSTRACT)
Superclass : 'Ljava/lang/Object;'
Interfaces -
Static fields -
Instance fields -

如果没错的话Class #0只的是其中的第一个类,当然还有很多
使用 dexdump -m class.dex,显示如下:
Processing '/home/devilogic/workspace/tryme/bin/classes.dex'...
Opened '/home/devilogic/workspace/tryme/bin/classes.dex', DEX version '035'
No register maps found
从结果看来输出没有找到寄存器图。这玩意慢慢再看是个什么。
其余的i,l,t三个参数都是辅助参数。可以忽略掉。

今天上午对dex就到此了。下午开始对照文档分析dexdump的代码。争取今天晚上把dex文件结构搞明白。

本文出自 “西西东东与南南” 博客,请务必保留此出处http://devilogic.blog.51cto.com/7117723/1198916
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: