Dalvik指令分析(三) dex文件的结构

     以上一篇文章生成的dex文件为例,讲解dex文件结构,这个dex文件结构非常简单,只有一个HelloWorld.java

文件,dex文件的基本格式请参考官方文档,对照dex文件的各个组成部分,我们可以将dex的内容进行分解。

1、文件头

header header_item the header
上述dex文件header部分的内容如下:

64 65 78 0A 30 33 35 00 52 5B 33 08 D6 16 D3 44
F7 27 50 E9 D6 16 9A 3E 6D 53 EF F9 92 28 70 FA
98 02 00 00 70 00 00 00 78 56 34 12 00 00 00 00
00 00 00 00 04 02 00 00 0C 00 00 00 70 00 00 00
06 00 00 00 A0 00 00 00 02 00 00 00 B8 00 00 00
01 00 00 00 D0 00 00 00 04 00 00 00 D8 00 00 00
01 00 00 00 F8 00 00 00 80 01 00 00 18 01 00 00
现在开始分解header部分的内容:

64 65 78 0A 30 33 35 00
这部分是dex_magic的值对应的ASCII码值为:dex 035

52 5B 33 08

这部分是checksum,计算checksum的逻辑如下面的代码:

private static void calcChecksum(byte bytes[]) {
		Adler32 a32 = new Adler32();
		a32.update(bytes, 12, bytes.length - 12);
		int sum = (int) a32.getValue();
		checksum[0] = (byte) sum;
		checksum[1] = (byte) (sum >> 8);
		checksum[2] = (byte) (sum >> 16);
		checksum[3] = (byte) (sum >> 24);

		try {
			String decoded = new String(checksum, "UTF-8");
			System.out.println(decoded);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		bytes[8] = (byte) sum;
		bytes[9] = (byte) (sum >> 8);
		bytes[10] = (byte) (sum >> 16);
		bytes[11] = (byte) (sum >> 24);
	}

其中,参数bytes[]为dex文件的字节流,计算出来的值写入bytes数组中,下标为8-11

D6 16 D3 44 F7 27 50 E9 D6 16 9A 3E 6D 53 EF F9
92 28 70 FA
这部分是sha1的签名,计算signature的逻辑如下:

private static void calcSignature(byte bytes[]) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException ex) {
			throw new RuntimeException(ex);
		}
		md.update(bytes, 32, bytes.length - 32);
		try {
			int amt = md.digest(bytes, 12, 20);
			if (amt != 20)
				throw new RuntimeException((new StringBuilder())
						.append("unexpected digest write:").append(amt)
						.append("bytes").toString());
		} catch (DigestException ex) {
			throw new RuntimeException(ex);
		}
	}

98 02 00 00
这部分是文件大小:即0x0298=664bytes

70 00 00 00
这部分是头的大小,112bytes

78 56 34 12
这部分是大小端的标志,dex文件缺省是小端的,这个dex文件是小端的,因为对应的值为0x12345678,系统

里的定义如下:

uint ENDIAN_CONSTANT = 0x12345678;
uint REVERSE_ENDIAN_CONSTANT = 0x78563412;

00 00 00 00 00 00 00 00
这全0的八字节是link_size和link_off字段,主要用在文件的静态链接上,该dex不是静态链接文件,所有为0

04 02 00 00

这部分为map_off字段,值为0x204,即516,这个值是map_list所在位置相对文件起始位置的偏移量。map_list

是对整个dex文件的描述,分不同的类型,包括头、字符串、类型、函数原型、类、代码等等,其实和header的

信息有一些冗余,主要是在dex文件生成后对文件做一些校验工作,dx进程在生成dex文件后,会根据map_list的

内容对dex做一些校验工作,这个在后面介绍dx进程的时候会描述。

0C 00 00 00 70 00 00 00
这部分内容为string_ids_size和string_ids_off,各占四字节

和map_list类似,string也有一个string_list,上面的两个值就是用来标识有多少个字符串,以及string_list

的偏移的。

header部分余下的都是各个list的长度和对应的偏移量,如type_ids_size和type_ids_off,指向type_list,

还有proto_list,field_list,method_list,code_item_list, class_def_item_list,data_list。这些list包含了

程序里的字符串信息、函数原型、字段、函数描述、类描述信息,这些也就组成了所有的程序内容。

dex header部分的分析基本完成了,header部分是整个dex文件的描述,也是文件各部分内容的索引,

掌握了header部分就可以继续分析其他部分内容,比如method_list,比如code_item_list。

在分析的过程中,要经常参考android源码,主要是数据结构的定义,因为涉及到数据元素的大小以及

成员,所以还是很费时间和精力的,但是这些都很有意义,让您在理解了一个可执行文件的结构的同时,

也熟悉android的源码。如果您在分析其他部分时,碰到问题可以联系我,在时间允许的情况下我会帮

您一起分析、解答问题。










你可能感兴趣的:(dex,dalvik)