VMprotect静态跟踪 字节码反编译
文章目錄
- VMprotect靜態(tài)跟蹤
- (1)虛擬執(zhí)行特點:
- (2)執(zhí)行引擎的虛擬執(zhí)行
- (3)分析條件跳轉(zhuǎn)的兩條出邊
- 字節(jié)碼反編譯
- (1)中間表示語言
- (2)指令化簡和優(yōu)化
- **常數(shù)收縮:**
- **活躍變量分析:**
- **刪除無關(guān)代碼:**
- (3)轉(zhuǎn)換匯編指令——樹模式匹配
- (4)歸類映射寄存器
- (5)轉(zhuǎn)換匯編指令——動態(tài)規(guī)劃
- (6)寄存器染色
- **(一)基本塊內(nèi)的寄存器輪轉(zhuǎn):**
- **(二)基本塊間的寄存器輪轉(zhuǎn):**
- (三)寄存器的二義性問題
- Push\Pop的二義性:
- (四)識別寄存器的二義性步驟
VMprotect靜態(tài)跟蹤
(1)虛擬執(zhí)行特點:
允許讀寫靜態(tài)內(nèi)存與堆棧訪問
忽略其他內(nèi)存訪問與修改
解決了異常問題后,就可以從入口點一直虛擬執(zhí)行到出口了
(2)執(zhí)行引擎的虛擬執(zhí)行
分析虛擬機的一般傳統(tǒng)方法:
- 找到關(guān)鍵位置
- 動態(tài)執(zhí)行并使用記錄斷點記錄數(shù)據(jù)
- 輸出記錄日志
優(yōu)點:
- 尋找關(guān)鍵位置時間相對較短
缺點:
- 多路徑時只能走其中一條路徑
- 分析多個虛擬機時要重復(fù)做相同的工作
虛擬執(zhí)行方法:
- 虛擬執(zhí)行代碼
- 根據(jù)已分析字節(jié)碼靈活控制代碼
流程:
- 輸出記錄日志
優(yōu)點:
- 虛擬執(zhí)行不會對系統(tǒng)造成傷害
- 完整的字節(jié)碼流程
缺點:
- 指令正確但操作數(shù)的值不可靠
- 復(fù)雜度較高,開發(fā)時間較久
(3)分析條件跳轉(zhuǎn)的兩條出邊
因為虛擬執(zhí)行是不依賴運行時信息的,所以它無法判斷應(yīng)該走哪一條,必須把兩條邊都走過一遍。
- 在基本塊(BasicBlock)執(zhí)行前備份運行時環(huán)境
- 執(zhí)行到跳轉(zhuǎn)處分析指令流,獲得修改路徑關(guān)鍵點
- 退回基本塊起始位置
- 重新執(zhí)行并控制路徑
字節(jié)碼反編譯
(1)中間表示語言
VMP的Hanlder只能算是低級中間語言,缺少一些例如數(shù)據(jù)依賴,流程走向等信息,還不滿足反編譯的條件。需要將其轉(zhuǎn)換為包含更多信息的高級中間語言形式。
Push c Push b Add. d Pop EFL Pop A轉(zhuǎn)換后:
Stk1=push c Stk2=push b Stk3,Stk4=Add. d stk2,stk1 EFL=stk4 a=stk3轉(zhuǎn)換后:
Stk1=c Stk2=b Stk3,Stk4=Add. d stk2,stk1 EFL=stk4 A=stk3優(yōu)點:
(2)指令化簡和優(yōu)化
常數(shù)收縮:
Push 1A2FBCA0 Push F80499D8 Add. d Pop EFL采用常數(shù)收縮后:
Push 12345678活躍變量分析:
Stk0=Ctx24 Stk1=Ctx10 Stk2,EFL1=Add. d Stk0,Stk1 Ctx28=EFL1 Ctx30=Stk2 Stk3=Ctx30 Stk4=1111 Stk5,EFL2=Add. d Stk3,Stk4 Ctx28=EFL2 Ctx34=Stk5去除中間變量后:
Ctx30,Ctx28=Add. d Ctx24,Ctx10 Ctx34,Ctx28=Add. d Ctx30,1111去除無用變量后:
Ctx30=Add. d Ctx24,Ctx10 Ctx34,Ctx28=Add. d Ctx30,1111刪除無關(guān)代碼:
VMP在生成的字節(jié)碼中夾雜了一些自己的指令流,這些指令與原匯編代碼沒有任何關(guān)系,且對還原分析沒有任何好處,只會起到干擾的作用,需要根據(jù)特征制定一些規(guī)則來識別這些垃圾指令
(3)轉(zhuǎn)換匯編指令——樹模式匹配
匹配結(jié)果如下:
(4)歸類映射寄存器
經(jīng)過迭代后的最終結(jié)果是這樣:
Add Ctx30(Ctx24),Ctx10 Add Ctx34(Ctx30),1111雖然已經(jīng)轉(zhuǎn)換為匯編指令,但是還無法確定寄存器到底是哪一個,以目前所知的信息也的確無法判斷,步過,我們可以盡可能的確定一些信息,以供后面的分析參考。
在轉(zhuǎn)換規(guī)則中,預(yù)先明確定義了Add指令的第一個參數(shù)與結(jié)果是同一個寄存器(其他指令也是差不多,類似xchg的指令除外),所以可以推理得到,在指定的區(qū)別內(nèi)Ctx34,Ctx30,Ctx24,是同一個寄存器,這樣后面在專門針對寄存器識別的分析時,就可以一下確定這四個寄存器所映射的寄存器了
(5)轉(zhuǎn)換匯編指令——動態(tài)規(guī)劃
首先來看兩段指令
mov eax ,dword ptr[dei+0x100] add edi,100其中第一條里面包含了第二條的指令,第一條的權(quán)值應(yīng)該設(shè)得更高
add edi,100 Lea ebx,[edi+100]兩條指令僅僅是目標(biāo)寄存器不同,兩條指令的權(quán)值應(yīng)該相等
所謂動態(tài)規(guī)劃,通俗的講就是制定一些規(guī)則,根據(jù)實際情況來選擇最終匹配結(jié)果。
這里的意思是對每一個匹配規(guī)則設(shè)一個權(quán)值,使用計算后值最大的那個匹配規(guī)則來進行轉(zhuǎn)換
第二段的情況有些特殊,其中兩條指令唯一的不同只有目標(biāo)操作數(shù)。Add指令認(rèn)為目標(biāo)操作數(shù)與源操作數(shù)1相同,而lea指令無此限制。當(dāng)出現(xiàn)權(quán)值一樣的情況時,可以同時作為結(jié)果,在識別出寄存器后,再根據(jù)實際情況來匹配規(guī)則,在這兩個指令中選出更像的哪一個。
(6)寄存器染色
要識別前面所代表的寄存器,要從以下幾個方面進行分析:
從這三方面可以大體推理出各項所映射的寄存器
但僅僅是這樣的話只有在沒有跳轉(zhuǎn)指令的字節(jié)碼中,成功率才最高。因為還得考慮寄存器輪轉(zhuǎn)
(一)基本塊內(nèi)的寄存器輪轉(zhuǎn):
基本塊內(nèi)的寄存器輪轉(zhuǎn)比較容易簡單,只要轉(zhuǎn)換規(guī)則正確,就可以識別出寄存器
(二)基本塊間的寄存器輪轉(zhuǎn):
在執(zhí)行set.jmp之前,將Context中所有位置的值都臨時存放到了堆棧中,跳向目標(biāo)地址后又再全部把它彈出到不同位置中去,這樣就完成了一次輪換
它比基本塊內(nèi)的寄存器輪轉(zhuǎn)更麻煩,因為其中涉及到了二義性的問題
(三)寄存器的二義性問題
寄存器的二義性問題是一個很嚴(yán)肅的問題,因為如果不能正確分析和處理,將會在成一子放錯,滿盤皆輸?shù)木置妗?br /> 寄存器的二義性由指令的二義性衍生出,要解決指令的二義性,需要先解決寄存器的二義性問題。
Push\Pop的二義性:
Push\Pop在VMP中存在一種二義性,即傳值與傳引用。
傳值:
當(dāng)pop指令的作用是傳值時,表示員項中國的值放到目標(biāo)項中去,所映射的寄存器不變。
傳引用:
當(dāng)pop指令的作用是傳引用時,不但將值從源項放到目標(biāo)項中去,且目標(biāo)項所映射的寄存器也將被覆蓋
傳值是一般情況,即匯編指令的Push\Pop指令時,傳引用時特殊情況,如寄存器輪換等。
Add與Lea等其他指令的二義性:
這兩條指令廣義上講也是Push\Pop的二義性:
為Add指令時,pop指令的含義為傳引用
為Lea指令時,pop指令的含義為傳值
(四)識別寄存器的二義性步驟
總結(jié)
以上是生活随笔為你收集整理的VMprotect静态跟踪 字节码反编译的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VMprotect简介
- 下一篇: 逆向寒假生涯(27/100)