Android逆向基础----Android Dalvik虚拟机
?
Android Dalvik虛擬機(jī)的特點(diǎn):
?
l? 體積小,占用內(nèi)存空間小。
l? 專有DEX可執(zhí)行文件。
l? 常量池采用32位索引值,尋址類方法名,字段名,常量更快。
l? 基于寄存器架構(gòu),并擁有一套完整的指令系統(tǒng)。
l? 提供生命周期管理、堆棧管理、線程管理、安全和異常管理以及垃圾回收等重要功能。
l? 所有的Android程序都運(yùn)行在Android系統(tǒng)進(jìn)程里,每個(gè)進(jìn)程對(duì)應(yīng)一個(gè)Dalvik虛擬機(jī)實(shí)例。
?
1、Dalvik虛擬機(jī)與Java虛擬機(jī)的區(qū)別
Java虛擬機(jī)運(yùn)行的是Java字節(jié)碼,Dalvik虛擬機(jī)運(yùn)行的是Dalvik字節(jié)碼。Dalvik字節(jié)碼由Java字節(jié)碼轉(zhuǎn)換而來(lái),并打包成一個(gè)DEX可執(zhí)行文件,通過(guò)虛擬機(jī)解釋執(zhí)行。
2、Dalvik可執(zhí)行文件體積更小
Android SDK中的dx工具在轉(zhuǎn)換字節(jié)碼時(shí)會(huì)消除類文件的冗余信息,避免虛擬機(jī)在初始化時(shí)出現(xiàn)重復(fù)的文件加載與解析過(guò)程。另外,dx工具會(huì)將所有的Java類文件中的常量池進(jìn)行分解,消除其中的冗余信息,組合成一個(gè)新的共享常量池。這使得文件體積和解析文件的效率都得到了提高。
3、Dalvik虛擬機(jī)與Java虛擬機(jī)的架構(gòu)不同
Java虛擬機(jī)的架構(gòu)及參數(shù)傳遞
Java虛擬機(jī)基于棧架構(gòu)。需要頻繁的從棧上讀寫數(shù)據(jù),在這個(gè)過(guò)程中需要更多的指令分派與內(nèi)存訪問(wèn)次數(shù),耗費(fèi)CPU時(shí)間,消耗手機(jī)資源。
Java虛擬機(jī)的指令集被稱為零地址,是指指令的源參數(shù)與目標(biāo)參數(shù)都是隱含的,它通過(guò)Java虛擬機(jī)中提高的一種數(shù)據(jù)結(jié)構(gòu)“求值棧”來(lái)傳遞的。
對(duì)于Java程序來(lái)說(shuō),每個(gè)線程在執(zhí)行時(shí)都有一個(gè)PC計(jì)數(shù)器與一個(gè)Java棧。PC計(jì)數(shù)器以字節(jié)為單位記錄當(dāng)前運(yùn)行位置距離方法開(kāi)頭的偏移量,與ARM架構(gòu)和x86架構(gòu)類似,通過(guò)棧幀對(duì)棧中的數(shù)據(jù)進(jìn)行操作。
Java棧用于記錄Java方法調(diào)用的“活動(dòng)記錄”,Java棧以幀為單位保存線程的運(yùn)行狀態(tài),每調(diào)用一個(gè)方法就會(huì)分配一個(gè)新的棧幀壓入Java棧上,每從一個(gè)方法返回則彈出并撤銷響應(yīng)的棧幀。
每個(gè)棧幀包括局部變量區(qū)、求值棧(JVM規(guī)范中將其稱為“操作數(shù)棧”)和其他一些信息。局部變量區(qū)用于存儲(chǔ)方法的參數(shù)與局部變量,其中參數(shù)按源碼中從左到右順序保存在局部變量區(qū)開(kāi)頭的幾個(gè)slot中。
求棧值用于保存求值的中間結(jié)果和調(diào)用別的方法的參數(shù)等,JVM運(yùn)行時(shí)它的狀態(tài)如下圖
每條指令占用一個(gè)字節(jié)空間,foo()函數(shù)Java字節(jié)碼左邊的偏移量就是程序執(zhí)行到每一行代碼時(shí)PC的值,并且Java虛擬機(jī)最多只支撐0xff條指令。
仔細(xì)分析第一條指令iload_1的結(jié)構(gòu)
iload_1可分成兩部分,第一部分為下劃線左邊的iload,屬于JVM(Java虛擬機(jī))指令集中l(wèi)oad系列中的一條,i是指令前綴,表示操作類型為int類型,load表示將局部變量存入Java棧。第二部分為下劃線右邊的數(shù)字,表示要操作具體哪個(gè)變量,索引值從0開(kāi)始計(jì)數(shù),iload_1表示將第二個(gè)int類型的局部變量進(jìn)棧參數(shù)。
?
Dalvik虛擬機(jī)的架構(gòu)及參數(shù)傳遞
Dalvik虛擬機(jī)基于寄存器架構(gòu),數(shù)據(jù)訪問(wèn)通過(guò)寄存器間直接傳遞。比起Java虛擬機(jī)字節(jié)碼要簡(jiǎn)潔很多。
以第一條指令為例簡(jiǎn)單分析一下。指令add-int將v3與v4寄存器的值相加,然后保存到v0寄存器,v3和v4代表調(diào)用函數(shù)的所使用的兩個(gè)參數(shù)。這里用到的Dalvik字節(jié)碼參數(shù)表示法是v命名法,另一種是p命名法。
Dalvik虛擬機(jī)運(yùn)行時(shí)同樣為每個(gè)線程維護(hù)一個(gè)PC計(jì)數(shù)器與調(diào)用棧,與Java虛擬機(jī)不同的是,這個(gè)調(diào)用棧維護(hù)一份寄存器列表,寄存器的數(shù)量在方法結(jié)構(gòu)體的registers字段中給出,Dalvik虛擬機(jī)會(huì)根據(jù)這個(gè)值來(lái)創(chuàng)建一份虛擬的寄存器列表。
Dalvik虛擬機(jī)由于生成的代碼指令減少了,程序執(zhí)行速度會(huì)更快一些。
?
?
?
Dalvik是如何執(zhí)行程序的
?
Android系統(tǒng)的架構(gòu)采用分層思想,這樣的好處是擁有減少各層之間的依賴性、便于獨(dú)立分發(fā)、容易收斂問(wèn)題和錯(cuò)誤等優(yōu)點(diǎn)。
Android系統(tǒng)由linux內(nèi)核、函數(shù)庫(kù)、Android運(yùn)行時(shí)、應(yīng)用程序框架以及應(yīng)用程序組成。
Android系統(tǒng)加載完內(nèi)核后,第一個(gè)執(zhí)行的是init進(jìn)程,init進(jìn)程對(duì)設(shè)備進(jìn)行初始化,讀取init.rc文件并啟動(dòng)系統(tǒng)中重要外部程序Zygote。
Zygote進(jìn)程是Android所有進(jìn)程的孵化器,啟動(dòng)后首先初始化Dalvik虛擬機(jī),然后啟動(dòng)system_server并進(jìn)入Zygote模式,通過(guò)socket等候命令。
當(dāng)執(zhí)行一個(gè)Android應(yīng)用程序時(shí),system_server進(jìn)程通過(guò)socket方式發(fā)送命令給Zygote,Zygote收到命令后通過(guò)fork自身創(chuàng)建一個(gè)Dalvik虛擬機(jī)的實(shí)例來(lái)執(zhí)行應(yīng)用程序的入口函數(shù),這就是程序啟動(dòng)的流程。
?
Zygote提供三種
fork(),創(chuàng)建一個(gè)Zygote進(jìn)程
forkAndSpecialize(),創(chuàng)建一個(gè)非Zygote進(jìn)程(不能再fork)
forkSystemService(),創(chuàng)建一個(gè)系統(tǒng)服務(wù)進(jìn)程(子進(jìn)程跟隨父進(jìn)程終止)
?
fork之后,執(zhí)行的工作交給Dalvik虛擬機(jī)。虛擬機(jī)通過(guò)loadClassFromDex()函數(shù)完成類的裝載工作,每個(gè)類被成功解析后會(huì)擁有一個(gè)ClassObject類型的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)在運(yùn)行時(shí)環(huán)境中,虛擬機(jī)使用gDvm.loadedClasses全局哈希表來(lái)存儲(chǔ)與查詢所有裝載進(jìn)來(lái)的類,隨后,字節(jié)碼驗(yàn)證器使用dvmVerifyCodeFlow()函數(shù)對(duì)裝入的代碼進(jìn)行校驗(yàn),接著虛擬機(jī)調(diào)用FindClass()函數(shù)查找并裝載main方法類,隨后調(diào)用dvmInterpret()函數(shù)初始化解釋器并執(zhí)行字節(jié)碼流。
?
Dalvik虛擬機(jī)執(zhí)行程序流程
虛擬機(jī)線程->裝載程序類->驗(yàn)證字節(jié)碼->查找主類->執(zhí)行字節(jié)碼流->結(jié)束
?
關(guān)于Dalvik虛擬機(jī)JIT
JIT是即時(shí)編譯(動(dòng)態(tài)編譯),是通過(guò)在運(yùn)行時(shí)將字節(jié)碼翻譯為機(jī)器碼的技術(shù),使得程序的執(zhí)行速度更快。
主流的JIT包含兩種字節(jié)碼編譯方式:
method方式:以函數(shù)或方法為單位進(jìn)行編譯。
trace方式:以trace為單位進(jìn)行編譯。
執(zhí)行代碼分為冷路徑(在實(shí)踐運(yùn)行過(guò)程中很少被執(zhí)行的)和熱路徑(執(zhí)行比較頻繁的路徑),method會(huì)編譯整個(gè)方法,trace編譯的是獲取的熱路徑的代碼,節(jié)省內(nèi)存。
?
?編輯參考:Android軟件安全與逆向分析
轉(zhuǎn)載于:https://www.cnblogs.com/zhaijiahui/p/8810887.html
總結(jié)
以上是生活随笔為你收集整理的Android逆向基础----Android Dalvik虚拟机的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: WPF richTextBox 滚动到某
- 下一篇: python如何打开一个大文件?