快速简记:
结构 | 单位结构体占字节 | 共计字节 | ||
---|---|---|---|---|
DexHeader | - | 0x70h | ||
String Table | 4 | - | ||
Type Table | 4 | - | ||
Proto Table | 12 | - | ||
Field Table | 8 | - | ||
Method Table | 8 | - | ||
Class Def Table | 32 | - | ||
Data Section(含Map Section) | - | - | ||
## 练习用的dex文件链接 | ||||
https://github.com/eternalsakura/ctf_pwn/blob/master/android%E9%80%86%E5%90%91/Hello.dex | ||||
## 文件布局 | ||||
dex 文件可以分为3个模块,头文件(header)、索引区(xxxx_ids)、数据区(data)。 | ||||
头文件概况的描述了整个 dex 文件的分布,包括每一个索引区的大小跟偏移。索引区的ids 是 identifiers 的缩写,表示每个数据的标识,索引区主要是指向数据区的偏移。 | ||||
010Editor 中除了数据区(data)没有显示出来,其他区段都有显示,另外 link_data 在模板中被定为map_list |
||||
## header | ||||
header 描述了 dex 文件信息,和其他各个区的索引。010Editor中用结构体 struct header_item 来描述 header。 | ||||
|
magic
1 | // utility for reading/checking the magic value |
‘\n’ 10(十进制) 换行(newline)
checksum:
文件校验码,使用 alder32 算法校验文件除去 maigc、checksum 外余下的所有文件区域,用于检查文件错误。
uint类型,大小为4个字节。
signature
使用 SHA-1 算法 hash 除去 magic、checksum 和 signature 外余下的所有文件区域, 用于唯一识别本文件,大小为20字节。
1 | typedef ubyte SHA1[20] <read=SHA1Read, format=hex>; |
file_size
dex 文件大小,4个字节。
header_size
header 区域的大小,目前是固定为 0x70
endian_tag
大小端标签,dex 文件格式为小端,固定值为 0x12345678 常量
link_size
link section的大小
link_off
link section在文件中的偏移
map_off
map_item
的偏移地址,该 item 属于 data 区里的内容,值要大于等于 data_off
的大小,处于 dex 文件的末端。
string_ids_size
和string_ids_off
这两个字段表示dex中用到的所有的字符串内容的大小和偏移值,我们需要解析完这部分,然后用一个字符串池存起来,后面有其他的数据结构会用索引值来访问字符串,这个池子也是非常重要的。后面会详细介绍string_ids的数据结构
type_ids_size
和type_ids_off
这两个字段表示dex中的类型数据结构的大小和偏移值,比如类类型,基本类型等信息,后面会详细介绍type_ids的数据结构
proto_ids_size
和type_ids_off
这两个字段表示dex中的元数据信息数据结构的大小和偏移值,描述方法的元数据信息,比如方法的返回类型,参数类型等信息,后面会详细介绍proto_ids的数据结构
field_ids_size
和field_ids_off
这两个字段表示dex中的字段信息数据结构的大小和偏移值,后面会详细介绍field_ids的数据结构
method_ids_size
和method_ids_off
这两个字段表示dex中的方法信息数据结构的大小和偏移值,后面会详细介绍method_ids的数据结构
class_defs_size
和class_defs_off
这两个字段表示dex中的类信息数据结构的大小和偏移值,这个数据结构是整个dex中最复杂的数据结构.
data_size和
data_off`
这两个字段表示dex中数据区域的结构信息的大小和偏移值,这个结构中存放的是数据区域,比如我们定义的常量值等信息。
上述这些其实就是对应在下图中圈起来的部分的每部分的开头和大小。
string_ids
string_ids
区段描述了 dex 文件中所有的字符串。格式很简单只有一个偏移量,偏移量指向了 string_data
区段的一个字符串:
1 | ////////////////////////////////////////////////// |
一个string_id_item
里有两个数据结构:
1 | uint string_data_off |
根据string_data_off
可以找到字符串的数据位置。string_data
里存放字符串的大小和具体数据。
type_ids
type_ids 区索引了 dex 文件里的所有数据类型,包括 class 类型,数组类型(array types)和基本类型
(primitive types)。区段里的元素格式为 type_ids_item
type_ids_item
里面 descriptor_idx
的值的意思,是 string_ids
里的 index 序号,是用来描述此 type 的字符串。
1 |
|
proto_ids
proto 的意思是 method prototype 代表 java 语言里的一个 method 的原型 。proto_ids
里的元素为 proto_id_item
,结构如下:
1 | ////////////////////////////////////////////////// |
shorty_idx
: 跟type_ids
一样,它的值是一个string_ids
的 index 号 ,最终是一个简短的字符串描述,用来说明该 method 原型。return_type_idx
: 它的值是一个type_ids
的 index 号 ,表示该 method 原型的返回值类型。parameters_off
: 指向 method 原型的参数列表type_list
,若 method 没有参数,值为0。
参数列表的格式是type_list
,下面会有描述。
field_ids
filed_ids
区里面有 dex 文件引用的所有的 field。区段的元素格式是 field_id_item
,结构如下:
1 | ////////////////////////////////////////////////// |
class_idx
: 表示 field 所属的 class 类型,class_idx 的值是type_ids
的一个 index,并且必须指向一个 class 类型。type_idx
: 表示本 field 的类型,它的值也是type_ids
的一个 index 。name_idx
: 表示本 field 的名称,它的值是string_ids
的一个 index 。
method_ids
method_ids
描述了 dex 文件里的所有的 method。method_ids
的元素格式是method_id_item
,结构跟 fields_ids 很相似:
1 | ////////////////////////////////////////////////// |
class_idx
: 表示 method 所属的 class 类型,class_idx
的值是type_ids
的一个 index,并且必须指向一个 class 类型。proto_idx
: 表示 method 的类型,它的值也是 type_ids 的一个 index。name_idx
: 表示 method 的名称,它的值是 string_ids 的一个 index。
都是索引,分别指向类型池,函数原型池,字符串池
class_defs
概览
class_idx
: 描述具体的 class 类型,值是type_ids
的一个 index 。值必须是一个 class 类型,不能是数组类型或者基本类型。access_flags
: 描述 class 的访问类型,诸如 public , final , static 等。在 dex-format.html 里 “access_flags
Definitions” 有具体的描述 。superclass_idx
: 描述 supperclass 的类型,值的形式跟class_idx
一样 。interfaces_off
: 值为偏移地址,指向 class 的 interfaces,被指向的数据结构为type_list
。class 若没有 interfaces,则值为 0。source_file_idx
: 表示源代码文件的信息,值是string_ids
的一个 index。若此项信息缺失,此项值赋值为NO_INDEX
=0xffff ffff。annotions_off
: 值是一个偏移地址,指向的内容是该 class 的注释,位置在 data 区,格式为annotations_direcotry_item
。若没有此项内容,值为 0 。class_data_off
: 值是一个偏移地址,指向的内容是该 class 的使用到的数据,位置在 data 区,格式为class_data_item
。若没有此项内容值为 0。该结构里有很多内容,详细描述该 class 的 field、method, method 里的执行代码等信息,后面会介绍class_data_item
。static_value_off
: 值是一个偏移地址 ,指向 data 区里的一个列表 (list),格式为encoded_array_item
。若没有此项内容值为 0。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41typedef struct {
local int64 pos;
uint class_idx <read=LongTypeIdRead, comment="Type ID for this class">;
ACCESS_FLAGS access_flags <comment="Access flags">;
uint superclass_idx <read=LongTypeIdRead, comment="Type ID for this class's superclass">;
uint interfaces_off <comment="File offset to interface list">;
if(interfaces_off != 0) {
pos = FTell();
FSeek(odexpad + interfaces_off);
type_item_list interfaces <read=InterfacesRead, comment="Interface data">;
FSeek(pos);
}
uint source_file_idx <read=StringIdRead, comment="String ID for the name of the file with this class defined">;
uint annotations_off <comment="File offset to the annotation structure for this class">;
if(annotations_off != 0) {
pos = FTell();
FSeek(odexpad + annotations_off);
annotations_directory_item annotations <comment="Annotation data">;
FSeek(pos);
}
uint class_data_off <comment="File offset to the class data for this class">;
if(class_data_off != 0) {
pos = FTell();
FSeek(odexpad + class_data_off);
class_data_item class_data <comment="Class data">;
FSeek(pos);
}
uint static_values_off <comment="File offset to static field data">;
if(static_values_off != 0) {
pos = FTell();
FSeek(odexpad + static_values_off);
struct encoded_array_item static_values <comment="Static values">;
FSeek(pos);
}
} class_def_item <read=ClassDefItemRead, optimize=false>;type_list
type_list
在 data 区段,class_def_item->interface_off
就是指的这里的数据。数据结构如下:1
2
3
4
5
6
7
8
9
10struct type_list
{
uint size;
type_item list [size]
}
struct type_item
{
ushort type_idx //-->type_ids
}size: 表示类型个数
type_idx: 对应一个 type_ids 的 index
annotations_directory_item
class_def_item->annotations_off
指向的数据区段,定义了 annotation 相关的数据描述,数据结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29struct annotation_directory_item
{
uint class_annotations_off; //-->annotation_set_item
uint fields_size;
uint annotated_methods_size;
uint annotated_parameters_size;
field_annotation field_annotations[fields_size];
method_annotation method_annotations[annotated_methods_size];
parameter_annotation parameter_annotations[annotated_parameters_size];
}
struct field_annotation
{
uint field_idx;
uint annotations_off; //-->annotation_set_item
}
struct method_annotation
{
uint method_idx;
uint annotations_off; //-->annotation_set_item
}
struct parameter_annotation
{
uint method_idx;
uint annotations_off; //-->annotation_set_ref_list
}class_annotations_off
: 这个偏移指向了annotation_set_item
fields_size
: 表示属性的个数annotated_methods_size
: 表示方法的个数annotated_parameters_size
: 表示参数的个数
class_data_item
class_data_off
指向 data 区里的 class_data_item
结构,class_data_item
里存放着本 class 使用到的各种数据,下面是 class_data_item
的结构 :
1 | typedef struct { |
static_fields_size
: 静态成员变量的个数instance_fields_size
: 实例成员变量个数direct_methods_size
: 直接函数个数virtual_methods_size
: 虚函数个数encoded_methods
access_flags
: 访问权限,比如 public、private、static、final 等。code_off
: 一个指向 data 区的偏移地址,目标是本 method 的代码实现。被指向的结构是code_item
,有近 10 项元素。code_item
code_item
结构里描述着某个 method 的具体实现.
map_list
map_list
中大部分 item 跟 header 中的相应描述相同,都是介绍了各个区的偏移和大小,但是 map_list
中描述的更加全面,包括了 HEADER_ITEM 、TYPE_LIST、STRING_DATA_ITEM、DEBUG_INFO_ITEM
等信息。