Android之DEX文件指令解析

转载自公众号“嵌入式Linux技术分享 ”

我们的重点不是分析Android的DEX格式,因为DEX格式部分可以直接通过010Editor解析出来的,这部分直接贴出自动解析图,我们的重点是根据指令集内容通过查询手册分析出具体的汇编指令。

首先编写简单的HelloWorld程序,Java代码如下

使用Java8编译器编译生成Hello.class,然后使用Android SDK29.0.2的dx将class文件转换成DEX文件,注意Java版本与SDK版本需要匹配,可使用javap -verbose Hello命令查看major version字段确定Java编译器的版本。

下面使用010 Editor软件分析DEX文件,选择DEX.bt脚本,点击Templates->Run Template对DEX文件进行分析。

先列出DEX文件的格式,如下

header

String_ids

Type_ids

Proto_ids

Field_ids

Method_ids

Class_def

data

Link_data

直接根据010Editor软件显示,如下是string_ids内容,

据此,再贴出type_ids内容如下,

然后贴出proto_ids

下面贴出的是field_ids

如下是method_ids

下面部分是重点,首先我们寻找指令,如下图所示该DEX有两个method,我们先分析第一个method的指令

参考指令文档链接https://source.android.google.cn/devices/tech/dalvik/dalvik-bytecode

该指令格式,查询“字节码格式”表,开头“70”的Opcode为invoke-dirct,格式为0x35c,如下表所示。

查询“说明格式”表,知道0X35c的指令格式如下图所示,为A|G|op BBBB F|E|D|C。

根据指令内容是“7010 0300 0000 0E00”,在指令“7010”(按照小端字节排序是“1070”)中,A=1,所以对应”[A=1] op {vC}, kind@BBBB”格式,解析得到BBBB=0X0003,C=D=E=F=0,因为BBBB属于kind@类型,查method_ids表,得Java.lang.Object.()。

所以第一条指令是invoke-direct {v0}, Ljava/lang/Object;->()V

指令最后的0E00,先根据0E查“字节码格式”表,得到其opcode为return-void,如下结果。

再根据上图中10X,查“说明格式”表,如下所示。

所以指令指令最后的0E00,对应的是“return-void”

下面解析第二个method方法,如下是指令截图,指令内容为“6200 0000 1A01 0100 6E20 0200 1000 0E00”,

根据下图可以解析“6200 0000”,查询field_ids,得到汇编为sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;

根据下图可以解析“1A01 0100”,查询string_ids,得到const-string v1, "Hello, world!"

根据下图可以解析“6E20 0200 1000”,其中A=2,BBBB=2, F=E=C=0 D=1,查询module_ids表,得到invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

最后一个“0E00”指令,前面已经分析过,解析得到return-void。

下面贴出Hello.java对应的Smali反汇编结果,证明了我们的分析是正确的。

为了贴近实战,我们分析一个实际的Android APK,众所周知,Android Studio创建新的工程,自动生成默认输出“Hello World!”的代码,其MainActivity.java源码如下,

1
将其编译成的APK转成对应的DEX文件,利用010Editor进行分析,如下所示。
1
 
1
 

我们只分析MainActivity.java中的类,该类包含一个虚拟方法,一个直接方法,我们分析指令最多的虚拟方法,我们只分析最核心的指令部分,其对应的指令集是“6F20 620D 2100 1400 1C00 097F 6E20 633C 0100 0E00”。

下面是指令“6F20 620D 2100”解析过程,其中A=2,BBBB=0X0D62=3426,F=E=0,D=2,C=1。

1
 
1
查询method_ids表,如下

最终得到,

invole-super {v1,v2}

Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

下面是指令“1400 1C00 097F”解析过程,其中AA=0,BBBBBBBB=0X7F09001C,

最终得到const v0, 0x7f09001c

下面是指令“6E20 633C 0100”解析过程,A=2,BBBB=0X3C63=15459,F=E=0,D=0,C=1,

最终得到invoke-virtual {v1, v0}, Lcom/example/prj/MainActivity;->setContentView(I)V

最后贴下MainActivity类的Smali代码,论证了上面分析的正确性。

Android之DEX文件指令解析

我们的重点不是分析Android的DEX格式,因为DEX格式部分可以直接通过010Editor解析出来的,这部分直接贴出自动解析图,我们的重点是根据指令集内容通过查询手册分析出具体的汇编指令。

首先编写简单的HelloWorld程序,Java代码如下

使用Java8编译器编译生成Hello.class,然后使用Android SDK29.0.2的dx将class文件转换成DEX文件,注意Java版本与SDK版本需要匹配,可使用javap -verbose Hello命令查看major version字段确定Java编译器的版本。

下面使用010 Editor软件分析DEX文件,选择DEX.bt脚本,点击Templates->Run Template对DEX文件进行分析。

先列出DEX文件的格式,如下

header

String_ids

Type_ids

Proto_ids

Field_ids

Method_ids

Class_def

data

Link_data

直接根据010Editor软件显示,如下是string_ids内容,

据此,再贴出type_ids内容如下,

然后贴出proto_ids

下面贴出的是field_ids

如下是method_ids

下面部分是重点,首先我们寻找指令,如下图所示该DEX有两个method,我们先分析第一个method的指令

参考指令文档链接https://source.android.google.cn/devices/tech/dalvik/dalvik-bytecode

该指令格式,查询“字节码格式”表,开头“70”的Opcode为invoke-dirct,格式为0x35c,如下表所示。

查询“说明格式”表,知道0X35c的指令格式如下图所示,为A|G|op BBBB F|E|D|C。

根据指令内容是“7010 0300 0000 0E00”,在指令“7010”(按照小端字节排序是“1070”)中,A=1,所以对应”[A=1] op {vC}, kind@BBBB”格式,解析得到BBBB=0X0003,C=D=E=F=0,因为BBBB属于kind@类型,查method_ids表,得Java.lang.Object.()。

所以第一条指令是invoke-direct {v0}, Ljava/lang/Object;->()V

指令最后的0E00,先根据0E查“字节码格式”表,得到其opcode为return-void,如下结果。

再根据上图中10X,查“说明格式”表,如下所示。

所以指令指令最后的0E00,对应的是“return-void”

下面解析第二个method方法,如下是指令截图,指令内容为“6200 0000 1A01 0100 6E20 0200 1000 0E00”,

根据下图可以解析“6200 0000”,查询field_ids,得到汇编为sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;

根据下图可以解析“1A01 0100”,查询string_ids,得到const-string v1, "Hello, world!"

根据下图可以解析“6E20 0200 1000”,其中A=2,BBBB=2, F=E=C=0 D=1,查询module_ids表,得到invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

最后一个“0E00”指令,前面已经分析过,解析得到return-void。

下面贴出Hello.java对应的Smali反汇编结果,证明了我们的分析是正确的。

为了贴近实战,我们分析一个实际的Android APK,众所周知,Android Studio创建新的工程,自动生成默认输出“Hello World!”的代码,其MainActivity.java源码如下,

1
将其编译成的APK转成对应的DEX文件,利用010Editor进行分析,如下所示。
1
 
1
 

我们只分析MainActivity.java中的类,该类包含一个虚拟方法,一个直接方法,我们分析指令最多的虚拟方法,我们只分析最核心的指令部分,其对应的指令集是“6F20 620D 2100 1400 1C00 097F 6E20 633C 0100 0E00”。

下面是指令“6F20 620D 2100”解析过程,其中A=2,BBBB=0X0D62=3426,F=E=0,D=2,C=1。

1
 
1
查询method_ids表,如下

最终得到,

invole-super {v1,v2}

Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

下面是指令“1400 1C00 097F”解析过程,其中AA=0,BBBBBBBB=0X7F09001C,

最终得到const v0, 0x7f09001c

下面是指令“6E20 633C 0100”解析过程,A=2,BBBB=0X3C63=15459,F=E=0,D=0,C=1,

最终得到invoke-virtual {v1, v0}, Lcom/example/prj/MainActivity;->setContentView(I)V

最后贴下MainActivity类的Smali代码,论证了上面分析的正确性。