之前面试被问到DEX文件解析,由于时间太过于久远,忘得都有点差不多了,好记性不如烂笔头。特此记录一下。
DEX文件的生成
首先我们要知道,JVM是JAVA虚拟机,使用运行JAVA字节码程序。Dalvik是Google设计的用于Android平台的运行时环境,适合移动环境ART即Android Runtime,是Google为了替换Dalvik设计的新Android运行时环境,在Android 4.4及以上启动。ART比Dalvik的性能更好。Android程序一般使用Java语言开发,但是Dalvik虚拟机并不支持直接执行JAVA字节码,因此要进行编译生成的.class文件进行翻译,解释,解释,压缩等处理,这个处理过程是由dx进行的,目的就是使其中各个类能够共享数据,在一定程度上降低了冗余,同时也使文件结构更加经凑,处理完成后生成的生成会以.dex结尾,称为Dex文件。Dex文件格式是专为Dalvik设计的一种压缩格式。所以可以简单的理解为:Dex文件是很多.class文件处理后的生成物,最终可以在Android运行时环境中执行。
我们写一个简单的Demo.java,然后将他先转变为.class文件,再用dx(dx在SDK目录的build-tools文件目录下)将.class文件转化为.dex文件。使用010editor分析。
public class Hello {
private String helloString = "hello! World!";
public static void main(String[] args) {
Hello hello = new Hello();
hello.fun(hello.helloString);
}
public void fun(String a) {
System.out.println(a);
}
}
使用010editor打开生成的dex文件。
DEX文件总览
首先先从理论上了解一下DEX文件的结构
先从文件头开始
对于文件头中的各字段,我们可以在010editor中都可以看到,并且可以看到类型,偏移量,长度等等。
文件头大小一般是固定为 0x70 个字节,首先第一个是Magic,长度是8个字节,为64 65 78 0A 30 33 35 00,转化成ascii后,就是dex035,目前,dex的魔数固定为dex.035。
接下来是checksum,他是dex文件的校验和,通过它可以判断dex文件是否被损坏或者被篡改。注意,它采用小端序存储,所用的算法是Adler-32校验算法。
signature表示的就是把整个dex文件用SHA-1签名得到的一个值。
file_size是dex总长度。
header_size表示DexHeader头结构的大小,值为112,也就是70h。
endianTag代表 字节序标记,用于指定dex运行环境的cpu。
mapOff它指定了DexMapList的文件偏移
接下来的stringIdsSize 和 stringIdsOff字段,这两个字段指定了dex文件中所有用到的字符串的个数和位置偏移。其实就是指向的Header下面的字符串段string_ids。
typeIdsSize和typeIdsOff,代表的是类的类型的数量和位置偏移。
可以看到我们这里面有7个类。
然后,我们看一下typeldsoff,发现对应的就是一个新的分区,DexTypeId这种数据。然后这个分区里面的数据跟上面的都是对应的。
protoIdsSize和protoIdsOff,它们代表的是dex文件中方法原型的个数和位置偏移。跟上面分析相似,跳过了。不过要知道的是,这个里面也会有一个新的数据类型。
参考
1.官方文档
2. https://tech.youzan.com/qian-tan-android-dexwen-jian/