Android安全與逆向之Dalvik虛擬機架構(gòu)和如何執(zhí)行程序以及JIT(即時編譯)
1、Dalvik虛擬機架構(gòu)和Java虛擬機的架構(gòu)不同
1、Java虛擬機基于棧結(jié)構(gòu),需要頻繁從棧讀取或?qū)懭霐?shù)據(jù),這個過程需要更多的指令與內(nèi)存訪問次數(shù),會消耗cpu時間
2、Dalvik虛擬機基于寄存器,數(shù)據(jù)訪問通過寄存器直接傳遞,比棧方式快。
public class Hello {
public int foo(int a, int b) {
return (a + b) * (a - b);
}
public static void main(String[] args) {
Hello hello = new Hello();
System.out.println(hello.foo(5, 3));
}
}
保存為Hello.java文件,打開終端執(zhí)行
javac Hello.java 編譯生存Hello.class文件
然后再執(zhí)行 dx --dex --output=Hello.dex Hello.class 生存dex文件
javap -c -classpath .Hello 命令執(zhí)行后得到下面代碼:
public int foo(int, int);
Code:
0: iload_1
1: iload_2;
2: iadd
3: iload_1
4: iload_2
5: isub
6: imul
7: ireturn
使用dexdump.exe查看foo()函數(shù)的Dalvik字節(jié)碼,執(zhí)行下面命令
dexdump.exe -d Hello.dex
得到如下代碼
0000:add-int v0, v3, v4
0002:sub-int v1, v3, v4
0004:mul-int/2addr v0, v1
0005:return v0
Java字節(jié)碼分析:8個命令 8個字節(jié),至于怎么壓棧進棧就不詳細講了
Dalvik字節(jié)碼分析:4條命令完成操作
代碼指令減少,速度更快。
2、Dalvik虛擬機如何執(zhí)行程序的
Android系統(tǒng)有Linux內(nèi)核、函數(shù)庫、Android運行時、應用程序框架和應用層組成。Dalvik虛擬機屬于Android運行時環(huán)境
Android系統(tǒng)啟動加載完成內(nèi)核后,第一個執(zhí)行的是init進程,init進程首要做的是設備初始化工作,然后讀取inic.rc文件并啟動系統(tǒng)中的重要的外部程序Zygote
Zygote是所有進程的孵化器,它啟動會初始化Dalvik虛擬機,然后啟動system_server并進入Zygote模式,通過socket等候命令,當執(zhí)行一個Android應用程序時,system_server
進程通過socket方式發(fā)送命令給Zygote,Zygote收到命令后通過fork自身創(chuàng)建一個Dalvik虛擬機的實例來執(zhí)行應用程序的入口函數(shù),這樣程序啟動完成,流程圖如下
Zygote提供3種創(chuàng)建進程的方法
1、fork(),創(chuàng)建一個Zygote進程
2、forkAndSpecialize()創(chuàng)建一個非Zygote進程
3、forSystemServer()創(chuàng)建一個系統(tǒng)服務進程
Zygote可以再fork()出其他進程,非Zygote進程不可以fork其它進程,而系統(tǒng)服務進程在終止后它的子進程也必須終止
當進程fork()成功之后,執(zhí)行的工作就交給Dalvik虛擬機,Dalvik虛擬機首先通過loadClassfromDex()函數(shù)完成類的裝載工作,每個類成功解析后會擁有一個classObject
類型的數(shù)據(jù)結(jié)構(gòu)存儲在運行時環(huán)境中,虛擬機使用gDvm.loadedClasses全局哈希表來存儲與查詢所有裝載進來的類,然后字節(jié)碼驗證器是有那個dvmVerifyCodeFlow()函數(shù)對裝入的daim進行
校驗,然后虛擬機調(diào)用FindClass()函數(shù)查找并裝載main方法類,隨后調(diào)用dvmInterpret()函數(shù)初始化解釋器并執(zhí)行字節(jié)碼流,過程如下
3、Dalvik虛擬機JIT(既時編譯)
JIT(既時編譯),又為動態(tài)編譯,是一種通過運行時將字節(jié)碼編譯為機器貓的技術(shù),讓程序執(zhí)行更快Android2.2以上
JIT包含2兩字節(jié)碼編譯方式
1、method方式:以函數(shù)或方法為單位進行編譯
2、trace方式:以trace為單位進行編譯
trace方式解釋:函數(shù)的有些路徑在實際運行過程中很少被執(zhí)行的,這部分代碼為“冷路徑”,而執(zhí)行比較頻繁的路徑為“熱路徑”傳統(tǒng)的method方式會編譯整個方法的代碼,這
會在“冷路徑”上浪費很多編譯世家,消耗內(nèi)存,trace方式能快速獲取“熱路徑”,更短時間和內(nèi)存編譯代碼。
作者:chen.yu
深信服三年半工作經(jīng)驗,目前就職游戲廠商,希望能和大家交流和學習,
微信公眾號:編程入門到禿頭 或掃描下面二維碼
零基礎入門進階人工智能(鏈接)