j00ru <j00ru vx gmail com> |
Sunday, January 20 2008 11:37.16 CST |
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):
.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
Man I think you still don't get the thing out hehe..
"Seems that these tested VMs change the exception value to stay undetected instead of just letting the real processor generate one."
VirtualBox is an open source so why not looking at it first ?
|
|
sovietskicpu: Yeah you're right, I'm gonna check it ;> just posted some more info from experiments but... I'll try to confirm everything I wrote ;> |
@sovietskicpu
Hmm I don't see your point. The exceptions send to the program on both guest and host PC differ, that is a fact. And meanwhile, both the guest and host OS show the same CPU Type.
If the type is the same, but the exceptions differ, this can be used to check if the guest machine is in fact a guest machine.
Which part of this troubles u ? |
GynvaelColdwind,
"Which part of this troubles u ?"
hehe I am not in troubles :p
Looking at this : "Seems that these tested VMs change the exception value to stay undetected instead of just letting the real processor generate one." made me suggest to j00ru to first take a look at VirtualBox sources.
GynvaelColdwind, with all my respect man, you still won't see my point if you think this way.Please go "study" Boch/QEMU/VirtualBox sources code, try to better understand the emulation technologie in depth then we will make a rich and good discussion about VM Detections subtilities.
The difference in the returned exception value is not due to any supervisor intentional modifications but it is due to the ILL handling mechanism of instructions PREFIXES by the disassemblers engines of the tested Virtual Machines. |
sovietskicpu,
I'll guess I'll take a look in spare time at the sources (well, I know Bochs source quite well).
Anyway, I see your point, but please note that whatever we call the place that is wrong in the virtual machine, should it be the exception handling mechanism (as j00ru has written in the post), or the disassembler mechanism (as You stated in your post, and I tend to agree with u that it is more likely), it does not change the fact that this works the way it does, and can be used to detect the virtual machine. And just that is my point. |
|
I absolutly agree with you in that !! |
sovietskicpu: once more to tell, You are right ;>
My purpose was to prove that VMWare/VirtualPC/others can be detected with this method as well as AV emulators (in response to your comment on my previous post) ;>
VMs modifying the exception code was just an assumption, nothing really meaningful ;-) But the fact is that exceptions differ, doesn't matter why, when it comes to detection ;> |
j00ru,
you are right too, I dont deny in anyway your discoveries. I think your code will be soon included in some of the incoming Rootkits/VX and I bet that some guys from the AV scene, snooping around, will begin to add your VM detection algo to their stupid heuristic sensors hehe...
"doesn't matter why, when it comes to detection"
the WHY always really matter when it comes to future detections. You are a reverser, so the WHY is the key of everythings... hehe I was kidding :p |
Hahaha, of course ;)
What I meant was only that even without the knowledge of how something works, it does ;> but WHY is the key of everything indeed ;) |
See more examples here:
http://pferrie.tripod.com/papers/attacks.pdf
and
http://pferrie.tripod.com/papers/attacks2.pdf
These are getting old now. I must finish v3 one day.
Also some funny behaviours here:
http://www.symantec.com/enterprise/security_response/weblog/2007/01/locked_and_loaded.html
and here:
http://www.symantec.com/enterprise/security_response/weblog/2007/02/x86_fetchdecode_anomalies.html |
Heuh ??? Damn it !!! the real Peter Ferrie from SYMANTEC is here !!
"I bet that some guys from the AV scene, snooping around, will begin to add your VM detection algo to their stupid heuristic sensors hehe..." : ==> Has already did its effect very quickly i think hahaha...
attacks.pdf and attacks1.pdf I already know them by heart btw :p
Is there some jobs openings in symantec ???
|
There are always openings. :-)
Regarding the exception that is generated, it's a Windows bug, not a CPU behaviour.
The 0xc0000005 (int 0d) is the proper one.
|
|
heuh ? any explanation of this ? |
> See more examples here:
> http://pferrie.tripod.com/papers/attacks.pdf
> and
> http://pferrie.tripod.com/papers/attacks2.pdf
> These are getting old now. I must finish v3 one day.
Cui bono?
|
sovietskicpu: Windows sees the int 0dh exception and examines the instruction that caused it. After seeing so many prefixes, it gives up and issues an improper int 06h. It is similar to the invalid lock: exception when a 0f0h appears inside the instruction, even if it is not a prefix (the link to that is in my earlier comment).
EliCZ: it's for all kinds of people. Some fix their bugs and improve their anti-detection. Some people gain new insights into how some VMs work. Of course, some people might use it for bad purposes, but it has more good uses than bad ones. It's a sharing of research. I think that's important.
|
@PeterFerrie
"It's a sharing of research. I think that's important."
Yeah, it is, share it, share it ;>
Btw concealing such papers would be security by obscurity anyway... |
|