Android软件安全与逆向分析——dalvik虚拟机与Java虚拟机的区别(带实例)
Dalvik虚拟机的特点:体积小,占用内存空间小专有的DEX 可执行文件格式,体积更小,执行速度更快常量池采用32位索引值,寻址类方法名、字段名、常量更快基于寄存器架构,拥有一套完整的指令系统提供了对象生命周期管理、堆栈管理、线程管理、安全和异常管理以及垃圾回收等重要功能所有的Android程序都运行在Android系统进程里,每个进程对应着一dalvik虚拟机实例Da
Dalvik虚拟机的特点:
- 体积小,占用内存空间小
- 专有的DEX 可执行文件格式,体积更小,执行速度更快
- 常量池采用32位索引值,寻址类方法名、字段名、常量更快
- 基于寄存器架构,拥有一套完整的指令系统
- 提供了对象生命周期管理、堆栈管理、线程管理、安全和异常管理以及垃圾回收等重要功能
- 所有的Android程序都运行在Android系统进程里,每个进程对应着一dalvik虚拟机实例
Dalvik虚拟机与Java虚拟机的区别:
1、Java虚拟机运行的是Java字节码,Dalvik虚拟机运行的是Dalvik字节码
传统的Java程序经过编译,生成Java字节码保存在class文件中,Java虚拟机通过解码class文件中的内容来运行程序;
而Dalvik虚拟机运行的是Dalvik字节码,它由Java字节码转换而来,并被打包到一个DEX(Dalvik Executable)可执行文件中,Dalvik虚拟机通过解释DEX文件来执行这些字节码。
2、Dalvik可执行文件体积更小
Android SDK中有一个叫dx的工具负责将Java字节码转换为Dalvik字节码,它将Java类文件重新排列,消除文件中出现的冗余信息,避免虚拟机在初始化时出现重复的加载与解析过程。
3、Java虚拟机与Dalvik虚拟机架构不同
Java虚拟机基于栈架构,程序在运行虚拟机时需要频繁的从栈上读取或写入数据;
而Dalvik虚拟机基于寄存器架构,数据的访问通过寄存器间直接传递。
实例证明:
测试代码:(Hello.java)
public class Hello{
public int foo(int a,int b){
return (a + b) * (a - b);
}
public static void main(String[] argc){
Hello hello = new Hello();
System.out.println(hello.foo(5,3));
}
}
使用编译命令生成class文件
javac Hello.java
先来分析Java虚拟机中的存储和运行情况:
使用Javap命令反编译class文件,查看class文件中的foo函数的字节码
javap -c -classpath . Hello
关于参数作用的解释:
运行结果:
图中黄色框框内的为foo函数的字节码,代码中每条指令占用1个字节,一共占用了8个字节,并且这些指令都没有参数。
在Java虚拟机中,指令的源参数和目标参数都是隐含的,称为零地址形式。
对于Java程序,每个线程在执行时都有一个PC计数器和一个Java栈。
PC计数器只对当前方法有效,Java虚拟机通过PC计数器的值来取指令执行。
Java栈用于记录Java方法调用的“活动记录”,以帧为单位保存线程的运行状态,每调用一个方法就会分配一个新的栈帧压入Java栈,没从一个方法返回则弹出并撤销相应的栈帧,每个栈帧包括局部变量区、求值栈和其他一些信息。方法的参数按从左到右的顺序保存在局部变量区开头的几个slot中。
对于foo()函数,图示如下:
由于每条指令占用一个字节的空间,foo()函数的Java字节码左边的偏移量就是程序执行到每一行代码时PC的值,Java虚拟机最多只支持0xff条指令。
第一条指令iload_1可分为两部分:
第一部分为下划线左边的iload,iload是JVM指令集中的一条指令,i是指令前缀,表示操作类型为int类型,load表示将局部变量存入Java栈,类似的有lload、fload、dload,分别表示将long、float、double类型的数据进栈;
第二部分为下划线右边的数字,表示要操作具体两个局部变量,索引值从0开始计数;
iload_1表示将第二个int类型的局部变量进栈,即foo()函数的第一个参数
下面的几条指令同理。
第8条ireturn函数返回一个int值。
---------------------------转角分割线---------------------------------------
再来分析Dalvik虚拟机中的情况:
首先需要把class文件转换成dex文件,需要用到的命令为
dx --dex --output=Hello.dex Hello.class
关于参数的解释为:
可是执行的时候问题出现了,总是报Hello.class找不到的错误。。。
尝试了N次,大概共有三种方法,但是我只成功了两种,第三种还有问题没有解决。。。
方法一:将Hello.class文件与dx放在同一目录下,dx在SDK里面的build-tools文件夹下
命令同上
方法二:在help里面的第二个黄色框框后面,还有一个directory选项,所以将Hello.class替换为它所在的目录
这两种方法所生成的hex文件都在dx的同一目录下
dx --dex --output=Hello.dex e:/security/3
方法三:我用的是JDK1.7,貌似是版本太高了,所以要强制使用1.6重新编译
但是我不知道咋回事老错。。。。
总之现在得到了hex文件。。呵呵呵
现在要反编译Hello.hex文件得到Dalvik字节码,命令为
dexdump -d Hello.hex
关于参数的解释:
得到的结果为(黄色框框的部分)
有点不忍直视。。这一块的字节码为:
|[000198] Hello.foo:(II)I
|0000: add-int v0, v3, v4
|0002: sub-int v1, v3, v4
|0004: mul-int/2addr v0, v1
|0005: return v0
v3、v4代表函数的两个参数
第一条指令为V3、V4相加存入V0寄存器,以下同理。
仅用了四条指令....当然执行速度更快了。
Dalvik虚拟机运行时同样回味每个线程维护一个PC计数器和调用栈,至少这个调用栈维护一份寄存器列表,寄存器的数量在方法结构体的registers字段中给出,Dalvik虚拟机会根据这个值来创建一份虚拟的寄存器列表。
状态图如下:
---------------------------疲惫的分割线-------------------------------------
更多推荐
所有评论(0)