3.3.虛擬執(zhí)行環(huán)境與調(diào)試器檢測
在前面所有的節(jié)里面的內(nèi)容全部都是貫穿的,沒有一個地方遺漏下來的在解析,但是這一節(jié)和上一節(jié)的結(jié)尾并沒有連接在一起,不是我想藏著捏著搞流水賬脫文出來,實在是沒有精力一條一條的去說。我已經(jīng)想吐了,沒有心情繼續(xù)寫下去了,越是想著全盤托出,有些地方老是更有壓力害怕遺漏了東西。還有一個是想趕快結(jié)稿的心理也有一些。再說,VMP的ANTI檢測是很有趣的一個部分,當你知道下面有一節(jié)很有趣,而一直繞在上面的基礎地方,實在也有點心急?傊,如果你發(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相關資料。構(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中,將保存當前的結(jié)構(gòu),重新初始化一個VM,并在這個VM里面修改掉context結(jié)構(gòu)中EIP指針。要看懂修改的偽指令,還是復習一下SEH回調(diào)函數(shù):
首先看好SEH回調(diào)函數(shù)的參數(shù),它一共有4個參數(shù):
SEH_Handler proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
對應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)無用了,釋放掉恢復原來的SEH,直接放偽指令的實現(xiàn)過程了,不明白的查SEH資料:
0013F788 00000000 ....
VM_FS:[EBPSTACK] ;FS:[O]的值取出來,得到當前的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 ;恢復原來的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]的值當前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設置單步模式(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指令這里,程序就被攔截下來了。看一下OD下角的提示框顯示:
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程序設置的TF位就會和OD調(diào)試器的TF位相同,OD以為是自己的單步調(diào)試,就不會觸發(fā)這個異常,而一旦你F9運行程序,OD才會發(fā)現(xiàn):哦,原來這里調(diào)試的程序自己設置一個TF單步異常!注意看OD給的提示消息:中斷在應用程序設置的單步陷阱-Shift+Run/Step跳過程序異常
本文導航
- 第1頁: 首頁
- 第2頁: VMProtect虛擬機簡介
- 第3頁: VMProtect2.04偽指令匯總
- 第4頁: .NAND(與非門)
- 第5頁: NOTEPAD全程跟蹤
- 第6頁: VMP外殼函數(shù)獲取
- 第7頁: 虛擬執(zhí)行環(huán)境與調(diào)試器檢測