日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

彻底弄懂dalvik字节码【三】

發布時間:2025/3/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 彻底弄懂dalvik字节码【三】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【一】、【二】中從代碼的角度分析了dalvik字節碼解釋執行的過程,這篇文章以一個例子來實際分析一下。

我們以這篇文章中提到的crackme為例,下載鏈接參見那篇文章。我們只分析dalvik字節碼,因此忽略so。

0x01:

使用Jeb打開crackme.apk,找到MainActivity的onCreate方法,其smali內容是:

.method protected onCreate(Bundle)V.registers 5.param p1, "savedInstanceState".prologue 00000000 invoke-super AppCompatActivity->onCreate(Bundle)V, p0, p1 00000006 const v2, 0x7F040019 0000000C invoke-virtual MainActivity->setContentView(I)V, p0, v2 00000012 const v2, 0x7F0C0050 00000018 invoke-virtual MainActivity->findViewById(I)View, p0, v2 0000001E move-result-object v1 00000020 check-cast v1, EditText.local v1, txt:Landroid/widget/EditText; 00000024 const v2, 0x7F0C0051 0000002A invoke-virtual MainActivity->findViewById(I)View, p0, v2 00000030 move-result-object v0 00000032 check-cast v0, Button.local v0, btn:Landroid/widget/Button; 00000036 sget-boolean v2, MainActivity->$assertionsDisabled:Z 0000003A if-nez v2, :4E :3E 0000003E if-nez v0, :4E :42 00000042 new-instance v2, AssertionError 00000046 invoke-direct AssertionError-><init>()V, v2 0000004C throw v2 :4E 0000004E new-instance v2, MainActivity$1 00000052 invoke-direct MainActivity$1-><init>(MainActivity, EditText)V, v2, p0, v1 00000058 invoke-virtual Button->setOnClickListener(View$OnClickListener)V, v0, v2 0000005E return-void .end method

smali 對于Android,可以理解為匯編對于C。smali中定義了一套完整的dalvik操作碼(類似于匯編的指令集),構成了dalvik虛擬機最核心的部分。

字節碼是二進制的,這些二進制通過一定的方式可以被解釋成為smali指令。我們來看看這個過程。

0x02:

使用010editor打開crackme.apk中的classes.dex,應用dex模板,結果如下:


dex文件格式參見這篇文章

我們分析的目標是MainActivity的onCreate方法,直接找到它:



因為onCreate是重寫的父類方法,所以在virtual_methods中,我們看到這個方法需要5個寄存器,2個參數,3個內部方法調用參數,48條指令。字節碼在insns中。

0x03:

下面進入對字節碼的分析,在【二】中分析方法執行時, dvmInterpretPortable的最后一個語句:

FINISH(0); /* fetch and execute first instruction */

即為定位到insns的起始處,并取2個字節的內容放置到inst變量中,之后取出inst的低字節數值作為handlerTable數組的索引號,然后跳轉到對應符號去執行。

代碼上的跟蹤比較繁瑣,好在google有相關的文檔:【Dalvik bytecode】、【Dalvik Executable instruction formats】,我們根據文檔來分析。

在這個例子中,第一個“兩字節”是:6F 20, 其低字節是6F,代表著handlerTable數組的索引號,查詢文檔:


表示操作符是invoke-super。

查看OP_INVOKE_SUPER.cpp,里面有對此指令的執行過程:

HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)GOTO_invoke(invokeSuper, false); OP_END

其中:

# define HANDLE_OPCODE(_op) op_##_op: OP_INVOKE_SUPER = 0x6f, #define GOTO_invoke(_target, _methodCallRange) \do { \methodCallRange = _methodCallRange; \goto _target; \} while(false)

翻譯一下就是:

op_0x6f:do{methodCallRange = false;goto invokeSuper;}while(false)

invokeSuper在gotoTargets.cpp中定義:

GOTO_TARGET(invokeSuper, bool methodCallRange){Method* baseMethod;u2 thisReg;EXPORT_PC();vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ref = FETCH(1); /* method ref */vdst = FETCH(2); /* 4 regs -or- first reg */if (methodCallRange) {ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",vsrc1, ref, vdst, vdst+vsrc1-1);thisReg = vdst;} else {ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);thisReg = vdst & 0x0f;}... //此處省略后后面的內容

其中:

#define GOTO_TARGET(_target, ...) _target:#define GOTO_TARGET_END

翻譯一下就是:

invokeSuper:{Method* baseMethod;u2 thisReg;EXPORT_PC();vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ref = FETCH(1); /* method ref */vdst = FETCH(2); /* 4 regs -or- first reg */if (methodCallRange) {ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",vsrc1, ref, vdst, vdst+vsrc1-1);thisReg = vdst;} else {ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);thisReg = vdst & 0x0f;}... //此處省略后后面的內容

這樣就找到了invokeSuper真正執行的地方了,可以看到,依然是解析字節碼和獲取新字節碼解析的過程。代碼跟蹤同樣比較復雜,我們直接看文檔:


從圖中可以看出6f的格式是35c(后面會用到),語法格式為:

invoke-*kind*{vC, vD, vE, vF, vG}, meth@BBBB

其中的A、B、C的解釋在后面一列有說明,光看這個還不能看懂,看一下35c:


這個文檔我一開始也看得不是太懂,簡單的還能對應起來,復雜的(現在這個例子)就搞不清楚了,文檔只能理解個大概,最后我選擇看代碼。這里直接說我看代碼看明白的:

首先 6F 20 中的 6F表示操作碼,20又分兩個4位來解釋,2表示寄存器的數量,0代表啥還沒有看明白:(,隨后的兩個字節 47 2A 表示的是method id,47 2A 表示數值是0x2A47,即10823,如圖:


所以我們大概明白了:

invoke-super AppCompatActivity->onCreate(Bundle)V

隨后的兩個字節 43 00 也是需要被解析的,是用來確定寄存器標號的,至于怎么映射為 p0 p1,我也沒有看懂(代碼在gotoTargets.cpp的GOTO_TARGET(invokeSuper, bool methodCallRange)中,歡迎有興趣的同學繼續研究并加微信交流)。

0x04:

至此,我們分析完第一條指令的字節碼解釋過程了。在源碼中,你可以看到,它不光是解釋成smali這么簡單,它真正的去尋找父類的onCreate方法,構造函數堆棧并進行調用。
pc指針隨著執行過程不斷往后移動,當方法返回后,繼續去下一個“兩字節”進行解釋執行。這個例子中的下一個“兩字節"是14 02,其中14為操作碼,如圖:


可以看到是const vAA, #+BBBBBBBB,和我們在Jeb中看到的const v2, 0x7F040019能夠對上。后續的過程和前面完全一致,只是處理的是不同的操作碼而已。

0x05:

至此,此系列文章結束。其中有一些細節我也沒有弄得很清楚(回頭弄明白再來更新),但是大致流程已經清晰了。歡迎有興趣的同學在此基礎上繼續研究,可以加我微信進行交流。微信見首頁二維碼。



作者:difcareer
鏈接:http://www.jianshu.com/p/aba1f966d7f2
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

總結

以上是生活随笔為你收集整理的彻底弄懂dalvik字节码【三】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。