此文章是我學(xué)習(xí)VMProtect2.04加殼程序的心得。在調(diào)試的過程中,尤其是初期,參考和查閱了N多的網(wǎng)絡(luò)資料,在此一并表示感謝。在計算機書中,最著名的兩類書名當(dāng)屬:XXXX從入門到精通和21天學(xué)會XXXX,我在仔細思考,最終覺得還是前者比較有吸引力。OD的UDD文件的使用,在D:盤下新建文件夾Unpack,把加殼記事本放入文件夾內(nèi),把UDD文件放入OD的UDD文件夾內(nèi)。OD打開加殼記事本后,UDD文件會自動生效。
聲明:本文在非盈利性用途可自由傳播。
軟件:正版VMProtect2.04加密的Win98記事本
加密選項:除了 編譯--調(diào)試模式與水印 以外,全部打鉤;虛擬計算機--數(shù)量為默認值1;編譯類型:超級(變異+虛擬)
調(diào)試器:官網(wǎng)下載的OllyDbg2.0
加殼程序下載:NOTEPAD.rar下載此附件需要消耗2Kx,下載中會自動扣除。
UDD文件:NOTEPAD-udd.rar下載此附件需要消耗2Kx,下載中會自動扣除。(這是是整理了偽指令的UDD文件,后續(xù)還會更新)
本文的結(jié)構(gòu):
序言
文章簡介
1.基礎(chǔ)知識
1.1.VMProtect虛擬機簡介
1.2.VM堆棧
1.3.偽指令匯總
2.綜合運用
2.1.常見偽指令組合
2.2.NAND(與非門)
2.3.EFLAGS標志位檢測+跳轉(zhuǎn)
3.NOTEPAD全程跟蹤
3.1.TLS
3.2.VMP外殼函數(shù)獲取
3.3.虛擬執(zhí)行環(huán)境與調(diào)試器檢測
3.4.HASH值分塊檢測與API獲取
3.5.重點解密循環(huán)
4.實驗室(暫定)
尾聲
1.基礎(chǔ)知識
1.1.VMProtect虛擬機簡介
虛擬機加密,是指像VMP這樣的保護程序,它會把源程序的X86指令變成自定義的偽指令,等到執(zhí)行的時候,VMP內(nèi)置在保護程序中的VM就會啟動,讀取偽指令,然后解析執(zhí)行。
VMP是一個堆棧虛擬機,它的一切操作都是基于堆棧傳遞的。在VMP中,每一個偽指令就是一個handler,VM中有一個核心的Dispatch部分,它通過讀取程序的bytecode,然后在DispatchiTable里面定位到不同的handler中執(zhí)行。絕大多數(shù)情況下,在一個handler中執(zhí)行完成后,程序?qū)⒒氐紻ispatch部分,然后到next handler中執(zhí)行。
http_imgload.jpg下載此附件需要消耗2Kx,下載中會自動扣除。
在上面的框架中,核心的部件就是Dispatch部分,下面并列的部件就是handlers。
經(jīng)過VMP加密的X86指令,一條簡單的指令被分解成數(shù)條VMP的偽指令,它按照自己的偽指令排列去實現(xiàn)原指令的功能,在加上其他的花指令混亂等等,你將完全看不到源程序指令。VMP自帶的各種機制都不再是以X86指令的形式去實現(xiàn),而是用自己的偽指令去測試。
在VMP的VM運行過程中,各個寄存器的基本用途是:EBP和EDI是VM堆棧指針(不是常規(guī)的堆棧);ESI是偽指令指針(相當(dāng)于常規(guī)的EIP);EAX是VM解密數(shù)據(jù)的主運算寄存器;EBX是VM解密數(shù)據(jù)的輔運算寄存器;ECX是常規(guī)的循環(huán)計數(shù)器;ESP是常規(guī)的堆棧棧頂指針。EDX是讀取偽指令表數(shù)據(jù);
EDI、EBP分別指向VM堆棧的上下限位置,EBP指向堆棧的下限并向上發(fā)展,EDI指向堆棧的上限并使用[EDI+EAX]的方式向下發(fā)展;ESI指向的內(nèi)存塊里包括要執(zhí)行的偽指令序列,而不同的是,當(dāng)VM要是使用到立即數(shù)時,也是從ESI讀取?梢奅SI內(nèi)存塊里面是精心構(gòu)建的數(shù)據(jù)塊,只有VM自身執(zhí)行過程中,才能知道下一個數(shù)據(jù)是代表偽指令還是立即數(shù);在VM運算中EAX寄存器很多時候通常只有AL參與運算然后在存取時再以AX或EAX得方式存;EBX在很多加密數(shù)據(jù)運算中,都會參與到EAX值的計算中,協(xié)助運算中正確的值。而每次EAX的值運算結(jié)束后,反過來會計算好下一次運算中EBX的值。所以EBX的數(shù)據(jù)一旦出錯,下一個數(shù)據(jù)解密必然錯誤;在VM運行中,通常一切操作都是在VM堆棧內(nèi)完成的,所以絕大多數(shù)情況下對ESP的操作都是花指令或junk code。在一些虛擬與現(xiàn)實(比如說調(diào)用系統(tǒng)函數(shù))交接的地方,系統(tǒng)并不知道VM堆棧的存在,這就需要把數(shù)據(jù)(比如系統(tǒng)函數(shù)的調(diào)用參數(shù))移動到常規(guī)ESP棧頂。EDX是一個較少使用的寄存器,只在一些解密循環(huán)里面參與運算。而它的一個主要的運用是在DISPATCH部件里,根據(jù)ESI的值來獲取DispatchTable的數(shù)據(jù),讓VM執(zhí)行下一條偽指令。
1.2.VM堆棧
VMP的VM是基于堆棧的虛擬家,理解好VM的堆?臻g劃分和操作,是理解整個VM運行的基礎(chǔ)。
VMProtect2.04加殼程序是從TLS開始運行的,我們首先點擊OD的options菜單,修改Startup and exit選項,讓OD中斷在TLS callback里。加殼程序運行后,VMP初始化VM,并進入DISPATCH部分。這里我們就以初始化后的堆棧為例。
VM的堆棧一共使用61個DWORD,上下分別有2個堆棧指針,下面為EBP指針,上面為EDI指針。下面是VM初始化時,給EDI和EBP指針賦值后的堆棧。
EDI=0013F8BC
EBP=0013F9B0
CPU Stack
Locked Value ASCII Comments
0013F8BC 009539E8 9. ;這里是EDI指向
0013F8C0 00950000 ...
0013F8C4 00150000 ...
0013F8C8 00000080 ...
0013F8CC 019314D6
0013F8D0 0013F8A8 .
0013F8D4 7C92E920 |
0013F8D8 00000000 ....
0013F8DC 00000000 ....
0013F8E0 00000000 ....
0013F8E4 FFFFFFFF
0013F8E8 7C98FEFF |
0013F8EC 7C00ADE7 .|
0013F8F0 00000000 ....
0013F8F4 00150000 ...
0013F8F8 0013F6F0 .
0013F8FC 0013F940 @.
0013F900 0013F944 D.
0013F904 7C92E920 |
0013F908 7C9301E0 |
0013F90C FFFFFFFF
0013F910 7C9301DB |
0013F914 7C9314D6 |
0013F918 7C931514 |
0013F91C 7C99E120 |
0013F920 7C9314EA |
0013F924 5ADF1158 XZ
0013F928 00000001 ...
0013F92C 00000000 ....
0013F930 7FFDA000 .
0013F934 7FFDF000 .
0013F938 00158070 p.
0013F93C 0013F890 .
0013F940 00000000 ....
0013F944 0043D759 YC.
0013F948 0000E9ED ..
0013F94C 409B0002 .@
0013F950 00000020 ...
0013F954 0013F9CC .
0013F958 0013F96C l.
0013F95C 0043E9ED C.
0013F960 000359F4 Y.
0013F964 00000020 ...
0013F968 004253CD SB.
0013F96C 409B0000 ..@
0013F970 00000020 ...
0013F974 0013F9CC .
0013F978 0013F98C .
0013F97C 00000000 .... ;這里是EBP指向
0013F980 00000000 .... ;這里是VM初始化保存的各個寄存器
0013F984 00000246 F..
0013F988 000359F4 Y.
0013F98C 00000020 ...
0013F990 00000000 ....
0013F994 0013F9CC .
0013F998 004253CD SB.
0013F99C 000359F4 Y.
0013F9A0 00400000 ..@.
0013F9A4 0013F9C0 .
0013F9A8 C456C619 V ;這里是VMP的2個加密數(shù)據(jù)
0013F9AC 2EF6420A .B.
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;這里是TLS進來時的棧頂
關(guān)于2個加密數(shù)據(jù)和初始化的過程我們后續(xù)來說,這里我們主要關(guān)注VM的堆棧劃分。
我把上面的EDI指向的堆棧稱為EDISTACK,把EBP指向的堆棧稱為EBPSTACK。在VM中,EBPSTACK是運算區(qū),各類數(shù)據(jù)的運算操作在這里完成;EDISTACK是存儲區(qū)包括長期存儲數(shù)據(jù)和臨時存儲EBPSTACK的運算數(shù)。
下面我們來看一條數(shù)據(jù)移動偽指令:
命名:
VM_MOVdw_EDISTACKdw_EBPSTACKdw
代碼:
0043DC19 |. F6D8 NEG AL ; *
0043DC26 |. C0C8 07 ROR AL,7 ; *
0043DC34 |. 2C 20 SUB AL,20 ; *
0043DC41 |. 24 3C AND AL,3C ; *
0043E080 |$ 8B55 00 MOV EDX,DWORD PTR SS:[EBP] ; *
0043E086 |. 83C5 04 ADD EBP,4 ; *
0043D3D7 /> /891438 MOV DWORD PTR DS:[EDI+EAX],EDX ; *
功能:
把1個dword的數(shù)據(jù)從EBPSTAK棧頂移動到EDISTACK,使用EAX作為偏移量
在EDISTACK的數(shù)據(jù)移動中,使用[EDI+EAX]的方式來存儲與獲取各個值。通過計算不同的EAX的值,可以到達EDISTACK中不同位置。在計算EAX值時,實際真正計算的是AL的值,我們來考慮一下AL的最小值和最大值,AL=00時[EDI+EAX]=[0013F8BC+00000000]=0013F8BC,AL=FF時[EDI+EAX]=[0013F8BC+000000FF]=0013F9BB,這是使用[EDI+EAX]可以讀取的上下限。但是,在VM的AL值計算過程中,最后有一條AND AL,0x3C指令,0x3C=00111100bit由于這條指令的限制,無論AL為任何值(從00000000bit到11111111bit),通過AND操作,只能有1111bit的活動空間大小,1111bit相當(dāng)于16,所以EDISTACK最多可以讀取16個dword;由于00111100bit最后兩個00位的限制,任何數(shù)字與它AND后,后兩位都必然為0,變成與4對齊的值,說明VM都是按照0013F8BC 0013F8C0 0013F8C4 0013F8C8這樣的4對齊來讀取。在讀取時,VM可以讀取byte word dword,但是VM將不會去讀取0013F8BE。
由于EDISTACK堆棧向下發(fā)展,EBPSTACK堆棧向上發(fā)展,EDISTACK有0x3C控制著范圍,而EBPSTACK是操作區(qū),沒有硬性的范圍控制。為了預(yù)防兩個空間相撞,在每次往EBPSTACK移動數(shù)據(jù)后,VM都有相應(yīng)的邊界檢測指令如下:
0043CE5A |. 8D47 50 LEA EAX,[EDI+50] ; *
0043EE5D |. 39C5 CMP EBP,EAX ; *
0043F08C |.^\0F87 29F6FFFF JA 0043E6BB ; *
比較結(jié)果 大于 ,這個正常的情況,在這個VM跟蹤過程中,我沒有發(fā)現(xiàn)一次小于的情況。如果小于,也就是EBPSTACK棧頂已經(jīng)到達[EDI+50]位置,VM將會重新分配堆?臻g。0x50的偏移量比0x3C的偏移量多5個dword的緩沖區(qū)。我們來手動修改EBP指針,看看VM的對于兩個堆棧空間即將相撞的處理情況:
CPU Disasm
Address Hex dump Command Comments
0043F092 |. 52 PUSH EDX ;
0043D6C1 |. 8D5424 08 LEA EDX,[ARG.2] ; *EDX獲得的是原來EDI指針地址0013F8BC
0043DF38 |. 8D4F 40 LEA ECX,[EDI+40] ; *0x40的偏移量是0x3C的偏移量數(shù)據(jù)1個dword結(jié)束后的位置
0043DF46 |. 29D1 SUB ECX,EDX ; *減法計算出數(shù)據(jù)存儲量
0043DF4B |. 8D45 80 LEA EAX,[EBP-80] ; *增加0x80的空間
0043DF5C |. 24 FC AND AL,FC ; *按4對齊
0043DF68 |. 29C8 SUB EAX,ECX ; *在增加原來數(shù)據(jù)大小的堆?臻g
0043DF6E |. 89C4 MOV ESP,EAX ; *
0043DF7E |. 56 PUSH ESI ; |Arg1 = NOTEPAD.425748, *
0043DF87 |. 89D6 MOV ESI,EDX ; |*
0043DB3A /$ 8D7C01 C0 LEA EDI,[EAX+ECX-40] ; *
0043EC1E . 89C7 MOV EDI,EAX ; *
0043EEED |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ ; *移動原來EDISTACK中存儲的數(shù)據(jù)
0043EEF7 |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10] ; *
0043EEFF |. 8B7424 10 MOV ESI,DWORD PTR SS:[ESP+10] ; *
這里我們可以看到,每次發(fā)現(xiàn)兩個堆?臻g即將相撞,VM都重新給EBP分配堆棧,并把原來EDISTACK存儲的數(shù)據(jù)移動到新的空間內(nèi)。
下面是使用OD跟蹤VM堆棧的幾個小技巧:
在OD中跟蹤VM數(shù)據(jù)移動時,雙擊0013F8BC地址,OD將會以0013F8BC為基址,顯示上下各個地址與它的偏移量,如圖:
CPU Stack
Locked Value ASCII Comments
$-C 759D0000 ..u
$-8 00000001 ...
$-4 0013F8FC .
$ ==> 009539E8 9. ;這里是0013F8BC,雙擊后的效果
$+4 00950000 ...
$+8 00150000 ...
$+C 00000080 ...
$+10 019314D6
在跟蹤VM時,在數(shù)據(jù)移動偽指令中的AND AL,0x3C的下一條指令下斷點,這樣每次進行數(shù)據(jù)移動,你都可以在這個斷點看到,數(shù)據(jù)的去向和來源,這是極其有用的。在很多復(fù)雜的運算地方,你需要在草稿紙上記下,EDISTACK中一些空間的數(shù)據(jù)時來自于什么時候?比如標志位ZF檢測+跳轉(zhuǎn)是VM的一個重要操作,而EFLAGS標志數(shù)都是相差不多或類似的00000286 00000246等等,如果你不能準確知道[EDI+EAX]存儲或讀取的位置,你將無法理解VM的操作。這非常的重要,請牢記!必要時連OD得數(shù)據(jù)窗口也一起配合顯示VM堆棧
把OD里的堆棧窗口拉高,讓它竟可能多的顯示數(shù)據(jù),在高分辨率的電腦上,最好是能夠顯示出整個VM的堆棧。默認情況下,堆棧窗口是隨著ESP指針的變化而自動顯示的,這對于我們要時刻盯著VM堆棧的需求不相符,在堆棧窗口-->右鍵-->Lock address 打鉤,這樣OD就會鎖定堆棧窗口。
到這里,關(guān)于堆?臻g的介紹就結(jié)束了。對堆棧的理解是本文的根基。
1.3.偽指令匯總
調(diào)試VMP前期的一個重要的體力活是,識別出所有的偽指令,并根據(jù)它的用途給它相應(yīng)的命名。以后就可以在DISPATCH部件的最后跳轉(zhuǎn)地址:
0043E11F |. C2 5000 RETN 50
下斷點,再盯著VM堆棧就可以知道VM的所有操作。
我們先來了解所有偽指令的DISPATCH(調(diào)遣)部件:
0043E6BF |. 8A46 FF MOV AL,BYTE PTR DS:[ESI-1] ; *
0043E6C4 |. 30D8 XOR AL,BL ; *
0043E6CE |. F6D0 NOT AL ; *
0043E6D6 |. FEC8 DEC AL ; *
0043E6DA |. C0C8 07 ROR AL,7 ; *
0043E6E1 |. 83EE 01 SUB ESI,1 ; *
0043E6ED |. 30C3 XOR BL,AL ; *
0043D02F |. 0FB6C0 MOVZX EAX,AL ; *
0043F124 |. 8B1485 DBE143 MOV EDX,DWORD PTR DS:[EAX*4+43E1DB] ; *
0043E100 |> /81C2 6B197FB6 ADD EDX,B67F196B ; *
0043E10A |. 895424 3C MOV DWORD PTR SS:[ESP+3C],EDX ; *
0043E11B |. FF7424 4C PUSH DWORD PTR SS:[ESP+4C] ; *
0043E11F |. C2 5000 RETN 50
首先從ESI中解密獲得下一條偽指令在DispatchTable(調(diào)遣表)中的偏移量,使用[EAX*4+43E1DB]來讀取出偽指令地址,簡單的ADD解密后,把真正的偽指令地址壓入ESP棧頂,最后用RETN 50跳轉(zhuǎn)到相應(yīng)的偽指令。
MOV EDX,DWORD PTR DS:[EAX*4+43E1DB]給我們提供的信息:DispatchTable的起始地址是0043E1DB,最后一個dword的開始地址是以AL的最大值FF作為偏移量[FF*4+43E1DB]=0043E5D7。我們把記事本0043E1DB--0043E5D7的數(shù)據(jù)粘貼:
CPU Dump
Address Hex dump ASCII
0043E1D0 09|BA C4 49 D0| .I
0043E1E0 BA C4 49 1E|B7 C4 49 E6|C4 C4 49 53|D1 C4 49 05| IIISI
0043E1F0 BE C4 49 75|D1 C4 49 D4|CE C4 49 0C|D6 C4 49 C3| IuII.I
0043E200 BD C4 49 7B|CE C4 49 67|BE C4 49 26|BF C4 49 EB| I{IgI&I
0043E210 C2 C4 49 82|D0 C4 49 3A|BA C4 49 1E|B5 C4 49 A8| II:II
0043E220 C4 C4 49 1E|B5 C4 49 2E|C8 C4 49 B9|BB C4 49 E9| II.II
0043E230 C3 C4 49 2D|B8 C4 49 95|C1 C4 49 82|D0 C4 49 75| I-IIIu
0043E240 D1 C4 49 C3|BE C4 49 16|B6 C4 49 2D|B8 C4 49 75| I鎂II-Iu
0043E250 D1 C4 49 95|C1 C4 49 EB|C2 C4 49 52|BF C4 49 B4| IIIRI
0043E260 D3 C4 49 8B|D3 C4 49 05|CE C4 49 52|BF C4 49 D4| IIIRI
0043E270 CE C4 49 E8|B8 C4 49 C3|BD C4 49 C3|BE C4 49 5E| II媒I鎂I^
0043E280 B4 C4 49 B1|B8 C4 49 61|BD C4 49 5D|BF C4 49 E9| IIaI]I
0043E290 C3 C4 49 26|BF C4 49 5F|D0 C4 49 B4|D3 C4 49 E6| I&I_II
0043E2A0 C4 C4 49 EC|B7 C4 49 1E|B5 C4 49 0D|C0 C4 49 0D| III.I.
0043E2B0 C0 C4 49 C3|BD C4 49 5D|BF C4 49 7B|CE C4 49 C3| I媒I]I{I
0043E2C0 BD C4 49 1E|B5 C4 49 82|D0 C4 49 8A|B9 C4 49 A6| IIII
0043E2D0 D1 C4 49 EB|C2 C4 49 D4|CE C4 49 61|BD C4 49 09| IIIaI.
0043E2E0 BA C4 49 53|D1 C4 49 61|BD C4 49 3A|BA C4 49 3A| ISIaI:I:
0043E2F0 D0 C4 49 0C|D6 C4 49 3A|BA C4 49 1E|B7 C4 49 05| I.I:II
0043E300 CE C4 49 0D|C0 C4 49 82|D0 C4 49 27|D2 C4 49 7C| I.II'I|
0043E310 BD C4 49 E8|B8 C4 49 41|C2 C4 49 E9|C3 C4 49 25| IIAII%
0043E320 CE C4 49 53|C6 C4 49 61|BD C4 49 53|C6 C4 49 83| ISIaISI
0043E330 D6 C4 49 53|C6 C4 49 5D|BF C4 49 53|C6 C4 49 A8| ISI]ISI
0043E340 C4 C4 49 53|C6 C4 49 5F|D0 C4 49 53|C6 C4 49 E6| ISI_ISI
0043E350 C4 C4 49 53|C6 C4 49 3A|BA C4 49 53|C6 C4 49 00| ISI:ISI.
0043E360 C7 C4 49 53|C6 C4 49 2D|B8 C4 49 53|C6 C4 49 25| ISI-ISI%
0043E370 CE C4 49 53|C6 C4 49 83|D6 C4 49 53|C6 C4 49 1E| ISIISI
0043E380 B7 C4 49 53|C6 C4 49 C3|BD C4 49 53|C6 C4 49 62| ISI媒ISIb
0043E390 CF C4 49 53|C6 C4 49 12|D3 C4 49 53|C6 C4 49 E8| ISIISI
0043E3A0 B8 C4 49 05|CE C4 49 1E|B7 C4 49 8A|B9 C4 49 B4| IIII
0043E3B0 D3 C4 49 B9|BB C4 49 A6|D1 C4 49 E8|B8 C4 49 FE| IIII
0043E3C0 C0 C4 49 82|D0 C4 49 53|D1 C4 49 2D|B8 C4 49 52| IISI-IR
0043E3D0 BF C4 49 3A|D0 C4 49 C3|BE C4 49 A6|C1 C4 49 C3| I:I鎂II
0043E3E0 BE C4 49 5E|B4 C4 49 82|D0 C4 49 7C|BD C4 49 C3| I^II|I
0043E3F0 BD C4 49 C3|BE C4 49 1E|B7 C4 49 61|BD C4 49 A6| I鎂IIaI
0043E400 C1 C4 49 82|D0 C4 49 12|D3 C4 49 FE|C0 C4 49 25| IIII%
0043E410 CE C4 49 0C|D6 C4 49 09|BA C4 49 2E|C8 C4 49 67| I.I.I.Ig
0043E420 BE C4 49 8A|B9 C4 49 EB|C2 C4 49 D4|CE C4 49 95| IIII
0043E430 C1 C4 49 D1|C7 C4 49 09|BA C4 49 00|C7 C4 49 B9| II.I.I
0043E440 BB C4 49 D1|C7 C4 49 B4|D3 C4 49 5E|B4 C4 49 D1| III^I
0043E450 C7 C4 49 A8|C4 C4 49 A6|C1 C4 49 12|D3 C4 49 B4| IIII
0043E460 D3 C4 49 D0|BA C4 49 41|C2 C4 49 82|D0 C4 49 B1| I瀉IAII
0043E470 B8 C4 49 1E|B5 C4 49 27|D2 C4 49 82|D0 C4 49 75| II'IIu
0043E480 D1 C4 49 5E|B4 C4 49 25|CE C4 49 16|B6 C4 49 7B| I^I%II{
0043E490 CE C4 49 7C|BD C4 49 EB|C2 C4 49 27|D2 C4 49 83| I|II'I
0043E4A0 D6 C4 49 12|D3 C4 49 2E|C8 C4 49 1E|B5 C4 49 E6| II.II
0043E4B0 C4 C4 49 C3|BD C4 49 95|C1 C4 49 1E|B5 C4 49 EC| I媒III
0043E4C0 B7 C4 49 B9|BB C4 49 5F|D0 C4 49 83|D6 C4 49 8A| II_II
0043E4D0 B9 C4 49 A6|C1 C4 49 D4|CE C4 49 8B|D3 C4 49 0D| IIII.
0043E4E0 C0 C4 49 E8|B8 C4 49 2D|B8 C4 49 61|BD C4 49 82| II-IaI
0043E4F0 D0 C4 49 12|D3 C4 49 1E|B5 C4 49 7C|BD C4 49 D1| III|I
0043E500 C7 C4 49 7C|BD C4 49 05|CE C4 49 A6|C1 C4 49 5F| I|III_
0043E510 D0 C4 49 1E|B7 C4 49 7B|CE C4 49 0C|D6 C4 49 05| II{I.I
0043E520 BE C4 49 9F|C2 C4 49 B9|BB C4 49 9F|C2 C4 49 D4| IIII
0043E530 CE C4 49 9F|C2 C4 49 EC|B7 C4 49 9F|C2 C4 49 62| IIIIb
0043E540 CF C4 49 9F|C2 C4 49 2D|B8 C4 49 9F|C2 C4 49 0C| II-II.
0043E550 D6 C4 49 9F|C2 C4 49 0D|C0 C4 49 9F|C2 C4 49 05| II.II
0043E560 BE C4 49 9F|C2 C4 49 C3|BD C4 49 9F|C2 C4 49 53| II媒IIS
0043E570 D1 C4 49 9F|C2 C4 49 75|D1 C4 49 9F|C2 C4 49 05| IIuII
0043E580 CE C4 49 9F|C2 C4 49 75|D1 C4 49 9F|C2 C4 49 27| IIuII'
0043E590 D2 C4 49 9F|C2 C4 49 09|BA C4 49 9F|C2 C4 49 B9| II.II
0043E5A0 B5 C4 49 E6|C4 C4 49 09|BA C4 49 8B|D3 C4 49 25| II.II%
0043E5B0 CE C4 49 0D|C0 C4 49 B9|B5 C4 49 E9|C3 C4 49 12| I.III
0043E5C0 D3 C4 49 FE|C0 C4 49 05|CE C4 49 83|D6 C4 49 0D| IIII.
0043E5D0 C0 C4 49 EC|B7 C4 49 D0|BA C4 49 II瀉I
雖然DispatchTable的數(shù)據(jù)很多,但是很多不同的偏移量指向的相同的數(shù)據(jù),這是一種保護方式。我們反過來想,如果DispatchTable中每個dword指向的是不同的偽指令,這就意味著每個EAX偏移量指向著唯一的一條偽指令,進一步的來說就是每個ESI值代表著唯一的一條偽指令。那么,如果有人逆向這個算法,就可以知道每個ESI值對應(yīng)的是哪個偽指令,這樣就可以直接讀取ESI值而了解VMP的執(zhí)行偽指令,基本等于半自動識別VMP。一名對VMP經(jīng)驗豐富的人,只要看著VM執(zhí)行的偽指令盯著EBPSTACK堆棧,就可以理解VM的情況,F(xiàn)在,由于多個ESI值指向相同的偽指令,還有動態(tài)EBX解碼,將會艱難的多。
我們在OD中尋找一個空間,寫一段循環(huán)代碼,把DispatchTable的數(shù)據(jù)全部解密出來:
原來的代碼:
0043F11F \38F5 CMP CH,DH
0043F121 66:FFC2 INC DX
0043F124 8B1485 DBE14300 MOV EDX,DWORD PTR DS:[EAX*4+43E1DB] ; *
0043F12B F9 STC
0043F12C 84F4 TEST AH,DH
0043F12E 60 PUSHAD
0043F12F ^ E9 CC5EFCFF JMP 0043E100
把最后一條指令修改為:
0043F12F ^\E9 CC5EFCFF JMP 00405000
在00405000添加循環(huán)代碼:
CPU Disasm
Address Hex dump Command Comments
00405000 60 PUSHAD
00405001 BE DBE14300 MOV ESI,0043E1DB ; DispatchTable地址
00405006 BF 00514000 MOV EDI,00405100 ; 解密循環(huán)地址
0040500B B9 00010000 MOV ECX,100
00405010 31DB XOR EBX,EBX
00405012 8B0433 MOV EAX,DWORD PTR DS:[ESI+EBX]
00405015 05 6B197FB6 ADD EAX,B67F196B ; 解密指令只有1條ADD
0040501A 89043B MOV DWORD PTR DS:[EDI+EBX],EAX
0040501D 83C3 04 ADD EBX,4
00405020 49 DEC ECX
00405021 ^ 75 EF JNE SHORT 00405012
00405023 61 POPAD
00405024 E9 8E900200 JMP 0043E100
循環(huán)結(jié)束后,在00405100中就還原了整個DispatchTable:
CPU Dump
Address Hex dump ASCII
00405100 74 D3 43 00|3B D4 43 00|89 D0 43 00|51 DE 43 00| tC.;C.C.QC.
00405110 BE EA 43 00|70 D7 43 00|E0 EA 43 00|3F E8 43 00| C.pC.C.?C.
00405120 77 EF 43 00|2E D7 43 00|E6 E7 43 00|D2 D7 43 00| wC..C.C.C.
00405130 91 D8 43 00|56 DC 43 00|ED E9 43 00|A5 D3 43 00| C.VC.C.C.
00405140 89 CE 43 00|13 DE 43 00|89 CE 43 00|99 E1 43 00| C.C.C.C.
00405150 24 D5 43 00|54 DD 43 00|98 D1 43 00|00 DB 43 00| $C.TC.C..C.
00405160 ED E9 43 00|E0 EA 43 00|2E D8 43 00|81 CF 43 00| C.C..C.C.
00405170 98 D1 43 00|E0 EA 43 00|00 DB 43 00|56 DC 43 00| C.C..C.VC.
00405180 BD D8 43 00|1F ED 43 00|F6 EC 43 00|70 E7 43 00| C.C.C.pC.
00405190 BD D8 43 00|3F E8 43 00|53 D2 43 00|2E D7 43 00| C.?C.SC..C.
004051A0 2E D8 43 00|C9 CD 43 00|1C D2 43 00|CC D6 43 00| .C.C.C.C.
004051B0 C8 D8 43 00|54 DD 43 00|91 D8 43 00|CA E9 43 00| C.TC.C.C.
004051C0 1F ED 43 00|51 DE 43 00|57 D1 43 00|89 CE 43 00| C.QC.WC.C.
004051D0 78 D9 43 00|78 D9 43 00|2E D7 43 00|C8 D8 43 00| xC.xC..C.C.
004051E0 E6 E7 43 00|2E D7 43 00|89 CE 43 00|ED E9 43 00| C..C.C.C.
004051F0 F5 D2 43 00|11 EB 43 00|56 DC 43 00|3F E8 43 00| C.C.VC.?C.
00405200 CC D6 43 00|74 D3 43 00|BE EA 43 00|CC D6 43 00| C.tC.C.C.
00405210 A5 D3 43 00|A5 E9 43 00|77 EF 43 00|A5 D3 43 00| C.C.wC.C.
00405220 89 D0 43 00|70 E7 43 00|78 D9 43 00|ED E9 43 00| C.pC.xC.C.
00405230 92 EB 43 00|E7 D6 43 00|53 D2 43 00|AC DB 43 00| C.C.SC.C.
00405240 54 DD 43 00|90 E7 43 00|BE DF 43 00|CC D6 43 00| TC.C.C.C.
00405250 BE DF 43 00|EE EF 43 00|BE DF 43 00|C8 D8 43 00| C.C.C.C.
00405260 BE DF 43 00|13 DE 43 00|BE DF 43 00|CA E9 43 00| C.C.C.C.
00405270 BE DF 43 00|51 DE 43 00|BE DF 43 00|A5 D3 43 00| C.QC.C.C.
00405280 BE DF 43 00|6B E0 43 00|BE DF 43 00|98 D1 43 00| C.kC.C.C.
00405290 BE DF 43 00|90 E7 43 00|BE DF 43 00|EE EF 43 00| C.C.C.C.
004052A0 BE DF 43 00|89 D0 43 00|BE DF 43 00|2E D7 43 00| C.C.C..C.
004052B0 BE DF 43 00|CD E8 43 00|BE DF 43 00|7D EC 43 00| C.C.C.}C.
004052C0 BE DF 43 00|53 D2 43 00|70 E7 43 00|89 D0 43 00| C.SC.pC.C.
004052D0 F5 D2 43 00|1F ED 43 00|24 D5 43 00|11 EB 43 00| C.C.$C.C.
004052E0 53 D2 43 00|69 DA 43 00|ED E9 43 00|BE EA 43 00| SC.iC.C.C.
004052F0 98 D1 43 00|BD D8 43 00|A5 E9 43 00|2E D8 43 00| C.C.C..C.
00405300 11 DB 43 00|2E D8 43 00|C9 CD 43 00|ED E9 43 00| C..C.C.C.
00405310 E7 D6 43 00|2E D7 43 00|2E D8 43 00|89 D0 43 00| C..C..C.C.
00405320 CC D6 43 00|11 DB 43 00|ED E9 43 00|7D EC 43 00| C.C.C.}C.
00405330 69 DA 43 00|90 E7 43 00|77 EF 43 00|74 D3 43 00| iC.C.wC.tC.
00405340 99 E1 43 00|D2 D7 43 00|F5 D2 43 00|56 DC 43 00| C.C.C.VC.
00405350 3F E8 43 00|00 DB 43 00|3C E1 43 00|74 D3 43 00| ?C..C.<C.tC.
00405360 6B E0 43 00|24 D5 43 00|3C E1 43 00|1F ED 43 00| kC.$C.<C.C.
00405370 C9 CD 43 00|3C E1 43 00|13 DE 43 00|11 DB 43 00| C.<C.C.C.
00405380 7D EC 43 00|1F ED 43 00|3B D4 43 00|AC DB 43 00| }C.C.;C.C.
00405390 ED E9 43 00|1C D2 43 00|89 CE 43 00|92 EB 43 00| C.C.C.C.
004053A0 ED E9 43 00|E0 EA 43 00|C9 CD 43 00|90 E7 43 00| C.C.C.C.
004053B0 81 CF 43 00|E6 E7 43 00|E7 D6 43 00|56 DC 43 00| C.C.C.VC.
004053C0 92 EB 43 00|EE EF 43 00|7D EC 43 00|99 E1 43 00| C.C.}C.C.
004053D0 89 CE 43 00|51 DE 43 00|2E D7 43 00|00 DB 43 00| C.QC..C..C.
004053E0 89 CE 43 00|57 D1 43 00|24 D5 43 00|CA E9 43 00| C.WC.$C.C.
004053F0 EE EF 43 00|F5 D2 43 00|11 DB 43 00|3F E8 43 00| C.C.C.?C.
00405400 F6 EC 43 00|78 D9 43 00|53 D2 43 00|98 D1 43 00| C.xC.SC.C.
00405410 CC D6 43 00|ED E9 43 00|7D EC 43 00|89 CE 43 00| C.C.}C.C.
00405420 E7 D6 43 00|3C E1 43 00|E7 D6 43 00|70 E7 43 00| C.<C.C.pC.
00405430 11 DB 43 00|CA E9 43 00|89 D0 43 00|E6 E7 43 00| C.C.C.C.
00405440 77 EF 43 00|70 D7 43 00|0A DC 43 00|24 D5 43 00| wC.pC..C.$C.
00405450 0A DC 43 00|3F E8 43 00|0A DC 43 00|57 D1 43 00| .C.?C..C.WC.
00405460 0A DC 43 00|CD E8 43 00|0A DC 43 00|98 D1 43 00| .C.C..C.C.
00405470 0A DC 43 00|77 EF 43 00|0A DC 43 00|78 D9 43 00| .C.wC..C.xC.
00405480 0A DC 43 00|70 D7 43 00|0A DC 43 00|2E D7 43 00| .C.pC..C..C.
00405490 0A DC 43 00|BE EA 43 00|0A DC 43 00|E0 EA 43 00| .C.C..C.C.
004054A0 0A DC 43 00|70 E7 43 00|0A DC 43 00|E0 EA 43 00| .C.pC..C.C.
004054B0 0A DC 43 00|92 EB 43 00|0A DC 43 00|74 D3 43 00| .C.C..C.tC.
004054C0 0A DC 43 00|24 CF 43 00|51 DE 43 00|74 D3 43 00| .C.$C.QC.tC.
004054D0 F6 EC 43 00|90 E7 43 00|78 D9 43 00|24 CF 43 00| C.C.xC.$C.
004054E0 54 DD 43 00|7D EC 43 00|69 DA 43 00|70 E7 43 00| TC.}C.iC.pC.
004054F0 EE EF 43 00|78 D9 43 00|57 D1 43 00|3B D4 43 00| C.xC.WC.;C.
Intel的Little Endian(小尾)方式存儲讓我們看的非常的別扭。在OD的主窗口(CPU窗口)中來到00405000 .data段,看一下00405100的顯示:
004050F2 0000 ADD BYTE PTR DS:[EAX],AL
004050F4 0000 ADD BYTE PTR DS:[EAX],AL
004050F6 0000 ADD BYTE PTR DS:[EAX],AL
004050F8 0000 ADD BYTE PTR DS:[EAX],AL
004050FA 0000 ADD BYTE PTR DS:[EAX],AL
004050FC 0000 ADD BYTE PTR DS:[EAX],AL
004050FE 0000 ADD BYTE PTR DS:[EAX],AL
00405100 ^ 74 D3 JE SHORT 004050D5
00405102 43 INC EBX
00405103 003B ADD BYTE PTR DS:[EBX],BH
00405105 D4 43 AAM 43
00405110 BE EA430070 MOV ESI,700043EA
OD把我們的數(shù)據(jù)當(dāng)做代碼來顯示了。點擊右鍵-->Analysis-->Analyse code Ctrl + A ,彈出對話框是否分析,點擊確定。顯示如下:
004050FB 00 DB 00
004050FC 00 DB 00
004050FD 00 DB 00
004050FE 00 DB 00
004050FF 00 DB 00
00405100 . 74D34300 DD 0043D374
00405104 . 3BD44300 DD 0043D43B
00405108 . 89D04300 DD 0043D089
0040510C . 51DE4300 DD 0043DE51
00405110 . BEEA4300 DD 0043EABE
00405114 . 70D74300 DD 0043D770
00405118 . E0EA4300 DD 0043EAE0
0040511C . 3FE84300 DD 0043E83F
00405120 . 77EF4300 DD 0043EF77
00405124 . 2ED74300 DD 0043D72E
00405128 . E6E74300 DD 0043E7E6
0040512C . D2D74300 DD 0043D7D2
OD正確的以數(shù)據(jù)方式顯示,并且已經(jīng)按照我們?nèi)粘5牧?xí)慣把數(shù)據(jù)按照Big Endian(大尾)方式顯示。
對于DispatchTable中重復(fù)的數(shù)據(jù),我們也要把他清除,在剛才00405000的匯編代碼下面繼續(xù):
CPU Disasm
Address Hex dump Command Comments
00405000 60 PUSHAD
00405001 BE DBE14300 MOV ESI,0043E1DB ; DispatchTable地址
00405006 BF 00514000 MOV EDI,00405100 ; 解密循環(huán)地址
0040500B B9 00010000 MOV ECX,100
00405010 31DB XOR EBX,EBX
00405012 8B0433 MOV EAX,DWORD PTR DS:[ESI+EBX]
00405015 05 6B197FB6 ADD EAX,B67F196B ; 解密指令只有1條ADD
0040501A 89043B MOV DWORD PTR DS:[EDI+EBX],EAX
0040501D 83C3 04 ADD EBX,4
00405020 49 DEC ECX
00405021 ^ 75 EF JNE SHORT 00405012
00405023 61 POPAD
00405024 EB 03 JMP SHORT 00405029
00405026 90 NOP
00405027 90 NOP
00405028 90 NOP
00405029 60 PUSHAD
0040502A BE 00514000 MOV ESI,00405100 ; TispatchTable
0040502F BF 005A4000 MOV EDI,00405A00 ; new DispatchTable
00405034 B9 00010000 MOV ECX,100
00405039 BA 00000000 MOV EDX,0
0040503E 8D1C8D 00000000 LEA EBX,[ECX*4]
00405045 8B06 MOV EAX,DWORD PTR DS:[ESI]
00405047 83F8 00 CMP EAX,0
0040504A 74 1A JE SHORT 00405066
0040504C 8907 MOV DWORD PTR DS:[EDI],EAX
0040504E 83C7 04 ADD EDI,4
00405051 83C2 04 ADD EDX,4
00405054 39DA CMP EDX,EBX
00405056 74 0E JE SHORT 00405066
00405058 3B0432 CMP EAX,DWORD PTR DS:[ESI+EDX]
0040505B ^ 75 F4 JNE SHORT 00405051
0040505D C70432 00000000 MOV DWORD PTR DS:[ESI+EDX],0
00405064 ^ EB EB JMP SHORT 00405051
00405066 83C6 04 ADD ESI,4
00405069 49 DEC ECX
0040506A ^ 75 CD JNE SHORT 00405039
0040506C 61 POPAD
0040506D E9 8E900200 JMP 0043E100
第一部分是前面解密代碼,第二部分是分別比較00405100中的數(shù)據(jù),把相同的全部放00000000,同時把非0的數(shù)據(jù)存入00405A00中。
執(zhí)行完這些代碼后,00405A00中生成了VM中所有的偽指令,在通過OD把它按照數(shù)據(jù)顯示出來如下:
CPU Disasm
Address Hex dump Command Comments
00405A00 . \74D34300 DD 0043D374
00405A04 . 3BD44300 DD 0043D43B
00405A08 . 89D04300 DD 0043D089
00405A0C . 51DE4300 DD 0043DE51
00405A10 . BEEA4300 DD 0043EABE
00405A14 . 70D74300 DD 0043D770
00405A18 . E0EA4300 DD 0043EAE0
00405A1C . 3FE84300 DD 0043E83F
00405A20 . 77EF4300 DD 0043EF77
00405A24 . 2ED74300 DD 0043D72E
00405A28 . E6E74300 DD 0043E7E6
00405A2C . D2D74300 DD 0043D7D2
00405A30 . 91D84300 DD 0043D891
00405A34 . 56DC4300 DD 0043DC56
00405A38 . EDE94300 DD 0043E9ED
00405A3C . A5D34300 DD 0043D3A5
00405A40 . 89CE4300 DD 0043CE89
00405A44 . 13DE4300 DD 0043DE13
00405A48 . 99E14300 DD 0043E199
00405A4C . 24D54300 DD 0043D524
00405A50 . 54DD4300 DD 0043DD54
00405A54 . 98D14300 DD 0043D198
00405A58 . 00DB4300 DD 0043DB00
00405A5C . 2ED84300 DD 0043D82E
00405A60 . 81CF4300 DD 0043CF81
00405A64 . BDD84300 DD 0043D8BD
00405A68 . 1FED4300 DD 0043ED1F
00405A6C . F6EC4300 DD 0043ECF6
00405A70 . 70E74300 DD 0043E770
00405A74 . 53D24300 DD 0043D253
00405A78 . C9CD4300 DD 0043CDC9
00405A7C . 1CD24300 DD 0043D21C
00405A80 . CCD64300 DD 0043D6CC
00405A84 . C8D84300 DD 0043D8C8
00405A88 . CAE94300 DD 0043E9CA
00405A8C . 57D14300 DD 0043D157
00405A90 . 78D94300 DD 0043D978
00405A94 . F5D24300 DD 0043D2F5
00405A98 . 11EB4300 DD 0043EB11
00405A9C . A5E94300 DD 0043E9A5
00405AA0 . 92EB4300 DD 0043EB92
00405AA4 . E7D64300 DD 0043D6E7
00405AA8 . ACDB4300 DD 0043DBAC
00405AAC . 90E74300 DD 0043E790
00405AB0 . BEDF4300 DD 0043DFBE
00405AB4 . EEEF4300 DD 0043EFEE
00405AB8 . 6BE04300 DD 0043E06B
00405ABC . CDE84300 DD 0043E8CD
00405AC0 . 7DEC4300 DD 0043EC7D
00405AC4 . 69DA4300 DD 0043DA69
00405AC8 . 11DB4300 DD 0043DB11
00405ACC . 3CE14300 DD 0043E13C
00405AD0 . 0ADC4300 DD 0043DC0A
00405AD4 . 24CF4300 DD 0043CF24
這個VM一共有52條偽指令,在本節(jié)中我將一一列出這52條偽指令。每個分析VMP的人都有自己對偽指令的命名方式。
移動到EBPSTACK的數(shù)據(jù)使用PUSH指令,移動到EDISTACK的數(shù)據(jù)使用MOV指令。在VM中,對數(shù)據(jù)的操作包括byte和dword,而存儲的方式是word和dword,當(dāng)遇到byte和word交織在一起的時候,可以就把數(shù)據(jù)作為word操作來看。
下面我以:VM_PUSHw_MEMORYb為例說明我的命名規(guī)則:
偽指令的命名統(tǒng)一使用VM_開頭;并接上直觀的助記符PUSH;EBPSTACK是移動的目的地;MEMORY是移動的來源地;w代表word、b代表byte、dw代表dword;這條指令的表示:這是一條移動指令,把1個byte的數(shù)據(jù)從內(nèi)存塊移動到EBPSTACK,存儲時是按照word來存儲。
在VMP的偽指令中包含有大量的花指令和junk code,在本文列出的偽指令都是去除了這些無用代碼。
0043DC0A命名:
VM_MOVdw_EDISTACKdw_EBPSTACKdw
代碼:
0043DC19 |. F6D8 NEG AL ; *
0043DC26 |. C0C8 07 ROR AL,7 ; *
0043DC34 |. 2C 20 SUB AL,20 ; *
0043DC41 |. 24 3C AND AL,3C ; *
0043E080 |$ 8B55 00 MOV EDX,DWORD PTR SS:[EBP] ; *
0043E086 |. 83C5 04 ADD EBP,4 ; *
0043D3D7 /> /891438 MOV DWORD PTR DS:[EDI+EAX],EDX ; *
功能:
把EBPSTACK棧頂1個dword的數(shù)據(jù)存儲到EDISTACK
0043E7E6命名:
VM_MOVw_EDISTACKw_EBPSTACKw
代碼:
0043E7EC 0FB646 FF MOVZX EAX,BYTE PTR DS:[ESI-1] ; *
0043E7F6 28D8 SUB AL,BL ; *
0043E7FE C0C8 05 ROR AL,5 ; *
0043E80C F6D8 NEG AL ; *
0043E816 34 0E XOR AL,0E ; *
0043E822 28C3 SUB BL,AL ; *
0043E82E 66:8B55 00 MOV DX,WORD PTR SS:[EBP] ; *
0043E835 83C5 02 ADD EBP,2 ; *
0043F03F 4E DEC ESI ; *
0043F045 66:891438 MOV WORD PTR DS:[EDI+EAX],DX ; *
功能:
把EBPSTACK棧頂1個word的數(shù)據(jù)存儲到EDISTACK
0043D374命名:
VM_MOVb_EDISTACKb_EBPSTACKw
代碼:
0043D377 |. 8A46 FF MOV AL,BYTE PTR DS:[ESI-1] ; *
0043F148 /> \30D8 XOR AL,BL ; *
0043D460 |. FEC0 INC AL ; |*
0043D469 |. C0C8 07 ROR AL,7 ; |*
0043D473 |. FEC0 INC AL ; |*
0043D215 |. 30C3 XOR BL,AL ; *
0043EA9C |. 4E DEC ESI ; *
0043EAA0 |. 66:8B55 00 MOV DX,WORD PTR SS:[EBP] ; *
0043EAAC |. 83C5 02 ADD EBP,2 ; *
0043DBDA /> /881438 MOV BYTE PTR DS:[EDI+EAX],DL ; *
把EBPSTACK棧頂1個word的數(shù)據(jù)按照byte的方式存儲到EDISTACK
0043D21C命名:
VM_PUSHw_IMMEDIATEw
代碼:
0043D21F 66:8B46 FE MOV AX,WORD PTR DS:[ESI-2] ; *
0043D22D 86E0 XCHG AL,AH ; *
0043E01A 66:29D8 SUB AX,BX ; *
0043E022 66:05 71F2 ADD AX,0F271 ; *
0043E036 66:F7D8 NEG AX ; *
0043E03D 66:35 A61C XOR AX,1CA6 ; *
0043E054 66:29C3 SUB BX,AX ; *
0043E054 66:29C3 SUB BX,AX ; *
0043E976 8D76 FE LEA ESI,[ESI-2] ; *
0043D094 /66:8945 00 MOV WORD PTR SS:[EBP],AX ; *
功能:
從ESI數(shù)據(jù)中取得1個word的立即數(shù)壓入EBPSTACK
0043E83F命名:
VM_PUSHdw_IMMEDIATEdw
代碼:
0043E845 . 8B46 FC MOV EAX,DWORD PTR DS:[ESI-4] ; *
0043E84D . 0FC8 BSWAP EAX ; *
0043E852 . 01D8 ADD EAX,EBX ; *
0043E857 . C1C8 04 ROR EAX,4 ; *
0043D952 . 8D76 FC LEA ESI,[ESI-4] ; *
0043D956 . 2D E131FF38 SUB EAX,38FF31E1 ; *
0043D967 . C1C0 0A ROL EAX,0A ; |*
0043D96C . 01C3 ADD EBX,EAX ; |*
0043D970 . 83ED 04 SUB EBP,4 ; |*
0043D710 |$ 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
從ESI數(shù)據(jù)中獲得1個dword的立即數(shù),壓入EBPSTACK
0043DB11命名:
VM_PUSHdw_IMMEDIATEw
代碼:
0043DB1E 66:8B46 FE MOV AX,WORD PTR DS:[ESI-2] ; *
0043D171 /86E0 XCHG AL,AH ; *
0043E948 66:29D8 SUB AX,BX ; *
0043E951 66:05 71F2 ADD AX,0F271 ; *
0043E95C 66:F7D8 NEG AX ; *
0043E969 8D76 FE LEA ESI,[ESI-2] ; *
0043D62C 66:35 A61C XOR AX,1CA6 ; *
0043D640 \66:29C3 SUB BX,AX ; *
0043D648 98 CWDE ; *
0043D190 83ED 04 SUB EBP,4 ; *
0043D933 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
從ESI數(shù)據(jù)中獲得1個word的立即數(shù),按照dword的方式壓入EBPSTACK
0043D978命名:
VM_PUSHw_IMMEDIATEb
代碼:
0043D979 . 0FB646 FF MOVZX EAX,BYTE PTR DS:[ESI-1] ; *
0043D97E . 30D8 XOR AL,BL ; *
0043D1ED . FEC8 DEC AL ; *
0043D1F0 . F6D8 NEG AL ; *
0043D1F7 . F6D0 NOT AL ; *
0043D1FD . 30C3 XOR BL,AL ; *
0043CEE8 > /83ED 02 SUB EBP,2 ; *
0043DD79 |. 66:8945 00 MOV WORD PTR SS:[EBP],AX ; |*
0043DD62 /$ 4E DEC ESI ; *
功能:
從ESI數(shù)據(jù)中獲得1個byte的立即數(shù),按照word的方式壓入EBPSTACK
0043D3A5命名:
VM_PUSHdw_IMMEDIATEb
代碼:
0043D3A7 0FB646 FF MOVZX EAX,BYTE PTR DS:[ESI-1] ; *
0043D3AC 30D8 XOR AL,BL ; *
0043D848 FEC8 DEC AL ; *
0043D855 F6D8 NEG AL ; *
0043D866 F6D0 NOT AL ; *
0043D86D 30C3 XOR BL,AL ; *
0043ED8C 66:98 CBW ; *
0043CF7B 98 CWDE ; *
0043EC00 8D76 FF LEA ESI,[ESI-1] ; *
0043DB94 83ED 04 SUB EBP,4 ; *
0043DB9F 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
從ESI數(shù)據(jù)中獲得1個byte的立即數(shù),按照dword的方式壓入EBPSTACK
0043CF24命名:
VM_ADDdw_EBPSTACK
代碼:
0043CF2F |. 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043EED3 |. 0145 04 ADD DWORD PTR SS:[EBP+4],EAX ; *
0043CE4F |. 9C PUSHFD ; *
0043CE50 |. 8F4424 3C POP DWORD PTR SS:[ESP+3C] ; *
0043D1BF /> \FF7424 3C PUSH DWORD PTR SS:[ESP+3C] ; *
0043D1C3 |. 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
把EBPSTACK棧頂?shù)?個dword數(shù)據(jù)相加,結(jié)果存儲在[EBP+4],EFLAGS標志存儲在棧頂。
例:
0013F97C 8021D2F0 !
0013F980 00000000 ....
VM_ADDdw_EBPSTACK
0013F97C 00000286 ..
0013F980 8021D2F0 !
0043D43B命名:
VM_PUSHdw_MEMORYdw
代碼:
0043D43F 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D10A 8B00 MOV EAX,DWORD PTR DS:[EAX] ; *
0043D447 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
把EBPSTACK棧頂數(shù)據(jù)作為內(nèi)存地址,從中讀取1個dword的數(shù)據(jù)壓入EBPSTACK
0043E9CA命名:
VM_PUSHw_MEMORYw
代碼:
0043E9D0 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043E9D9 83C5 02 ADD EBP,2 ; *
0043DEBB 66:36:8B00 MOV AX,WORD PTR SS:[EAX] ; *
0043DDC4 66:8945 00 MOV WORD PTR SS:[EBP],AX ; *
功能:
把EBPSTACK棧頂數(shù)據(jù)作為內(nèi)存地址,從中讀取1個word的數(shù)據(jù)壓入EBPSTACK
0043D8BD命名:
VM_PUSHw_MEMORYb
代碼:
0043D57B |. 8B55 00 MOV EDX,DWORD PTR SS:[EBP]
0043D589 |. 83C5 02 ADD EBP,2 ; *
0043D591 |. 8A02 MOV AL,BYTE PTR DS:[EDX] ; *
0043E70B |. 66:8945 00 MOV WORD PTR SS:[EBP],AX ; *
功能:
把EBPSTACK棧頂數(shù)據(jù)作為內(nèi)存地址,從中讀取1個byte的數(shù)據(jù),按照word的方式壓入EBPSTACK
0043DC56命名:
VM_PUSHw_EDISTACKw
代碼:
0043DC5C 8A46 FF MOV AL,BYTE PTR DS:[ESI-1] ; *
0043DC66 28D8 SUB AL,BL ; *
0043DC6D C0C8 05 ROR AL,5 ; *
0043EADA 4E DEC ESI ; *
0043EE2E \F6D8 NEG AL ; *
0043EE34 34 0E XOR AL,0E ; *
0043E740 28C3 SUB BL,AL ; *
0043E746 66:8B0438 MOV AX,WORD PTR DS:[EDI+EAX] ; *
0043D9E4 83ED 02 SUB EBP,2 ; *
0043EE44 66:8945 00 MOV WORD PTR SS:[EBP],AX ; *
功能:
從EDISTACK中讀取1個word數(shù)據(jù)壓入EBPSTACK
0043CF81命名:
VM_PUSHw_EDISTACKb
代碼:
0043CF84 8A46 FF MOV AL,BYTE PTR DS:[ESI-1] ; *
0043CF8E 30D8 XOR AL,BL ; *
0043EE0A \FEC0 INC AL ; *
0043EE11 C0C8 07 ROR AL,7 ; *
0043EE1E FEC0 INC AL ; *
0043D59C 30C3 XOR BL,AL ; *
0043D2CE 4E DEC ESI ; *
0043D2D7 8A0438 MOV AL,BYTE PTR DS:[EDI+EAX] ; *
0043D2E6 83ED 02 SUB EBP,2 ; *
0043D075 66:8945 00 MOV WORD PTR SS:[EBP],AX ; *
功能:
從EDISTACK中讀取1個byte數(shù)據(jù),按照word方式壓入EBPSTACK
0043D72E命名:
VM_PUSHdw_EBP
代碼:
0043D72F /. 89E8 MOV EAX,EBP ; *
0043E613 /$ 83ED 04 SUB EBP,4 ; *
0043E61C |. 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
復(fù)制EBP指針到EBPSTACK棧頂
例:
EBP 0013F9AC
0013F9AC 00000000 ....
VM_PUSHdw_EBP
0013F9A8 0013F9AC .
0013F9AC 00000000 ....
0043EABE命名:
VM_COPYdw_EBPSTACK
代碼:
0043EACC 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043DE1B 36:8B00 MOV EAX,DWORD PTR SS:[EAX] ; *
0043DE25 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
把EBPSTACK棧頂數(shù)據(jù)作為堆棧地址,從中讀取一個dword的數(shù)據(jù)壓入EBPSTACK
例:
0013F998 F99E
0013F99C 02460013 .F
0013F9A0 0000 ...
VM_COPYdw_EBPSTACK
0013F998 0246
0013F99C 02460000 ..F
0013F9A0 0000 ...
0043E790命名:
VM_COPYw_EBPSTACK
代碼:
0043E79C |. 8B55 00 MOV EDX,DWORD PTR SS:[EBP] ; *
0043E7A7 |. 83C5 02 ADD EBP,2 ; *
0043E7AE |. 36:8A02 MOV AL,BYTE PTR SS:[EDX] ; *
0043D01B |. 66:8945 00 MOV WORD PTR SS:[EBP],AX ; *
功能:
把EBPSTACK棧頂數(shù)據(jù)作為堆棧地址,從中讀取一個byte的數(shù)據(jù),按照word的方式壓入EBPSTACK
例:
0013F9A8 0013F9AC .
0013F9AC 0000 ....
VM_COPYw_EBPSTACK
0013F9A8 0000
0013F9AC 0000 ....
0043D198命名:
VM_NANDdw
代碼:
0043D1A3 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D1AD 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043DEAE F7D0 NOT EAX ; *
0043DDE1 /F7D2 NOT EDX ; *
0043CDC2 21D0 AND EAX,EDX ; *
0043E0F8 8945 04 MOV DWORD PTR SS:[EBP+4],EAX ; *
0043D0FB /9C PUSHFD ; *
0043D0FC 8F4424 2C POP DWORD PTR SS:[ESP+2C] ; *
0043EC46 FF7424 34 PUSH DWORD PTR SS:[ESP+34] ; *
0043EC4A 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
dword版的與非門,從EBPSTACK的棧頂讀取2個dword作為操作數(shù),結(jié)果存儲在第二個操作數(shù)位置,EFLAGS標志存儲在棧頂。
例:
0013F9A8 00000286 ..
0013F9AC 00000286 ..
VM_NANDdw
0013F9A8 00000282 ..
0013F9AC FFFFFD79 y
0043EB92命名:
VM_NANDw
代碼:
0043EB94 |. 66:8B45 00 MOV AX,WORD PTR SS:[EBP] ; *
0043EBA5 |. 66:8B55 02 MOV DX,WORD PTR SS:[EBP+2] ; *
0043EBB3 |. F6D0 NOT AL ; *
0043EBBB |. F6D2 NOT DL ; *
0043EBC1 |. 83ED 02 SUB EBP,2 ; *
0043EBC5 |. 20D0 AND AL,DL ; *
0043EBCD |. 66:8945 04 MOV WORD PTR SS:[EBP+4],AX ; *
0043EBD5 |. 9C PUSHFD ; *
0043D26F |$ FF7424 28 PUSH DWORD PTR SS:[ESP+28] ; *
0043D273 |. 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
word版的與非門,從EBPSTACK的棧頂讀取2個word作為操作數(shù),結(jié)果存儲在第二個操作數(shù)位置,EFLAGS標志存儲在棧頂。
例:
EBP 0013F9AA
0013F9A8 0000
0013F9AC 0000 ....
VM_NANDw
0013F9A8 00000286 ..
0013F9AC 00FF ...
0043EB11命名:
VM_ADDw_EBPSTACK
代碼:
0043EB14 |. 8A45 00 MOV AL,BYTE PTR SS:[EBP] ; *
0043EB1C |. 83ED 02 SUB EBP,2 ; *
0043EB21 |. 0045 04 ADD BYTE PTR SS:[EBP+4],AL ; *
0043EB26 |. 9C PUSHFD ; *
0043EB27 |. 8F4424 20 POP DWORD PTR SS:[ESP+20] ; *
0043E8F9 |> /FF7424 40 PUSH DWORD PTR SS:[ESP+40] ; *
0043E8FD |. |8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
把EBPSTACK棧頂?shù)?個word數(shù)據(jù)中的低byte相加,結(jié)果存儲在第二個操作數(shù)位置,EFLAGS標志存儲在棧頂。
例:
0013F9AC 000000FF ...
VM_ADDw_EBPSTACK
0013F9A8 0286
0013F9AC 00FF0000 ...
0043DFBE命名:
VM_PUSHdw_EDISTACKdw
代碼:
0043DFC1 F6D8 NEG AL ; *
0043DFCD C0C8 07 ROR AL,7 ; *
0043DFDA 2C 20 SUB AL,20 ; *
0043DFDD 24 3C AND AL,3C ; *
0043CE6C 8B1438 MOV EDX,DWORD PTR DS:[EDI+EAX] ; *
0043CE71 83ED 04 SUB EBP,4 ; *
0043CE79 8955 00 MOV DWORD PTR SS:[EBP],EDX ; *
功能:
把1個dword的數(shù)據(jù)從EDISTACK壓入EBPSTACK
0043D7D2命名:
VM_SHRdw_EBPSTACK
代碼:
0043D7DA 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D7E6 8A4D 04 MOV CL,BYTE PTR SS:[EBP+4] ; *
0043D4F8 83ED 02 SUB EBP,2 ; *
0043D504 D3E8 SHR EAX,CL ; *
0043F17D \8945 04 MOV DWORD PTR SS:[EBP+4],EAX ; *
0043EA2E 9C PUSHFD ; *
0043EA30 FF7424 20 PUSH DWORD PTR SS:[ESP+20] ; *
0043EA34 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
把EBPSTACK棧頂1個dword作為操作數(shù),[EBP+4]作為移動位數(shù),邏輯右移。結(jié)果dword存儲在第二個操作數(shù)和第一個操作數(shù)的高byte,EFLAGS標志存儲在棧頂。
例:
0013F99C 0040
0013F9A0 00040000 ...
VM_SHRdw_EBPSTACK
0013F99C 00000202 ..
0013F9A0 00000004 ...
0043E9A5命名:
VM_SHLdw_EBPSTACK
代碼:
0043E9A9 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043E9B5 8A4D 04 MOV CL,BYTE PTR SS:[EBP+4] ; *
0043E0B2 >83ED 02 SUB EBP,2 ; *
0043E0BC D3E0 SHL EAX,CL ; *
0043CDEA 8945 04 MOV DWORD PTR SS:[EBP+4],EAX ; *
0043DD1A \9C PUSHFD
0043DD1B 8F4424 28 POP DWORD PTR SS:[ESP+28]
0043DD24 FF7424 2C PUSH DWORD PTR SS:[ESP+2C] ; *
0043DD28 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
把EBPSTACK棧頂1個dword作為操作數(shù),[EBP+4]作為移動位數(shù),邏輯左移。結(jié)果dword存儲在第二個操作數(shù)和第一個操作數(shù)的高byte,EFLAGS標志存儲在棧頂。
0043DE51命名:
VM_SHRDdw_EBPSTACK
代碼:
0043DE5D 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043DE69 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043DE6E 8A4D 08 MOV CL,BYTE PTR SS:[EBP+8] ; *
0043DE73 83C5 02 ADD EBP,2 ; *
0043DE7A 0FADD0 SHRD EAX,EDX,CL ; *
0043D38F 8945 04 MOV DWORD PTR SS:[EBP+4],EAX ; *
0043D66C 9C PUSHFD ; *
0043D66D 8F4424 34 POP DWORD PTR SS:[ESP+34] ; *
0043D67F FF7424 40 PUSH DWORD PTR SS:[ESP+40] ; *
0043D683 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
EBPSTACK雙精度右移指令,執(zhí)行完畢后,結(jié)果和EFLAGS存儲到EBPSTACK
0043D524命名:
VM_SHLDdw_EBPSTACK
代碼:
0043D529 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D537 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043D545 8A4D 08 MOV CL,BYTE PTR SS:[EBP+8] ; *
0043D550 83C5 02 ADD EBP,2 ; *
0043D558 0FA5D0 SHLD EAX,EDX,CL ; *
0043D637 8945 04 MOV DWORD PTR SS:[EBP+4],EAX ; *
0043CED3 9C PUSHFD
0043D8F4 \FF7424 34 PUSH DWORD PTR SS:[ESP+34] ; *
0043D8F8 8F45 00 POP DWORD PTR SS:[EBP] ; *
功能:
EBPSTACK雙精度左移指令,執(zhí)行完畢后,結(jié)果和EFLAGS存儲到EBPSTACK
0043D089命名:
VM_JMP
代碼:
0043D722 8B75 00 MOV ESI,DWORD PTR SS:[EBP] ; *
0043EF1F \83C5 04 ADD EBP,4 ; *
0043E6A9 89F3 MOV EBX,ESI ; *
0043E6B8 0375 00 ADD ESI,DWORD PTR SS:[EBP] ; *
功能:
把EBPSTACK棧頂?shù)刂芬苿拥紼SI,重新初始化EBX和ESI。
0043EF77命名:
VM_EBPSTACK_CALL
代碼:
0043EF7B 0FB646 FF MOVZX EAX,BYTE PTR DS:[ESI-1] ; *
0043EF82 30D8 XOR AL,BL ; *
0043EF8D FEC8 DEC AL ; *
0043EF99 F6D8 NEG AL ; *
0043EFAF 8D76 FF LEA ESI,[ESI-1] ; *
0043EFB3 F6D0 NOT AL ; *
0043EFC4 30C3 XOR BL,AL ; *
0043EFCD 0FB6C8 MOVZX ECX,AL ; *
0043EFDC 894D FC MOV DWORD PTR SS:[EBP-4],ECX ; *
0043ECEA 31C0 XOR EAX,EAX ; *
0043E0C6 87448D 00 XCHG DWORD PTR SS:[ECX*4+EBP],EAX ; * parameter
0043E0CD 894424 24 MOV DWORD PTR SS:[ESP+24],EAX ; *
0043EE89 83E9 01 SUB ECX,1 ; *
0043EE9C ^\0F85 3FFEFFFF JNE 0043ECE1 ; *
0043CF5B 29C0 SUB EAX,EAX ; *
0043CF6A C74424 04 B7EE4 MOV DWORD PTR SS:[ESP+4],0043EEB7 ; *
0043CF60 8745 00 XCHG DWORD PTR SS:[EBP],EAX ; *
0043DDF9 894424 08 MOV DWORD PTR SS:[ESP+8],EAX ; *
0043DDFD FF7424 04 PUSH DWORD PTR SS:[ESP+4] ; *
0043DE0C FF7424 34 PUSH DWORD PTR SS:[ESP+34] ; *
0043DE10 C2 3800 RETN 38 ; VM_APICALL
功能:
VM中最復(fù)雜的偽指令,用于系統(tǒng)API調(diào)用和程序過程調(diào)用。ESI數(shù)據(jù)中取得參數(shù)的個數(shù),EAX循環(huán)取得參數(shù),壓入ESP指針指向的常規(guī)堆棧。大量使用[ESP+X]的方式調(diào)用,摻雜著廢壓棧操作,靜態(tài)看代碼難以看出。返回地址是常量壓入的0043EEB7。這條偽指令涉及內(nèi)容眾多,分支龐大,系統(tǒng)API調(diào)用和程序過程調(diào)用的走向都是不同的,在后面章節(jié)詳述。我這里列舉的是一次只有1個參數(shù)的系統(tǒng)API調(diào)用
0043D891命名:
VM_MOVdw_MEMORYdw_EBPSTACKdw
代碼:
0043D897 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D8A1 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043D8A6 83C5 08 ADD EBP,8 ; *
0043D8AA 8910 MOV DWORD PTR DS:[EAX],EDX ; *
功能:
EBPSTACK棧頂數(shù)據(jù)作為地址,把棧頂?shù)牡诙䝼dword存儲到地址內(nèi)
0043EFEE命名:
VM_MOVdw_MEMORYdw_EBPSTACKdw
代碼:
0043EFF3 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043F005 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043F010 83C5 08 ADD EBP,8 ; *
0043D335 36:8910 MOV DWORD PTR SS:[EAX],EDX ; *
功能:
EBPSTACK棧頂數(shù)據(jù)作為地址,把棧頂?shù)牡诙䝼dword存儲到地址內(nèi)。與上一條偽指令完全相同
0043D157命名:
VM_MOVdw_MEMORYdw_EBPSTACKdw
代碼:
0043D159 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D169 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043CDF7 83C5 08 ADD EBP,8 ; *
0043CE09 26:8910 MOV DWORD PTR ES:[EAX],EDX ; *
EBPSTACK棧頂數(shù)據(jù)作為地址,把棧頂?shù)牡诙䝼dword存儲到地址內(nèi)。與上兩條偽指令完全相同
0043E9ED命名:
VM_MOVw_MEMORYw_EBPSTACKw
代碼:
0043E9F7 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043E9FD 66:8B55 04 MOV DX,WORD PTR SS:[EBP+4] ; *
0043EA02 83C5 06 ADD EBP,6 ; *
0043EA0D 66:8910 MOV WORD PTR DS:[EAX],DX ; *
功能:
EBPSTACK棧頂數(shù)據(jù)作為地址,把棧頂?shù)牡诙䝼word存儲到地址內(nèi)
0043D6CC命名:
VM_MOVb_MEMORYb_EBPSTACKb
代碼:
0043D6D3 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D6DB 8A55 04 MOV DL,BYTE PTR SS:[EBP+4] ; *
0043EC6C 83C5 06 ADD EBP,6 ; *
0043D495 36:8810 MOV BYTE PTR SS:[EAX],DL ; *
功能:
EBPSTACK棧頂數(shù)據(jù)作為地址,把棧頂?shù)牡诙䝼byte存儲到地址內(nèi)
0043CE89命名:
VM_HASH
代碼:
0043CE98 8B55 00 MOV EDX,DWORD PTR SS:[EBP] ; *
0043CEA0 83C5 04 ADD EBP,4 ; *
0043CEA6 31C0 XOR EAX,EAX ; *
0043DCC0 89C1 MOV ECX,EAX ; *
0043E6FA C1E0 07 SHL EAX,7 ; *
0043E701 C1E9 19 SHR ECX,19 ; *
0043D2BD /09C8 OR EAX,ECX ; *
0043D7EF \3202 XOR AL,BYTE PTR DS:[EDX] ; *
0043D7F2 42 INC EDX ; *
0043DD12 FF4D 00 DEC DWORD PTR SS:[EBP] ; *
0043F023 ^\0F85 7FDEFFFF JNE 0043CEA8 ; *
0043D9FA 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
計算一段數(shù)據(jù)的HASH值,EBPSTACK棧頂?shù)谝粋dword是數(shù)據(jù)地址,第二個dword是數(shù)據(jù)大小
0043DE13命名:
VM_MOVdw_EBPreg_EBPSTACK
代碼:
0043F134 \8B6D 00 MOV EBP,DWORD PTR SS:[EBP] ; *
功能:
給EBP寄存器賦值EBPSTACK棧頂數(shù)據(jù)
0043DD54命名:
VM_FS:[EBPSTACK]
代碼:
0043DD5A 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043F10E 64:8B00 MOV EAX,DWORD PTR FS:[EAX] ; *
0043F112 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
功能:
讀取FS[X]數(shù)據(jù),X=EBPSTACK棧頂數(shù)據(jù)
0043D8C8命名:
VM_SEH
代碼:
0043D8CF 8B45 00 MOV EAX,DWORD PTR SS:[EBP] ; *
0043D8DE 8B55 04 MOV EDX,DWORD PTR SS:[EBP+4] ; *
0043D8E7 83C5 08 ADD EBP,8 ; *
0043D243 64:8910 MOV DWORD PTR FS:[EAX],EDX ; *
功能:
給FS[X]傳遞Y數(shù)據(jù),X=EBPSTACK棧頂數(shù)據(jù),Y=EBPSTACK棧頂?shù)?個數(shù)據(jù)。在實踐中都是用于給FS[0]賦值,構(gòu)建SEH
0043DA69命名:
VM_EXIT
代碼:
0043DA6F 89EC MOV ESP,EBP ; *
0043DA73 58 POP EAX ; *
0043DA7E 59 POP ECX ; *
0043DA87 9D POPFD ; *
0043DA8D 5D POP EBP ; *
0043CDB1 /59 POP ECX ; *
0043CDB8 8B5C24 08 MOV EBX,DWORD PTR SS:[ESP+8] ; *
0043F068 8B6C24 14 MOV EBP,DWORD PTR SS:[ESP+14] ; *
0043F06D 8B4424 38 MOV EAX,DWORD PTR SS:[ESP+38] ; *
0043F06D 8B4424 38 MOV EAX,DWORD PTR SS:[ESP+38] ; *
0043DC99 8B7C24 44 MOV EDI,DWORD PTR SS:[ESP+44] ; *
0043DCA7 5E POP ESI ; *
0043DCB6 FF7424 04 PUSH DWORD PTR SS:[ESP+4] ; *
0043DCBA C2 0800 RETN 8 ; *
功能:
給各個寄存器賦值EBPSTACK中的數(shù)據(jù),EBPSTACK中的最后一個數(shù)據(jù)是跳轉(zhuǎn)地址
0043EC7D命名:
VM_MOVdw_EFLreg_EBPSTACK
代碼:
0043EC80 FF75 00 PUSH DWORD PTR SS:[EBP] ; *
0043EC83 8F4424 08 POP DWORD PTR SS:[ESP+8] ; *
0043EC8E FF7424 28 PUSH DWORD PTR SS:[ESP+28] ; *
0043EC92 9D POPFD ; *
功能:
給EFLAGE寄存器賦值EBPSTACK棧頂數(shù)據(jù)
在F7跟蹤加殼記事本的過程中,并不是所有的偽指令都使用到了,以下是沒有被執(zhí)行到的偽指令:
00405A14 . 70D74300 DD 0043D770
00405A18 . E0EA4300 DD 0043EAE0
00405A48 . 99E14300 DD 0043E199
00405A58 . 00DB4300 DD 0043DB00
00405A5C . 2ED84300 DD 0043D82E
00405A68 . 1FED4300 DD 0043ED1F
00405A6C . F6EC4300 DD 0043ECF6
00405A70 . 70E74300 DD 0043E770
00405A74 . 53D24300 DD 0043D253
00405A78 . C9CD4300 DD 0043CDC9
00405A94 . F5D24300 DD 0043D2F5
00405AA4 . E7D64300 DD 0043D6E7
00405AA8 . ACDB4300 DD 0043DBAC
00405AB8 . 6BE04300 DD 0043E06B
00405ABC . CDE84300 DD 0043E8CD
00405ACC . 3CE14300 DD 0043E13C
由于沒有實際的走過這些偽指令,靜態(tài)分析后覺得,有個別偽指令的代碼怕提取錯了。把這些指令寫成簡介模式:
0043D770
EBPSTACK的byte邏輯右移指令
0043EAE0
VM_JMP跳轉(zhuǎn)指令,重新給ESI賦值EBPSTACK棧頂數(shù)據(jù)
0043E199
復(fù)制EBPSTACK棧頂1個word的數(shù)據(jù)
0043DB00
把EBPSTACK棧頂數(shù)據(jù)作為地址,讀取其中1個word的數(shù)據(jù)壓入EBPSTACK
0043D82E
VM_DIV除法指令
0043ED1F
CPUID指令,結(jié)果壓入EBPSTACK。
0043ECF6
把EBPSTACK數(shù)據(jù)1個byte移動到棧頂內(nèi)存地址內(nèi)
0043E770
給EBP寄存器的低word位賦值棧頂數(shù)據(jù)
0043D253
把SS段寄存器壓入EBPSTACK棧頂
0043CDC9
另一種方式的word版NAND,不過這個是在EBPSTACK堆棧內(nèi)完成運算過程
0043D2F5
EBPSTACK的byte邏輯左移指令
0043D6E7
EBPSTACK的word邏輯左移指令
0043DBAC
EBPSTACK的word邏輯右移指令
0043E06B
EBPSTACK的word加法
0043E8CD
把EAX和EDX壓入EBPSTACK
0043E13C
把EBPSTACK數(shù)據(jù)1個word移動到棧頂內(nèi)存地址內(nèi)
到這里,所有的偽指令都羅列完畢,真的是體力活呀!
2.綜合運用
2.1.常見偽指令組合
在VMP的偽指令的執(zhí)行中有一些常見的組合套路,熟悉它們能讓我們在跟蹤VMP時更加的得心應(yīng)手。這些組合與操作數(shù)的長度是無關(guān)的,下面的偽指令將去掉b w dw等標記。在例子部分,我將使用dword操作數(shù)來舉例,直觀明了。
2.1.1.
VM_PUSH_EBP ;復(fù)制EBP指針到EBPSTACK棧頂
VM_COPY_EBPSTACK ;把EBPSTACK棧頂數(shù)據(jù)作為堆棧地址,從中讀取一個數(shù)據(jù)壓入EBPSTACK
這兩條指令是VMP中結(jié)合的極其緊密的組合,它們幾乎總是一起出現(xiàn)的,用于把EBPSTACK堆棧中的數(shù)據(jù)復(fù)制起來到EBPSTACK。而很多情況下它們復(fù)制的就是原來的棧頂數(shù)據(jù)。在使用NAND來完成NOT(A)的運算中,它們是必備的前奏。凡是需要把操作數(shù)一個變兩個的地方都有它們的身影。
例:
EBP 0013F9AC
0013F9AC 00000000 ....
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSH_EBP
EBP 0013F9A8
0013F9A8 0013F9AC .
0013F9AC 00000000 ....
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPY_EBPSTACK
EBP 0013F9A8
0013F9A8 00000000 ....
0013F9AC 00000000 ....
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
2.1.2.
VM_NAND|VM_ADD_EBPSTACK|VM_SHLD_EBPSTACK|VM_SHR_EBPSTACK等等
VM_MOV_EDISTACK_EBPSTACK ;把1個數(shù)據(jù)從EBPSTAK棧頂移動到EDISTACK,使用EAX作為偏移量
在VMP所有的運算偽指令中都是統(tǒng)一的模式,運算后的EFLAGS寄存器值位于EBPSTACK棧頂,運算結(jié)果位于緊接棧頂?shù)腫EBP+4]。在運算結(jié)束后,跟上一條VM_MOV_EDISTACK_EBPSTACK把運算后的標志位移動到EDISTACK,在很多時候,這都是一條廢指令操作,純粹是為去掉棧頂數(shù)據(jù),以便繼續(xù)操作運算結(jié)果。
如果接下來VM進行檢測標志位的相關(guān)操作,這條指令就變得異常重要。例如:在對系統(tǒng)函數(shù)的CC碼int3斷點檢測中,取出系統(tǒng)函數(shù)開頭的第一個byte數(shù)據(jù)XX,把它與CC相減,再跟上一個ZF標志位檢測+跳轉(zhuǎn)。在這個時候反過來,運算結(jié)果完全無用,而我們一定要在移動指令的EAX偏移量哪里下好斷點,觀察好EFLAGS寄存器值的走向與來源。
2.1.3.
在進行跳轉(zhuǎn)時,圍繞VM_JMP的前后,有大量無價值的數(shù)據(jù)移動操作。假設(shè)現(xiàn)在我們剛進行了一次條件判斷,VM剛剛把要跳轉(zhuǎn)的地址確定并解密出來:
EBP 0013F9A8
0013F9A8 00000202 .. ;最后一次解密運算得到的EFLAGS
0013F9AC 0043651A eC. ;跳轉(zhuǎn)地址
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
EBP 0013F9B0
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
EBP 0013F980
0013F980 8021D2F0 !
0013F984 0013F9C0 .
0013F988 00000246 F..
0013F98C 00000020 ...
0013F990 000359F4 Y.
0013F994 0013F9CC .
0013F998 00400000 ..@. ; OFFSET NOTEPAD
0013F99C 00000000 ....
0013F9A0 004253CD SB. ; RETURN from NOTEPAD.004255DB to NOTEPAD.004253CD
0013F9A4 000359F4 Y.
0013F9A8 00400000 ..@. ; 該帶著走的數(shù)據(jù)都要在EBPSTACK里面帶著走,到這里還沒有完畢的。
0013F9AC 0043651A eC. ;還有其他的數(shù)據(jù)要放入,8021D2F0要隱藏一下
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEdw
0013F97C 7FDE2D10 -
0013F980 8021D2F0 !
0013F984 0013F9C0
VM_ADDdw_EBPSTACK
0013F97C 00000247 G..
0013F980 00000000 ....
0013F984 0013F9C0
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F980 00000000 ....
0013F984 0013F9C0
VM_PUSHdw_EDISTACKdw
VM_PUSHdw_EDISTACKdw
0013F978 0043651A eC.
0013F97C 00000000 ....
0013F980 00000000 ....
0013F984 0013F9C0 .
0013F988 00000246 F..
0013F98C 00000020 ...
0013F990 000359F4 Y.
0013F994 0013F9CC .
0013F998 00400000 ..@. ; OFFSET NOTEPAD
0013F99C 00000000 ....
0013F9A0 004253CD SB. ; RETURN from NOTEPAD.004255DB to NOTEPAD.004253CD
0013F9A4 000359F4 Y.
0013F9A8 00400000 ..@. ; OFFSET NOTEPAD.B
0013F9AC 0043651A eC.
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_JMP ;帶著14個數(shù)據(jù),VM終于跳轉(zhuǎn),除了棧頂0043651A放入ESI,其他13個數(shù)據(jù)要重新保存
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F980 00000000 ....
0013F984 0013F9C0 .
VM_PUSHdw_IMMEDIATEdw
0013F97C 8021D2F0 !
0013F980 00000000 ....
0013F984 0013F9C0 .
VM_ADDdw_EBPSTACK
0013F97C 00000286 ..
0013F980 8021D2F0 !
0013F984 0013F9C0 . ;重新恢復(fù)出來
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw ;到這里停一下,搞個小運算,原EDX=000359F4 XOR 4DFD2FC2
0013F990 000359F4 Y.
0013F994 0013F9CC .
0013F998 00400000 ..@. ; OFFSET NOTEPAD.B
0013F99C 00000000 ....
0013F9A0 004253CD SB. ; RETURN from NOTEPAD.004255DB to NOTEPAD.004253CD
0013F9A4 000359F4 Y.
0013F9A8 00400000 ..@. ; OFFSET NOTEPAD.B
0013F9AC 0043651A eC.
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EBP
0013F98C 0013F990 .
0013F990 000359F4 Y.
0013F994 0013F9CC .
VM_COPYdw_EBPSTACK
0013F98C 000359F4 Y.
0013F990 000359F4 Y.
0013F994 0013F9CC .
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F990 000359F4 Y.
0013F994 0013F9CC .
VM_PUSHdw_EBP
0013F98C 0013F990 .
0013F990 000359F4 Y.
0013F994 0013F9CC .
VM_COPYdw_EBPSTACK
0013F98C 000359F4 Y.
0013F990 000359F4 Y.
0013F994 0013F9CC .
VM_NANDdw
0013F98C 00000282 ..
0013F990 FFFCA60B
0013F994 0013F9CC .
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F990 FFFCA60B
0013F994 0013F9CC .
VM_PUSHdw_IMMEDIATEdw
0013F98C B202D03D =
0013F990 FFFCA60B
0013F994 0013F9CC .
VM_NANDdw
0013F98C 00000206 ..
0013F990 000109C0 ..
0013F994 0013F9CC .
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F990 000109C0 ..
0013F994 0013F9CC .
VM_PUSHdw_IMMEDIATEdw
0013F98C 4DFD2FC2 /M
0013F990 000109C0 ..
0013F994 0013F9CC .
VM_PUSHdw_EDISTACKdw
0013F988 000359F4 Y.
0013F98C 4DFD2FC2 /M
0013F990 000109C0 ..
0013F994 0013F9CC .
VM_NANDdw
0013F988 00000286 ..
0013F98C B2008009 ..
0013F990 000109C0 ..
0013F994 0013F9CC .
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F98C B2008009 ..
0013F990 000109C0 ..
0013F994 0013F9CC .
VM_NANDdw
0013F98C 00000206 ..
0013F990 4DFE7636 6vM
0013F994 0013F9CC .
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
VM_MOVdw_EDISTACKdw_EBPSTACKdw
EBP 0013F9B0
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
每一次VM_JMP跳轉(zhuǎn),都要帶著14個數(shù)據(jù)轉(zhuǎn),而其中呢VM還要搞上一點暗碼轉(zhuǎn)移。以后看到是VM_JMP跳轉(zhuǎn)的狀況,就是看著EBP指針,嘩嘩嘩的讓它執(zhí)行,完畢了才停下來。中間的操作完全可以無視,我也是為了完整的表達才把它粘貼出了代碼,實際看的時候,不用管。整個過程:要帶著走的數(shù)據(jù)移到EBPSTACK-->VM_JMP跳轉(zhuǎn)-->重新把數(shù)據(jù)保存到EDISTACK。關(guān)于其中000359F4 XOR 4DFD2FC2的過程,請參考下一節(jié)2.2.NAND。
由于其他的組合都和NAND或標志位檢測+跳轉(zhuǎn)相關(guān),放在下兩節(jié)中。這一節(jié)中的3個組合熟悉后,已經(jīng)可以無視掉一部分VM的操作。
2.2.NAND(與非門)
本文的兩節(jié)重頭戲來了,NAND(與非門)與EFLAGS標志位檢測+跳轉(zhuǎn),理解完了這兩節(jié)后,對于VM就可以無視了,一切偽指令在你眼里都是正常的指令。跟蹤VMP就和跟蹤普通程序一樣,想看API獲取就看API獲取,想看看程序的anti方式就看anti方式。一切都回到了正常,你可以看穿VM(虛擬機)這個嚇人的外衣。
2.2.1.NAND起源
NAND(與非門)和NOR(或非門)來源于de Morgan's Laws(德·摩根定律),運用于邏輯、數(shù)字電路等方面,本節(jié)專注于它與and or xor not 之間的聯(lián)系。
德·摩根定律是屬于邏輯學(xué)的定律。 德·摩根定律(或稱德·摩根定理)是形式邏輯中有關(guān)否定所描述的系統(tǒng)方式中的邏輯運算符對偶對的一系列法則。由此引出的關(guān)系也就被稱為“德·摩根二重性”。
奧古斯都·德·摩根首先發(fā)現(xiàn)了在命題邏輯中存在著下面這些關(guān)系:
非(P 且 Q)=(非 P)或(非 Q)
非(P 或 Q)=(非 P)且(非 Q)
德·摩根的發(fā)現(xiàn)影響了喬治·布爾從事的邏輯問題代數(shù)解法的研究,這鞏固了德·摩根作為該規(guī)律的發(fā)現(xiàn)者的地位,盡管亞里士多德也曾注意到類似現(xiàn)象、且這也為古希臘與中世紀的邏輯學(xué)家熟知(引自Bocheński《形式邏輯歷史》)。(引自維基百科,關(guān)鍵字:德·摩根定律)
我們再來看它在數(shù)學(xué)邏輯中的表示:
1.jpg下載此附件需要消耗2Kx,下載中會自動扣除。
(引自:MathWorld,關(guān)鍵字:de Morgan's Laws)
由于不是用我們熟悉的計算機方式來表達,上面的兩段解說比較抽象,請看2.2.2.
2.2.2.NAND與邏輯運算
在加殼記事本中使用的是NAND,下面部分將專注于NAND。對于NOR,理論都是一樣的,只是不用NAND來實現(xiàn)。
NAND(A,B):
NOT(A)
NOT(B)
ADN(A,B)
這就是NAND的操作方式。NAND的價值在于:使用NAND可以實現(xiàn)NOT AND OR XOR這4個邏輯運算。
NOT(A):
NAND(A,A)
AND(A,B):
NAND(NAND(A,A),NAND(B,B))
OR(A,B):
NAND(NAND(A,B),NAND(A,B))
XOR(A,B):
NAND(NAND(NAND(A,A),NAND(B,B)),NAND(A,B))
2.2.3.VMP偽指令執(zhí)行過程
NOT(4DBE4AD8):
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EBP
0013F9A8 0013F9AC .
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPYdw_EBPSTACK
0013F9A8 4DBE4AD8 JM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9A8 00000286 ..
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(A,A)
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
NOT(4DBE4AD8)=B241B527
AND(4DBE4AD8,4DFD2FC2):
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EBP
0013F9A8 0013F9AC .
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPYdw_EBPSTACK
0013F9A8 4DBE4AD8 JM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9A8 00000286 ..
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(A,A),NAND(B,B))
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEdw
0013F9A8 B202D03D =
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(A,A),NAND(B,B))**B202D03D=NAND(B,B)**
VM_NANDdw
0013F9A8 00000206 ..
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(A,A),NAND(B,B))VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VMP的B數(shù)據(jù)是直接傳遞它的相反數(shù)B202D03D給VM,相當(dāng)于隱藏了一次NAND(B,B)的過程。AND(4DBE4AD8,4DFD2FC2)=4DBC0AC0
OR (00000293,00000100):
0013F780 00000293 ..
0013F784 00000100 ...
VM_NANDdw ;NAND(NAND(A,B),NAND(A,B))
0013F784 FFFFFC6C l
VM_PUSHdw_EBP
VM_COPYdw_EBPSTACK ;復(fù)制結(jié)果,就相當(dāng)于NAND(NAND(A,B),NAND(A,B))
0013F780 FFFFFC6C l
0013F784 FFFFFC6C l
VM_NANDdw ;NAND(NAND(A,B),NAND(A,B))
0013F784 00000393 ..
OR (00000293,00000100)=00000393
XOR(4DBE4AD8,4DFD2FC2):
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EBP
0013F9A8 0013F9AC .
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPYdw_EBPSTACK
0013F9A8 4DBE4AD8 JM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9A8 00000286 ..
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(NAND(A,A),NAND(B,B)),NAND(A,B))
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEdw
0013F9A8 B202D03D =
0013F9AC B241B527 'A
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(NAND(A,A),NAND(B,B)),NAND(A,B))**B202D03D=NAND(B,B)**
VM_NANDdw
0013F9A8 00000206 ..
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(NAND(A,A),NAND(B,B)),NAND(A,B))
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EDISTACKdw
0013F9A8 4DBE4AD8 JM
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEdw
0013F9A4 4DFD2FC2 /M
0013F9A8 4DBE4AD8 JM
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9A4 00000282 ..
0013F9A8 B2009025 %.
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(NAND(A,A),NAND(B,B)),NAND(A,B))
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9A8 B2009025 %.
0013F9AC 4DBC0AC0 .M
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9A8 00000202 ..
0013F9AC 0043651A eC.
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(NAND(A,A),NAND(B,B)),NAND(A,B))
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 0043651A eC.
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
上面這條XOR指令,就是VM在確定跳轉(zhuǎn)地址后的解密指令。加密地址是A數(shù)據(jù)4DBE4AD8,XOR運算后得到ESI跳轉(zhuǎn)地址0043651A。
在VMP中,減法是采用迂回的方式實現(xiàn)的:
A-B:
NOT(A)
A=A+B
NOT(A)
而NOT運算又要使用NAND來完成
A-B:
NAND(A,A)
A=A+B
NAND(A,A)
2.3.EFLAGS標志位檢測+跳轉(zhuǎn)
這一節(jié)看完后,就可以暢通無阻的瀏覽VMP的偽指令了。
2.3.1.判斷兩個數(shù)是否相同
舉例數(shù)據(jù):
把立即數(shù)0000和內(nèi)存00427D51中的1個word數(shù)據(jù)比較,檢測是否為0。
整個過程分為兩個階段:
第一階段:執(zhí)行減法運算
A-B:
NAND(A,A) ;這里的標志位是無用的
A=A+B ;獲得標志位A
NAND(A,A) ;獲得標志位B
第二階段:合并兩個標志位
A=AND(A,00000815)
B=AND(B,FFFFF7EA)
A=A+B
第三階段:檢測ZF位+跳轉(zhuǎn)
構(gòu)建跳轉(zhuǎn)地址結(jié)構(gòu)
檢測ZF位
獲得加密跳轉(zhuǎn)地址
解密跳轉(zhuǎn)地址
調(diào)用VM_JMP
在開始這個部分前,把所有VM_MOV_EDISTACK_EBPSTACK偽指令中的AND AL,3C指令的下一條指令處下好斷點,我們要記錄下各個標志位的走向!000000286-->14(表示EFL存儲到偏移量14的[EDI+EAX]位置)
第一階段:
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHw_IMMEDIATEb
0013F9AC 0000
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;立即數(shù)IMM0000
VM_PUSHdw_IMMEDIATEdw
0013F9A8 7D51
0013F9AC 00000042 B...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHw_MEMORYb
0013F9AC 00000000
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;內(nèi)存數(shù)MEM0000。很明顯,我們看到兩個數(shù)是相同的
VM_PUSHdw_EBP
0013F9A8 0013F9AC .
0013F9AC 00000000 ....
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPYw_EBPSTACK
0013F9A8 0000
0013F9AC 00000000 ....
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;復(fù)制內(nèi)存數(shù)MEM0000
VM_NANDw
0013F9A8 00000286 ..
0013F9AC 000000FF ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NOT(MEM0000)=MEM00FF
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 000000FF ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;000000286-->14(表示EFL存儲到偏移量14的[EDI+EAX]位置)
VM_ADDb_EBPSTACK
0013F9A8 0286
0013F9AC 00FF0000 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;00FF=IMM0000+MEM00FF
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 00FF
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;標志位A 000000286-->04
VM_PUSHdw_EBP
0013F9A8 F9AE
0013F9AC 00FF0013 ..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPYw_EBPSTACK
0013F9AC 00FF00FF ..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDw
0013F9A8 0246
0013F9AC 00000000 ....
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NOT(00FF)
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 0000
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;標志位B 00000246-->3C
VM_MOVw_EDISTACKb_EBPSTACKw
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;
第一階段結(jié)束。
兩個操作數(shù)都是0000,很明顯這次判斷將是兩個數(shù)相同,減法后的ZF位置1。
運算的結(jié)果都是無用的,關(guān)鍵在于它的標志位,繼續(xù)看標志位ZF的檢測+跳轉(zhuǎn)
第二階段:
VM_PUSHdw_EDISTACKdw
0013F9AC 00000286 ..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;標志位A 000000286<--04
VM_PUSHdw_EDISTACKdw
0013F9A8 00000286 ..
0013F9AC 00000286 ..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;再來一次標志位A
VM_NANDdw
0013F9A8 00000282 ..
0013F9AC FFFFFD79 y
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(A,A)=NOT(A)=FFFFFD79
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC FFFFFD79 y
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEw
0013F9A8 FFFFF7EA
0013F9AC FFFFFD79 y
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(X,X)=NOT(00000815)=FFFFF7EA 傳遞相反數(shù),隱藏NOT(00000815)
VM_NANDdw
0013F9A8 00000202 ..
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(A,A),NAND(X,X))=標志位A 00000286 AND 00000815
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_EDISTACKdw
0013F9A8 00000246 F..
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;標志位B 00000246<--3C
VM_PUSHdw_EDISTACKdw
0013F9A4 00000246 F..
0013F9A8 00000246 F..
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;再來一次標志位B
VM_NANDdw
0013F9A4 00000282 ..
0013F9A8 FFFFFDB9
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(B,B)=NOT(B)=FFFFFDB9
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9A8 FFFFFDB9
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEw
0013F9A4 00000815 ..
0013F9A8 FFFFFDB9
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(Y,Y)=NOT(FFFFF7EA)=00000815 傳遞相反數(shù),隱藏NOT(FFFFF7EA)
VM_NANDdw
0013F9A4 00000206 ..
0013F9A8 00000242 B..
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(B,B),NAND(Y,Y))=標志位B 00000246 AND FFFFF7EA
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9A8 00000242 B..
0013F9AC 00000004 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_ADDdw_EBPSTACK
0013F9A8 00000202 ..
0013F9AC 00000246 F..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;兩個AND后的標志位相加
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 00000246 F..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;00000246-->00 暫存結(jié)果
第二階段結(jié)束
現(xiàn)在VMP已經(jīng)把兩個標志位合并成了一個,關(guān)于標志位合并的解析結(jié)束后再來看。繼續(xù)看第三階段:檢測ZF+跳轉(zhuǎn),注意看好堆棧數(shù)據(jù)的構(gòu)造,堆棧虛擬機的跳轉(zhuǎn)判斷有他獨特的地方!同時它巧妙的運用了ZF位在EFLAGS中的位置。
第三階段:
VM_PUSHdw_IMMEDIATEdw
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳轉(zhuǎn)地址1
VM_PUSHdw_IMMEDIATEdw
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳轉(zhuǎn)地址2
VM_PUSHdw_EBP
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳轉(zhuǎn)地址指針
VM_PUSHw_IMMEDIATEb
0013F9A0 0004
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;傳遞4,看好堆棧的構(gòu)造,下面的幾個操作是獨立的
VM_PUSHdw_EDISTACKdw
0013F99C 0246
0013F9A0 00040000 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;第二階段結(jié)果00000246<--00
VM_PUSHdw_EBP
0013F998 F99E
0013F99C 02460013 .F
0013F9A0 00040000 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_COPYdw_EBPSTACK
0013F998 0246
0013F99C 02460000 ..F
0013F9A0 00040000 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;復(fù)制標志位
VM_NANDdw
0013F998 0282
0013F99C FDB90000 ..
0013F9A0 0004FFFF .
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(A,A)=NOT(A)=NOT(00000246)=FFFFFDB9
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F99C FDB9
0013F9A0 0004FFFF .
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEb
0013F998 FFBF
0013F99C FDB9FFFF
0013F9A0 0004FFFF .
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(B,B)=NOT(00000040)=FFFFFFBF 傳遞相反數(shù),隱藏NOT(000000040)
VM_NANDdw
0013F998 0202
0013F99C 00400000 ..@. ; OFFSET NOTEPAD.B
0013F9A0 00040000 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(B,B),NAND(B,B))=標志位 00000246 AND 00000040
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F99C 0040
0013F9A0 00040000 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;AND結(jié)果是00000040,說明ZF位是1,兩個數(shù)相等;想想如果不相等,結(jié)果是00000000
VM_SHRdw_EBPSTACKb
0013F99C 00000202 ..
0013F9A0 00000004 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;右移4位剛好把00000040移動成00000004;如果不相等,右移后是00000000
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9A0 00000004 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_ADDdw_EBPSTACK
0013F9A0 00000206 ..
0013F9A4 0013F9AC .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;00000004+0013F9A8=0013F9AC;如果不相等,00000000+0013F9A8=0013F9A8
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9A4 0013F9AC .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳轉(zhuǎn)地址指針指向的就是判斷后的跳轉(zhuǎn)地址
VM_COPYdw_EBPSTACK
0013F9A4 4DBE4AD8 JM
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳轉(zhuǎn)地址指針指向的跳轉(zhuǎn)地址復(fù)制出來
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;把最終的跳轉(zhuǎn)地址暫存到EDISTACK,4DBE4AD8-->18
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;掃尾工作,釋放EBPSTACK
VM_MOVdw_EDISTACKdw_EBPSTACKdw
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;掃尾工作,釋放EBPSTACK
VM_PUSHdw_EDISTACKdw
0013F9AC 4DBE4AD8 JM
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;壓入判斷的跳轉(zhuǎn)地址4DBE4AD8<--18
第三階段結(jié)束
接下來VM將使用一次XOR運算解密4DBE4AD8數(shù)據(jù)(詳見2.2.3.XOR舉例),然后是VM_JMP指令調(diào)用的組合(詳見2.1.3.舉例),全過程結(jié)束。
兩個操作數(shù)都是0000,1個來自內(nèi)存空間,一個來自ESI的編譯數(shù)據(jù),同時這段代碼是在VM剛剛啟動就進行的了,都是定量。但是VM還要進行檢測,說明兩個數(shù)據(jù)是不確定的,VM在運行過程中要知道它是不是0,可以把它猜測為VMP內(nèi)部的一個信號。VM一開始就要知道到底應(yīng)該走向哪個分支。到后面我們會進行測試,如果這個信號比較結(jié)果不為0,VM的走向是怎樣的。
下面我們來詳解上面的操作過程,從第二階段合并標志位來看
第一階段:執(zhí)行減法運算
IMM0000-MEM0000:
NAND(IMM0000,IMM0000) ;這里的標志位是無用的
00FF=IMM00FF+MEM0000 ;獲得標志位A 000000286
NAND(00FF,00FF) ;獲得標志位B 000000246
第二階段:合并兩個標志位
00000004=AND(00000286,00000815)
00000242=AND(00000246,FFFFF7EA)
00000246=00000004+00000242
把兩個標志位分別AND后相加,AND操作時用于保留想要的標志位,加法把它合并起來。
關(guān)于EFLAGS標志位,Intel的資料顯示:
3.jpg下載此附件需要消耗2Kx,下載中會自動扣除。
各個標志位的詳細說明,請查閱Intel 64 and IA-32 Architectures Software Developer's Mannual(Intel 64位與IA-32體系結(jié)構(gòu)軟件開發(fā)者指南)中卷1的3.4.3 EFLAGS Register
關(guān)于ADD指令,Intel的資料顯示:
ADD—Add
Operation
DEST DEST SRC;
Flags Affected
The OF, SF, ZF, AF, CF, and PF flags are set according to the result.
把00000286 AND 00000815使用二進制表示:
0000 0000 0000 0000 0000 0010 1000 0110
AND 0000 0000 0000 0000 0000 1000 0001 0101
我們現(xiàn)在就可以看到,VM要保留的是 OF AF PF CF 位。那么,SF和ZF位為什么不在這里保留呢?我們要想到,由于這里并不是A-B的最后結(jié)果,SF 和 ZF位要等到最后的運算完成才能知道。在標志位A中,PF位為1,PF位被保留。
第一個AND數(shù)00000815與第二個AND數(shù)FFFFF7EA之間是有內(nèi)在聯(lián)系的。00000815+FFFFF7EA=FFFFFFFF,也就是說,這兩個這兩個AND操作時可以把所有的標志位都保留下來的,不會出現(xiàn)遺漏。而把它分開的話,是由于變換了減法的運算方式不進行保留對應(yīng)的保留。
最后的NAND(A,A):
NOT A ;第一個操作數(shù)
NOT A ;第二個操作數(shù)
AND A,A ;最終標志位B 00000246是來自這里
關(guān)于AND邏輯運算,Intel的資料顯示:
AND—Logical AND
Operation
DEST DEST AND SRC;
Flags Affected
The OF and CF flags are cleared; the SF, ZF, and PF flags are set according to the
result. The state of the AF flag is undefined.
把00000246 AND FFFFF7EA使用二進制表示:
0000 0000 0000 0000 0000 0010 0100 0110
AND 1111 1111 1111 1111 1111 0111 1110 1010
VM要把除了上面00000815保留了的 OF AF PF CF 以外的標志位都保留了下來。在標志位B中,IF ZF PF 和第二位是Intel的保留位默認為1 這4個標志位為1,所以IF ZF PF被保留。
兩個標志位相加后,最終合并成為兩個操作數(shù)SUB指令后的標志位00000246
下面我們來看第三階段:
構(gòu)建跳轉(zhuǎn)結(jié)構(gòu):
0013F9A0 0004
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
把兩個跳轉(zhuǎn)地址4DBE49D5與4DBE4AD8壓入堆棧。0013F9A8成為跳轉(zhuǎn)地址指針,指向第一個跳轉(zhuǎn)地址。如果0013F9A8指針+4,它就會指向第二個指針。最后還有1個0004,它并不是用于給指針+4的操作數(shù),它要參與到巧妙判斷ZF位的運算中。
接下來,VM用NAND執(zhí)行一次AND操作,操作數(shù)是:標志位00000246與00000040 (在NAND操作中,VM不意外的隱藏了一次NAND(B,B)操作,直接傳遞00000040的相反數(shù)FFFFFFBF)
0013F998 FFBF
0013F99C FDB9FFFF
0013F9A0 FFFF .
0013F9A0 0004 ;為了清晰變現(xiàn),把它分開顯示
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
VM_NANDdw
0013F99C 0040 ;運算結(jié)果為00000040
0013F9A0 00040000 ...
0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM
NAND操作是:
NOT(A)
NOT(B)
AND(A,B)
所以,在這條偽指令的內(nèi)部,00000246 AND 0000040
把00000246 AND 00000040使用二進制表示:
0000 0000 0000 0000 0000 0010 0100 0110
AND 0000 0000 0000 0000 0000 0000 0100 0000
唯一的檢測ZF位,如果ZF位為1,那么結(jié)果將是00000040,否則是00000000。由于ZF位剛好是在byte的4的位置,把它和前面的跳轉(zhuǎn)地址指針相加,0013F9A8+0則是不變,指向第一個地址,+4就指向第二個地址,所以剛好可以讓AND后的結(jié)果與指針0013F9A8進行1次加法運算,如果ZF位是1,0013F9A8+4將指向4DBE4AD8完成判斷跳轉(zhuǎn)。由于ZF位的前面還有1個byte的數(shù)據(jù)0,就是00000040中最后的1個byte0,如果直接和0013F9A8相加,就變成+40,所以要先進行1次4個bit的右移,00000040變?yōu)?0000004,這樣才正確。
ZF位為1,AND 00000040后: ZF位為0,AND 00000040后:
00000040 00000000
SHR(4) 00000004 SHR(4) 00000000
ADD 0013F9A8 ADD 0012F9A8
結(jié)果 0013F9AC 結(jié)果 0013F9A8
0013F9A4 0013F9AC . 0013F9A4 0013F9A8 .
0013F9A8 4DBE49D5 IM 0013F9A8 4DBE49D5 IM
0013F9AC 4DBE4AD8 JM 0013F9AC 4DBE4AD8 JM
ZF位的不同帶來跳轉(zhuǎn)地址的不同,把相應(yīng)的跳轉(zhuǎn)地址解密后,使用VM_JMP給VM的指令指針ESI賦值,全程結(jié)束。
進行ZF位比較的話,只需要比較最后的標志位B就可以了,而且可以進行直接的比較,不需要這樣截取+拼接,那么為什么VMP還需要在整個過程中截取了所有的標志位呢?我想,可以這么來考慮,在VMP中標志位的截取+拼接在代碼中是屬于一個模塊,不管VMP要檢測哪個標志位,它都是先調(diào)用這個模塊然后再進行標志位檢測。雖然在單純的ZF位檢測中,有了很多的不必要的操作,但是它增加了通用性,只要調(diào)用了這個模塊,VMP在后面可以接上任意標志位的檢測。
3.NOTEPAD全程跟蹤
在這一章里,我們將全過程瀏覽NOTEPAD.EXE文件。本章顯示的代碼,外殼的花指令將全部跳過,VM的偽指令則部份跳過。
3.1.TLS
3.1.1.到達Dispatch部份
VMProtect2.04加殼程序是從TLS開始運行的,我們首先點擊OD的options菜單,修改Startup and exit選項,讓OD中斷在TLS callback里。載入NOTOPAD.EXE后,程序停在這里:
004253CD $ 68 9AA597B7 PUSH B797A59A ; TLS callback function
當(dāng)前的寄存器值:
EAX 004253CD NOTEPAD.004253CD
ECX 00000020
EDX 000359F4
EBX 00000000
ESP 0013F9B0
EBP 0013F9CC
ESI 0013F9C0
EDI 00400000 NOTEPAD.
進入VM之前,VMP要保存當(dāng)前的各個寄存器值,VM堆棧要分配,同時給偽指令指針寄存器ESI賦值等等,初始化結(jié)束后,進入Dispatch部份VM開始運行。F7單步下去:
0043BD02 . C74424 40 0A4 MOV DWORD PTR SS:[ESP+40],2EF6420A ; |*
00429088 |> \C74424 44 19C MOV DWORD PTR SS:[ARG.17],C456C619 ; *
;壓入VM的兩個定量。
0043DCD2 |. 893424 MOV DWORD PTR SS:[ESP],ESI ; *
0043CF0D . 57 PUSH EDI ; *
0043CF17 . 891424 MOV DWORD PTR SS:[ESP],EDX ; *
0043CF1D . 50 PUSH EAX ; *
0043E17A |. 896C24 04 MOV DWORD PTR SS:[ARG.1],EBP ; *
0043D741 |> /871C24 XCHG DWORD PTR SS:[ESP],EBX ; *
0043D746 |. 894C24 20 MOV DWORD PTR SS:[ESP+20],ECX ; *
;7個寄存器保存完畢
0043D750 |. 875424 40 XCHG DWORD PTR SS:[ESP+40],EDX ; |Arg17, *
0043E62E /$ 9C PUSHFD ; *
0043E62F |. 8F4424 40 POP DWORD PTR SS:[ESP+40] ; *
0043E636 |. FF35 89D24300 PUSH DWORD PTR DS:[43D289] ; *
0043E63C |. 8F4424 3C POP DWORD PTR SS:[ESP+3C] ; *
0043E646 |. C74424 38 000 MOV DWORD PTR SS:[ESP+38],0 ; *
;多保存1個寄存器,由于ESP是動態(tài)的,這個位置相當(dāng)于是ESP寄存器的位置;EFLAGS;內(nèi)存地址[43D289];常量0;一共保存13個數(shù)據(jù)
0013F97C 00000000 .... ;常量0 20
0013F980 00000000 .... ;[43D289] 24 8121D2F0相加
0013F984 00000246 F.. ;EFLAGS 0C
0013F988 000359F4 Y. ;EDX(給ESP寄存器的位置) 00
0013F98C 00000020 ... ;ECX 08
0013F990 00000000 .... ;EBX 1C
0013F994 0013F9CC . ;EBP 28
0013F998 004253CD SB. ;EAX 10
0013F99C 000359F4 Y. ;EDX 2C
0013F9A0 00400000 ..@. ;EDI 30
0013F9A4 0013F9C0 . ;ESI 38
0013F9A8 C456C619 V ;常量B 3C
0013F9AC 2EF6420A .B. ;常量A 18
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
0043E65B |. 8B7424 68 MOV ESI,DWORD PTR SS:[ESP+68] ; *
;這里讀取的是常量A=2EF6420A,以下是解密2EF6420A的過程:
0043E665 |. 0FCE BSWAP ESI ; *
0043E66E |. 4E DEC ESI ; *
0043E67D |. 81F6 63A1000A XOR ESI,0A00A163 ; *
;結(jié)束,ESI=0042574E,這里就是VM的指令序列
0043E68C |. 8D6C24 34 LEA EBP,[ESP+34]
0043E692 |. 81EC 8C000000 SUB ESP,8C ; *
0043E69C |. 89E7 MOV EDI,ESP ; *
;第一條指令EBP取得的地址是0013F97C的位置,也就是13個保存數(shù)據(jù)的結(jié)束地址,要在這個的基礎(chǔ)上分配VM堆棧
;保存的13個dword=34byte,ESP在執(zhí)行減法前,位于0013F9FC的34個byte位置,減法分配8Cbyte;34+34+8C=F4byte=61dword
;VM堆棧的詳細分析請查閱1.2.VM堆棧
0043E6A9 |. 89F3 MOV EBX,ESI ; *
;EBX是VM解密數(shù)據(jù)的輔運算寄存器,初始化為VM的指令序列地址0042574E
0043E6B8 |. 0375 00 ADD ESI,DWORD PTR SS:[EBP] ; *
;ESI的地址還要和常量0相加,相加會改變VM指令序列的地址,決定VM第一次運行后要執(zhí)行的指令
;常量0可以看作是VM內(nèi)部的一個修正量,在NOTEPAD里它是0
到這里,一切初始化完成,程序已經(jīng)到達Dispatch(調(diào)遣)部份。整個過程概括為:保存數(shù)據(jù)、分配VM堆棧、給ESI賦值。下一條指令就是所有偽指令執(zhí)行完成后的返回地址0043E6BB。
0043E6BB |> >66:0FA5FA SHLD DX,DI,CL ; Dispatch 花指令,沒有什么意義
3.1.2.Dispatch部份解析
下面是第1條偽指令的獲取過程:
0043E6BF |. 8A46 FF MOV AL,BYTE PTR DS:[ESI-1] ; *
;開始讀取偽指令序列號,以下是解密偽指令序列號C0的過程:
0043E6C4 |. 30D8 XOR AL,BL
0043E6CE |. F6D0 NOT AL ; *
0043E6D6 |. FEC8 DEC AL ; *
0043E6DA |. C0C8 07 ROR AL,7 ; *
;結(jié)束,AL=E0,它將用于在DispatchTable(調(diào)遣表)中定位出偽指令地址。
0043E6E1 |. 83EE 01 SUB ESI,1 ; *
0043E6ED |. 30C3 XOR BL,AL ; *
;指令序列減1,計算好下一次BL的值
0043D02F |. 0FB6C0 MOVZX EAX,AL ; *
0043F124 |. 8B1485 DBE143 MOV EDX,DWORD PTR DS:[EAX*4+43E1DB] ; *
;取出偽指令地址49C4C29F,以下是解密49C4C29F的過程:
;DispatchTable的詳細分析請查閱1.3.偽指令匯總
0043E100 |> /81C2 6B197FB6 ADD EDX,B67F196B ; *
;只有1條解密指令,加上常量B67F196B,EDX=0043DC0A
0043E10A |. 895424 3C MOV DWORD PTR SS:[ESP+3C],EDX ; *
0043E11B |. FF7424 4C PUSH DWORD PTR SS:[ESP+4C] ; *
0043E11F |. C2 5000 RETN 50 ; Enter
;由于是使用RET指令來跳轉(zhuǎn),需要使用到真實堆棧指針ESP,在暫存EDX地址時,VM使用的空間是EDISTACK的上一個位置:
0013F8B8 0043DC0A .C. ; RETURN from NOTEPAD.0043D5C7 to NOTEPAD.0043DC0A
0013F8BC 00953F38 8?. ;這里是EDISTACK的上限
到這里,VM將進入執(zhí)行第一條偽指令。整個過程:初始化、從ESI指針獲得偽指令序列號、從DispatchTable獲得偽指令地址、跳轉(zhuǎn)執(zhí)行偽指令。Dispatch部份是VM中將會不斷重復(fù)重復(fù)再重復(fù)的執(zhí)行,所有的偽指令完畢后,都是返回到這里獲得下一條偽指令。
3.1.3.anti方式初現(xiàn)
通過前面章節(jié)的介紹,在這一節(jié)里,我將對NOTEPAD從TLS回調(diào)函數(shù)到TLS退出進行一次概論。這個過程將不再出現(xiàn)任何的x86指令代碼,前面介紹的偽指令組合和相關(guān)內(nèi)容將會被縮短和鏈接后跳過。
1.初始化(請查閱3.1.初始化)
NOTEPAD在TLS回調(diào)函數(shù)中斷后,經(jīng)過初始化過程后,開始執(zhí)行偽指令。VM將會把所有EBPSTACK中帶過來的13個初始化保留數(shù)據(jù)暫存至EDISTACK。
2.ESI數(shù)據(jù)0000與[00427D51]=0000進行比較+跳轉(zhuǎn)(請查閱2.3.1.判斷相同)
3.VMP將根據(jù)PE文件結(jié)構(gòu)讀取出程序入口的第一個字節(jié)進行CC碼檢測。VM會去到另外的堆棧空間操作整個過程,把ESP指針從0013F994-40=0013F954,在開頭構(gòu)建2個0013F954進行NAND(A,A)中,和前面稍有不同,這里不再詳述。過程:
0013F994-40=0013F954
MOV EBP,0013F954
0013F988 0013F994 .
0013F98C 0013F994 .
0013F990 00000040 @...
0013F994 0013F9C0 . ;計算前的EBP指針
VM_NANDdw
0013F98C FFEC066B k
0013F990 00000040 @...
0013F994 0013F9C0 .
VM_ADDdw_EBPSTACK
0013F990 FFEC06AB
0013F994 0013F9C0 .
VM_PUSHdw_EBP
VM_COPYw_EBPSTACK
0013F98C FFEC06AB
0013F990 FFEC06AB
0013F994 0013F9C0 .
VM_NANDdw
0013F990 0013F954 T.
0013F994 0013F9C0 .
VM_MOVdw_EBPreg_EBPSTACK
EBP 0013F954
堆棧移動到0013F954后,
VM_PUSHdw_IMMEDIATEdw ;壓入00427D51
開始從程序的入口地址根據(jù)PE文件格式定位:
VM_PUSHdw_IMMEDIATEdw ;壓入00400000,NOTEPAD程序的文件頭地址,OD數(shù)據(jù)窗口跟蹤
00400000 4D 5A 90 00|03 00 00 00|04 00 00 00|FF FF 00 00| MZ.........
00400010 B8 00 00 00|00 00 00 00|40 00 00 00|00 00 00 00| .......@.......
00400020 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400030 00 00 00 00|00 00 00 00|00 00 00 00|80 00 00 00| ...............
00400040 0E 1F BA 0E|00 B4 09 CD|21 B8 01 4C|CD 21 54 68| ..!L!Th
00400050 69 73 20 70|72 6F 67 72|61 6D 20 63|61 6E 6E 6F| is program canno
00400060 74 20 62 65|20 72 75 6E|20 69 6E 20|44 4F 53 20| t be run in DOS
00400070 6D 6F 64 65|2E 0D 0D 0A|24 00 00 00|00 00 00 00| mode....$.......
00400080 50 45 00 00|4C 01 09 00|65 91 46 35|00 00 00 00| PE..L..eF5....
00400090 00 00 00 00|E0 00 0F 01|0B 01 03 0A|00 F0 03 00| .....
004000A0 00 74 00 00|00 00 00 00|17 78 03 00|00 10 00 00| .t......x....
004000B0 00 50 00 00|00 00 40 00|00 10 00 00|00 10 00 00| .P....@.......
004000C0 04 00 00 00|00 00 00 00|04 00 00 00|00 00 00 00| ..............
004000D0 00 50 04 00|00 04 00 00|CE 59 03 00|02 00 00 00| .P....Y....
004000E0 00 00 10 00|00 10 00 00|00 00 10 00|00 10 00 00| ............
004000F0 00 00 00 00|10 00 00 00|FC 1D 02 00|50 0C 00 00| ........P...
00400100 18 66 03 00|A0 00 00 00|00 00 04 00|00 50 00 00| f........P..
00400110 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400120 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400130 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400140 F4 59 03 00|20 00 00 00|00 00 00 00|00 00 00 00| Y. ...........
00400150 00 00 00 00|00 00 00 00|B0 7D 03 00|4C 00 00 00| ........}.L...
00400160 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400170 00 00 00 00|00 00 00 00|2E 74 65 78|74 00 00 00| .........text...
00400180 9C 3E 00 00|00 10 00 00|00 00 00 00|00 00 00 00| >.............
00400190 00 00 00 00|00 00 00 00|00 00 00 00|20 00 00 60| ............ ..`
004001A0 2E 64 61 74|61 00 00 00|4C 08 00 00|00 50 00 00| .data...L...P..
004001B0 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
004001C0 00 00 00 00|40 00 00 C0|2E 69 64 61|74 61 00 00| ....@...idata..
004001D0 E8 0D 00 00|00 60 00 00|00 00 00 00|00 00 00 00| ....`..........
004001E0 00 00 00 00|00 00 00 00|00 00 00 00|40 00 00 40| ............@..@
004001F0 2E 76 6D 70|31 00 00 00|B8 4F 00 00|00 70 00 00| .vmp1...O...p..
00400200 00 50 00 00|00 10 00 00|00 00 00 00|00 00 00 00| .P.............
00400210 00 00 00 00|60 00 00 60|2E 76 6D 70|30 00 00 00| ....`..`.vmp0...
00400220 9C 0A 00 00|00 C0 00 00|00 00 00 00|00 00 00 00| ..............
00400230 00 00 00 00|00 00 00 00|00 00 00 00|60 00 00 60| ............`..`
00400240 2E 76 6D 70|32 00 00 00|A0 FD 00 00|00 D0 00 00| .vmp2........
00400250 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400260 00 00 00 00|20 00 00 20|2E 74 6C 73|00 00 00 00| .... .. .tls....
00400270 18 00 00 00|00 D0 01 00|00 10 00 00|00 60 00 00| .........`..
00400280 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 C0| ...............
00400290 2E 76 6D 70|33 00 00 00|85 11 02 00|00 E0 01 00| .vmp3......
004002A0 00 20 02 00|00 70 00 00|00 00 00 00|00 00 00 00| . ..p..........
004002B0 00 00 00 00|20 00 00 E2|2E 72 73 72|63 00 00 00| .... ...rsrc...
004002C0 B0 4F 00 00|00 00 04 00|00 50 00 00|00 90 02 00| O......P....
004002D0 00 00 00 00|00 00 00 00|00 00 00 00|40 00 00 40| ............@..@
004002E0 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
004002F0 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400300 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400310 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400320 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400330 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
00400340 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
..........................................................................
0013F94C 0000003C <...
0013F950 00400000 ..@. ; OFFSET NOTEPAD. ;DOS_header_addr
VM_ADDdw_EBPSTACK
0013F950 0040003C <.@. ;e_magic
VM_PUSHdw_MEMORYdw
0013F950 00000080 ...
取得e_magic的數(shù)值,獲取PE文件頭位置
0013F94C 00000080 ...
0013F950 00400000 ..@. ; OFFSET NOTEPAD
VM_ADDdw_EBPSTACK
0013F950 00400080 .@. ; ASCII "PE" ;IMAGE_NT_HEADERS
0013F94C 00400080 .@. ; ASCII "PE"
0013F950 00000028 (...
VM_ADDdw_EBPSTACK
0013F950 004000A8 .@. ;AddressOfEntryPoint
VM_PUSHdw_MEMORYdw
0013F950 00037817 x.
PE文件頭28偏移量的位置是屬于IMAGE_OPTIONAL_HEADER32結(jié)構(gòu)的AddressOfEntryPoint字段,程序執(zhí)行入口RVA00037817
0013F94C 00037817 x.
0013F950 00400000 ..@. ; OFFSET NOTEPAD
VM_ADDdw_EBPSTACK
0013F950 00437817 xC. ; NOTEPAD.
現(xiàn)在已經(jīng)獲得NOTEPAD的程序執(zhí)行入口地址
VM_PUSHw_IMMEDIATEb
0013F950 00CC
0013F94C 7817
0013F950 00CC0043 C..
VM_PUSHw_MEMORYb
0013F950 00CC0068 h..
從執(zhí)行入口地址讀取字節(jié)和CC進行比較,我沒有在入口地址下INT3斷點,取得的字節(jié)是68,接下來VMP進行減法和標志位ZF檢測,這里不再復(fù)述,在VM_JMP組合執(zhí)行完畢后,恢復(fù)EBPSTACK重新回到0013F994。
4.IF標志位置1
VM使用NAND進行1次AND操作,AND操作數(shù)的一個是700,截取的是DF,IF,TF位,另一個操作數(shù)是246,這樣保留的就是Interrupt Enable Flag(IF)位。最后通過偽指令VM_MOVdw_EFLreg_EBPSTACK把結(jié)果壓入EFlags寄存器。
0013F9A8 00000246 F..
0013F9AC 00000246 F..
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9AC FFFFFDB9
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_PUSHdw_IMMEDIATEw
0013F9A8 000008FF ..
0013F9AC FFFFFDB9
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_NANDdw
0013F9AC 00000200 ...
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
VM_MOVdw_EFLreg_EBPSTACK
3.1.4.TLS退出
0013F990 8021D2F0 !
0013F994 8021D2F0 !
0013F998 00000246 F..
0013F99C F6F93A39 9:
0013F9A0 00000020 ...
0013F9A4 00000000 ....
0013F9A8 0013F994 .
0013F9AC 004253CD SB. ; RETURN from NOTEPAD.004255DB to NOTEPAD.004253CD
0013F9B0 000359F4 Y.
0013F9B4 00400000 ..@. ; OFFSET NOTEPAD.B
0013F9B8 0013F9C0 .
0013F9BC 7C92118A | ; RETURN to ntdll.7C92118A
VM_EXIT
程序返回進入7C92118A,程序要從TLS中返回,我們?nèi)ラ_始地址00437817地址下斷點,在程序執(zhí)行地址攔截下程序。
7C92118A 8BE6 MOV ESP,ESI
7C92118C 5B POP EBX
7C92118D 5F POP EDI
7C92118E 5E POP ESI
7C92118F 5D POP EBP
7C921190 C2 1000 RETN 10
3.2.VMP外殼函數(shù)獲取
00437817 . 68 B59DF9FC PUSH FCF99DB5
在00437817把程序攔截下來后,和TLS相似,VMP開始初始化VM等等操作,這里不再復(fù)述。VM運行后還是先進行0000與[00427D51]中的0000進行比較+跳轉(zhuǎn)。接下來把VM堆棧重新分配和TLS里的相似:
0013FF8C 0013FF98
0013FF90 0013FF98
VM_NANDdw
0013FF90 FFEC0067 g.
0013FF94 00000800 ...
VM_ADDdw_EBPSTACK
0013FF94 FFEC0867 g
VM_PUSHdw_EBP
0013FF90 0013FF94 .
0013FF94 FFEC0867 g
VM_COPYdw_EBPSTACK
0013FF90 FFEC0867 g
0013FF94 FFEC0867 g
VM_NANDdw
0013FF94 0013F798 . ; UNICODE "er"
VM_MOVdw_EBPreg_EBPSTACK
偽指令進行了一次減法操作0013FF98-800=0013F798,最終把0013F798賦值給EBPSTACK,在這條指令里進行的邊界檢查中,將觸發(fā)這個VM堆棧的重新分配(詳情請查閱1.2.VM堆棧)
來到新的VM堆棧0013F798中,EF標志位也將再次的置1,一切都和TLS里相同。
3.2.1.動態(tài)鏈接庫
接下來就要進入大規(guī)模的anti檢測了,在進入之前還有一個準備工作,在接下來的使用中,需要使用到一個buffer(緩沖區(qū))用于存儲API函數(shù)的返回值,動態(tài)鏈接庫名字等等內(nèi)容,VM采用的方式是0013FF98-10=0013FF88,這樣就在0013FF88----0013FF98之間分配好了buffer,4個dword:
0013FF88 00000212 ..
0013FF8C 00000282 ..
0013FF90 00000202 ..
0013FF94 0013F798 . ; UNICODE "er"
0013FF98
在后面的anti檢測中,很多都會使用到這個buffer空間。接下來就開始往buffer內(nèi)寫入常量數(shù)據(jù):
0013F790 0013FF88 .
0013F794 6E72656B kern
VM_MOVdw_MEMORYdw_EBPSTACKdw ;寫入kern
VM_PUSHdw_IMMEDIATEdw
0013F78C 0013FF88 .
0013F790 00000004 ...
0013F794 32336C65 el32
VM_ADDdw_EBPSTACK ;buffer存儲地址+4
0013F790 0013FF8C .
0013F794 32336C65 el32
VM_MOVdw_MEMORYdw_EBPSTACKdw ;寫入el32
VM_PUSHdw_IMMEDIATEdw
0013F78C 00000008 ...
0013F790 0013FF88 .
0013F794 6C6C642E .dll
VM_ADDdw_EBPSTACK ;buffer存儲地址+8
0013F790 0013FF90 .
0013F794 6C6C642E .dll
VM_MOVdw_MEMORYdw_EBPSTACKdw ;寫入.dll
VM_PUSHdw_IMMEDIATEdw
0013F78C 0000000C ....
0013F790 0013FF88 .
0013F794 00000000 ....
VM_ADDdw_EBPSTACK ;buffer存儲地址+C
0013F790 0013FF94 .
0013F794 00000000 ....
VM_MOVdw_MEMORYdw_EBPSTACKdw ;寫入00000000
現(xiàn)在我們來看看buffer中整體寫入的數(shù)據(jù):
0013FF88 6E72656B kern
0013FF8C 32336C65 el32
0013FF90 6C6C642E .dll
0013FF94 00000000 ....
kernel32.dll鏈接庫,多么熟悉的字眼呀,VM寫入這個數(shù)據(jù)后,會開始進行一次VM_JMP的相關(guān)操作,準備跳轉(zhuǎn)到新的地方繼續(xù),下面是VM_JMP偽指令的數(shù)據(jù):
0013F75C 0042816C lB.
0013F760 00000000 ....
0013F764 7FF224A8 $
0013F768 7C92E514 | ; ntdll.KiFastSystemCallRet
0013F76C 7FFD8000 .
0013F770 00000202 ..
0013F774 00000000 ....
0013F778 0013FFB0 .
0013F77C 00000202 ..
0013F780 0013FF98 .
0013F784 0013FF88 . ; ASCII "kernel32.dll"
0013F788 7FF224A8 $
0013F78C 0013FF88 . ; ASCII "kernel32.dll"
0013F790 00000282 ..
0013F794 004389FB C. ; Entry point of procedure
VM_JMP
最終VM終于來到ANTI檢測和VM后期將要不斷調(diào)用的偽指令VM_EBPSTACK_CALL,用于API函數(shù)和程序自身過程調(diào)用,兩者的操作都是離開虛擬機環(huán)境的。API函數(shù)調(diào)用將進入系統(tǒng)空間,必然需要離開虛擬機環(huán)境,而這里的過程調(diào)用也是離開虛擬機環(huán)境的。離開虛擬機環(huán)境其實很簡單,只需要堆棧上變換一下,本來都是在VM堆棧的數(shù)據(jù)參數(shù)需要移動到ESP指針的堆?臻g內(nèi),正常的程序執(zhí)行它是使用ESP指針的,不懂得到VM堆棧內(nèi)取數(shù)據(jù)。
0013F78C 00428275 uB. ; RETURN from NOTEPAD.00436E08 to NOTEPAD.00428275
0013F790 0013FF88 . ; ASCII "kernel32.dll"
0013F794 004389FB C. ; Entry point of procedure
VM_EBPSTACK_CALL
關(guān)于這條偽指令,我再來詳細解說一下,首先它通過VM的ESI數(shù)據(jù)獲得這次函數(shù)調(diào)用的參數(shù)個數(shù)。這次它的參數(shù)是1個,然后把1給ECX,下面是這條偽指令內(nèi)部獲取參數(shù)的指令:
0043E0C6 87448D 00 XCHG DWORD PTR SS:[ECX*4+EBP],EAX ; *
0043E0CD 894424 24 MOV DWORD PTR SS:[ESP+24],EAX ; *
EBP=0013F78C,在循環(huán)里面通過[ECX*4+EBP]的方式,ECX的值就決定了要取出多少個參數(shù),取出的參數(shù)壓入ESP指向的堆棧,在這里顯示的是[ESP+24],24的偏移是因為有花指令,不用考慮。一切準備好后,就跳轉(zhuǎn)到00428275。最后的跳轉(zhuǎn)指令數(shù)據(jù)截。
$ ==> 00428275 uB. ; RETURN from NOTEPAD.00436E08 to NOTEPAD.00428275
$+4 9AF17581 u
$+8 14415549 IUA
$+C 0013F6D8 .
$+10 00428137 7B.
$+14 0013F78C .
$+18 0013F6C0 .
$+1C 80A6D7DB 爪
$+20 0043EF77 wC.
$+24 00000000 ....
$+28 00428275 uB. ; RETURN from NOTEPAD.00436E08 to NOTEPAD.00428275
$+2C 0043EED7 C.
$+30 00000246 F..
$+34 0043EED7 C.
$+38 00428275 uB. ; RETURN from NOTEPAD.00436E08 to NOTEPAD.00428275
$+3C 0043EEB7 C. ; RETURN from NOTEPAD.0043D111 to NOTEPAD.0043EEB7 ;執(zhí)行這條指令,去除38垃圾數(shù)據(jù)后跳轉(zhuǎn)數(shù)據(jù)
$+40 0013FF88 . ; ASCII "kernel32.dll"
0043DE10 C2 3800 RETN 38 ; Call Enter
既然是跳轉(zhuǎn)到00428275,我們來看看00428275處是什么樣的代碼,那里只有一條跳轉(zhuǎn)指令:
00428275 -/FF25 E47D4300 JMP DWORD PTR DS:[<&KERNEL32.LoadLibrary
現(xiàn)在就很清晰了,這次call是使用LoadLibrary函數(shù)來獲取Kernel32.dll鏈接庫句柄。我們在call return address處0043EEB7處下斷,然后就可以F9運行,直接攔截下系統(tǒng)調(diào)用結(jié)束后返回的結(jié)果EAX=7C800000。現(xiàn)在又要回到虛擬機中了,反過來就需要把數(shù)據(jù)放回到VM堆棧中,按照VM運行方式讓它在VM堆棧中操作。
在返回VM的過程中,首先是把原來EBPSTACK中的參數(shù)占據(jù)的位置釋放:
0043ED41 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] ; *這里是保存的本次call的參數(shù)個數(shù)
0043ED46 8D6C8D 00 LEA EBP,[ECX*4+EBP] ; *釋放掉對應(yīng)的空間
把EAX中的結(jié)果保存到EBPSTACK
EAX=7C800000
0043ED50 8945 00 MOV DWORD PTR SS:[EBP],EAX ; *
0013F790 7C800000 ..|
返回VM后,進行一次VM_JMP調(diào)用
3.2.2.循環(huán)
分配新的buffer空間,0013FF88-10=0013FF78再分配4個dword的空間出來,使用上面的方式往新的buffer空間寫入數(shù)據(jù)。4個dword寫入完成后buffer空間的數(shù)據(jù)如下:
0013FF78 8D7E029C ~
0013FF7C 8F81160C .
0013FF80 048DFF7E ~
0013FF84 00C78D05 .
0013FF88 6E72656B kern
0013FF8C 32336C65 el32
0013FF90 6C6C642E .dll
0013FF94 00000000 ....
調(diào)用VM_JMP跳轉(zhuǎn)到新的地方,接下來毫無疑問的是繼續(xù)進行call調(diào)用
0013F788 00421C48 HB. ; Entry point of procedure
0013F78C 7C800000 ..|
0013F790 0013FF78 x.
0013F794 00427C45 E|B.
VM_EBPSTACK_CALL
這次是帶著kernel32.dll的句柄7C800000和0013FF78兩個參數(shù)調(diào)用00421C48,這次是一個過程調(diào)用,我們下面來看00421C48的代碼:
00421C4E 55 PUSH EBP ; *
00421C58 8D6C24 04 LEA EBP,[ESP+4] ; *下面要使用EBP來讀取參數(shù),先保存后定位
00421C76 56 PUSH ESI ; *
00421C80 893C24 MOV DWORD PTR SS:[ESP],EDI ; *
00421C85 53 PUSH EBX ; *
00421C8C 52 PUSH EDX ; *
該保存的保存起來
00421C92 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; *讀取第一個參數(shù)kernel32.dll句柄7C800000
接下來的部分和TLS中的PE文件頭定位相似,不過TLS是使用偽指令實現(xiàn)的,這里用常規(guī)指令實現(xiàn)。
00436B42 8B70 3C MOV ESI,DWORD PTR DS:[EAX+3C] ; *
00436B4E 01C6 ADD ESI,EAX ; *
00436B5C 8B56 78 MOV EDX,DWORD PTR DS:[ESI+78] ; * 78偏移是導(dǎo)出表結(jié)構(gòu)位置,kernel32.dll的導(dǎo)出表RVA
0043A773 01C2 ADD EDX,EAX ; * 獲得導(dǎo)出表開始位置7C80262C
0043A77D 8B4E 7C MOV ECX,DWORD PTR DS:[ESI+7C] ; * 78偏移是導(dǎo)出表結(jié)構(gòu)位置,kernel32.dll的導(dǎo)出表大小
00435CB9 01D1 ADD ECX,EDX ; * 獲得導(dǎo)出表結(jié)束位置7C809345
00435CBE 894D F0 MOV DWORD PTR SS:[EBP-10],ECX ; * 保存起來
00435CCB 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+0C] ; * 這里獲取的是第二個參數(shù)0013FF78
0041EE80 8B7A 24 MOV EDI,DWORD PTR DS:[EDX+24] ; * 導(dǎo)出表24偏移的是AddressOfNamesOrdinals 指向輸入序列號數(shù)組
0041EE8B 01C7 ADD EDI,EAX ; * 輸入序列號數(shù)組地址7C804424
0041EE8F 8B5A 20 MOV EBX,DWORD PTR DS:[EDX+20] ; * 導(dǎo)出表20偏移的是AddressOfNames 函數(shù)名字的指針的地址
0041EE9B 01C3 ADD EBX,EAX ; * 函數(shù)名字的指針地址7C80353C
0041EEB1 8B4A 18 MOV ECX,DWORD PTR DS:[EDX+18] ; * 導(dǎo)出表18偏移的是NumberOfNames AddressOfNames數(shù)組的項數(shù)
一切準備就緒開始讀取導(dǎo)出表函數(shù)比較
0041EED5 83E9 01 SUB ECX,1 ; * 計數(shù)器第1個word減去
0041EEDF 894D FC MOV DWORD PTR SS:[EBP-4],ECX ; *
0041EEF0 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8] ; * 整個程序的載入偏移量
00428D66 034D FC ADD ECX,DWORD PTR SS:[EBP-4] ; *
00428D6B D1E9 SHR ECX,1 ; * 計數(shù)器除以2,按照word方式
00428D72 8B3C8B MOV EDI,DWORD PTR DS:[ECX*4+EBX] ; *
00428514 /01C7 ADD EDI,EAX ; *
EDI 7C806FB2 ASCII "GetVDMCurrentDirectories",到這里就得到API函數(shù)名了
0042851E 8B75 0C MOV ESI,DWORD PTR SS:[EBP+0C] ; * 0013FF78
0043A156 AC LODS BYTE PTR DS:[ESI] ; *
0043A159 F6D0 NOT AL ; *
0043A165 F6D8 NEG AL ; *
00435255 /FEC0 INC AL ; *
0043525C 34 37 XOR AL,37 ; *
0043552A FEC0 INC AL ; *
00435530 D0C0 ROL AL,1 ; *
0041E634 FEC0 INC AL ; *
接下來就是比較
004388E1 3A07 CMP AL,BYTE PTR DS:[EDI] ; *
004388E7 ^\0F8C 35EAFFFF JL 00437322 ; *
004388ED 8D7F 01 LEA EDI,[EDI+1] ; *
004219F2 /0F87 9A6B0100 JA 00438592 ; *
00425FB3 3B4D FC CMP ECX,DWORD PTR SS:[EBP-4] ; *
00425FC4 83C1 01 ADD ECX,1 ; *
00425FCD 894D F8 MOV DWORD PTR SS:[EBP-8],ECX ; *
注意好它的跳轉(zhuǎn)方式是通過JL和JA方式一起實現(xiàn),上面的是比較失敗后的循環(huán)。如果相同的話,JL和JA這里都不能跳轉(zhuǎn),我們?nèi)A的下一條指令攔截比較相同的情況:
004219F2 /0F87 9A6B0100 JA 00438592 ; *
004219F8 |E8 2B480000 CALL 00426228 ;F4這里
現(xiàn)在我們就找到第一個字母比較相同的函數(shù)是VirtualAlloc
0042968E 807F FF 00 CMP BYTE PTR DS:[EDI-1],0 ; *
0043712D ^\0F85 F213FFFF JNE 00428525 ; *
出來到外循環(huán)看是不是已經(jīng)比較到尾部,還沒有就回去比較第2個字節(jié),我們直接跳出循環(huán)看結(jié)果
0043712D ^\0F85 F213FFFF JNE 00428525 ; *
00437133 0FBAEF 16 BTS EDI,16 ;F4這里,所有字節(jié)都相同的函數(shù)是VirtualProtect
到這里比較完畢,要找的函數(shù)是VirtualProtect
0043C9C1 8B7A 24 MOV EDI,DWORD PTR DS:[EDX+24] ; * AddressOfNamesOrdinals
0043C9C7 01C7 ADD EDI,EAX ; *
0043C9CC 0FB70C4F MOVZX ECX,WORD PTR DS:[ECX*2+EDI] ; *
0043C9D6 29CF SUB EDI,ECX ; *
0043C9DB 8B7A 1C MOV EDI,DWORD PTR DS:[EDX+1C] ; * AddressOfFunctions
0043C9E3 01C7 ADD EDI,EAX ; *
0042862B /8B3C8F MOV EDI,DWORD PTR DS:[ECX*4+EDI] ; *
00438A9F \01F8 ADD EAX,EDI ; *
解說不過來了,大家不明白的去復(fù)習(xí)PE文件格式的導(dǎo)出表部分吧,上面的指令結(jié)束后,得到了VirtualProtect的系統(tǒng)地址7C801AD4
0043EEB7 89D1 MOV ECX,EDX ; call return address
回到call返回地址,數(shù)據(jù)壓入EBPSTACK這里等于0013F790
0013F790 7C801AD4 | ; kernel32.VirtualProtect
0013F794 00427C45 E|B.
我們在平時的代碼中也經(jīng)?梢钥吹,call調(diào)用完畢后檢測一下是不是0,VMP也是一樣的,只是用偽指令來實現(xiàn)
0013F78C 7C801AD4 | ; kernel32.VirtualProtect
0013F790 7C801AD4 | ; kernel32.VirtualProtect
0013F794 00427C45 E|B.
VM_NANDdw
0013F790 837FE52B +
0013F794 00427C45 E|B.
VM_PUSHdw_EBP
VM_COPYdw_EBPSTACK
0013F78C 837FE52B +
0013F790 837FE52B +
0013F794 00427C45 E|B.
VM_NANDdw
0013F790 7C801AD4 | ; kernel32.VirtualProtect
0013F794 00427C45 E|B.
兩個NOT指令為的就是要它的標志位來進行ZF位檢測+跳轉(zhuǎn)VM_JMP指令
接下來VM將會進行一次CC碼檢測,看看VirtualProtect函數(shù)開始地址有沒有下斷點,此部分不再復(fù)述,記錄關(guān)鍵數(shù)據(jù):
0013F78C 1AD4
0013F790 00CC7C80 |.
0013F794 00427C45 E|B.
讀取出7C801AD4函數(shù)的首字節(jié),與CC碼進行一次減法操作,獲取其中的標志位,進行ZF位檢測+跳轉(zhuǎn)
在前面的EBPSTACK中一直附帶著00427C45這個數(shù)據(jù)而沒有動靜,現(xiàn)在在確定一切安全沒有問題,VM再次調(diào)用VM_JMP控制VM跳轉(zhuǎn)到00427C45位置,下面我們就來看看00427C45是干什么操作的
0013F790 C9058E9B
0013F794 7C801AD4 | ; kernel32.VirtualProtect
VM_ADDdw_EBPSTACK
0013F794 4585A96F oE
0013F78C 0013F798
0013F790 00000020
0013F794 4585A96F oE
VM_ADDdw_EBPSTACK
0013F790 0013F7B8 .
0013F794 4585A96F oE
VM_MOVb_MEMORYb_EBPSTACKb
現(xiàn)在我們看清楚,00427C45這個VM子程序過程是把得到的系統(tǒng)地址加密起來存放,不讓它按照明碼的方式存儲。到這里完成了一個系統(tǒng)函數(shù)獲取到存儲的全過程,接下來程序回到 3.2.2.循環(huán) 的開頭,開始新的函數(shù)獲取,從往0013FF78壓入4個dword開始,接著就退出00427C45這個VM子程序過程。當(dāng)kernel32.dll結(jié)束后又進入下一個DLL文件,程序回到 3.2.1.動態(tài)鏈接庫 這一部分不再復(fù)述,接下來直接粘貼獲取的函數(shù)匯總
kernel32.dll:
0013F780 7C801AD4 | ; kernel32.VirtualProtect ;加密后0013F7B8 4585A96F oE
0013F790 7C809AF1 | ; kernel32.VirtualAlloc ;加密后0013F7C0 7ED1C93F ?~
0013F790 7C801A28 (| ; kernel32.CreateFileA ;加密后0013F7DC 45E78F5A ZE
0013F778 7C809BE7 鐩| ; kernel32.CloseHandle ;加密后0013F7D8 877DBA31 1}
0013F790 7C810B17 | ; kernel32.GetFileSize ;加密后0013F7E4 05F84F8C O
0013F790 7C80950A .| ; kernel32.CreateFileMappingA ;加密后0013F7F4 8B5A496C lIZ
0013F790 7C80B9A5 | ; kernel32.MapViewOfFile ;加密后0013F7C4 C2DC4B94 K
0013F790 7C80BA14 | ; kernel32.UnmapViewOfFile ;加密后0013F798 230A53C4 S.#
0013F790 7C80B741 A| ; kernel32.GetModuleHandleA ;加密后0013F7CC 058C4D40 @M
0013F794 7C813133 31| ; kernel32.IsDebuggerPresent ;加密后0013F7EC 9C056A3F ?j
0013F794 7C85AAF2 | ; kernel32.CheckRemoteDebuggerPresent ;加密后0013F7F8 77ED7C33 3|w
0013F790 7C863FCA ?| ; kernel32.UnhandledExceptionFilter ;加密后0013F7D0 35B5E8D3 5
ntdll.dll:
0013F794 7C92D7FE 讙| ; ntdll.ZwQueryInformationProcess ;加密后0013F7B0 D324C5FE $
0013F794 7C92DCAE 軖| ; ntdll.NtSetInformationThread ;加密后0013F7A8 E42D06B3 -
0013F794 7C92D92E .賿| ; ntdll.NtQuerySystemInformation ;明碼存儲00425E60 7C92D92E到這里所有的外殼函數(shù)獲取結(jié)束,VM執(zhí)行VM_JMP跳轉(zhuǎn)走,由于最后的1條系統(tǒng)函數(shù)地址是存儲在內(nèi)存中,00425E60進行加法操作,不讓他以明碼出現(xiàn),同時VM作為堆棧虛擬機,還是喜歡堆棧的存儲方式,所以再找一個堆?臻g0013F7E8,把暗碼地址放進去:
0013F790 03DDEA1E
0013F794 00425E64 d^B.
VM_ADDdw_EBPSTACK
0013F794 04204882 H
0013F78C 00000050 P...
0013F790 0013F798 .
0013F794 04204882 H
VM_ADDdw_EBPSTACK
0013F790 0013F7E8 .
0013F794 04204882 H
VM_MOVdw_MEMORYdw_EBPSTACKdw
3.3.虛擬執(zhí)行環(huán)境與調(diào)試器檢測
在前面所有的節(jié)里面的內(nèi)容全部都是貫穿的,沒有一個地方遺漏下來的在解析,但是這一節(jié)和上一節(jié)的結(jié)尾并沒有連接在一起,不是我想藏著捏著搞流水賬脫文出來,實在是沒有精力一條一條的去說。我已經(jīng)想吐了,沒有心情繼續(xù)寫下去了,越是想著全盤托出,有些地方老是更有壓力害怕遺漏了東西。還有一個是想趕快結(jié)稿的心理也有一些。再說,VMP的ANTI檢測是很有趣的一個部分,當(dāng)你知道下面有一節(jié)很有趣,而一直繞在上面的基礎(chǔ)地方,實在也有點心急?傊,如果你發(fā)現(xiàn)我有遺漏了沒有解說的地方就自己去看好了。下面我們就直接來到ANTI部分:
3.3.1.VMware
0013F78C 00000000 ....
0013F790 0043B7B2 C. ; RETURN from NOTEPAD.00435E6A to NOTEPAD.0043B7B2
0013F794 0013FF98 .
VM_FS:[EBPSTACK] ;讀取FS:[0]的數(shù)據(jù)
0013F78C |0013FFE0 .
0013F790 \0043B7B2 C. ; RETURN from NOTEPAD.00435E6A to NOTEPAD.0043B7B2
0013F794 0013FF98 .
0013F784 00000000 ....
0013F788 0013F78C .
0013F78C 0013FFE0 .
0013F790 0043B7B2 C. ; RETURN from NOTEPAD.00435E6A to NOTEPAD.0043B7B2
0013F794 0013FF98 .
VM_SEH
0013F78C |0013FFE0 . ; Pointer to next SEH record
0013F790 \0043B7B2 C. ; SE handler
0013F794 0013FF98 .
這是VM構(gòu)建新的SEH。讀取FS:[0]的原來的SEH地址,然后放入新的進去VM_SEH偽指令里實現(xiàn)的,不明白的自己去看SEH相關(guān)資料。構(gòu)建好SEH后程序調(diào)用VM_EXIT,
0013F770 00000000 ....
0013F774 0013FF98 .
0013F778 564D5868 hXMV
0013F77C 00005658 XV..
0013F780 [0042536C lSB. ; RETURN from NOTEPAD.00426E8B to NOTEPAD.0042536C
0013F784 31921C56 V1
0013F788 0042536C lSB. ; RETURN from NOTEPAD.00426E8B to NOTEPAD.0042536C
0013F78C 0013FFE0 . ; Pointer to next SEH record
0013F790 0043B7B2 C. ; SE handler
0013F794 0013FF98 .
VM_EXIT
接下來程序在
0042536C . ED IN EAX,DX ; I/O command
這條指令這里就卡死了。為什么呢?因為VM_EXIT中有著給各個寄存器賦值的操作,其中這里他就構(gòu)建了一個VMware的后門指令檢測。在這里算是VMP的第一個正規(guī)的ANTI來了。執(zhí)行這條指令時候的CPU狀態(tài)和VMware后門檢測的源碼:
CPU - main thread, module NOTEPAD
EAX 564D5868
ECX 0000000A
EDX 00005658
EBX 00000000
ESP 0013F78C
EBP 0013FF98
ESI 0013FF8C ASCII "ntdll.dll"
EDI 0013FF70
EIP 0042536C NOTEPAD.0042536C
VMware的后門指令檢測。這個么不用問為什么。這個就是后門
mov eax, 564D5868h
mov ebx, 00000000h
mov ecx, 0000000Ah
mov edx, 00005658h
in eax, dx
這個檢測很普通,由于只有在VMware下這條指令才有返回值,否則就是一次異常。而我們是在真實環(huán)境下的。這個太普通了。我根本沒有用什么虛擬機。想深入了解的自己google資料看。
我是沒有在VMware調(diào)試VMP,所以它必定異常出錯,現(xiàn)在就可以看到剛才構(gòu)建的SEH的作用了。去SEH地址下斷,然后忽略異常繼續(xù)調(diào)試。
0043B7B2 .^\E9 7DD2FFFF JMP 00438A34 ; VMware SEH
我們來到了這里繼續(xù)調(diào)試,在SEH中,將保存當(dāng)前的結(jié)構(gòu),重新初始化一個VM,并在這個VM里面修改掉context結(jié)構(gòu)中EIP指針。要看懂修改的偽指令,還是復(fù)習(xí)一下SEH回調(diào)函數(shù):
首先看好SEH回調(diào)函數(shù)的參數(shù),它一共有4個參數(shù):
SEH_Handler proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
對應(yīng)VMP里的SEH地址看看具體數(shù)據(jù)
0013F3C4 [7C9232A8 2| ; RETURN to ntdll.7C9232A8
0013F3C8 0013F4AC . ;第一個參數(shù):ExceptionRecord指針
0013F3CC 0013F78C . ;第二個參數(shù):SEH指針
0013F3D0 0013F4C0 . ;第三個參數(shù):Context指針
0013F3D4 0013F480 . ;第四個參數(shù):DispatcherContext指針
附CONTEXT結(jié)構(gòu)環(huán)境:
代碼:typedefstruct_CONTEXT{
/*000*/DWORD ContextFlags;
/*004*/DWORD Dr0;
/*008*/DWORD Dr1;
/*00C*/DWORD Dr2;
/*010*/DWORD Dr3;
/*014*/DWORD Dr6;
/*018*/DWORD Dr7;
/*01C*/FLOATING_SAVE_AREAFloatSave;
/*08C*/DWORD SegGs;
/*090*/DWORD SegFs;
/*094*/DWORD SegEs;
/*098*/DWORD SegDs;
/*09C*/DWORD Edi;
/*0A0*/DWORD Esi;
/*0A4*/DWORD Ebx;
/*0A8*/DWORD Edx;
/*0AC*/DWORD Ecx;
/*0B0*/DWORD Eax;
/*0B4*/DWORD Ebp;
/*0B8*/DWORD Eip; ;B8的偏移量位置是Eip
/*0BC*/DWORD SegCs;
/*0C0*/DWORD EFlags;
/*0C4*/DWORD Esp;
/*0C8*/DWORD SegSs;
/*0CC*/ BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
/*2CC*/}CONTEXT;
先用理論來說一下:
1)第三個參數(shù)得到context結(jié)構(gòu)地址0013F4C0。
2)context結(jié)構(gòu)基地址+B8得到Eip存儲地址。
3)把安全的返回地址放入Eip位置。
4)SEH異常返回,程序從新的Eip地址開始執(zhí)行。
下面來看偽指令的操作過程:
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_PUSHdw_IMMEDIATEb
0013F3C0 0000000C ....
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_PUSHdw_IMMEDIATEb
0013F3BC 00000008 ...
0013F3C0 0000000C ....
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_PUSHdw_EBP
0013F3B8 0013F3BC .
0013F3BC 00000008 ...
0013F3C0 0000000C ....
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_ADDdw_EBPSTACK
0013F3BC 0013F3C4 .
0013F3C0 0000000C ....
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_ADDdw_EBPSTACK
0013F3C0 0013F3D0 .
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
這是1)階段,加8獲得參數(shù)的位置,加C獲得第三個參數(shù):
0013F3C0 0013F3D0 .
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
0013F3C8 0013F4AC .
0013F3CC 0013F78C .
0013F3D0 0013F4C0 .
0013F3D4 0013F480 .
VM_COPYdw_EBPSTACK
0013F3C0 0013F4C0 .
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
這是1)階段,獲得context結(jié)構(gòu)地址0013F4C0
0013F3B8 0013F4C0 .
0013F3BC 000000B8 ...
0013F3C0 00436C7D }lC.
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_ADDdw_EBPSTACK
0013F3BC 0013F578 x. ; ASCII "lSB"
0013F3C0 00436C7D }lC.
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
這是2)階段,context結(jié)構(gòu)B8偏移量位置是Eip位置
VM_MOVdw_MEMORYdw_EBPSTACKdw
這是3)階段,本來Eip位置是發(fā)生異常的指令地址:
0013F578 0042536C lSB. ; RETURN from NOTEPAD.00426E8B to NOTEPAD.0042536C
經(jīng)過修改后,放入了返回后的執(zhí)行地址:
0013F578 00436C7D }lC.
0013F398 F32B430A .C+
0013F39C 00000000 ....
0013F3A0 00000246 F..
0013F3A4 7C9232BC 2|
0013F3A8 0013F4C0 .
0013F3AC 00000000 ....
0013F3B0 0013F3E4 .
0013F3B4 00000000 ....
0013F3B8 7C9232BC 2|
0013F3BC 00000000 ....
0013F3C0 00000000 ....
0013F3C4 7C9232A8 2| ; RETURN to ntdll.7C9232A8
VM_EXIT
這是4)階段。最后調(diào)用VM_EXIT返回,里面給寄存器賦值,讓系統(tǒng)從SEH返回,而返回后eip指針被修改,我們就需要從新放入的地址00436C7D攔截程序跟蹤。接下來重新初始化VM。我們繼續(xù)走起了,F(xiàn)在前面放置的SEH已經(jīng)無用了,釋放掉恢復(fù)原來的SEH,直接放偽指令的實現(xiàn)過程了,不明白的查SEH資料:
0013F788 00000000 ....
VM_FS:[EBPSTACK] ;FS:[O]的值取出來,得到當(dāng)前的SEH結(jié)構(gòu)存儲地址
0013F788 0013F78C .
VM_MOVdw_EBPreg_EBPSTACK ;移動EBP指針下去,到達SEH結(jié)構(gòu)存執(zhí)地址
0013F788 00000000 ....
0013F78C 0013FFE0 . ; Pointer to next SEH record
0013F790 0043B7B2 C. ; SE handler
VM_SEH ;恢復(fù)原來的SEH,0013FFE0放入FS:[0]
3.3.2.單步模式
這個檢測方法用偽指令來實現(xiàn)可以說是非常非常的猥瑣。這招對于一般的人來說毫無意義,因為都是直接運行或者從來不進偽指令里面去,很容易就過了,反倒是碰到我這樣F7單步走VM的人來說,不小心就中招了。總之十分猥瑣的方法。
0013F78C 00000000 ....
0013F790 0041F070 pA. ; RETURN from NOTEPAD.00423165 to NOTEPAD.0041F070
0013F794 0013FF98 .
VM_FS:[EBPSTACK] ;讀取FS:[0]的值當(dāng)前SEH結(jié)構(gòu)
0013F78C |0013FFE0 .
0013F790 \0041F070 pA. ; RETURN from NOTEPAD.00423165 to NOTEPAD.0041F070
0013F794 0013FF98 .
0013F784 00000000 ....
0013F788 0013F78C .
0013F78C 0013FFE0 .
0013F790 0041F070 pA. ; RETURN from NOTEPAD.00423165 to NOTEPAD.0041F070
0013F794 0013FF98 .
VM_SEH
0013F78C |0013FFE0 . ; Pointer to next SEH record
0013F790 \0041F070 pA. ; SE handler
0013F794 0013FF98 .
構(gòu)建新的SEH結(jié)構(gòu),現(xiàn)在的異常處理程序地址是0041F070
下面VM會進行一次OR操作,標志位00000293 OR 00000100=00000393并把結(jié)果壓入EFLAGS寄存器,偽指令過程如下:
0013F77C 0013F780 .
0013F780 00000008 ...
0013F784 00000100 ...
0013F788 00000293 ..
0013F78C 0013FFE0 . ; Pointer to next SEH record
0013F790 0041F070 pA. ; SE handler
0013F794 0013FF98 .
VM_ADDdw_EBPSTACK
0013F780 0013F788 .
0013F784 00000100 ...
0013F788 00000293 ..
VM_COPYdw_EBPSTACK
0013F780 00000293 ..
0013F784 00000100 ...
0013F788 00000293 ..
VM_NANDdw
0013F784 FFFFFC6C l
0013F788 00000293 ..
VM_PUSHdw_EBP
VM_COPYdw_EBPSTACK
0013F780 FFFFFC6C l
0013F784 FFFFFC6C l
0013F788 00000293 ..
VM_NANDdw
0013F784 00000393 ..
0013F788 00000293 ..
VM_PUSHdw_EBP
0013F780 0013F784 .
0013F784 00000393 ..
0013F788 00000293 ..
VM_PUSHdw_IMMEDIATEb
0013F77C 00000004 ...
0013F780 0013F784 .
0013F784 00000393 ..
0013F788 00000293 ..
VM_ADDdw_EBPSTACK
0013F780 0013F788 .
0013F784 00000393 ..
0013F788 00000293 ..
VM_MOVdw_MEMORYdw_EBPSTACKdw
0013F788 00000393 ..
0013F758 00000286 ..
0013F75C 0013FF8C . ; ASCII "ntdll.dll"
0013F760 00000206 ..
0013F764 00426C00 .lB.
0013F768 0000000A ....
0013F76C 00000000 ....
0013F770 0013FF98 .
0013F774 00000000 ....
0013F778 00005658 XV..
0013F77C 0013FF70 p.
0013F780 0013FF8C . ; ASCII "ntdll.dll"
0013F784 00428173 sB.
0013F788 00000393 ..
VM_EXIT
在VM_EXIT中,最后一個數(shù)據(jù)00000393是
00428173 9D POPFD ; *
被壓入了EFLAGS寄存器,現(xiàn)在我們可以看看00000100這個OR操作數(shù)影響的是Trap Flag(TF)位,這個過程就是把標志位的TF位置1。根據(jù)Intel資料:
TF (bit 8) Trap flag — Set to enable single-step mode for debugging;
clear to disable single-step mode.
也就是VM設(shè)置單步模式(single-step mode)。下面我們來回頭進好好看看00428173這個過程的詳細代碼:
00428173 |. 9D POPFD ; *
00428174 |. 0F31 RDTSC
00428176 |. 90 NOP
00428177 |. 9C PUSHFD
00428178 |. C70424 0A429C MOV DWORD PTR SS:[ESP],489C420A
0042817F |. 9C PUSHFD
00428180 \. E9 58030100 JMP 004384DD
這段代碼你要是一條一條的F7走下去,完全沒有問題。能夠一直走到JMP 004384DD這里,然后程序就開始初始化VM,看不到任何的問題。而事實上你已經(jīng)中招了。接下來就等著看被VMP發(fā)現(xiàn)的提示框吧。
而如果你直接在進入這個00428173的過程前來一個F9,比如說VM_EXIT偽指令處。你就會發(fā)現(xiàn)程序被攔截下來了
00428173 |. 9D POPFD ; * single-step mode
00428174 |. 0F31 RDTSC
00428176 |. 90 NOP ;*************************
00428177 |. 9C PUSHFD
00428178 |. C70424 0A429C MOV DWORD PTR SS:[ESP],489C420A
0042817F |. 9C PUSHFD
00428180 \. E9 58030100 JMP 004384DD
在NOP指令這里,程序就被攔截下來了?匆幌翺D下角的提示框顯示:
Break on single-step trap set by application - Shift+Run/Step to pass exception to the program
來說說原理,由于OD這樣的Ring3調(diào)試器,F(xiàn)7單步靠的就是TF標志位,所以如果你單步走這段代碼。VM程序設(shè)置的TF位就會和OD調(diào)試器的TF位相同,OD以為是自己的單步調(diào)試,就不會觸發(fā)這個異常,而一旦你F9運行程序,OD才會發(fā)現(xiàn):哦,原來這里調(diào)試的程序自己設(shè)置一個TF單步異常!注意看OD給的提示消息:中斷在應(yīng)用程序設(shè)置的單步陷阱-Shift+Run/Step跳過程序異常