安卓Dalvik虛擬機器學習(1)----Dalvik虛擬機器執行原理
安卓Dalvik虛擬機器相關知識點總結
0x01 Java虛擬機器與Dalvik虛擬機器的區別
Java虛擬機器執行的是Java位元組碼(儲存在class檔案中),Dalvik執行的是Dalvik位元組碼(由Java位元組碼轉化而來,打包到DEX檔案中)。
Dalvik可執行檔案更小。
由於Android SDK中的dx檔案對常量池進行了壓縮,使得相同字串、常量在DEX檔案中只出現一次。Java虛擬機器與Daivik虛擬機器架構不同
Java虛擬機器基於棧結構,資源開銷大,Dalvik虛擬機器基於暫存器結構,資料由暫存器直接傳遞,這樣的方式比基於棧結構的方式快得多。
這裡介紹以下把java檔案編譯成dex檔案的方法
- 先把java檔案編譯生成hello.class
javac Hello.java
- 在執行命令生成dex檔案
dx --dex --output=Hello.dex Hello.class
- javap對class檔案進行反編譯
javap -c -classpath . Hello
- 使用Android SDK 工具dexdump檢視函式的位元組碼
dexdump.exe -d Hello.dex
注意事項:筆者使用的JDK1.8,在使用dx生成dex檔案報錯如下:
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.RuntimeException: Helle.class: file not found
at com.android.dex.util.FileUtils.readFile(FileUtils.java:51)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:169)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
at com.android.dx.command .dexer.Main.processOne(Main.java:596)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:498)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:264)
at com.android.dx.command.dexer.Main.run(Main.java:230)
at com.android.dx.command.dexer.Main.main(Main.java:199)
at com.android.dx.command.Main.main(Main.java:103)
1 error; aborting
錯誤原因:預設生成的Hello.class檔案版本過低。
解決方法:強制指定class檔案的版本,使用如下命令重新編譯
javac -source 1.6 -target 1.6 Hello.java
0x01 Java位元組碼和Dalvik位元組碼的區別
下面這個例子我們對一個簡單的add函式位元組碼進行觀察
- 首先編寫原始的Java程式碼Hello.java
public class Hello{
public int add(int a,int b){
return a + b;
}
public static void main(String[] argc){
Hello hello = new Hello();
System.out.println(hello.add(5,3));
}
}
- 用上述Javac命令生成java.class,用javap命令反編譯class檔案得出add方法java位元組碼
public int add(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: ireturn
- 用上述的dx命令生成dex檔案,再用dexdump生成Dalvik位元組碼如下
Hello.add:(II)I
add-int v0, v2, v3
return v0
簡單對比:在這裡不對具體的位元組碼語法做講解,我們可以看出Dalvik位元組碼比Java位元組碼看起來簡潔一些,而且可以看出Java虛擬機器是基於棧結構的,Dalvik虛擬機器是基於暫存器結構的,v0, v2, v3代表暫存器
0x02 Dalvik虛擬機器的執行程式流程概述
流程簡單敘述:Dalvik虛擬機器執行緒首先通過loadClassFromDex()函式完成類的裝載工作,每個類被成功解析後會擁有一個ClassObject型別的資料結構儲存在執行環境中,虛擬機器使用gDvm.loadedClasses全域性雜湊表來儲存與查詢所有裝載進來的類,隨後,位元組碼驗證器使用dvmVerifyCodeFlow()函式對裝載的程式碼進行校驗,接著虛擬機器呼叫FindClass()函式查詢並且裝載main方法類,隨後呼叫dvmInterpret()函式初始化直譯器並執行位元組碼流,整個過程如下:
好了Dalvik虛擬機器執行原理介紹到此為止,下一章開始進入Dalvik虛擬機器組合語言的學習,如果大家有任何不懂得可以查考《Android軟體安全與逆向分析》第三章