Log in

View Full Version : Virtual Machine detection method cd.


OpenRCE_j00ru
January 23rd, 2008, 20:56
Due to some comments on my previous post (http://www.openrce.org/blog/view/1025/Old_new_Virtual_Machine_detection_method.) , I decided to write a simple tool and do some more research - just to check the exceptions generated by more (different) VMs on different platforms and processors (IA-32 / x64).
There are some new interesting facts, hehe ;>

Firstly, I launched the test program under Windows XP and Vista on a 64bit processor and the log looked like this:

14 bytes long: no exception
15 bytes - 0xc0000005 Exception
16 bytes - 0xc0000005 Exception
17 bytes - 0xc0000005 Exception
18 bytes - 0xc0000005 Exception
19 bytes - 0xc0000005 Exception
20 bytes - 0xc0000005 Exception
21 bytes - 0xc0000005 Exception
22 bytes - 0xc0000005 Exception
23 bytes - 0xc0000005 Exception


There's no Illegal Instruction exception generated anymore on x64 (tested on instructions up to 100 bytes long), huh.
The processors that the tests were made on are:

AuthenticAMD athlon x2 6000+ and Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz

Next then, I ran PrefTest (the tool name itself) on two Virtual Machines, using the same computers as before, and the results were different ;p

15 bytes - 0xc0000005 Exception
16 bytes - 0xc0000005 Exception
17 bytes - 0xc0000005 Exception
18 bytes - 0xc0000005 Exception
19 bytes - 0xc0000005 Exception
20 bytes - 0xc0000005 Exception
21 bytes - 0xc000001d Exception
22 bytes - 0xc000001d Exception
and so on...


Seems that these tested VMs change the exception value to stay undetected instead of just letting the real processor generate one.
To be precise, the log which part is shown above, was generated by PrefTest running on VMWare Workstation 6.0.2 build 59824 and VirtualBox 1.5.2.

The conclusion is that VMs modify the exceptions' types by hand (I think they do, but it's worth confirming), which is not a very good idea as they are still not the same ;>
The real processor's architecture should be taken into account to avoid such differences

Special thanks to GynvaelColdwind and omeg for helping me with this little research ;-)

And the PrefTest tool source code (isn't really pretty, but what is important, it works):

Code:
.586
.model flat, stdcall
assume fs:flat
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\gdi32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\msvcrt.lib


.data
OldAttr dd 0
TempVal dd 0
format1 db '%d bytes long: no exception',0ah,0
format2 db '%d bytes - 0x%.8x Exception',0ah,0

Eip dd 0
Pointer dd 0

.code
start:

call @F
@@:
pop eax ; EAX <--- EIP

_test:
jmp _protect
db 100 dup (90h)
jmp _return

_protect:
inc eax
inc eax
inc eax

; Eip - Esi
; Pointer - Edi
mov esi, eax
mov edi, eax
mov [Eip], esi
mov [Pointer], edi

invoke VirtualProtect, esi,100,PAGE_EXECUTE_READWRITE,offset OldAttr

_loop:

mov byte ptr [edi], 03eh
mov byte ptr [edi+1], 0c6h
mov byte ptr [edi+2], 05
mov dword ptr [edi+3], offset TempVal
mov byte ptr [edi+7], 0

inc edi
inc dword ptr [Pointer]
jmp _thread

_start:
; SEH
push offset _handler
push dword ptr fs:[0]
mov dword ptr fs:[0], esp

jmp [Eip]

_thread:
invoke CreateThread, NULL, 0, offset _start, 0, 0, 0
invoke WaitForSingleObject, eax, INFINITE
jmp _loop

_return:
mov esi, [Eip]
mov edi, [Pointer]

mov eax, edi
sub eax, esi
add eax, 6

invoke _imp__printf, offset format1, eax
invoke ExitThread, 0

_handler:
mov esi, [Eip]
mov edi, [Pointer]

mov eax, edi
sub eax, esi
cmp eax, 90
jge _end
add eax, 6

mov edx, [esp+4]
mov edx, [edx]
invoke _imp__printf, offset format2, eax, edx

invoke ExitThread, 0

_end:
invoke ExitProcess, 0

end start


https://www.openrce.org/blog/view/1029/Virtual_Machine_detection_method_cd.