Log in

View Full Version : VMware ring3 detection (RF handling)


deroko
August 9th, 2009, 11:17
Hello,

Here is one trick to detect vmware discovered by accidance

I was writing one unpacker, and for me RF was must have to make my unpacker simpler. Unpacker worked great on live system, and then I tried it in vmware, and I got many breaks at same part of the code which should be continued with RF.

RF from intel manual volume 3, chapter 18:

Code:
Because the debug exception for an instruction breakpoint is generated before the
instruction is executed, if the instruction breakpoint is not removed by the exception
handler; the processor will detect the instruction breakpoint again when the instruction
is restarted and generate another debug exception. To prevent looping on an
instruction breakpoint, the Intel 64 and IA-32 architectures provide the RF flag
(resume flag) in the EFLAGS register (see Section 2.3, “System Flags and Fields in
the EFLAGS Register,” in the Intel® 64 and IA-32 Architectures Software Developer’s
Manual, Volume 3A). When the RF flag is set, the processor ignores instruction
breakpoints.

Basically waht debugger would do with break point is:
- breakpoint reached -> clear breakpoint
- single step that instruction
- set breakpoint after singlestep
- continue execution
- too much not needed work...

For DebugRegister breaks on execution, you can simplfy this by setting RF in Eflags, and you don't have to remove your breakpoint on execution.

So here is how to detect VMWare presence using debug registers due to wrong RF handling:

Code allocates memory and stores there 0xC3, after that program generates exception to set debug registers. In exception handler code checks if exception occured 1st time (1st debug break) and sets RF (eg. continue execution), after that if exception occurs 2nd time, means that RF wasn't handled and that we have vmware (didn't try with other virtual machines).

main.c
Code:
#include "defs.h"

PVOID buffer;
DWORD dwExceptionCount;

ULONG filter(PEXCEPTION_INFO pei){
PCONTEXT pctx;

pctx = pei->pContext;
if (dwExceptionCount == 0){
dwExceptionCount++;
pctx->Dr7 = BPM_LOCAL_EXACT | BPM0_LOCAL_ENABLED;
pctx->Dr0 = (DWORD)buffer;
pctx->Eip += 2;
NtContinue(pctx, FALSE);
}else if (dwExceptionCount == 1){
dwExceptionCount++;
pctx->EFlags |= 0x10000;
NtContinue(pctx, FALSE);
}else if (dwExceptionCount == 2){
printf("[X] vmware detected\n";
ExitProcess(0);
}

return EXCEPTION_EXECUTE_HANDLER;
}

void __declspec(naked) hook_filter(void){
__asm push esp
__asm call filter
}

int __cdecl wmain(int argc, wchar_t **argv){
VOID (*func)();
DWORD dwOldProt;
PUCHAR kiuser;
printf("
ring3 VMWARE detection - (c) 2009 deroko of ARTeam\n";
kiuser = (PUCHAR)GetProcAddress(GetModuleHandle(L"ntdll.dll", "KiUserExceptionDispatcher";

VirtualProtect(kiuser, 7, PAGE_EXECUTE_READWRITE, &dwOldProt);
kiuser[0] = 0x68;
*(DWORD *)&kiuser[1] = (DWORD)hook_filter;
kiuser[5] = 0xc3;

buffer = func = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
*(DWORD *)func = 0xC3909090;

__asm xor eax, eax
__asm mov eax, [eax]
func();

printf("
vmware not detected\n";
ExitProcess(0);
}


defs.h
Code:

#include <windows.h>
#include <stdio.h>

// Dr6
#define BPM0_DETECTED 0x00000001
#define BPM1_DETECTED 0x00000002
#define BPM2_DETECTED 0x00000004
#define BPM3_DETECTED 0x00000008

// Dr7
#define BPM0_LOCAL_ENABLED 0x00000001
#define BPM0_W 0x00010000
#define BPM0_RW 0x00030000

#define BPM1_LOCAL_ENABLED 0x00000004
#define BPM1_W 0x00100000
#define BPM1_RW 0x00300000

#define BPM2_LOCAL_ENABLED 0x00000010
#define BPM2_W 0x01000000
#define BPM2_RW 0x03000000

#define BPM3_LOCAL_ENABLED 0x00000040
#define BPM3_W 0x10000000
#define BPM3_RW 0x30000000

#define BPM_LOCAL_EXACT 0x00000100

typedef LONG NTSTATUS;

NTSTATUS
NTAPI
NtContinue(__in PCONTEXT ctx, BOOL Alertalbe);

typedef struct{
PULONG ExceptionCodeAddress;
PCONTEXT pContext;
ULONG ExceptionCode;
ULONG ExceptionFlags;
PULONG ExceptionRecord;
ULONG ExceptionAddress;
ULONG NumberOfParameters;
ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}EXCEPTION_INFO, *PEXCEPTION_INFO;


output of the program running in vmware:
Code:

ring3 VMWARE detection - (c) 2009 deroko of ARTeam
[X] vmware detected

output of the program running on live system:

Code:

ring3 VMWARE detection - (c) 2009 deroko of ARTeam

vmware not detected


Hope you find it usefull

Daniel Pistelli
August 10th, 2009, 02:17
Nice trick deroko, doesn't work on Virtual Box though (tested with XP 32bit and Win7 64bit). I think it's a VMWare only behavior.

dELTA
August 10th, 2009, 08:14
Thanks for the info deroko, as always.

deroko
August 10th, 2009, 15:29
There is also one more trick to detect vmware in ring0 as from what I know vmware executes ring3 on live cpu. Just execute 66 BSWAP reg32 in ring0 in vmware which is undefined instruction (eg. undefined according to intel manual) and lower part of the register will be swaped, but on live cpu low part of register is always zeroed (tested it on intel and amd cpu). I found this when was writing disassembly engine to support all instructions from intel manual

evaluator
August 10th, 2009, 15:53
>>if exception occured 1st time (1st debug break) and sets RF

Is not RF already in c.EFLAGS ?

deroko
August 10th, 2009, 16:33
Sorry I ment 1st debug exception when dwExceptionCounte == 1 as 1st exception is to get access to drX (pf with xor eax,eax/mov eax,[eax]). my bad

evaluator
August 11th, 2009, 01:39
no, i mean, when DR-exception happens, CPU sets RF and it should be also in CTX.EFLAGs (check it),
so you not need set it again.

drizz
August 11th, 2009, 09:26
Hi,

What was your guest OS, i know win9x is obsolete, but 9x and NT systems handle RF differently.

deroko
August 11th, 2009, 17:18
@evaluator: no, RF is not set by default. There are some conditions when it's set but debug exception on execution is not setting this flag.

@drizz: it's winxp as guest, and winxp/vista as host. It doesn't really matter, as it seems to be vmware virtualization problem. VMWare version is 6.5.1

hartt
January 31st, 2010, 05:30
In my computer, the program running on live system (win xp pro sp3)

Quote:
ring3 VMWARE detection - (c) 2009 deroko of ARTeam
[X] vmware detected


The trick is not working :/

deroko
January 31st, 2010, 05:45
then there is something fishy with your cpu, as this behavior is defined in ia32 manuals.

hartt
January 31st, 2010, 06:37
It's strange.. My cpu is "Intel Core 2 Duo T7600".
Your system is 32 or 64 bits ?

deroko
January 31st, 2010, 14:05
it's 32bit... tested on t7200 and t9550. Do you have by any chance, anything, any hook driver which might block NtContinue? As vmware detected occurs only, and only when RF is not handled by your CPU, which is (and should be) handled by real cpu but not in vmware.

hartt
January 31st, 2010, 22:34
I have no hooks in ntdll.dll and SSDT with NtContinue.

I compiled your code in assembly.. RF flag is not handled by my real cpu because i have a loop
Source + binary in attachment.

Code:

BreakpointBugCheck proc

push _seh_handler
push fs:[0]
mov fs:[0], esp ; Install Exception Handler

xor eax, eax ; Exception Div by 0 for install BPH
div eax

_junk_code:
nop

_bph:
nop

_func_ret:
pop fs:[0] ; Delete Exception Handler
add esp, 4

mov eax, 1
retn ; Function Return

_seh_handler:
mov ecx, [esp+04h] ; ecx = EXCEPTION RECORD
mov ebx, [ecx] ; ebx = EXCEPTION CODE

cmp ebx, 0C0000094h ; Exception Code Div by 0
je _div_exception

cmp ebx, 80000004h ; Exception Code BreakpointH
je _bph_exception

_div_exception:
mov ecx, [esp+0Ch] ; ecx = CONTEXT RECORD
mov dword ptr [ecx+4h], _bph ; Dr0 register
mov dword ptr [ecx+18h], 101h ; Dr7 register
mov dword ptr [ecx+0B8h], _junk_code ; Eip register
xor eax, eax
retn ; Exception Handler Return

_bph_exception:
mov ecx, [esp+0Ch] ; ecx = CONTEXT RECORD
or dword ptr [ecx+0C0h], 10000h ; EFlags register (change RFFlag)
xor eax, eax
retn ; Exception Handler Return

BreakpointBugCheck endp