xorl %eax, %eax

Another VMM Detection Technique

with one comment

The previous week I was reading some stuff of the Intel manuals and came across a few really interesting instructions. One of those was VERR/VERW which according to Intel manual Volume 2B (pages 4-494) is defined like this:

Verifies whether the code or data segment specified with the source operand is read-
able (VERR) or writable (VERW) from the current privilege level (CPL). The source
operand is a 16-bit register or a memory location that contains the segment selector
for the segment to be verified. If the segment is accessible and readable (VERR) or
writable (VERW), the ZF flag is set; otherwise, the ZF flag is cleared. Code segments
are never verified as writable. This check cannot be performed on system segments.

I tried to test this since I found it really neat inside a VM (specifically, on VMware Workstation). It crashed! I tried it on my host OS and worked… Well, I spend the few next days discovering similar instructions and I have to admit that they are a few. When I came back to work on Friday I did a quick online research for this instruction and it seems that it was being used for VMM detection on malware at least since 2007. This is the reason why I’m posting this in here, I wouldn’t have posted it if it was even slightly new or innovative idea. Anyway, here is the dummy code:

#include <stdio.h>

int
main(void)
{
     unsigned long eflags;
     __asm__(
       "verr   313(%%eax)   \n"   \
       "pushf               \n"   \
       "popl   %0           \n"   \
       : "=r" (eflags)            );
     printf("you're cool! (eflags = %#x)\n", eflags);
     return 0;
}

This crappy little code, when executed on VM (I tried on VMware Workstation as well as VMware Server) has the following effect:

xorl@vmware:~$ gcc crap.c -o crap && ./crap
Segmentation fault
xorl@vmware:~$

On the other hand, this same code on the host OS works as expected from the Intel manual and terminates normally (since VERR/VERW only affects ZF flag of EFLAGS register):

xorl@debian:~$ gcc crap.c -o crap && ./crap
you’re cool! (eflags = 0x200286)
xorl@debian:~$

At a first glance, it looks weird but if you read the Intel’s description once again from the manual you’ll see this:

Operation

IF SRC(Offset) > (GDTR(Limit) or (LDTR(Limit))
    THEN ZF ← 0; FI;
Read segment descriptor;
IF SegmentDescriptor(DescriptorType) = 0 (* System segment *)
or (SegmentDescriptor(Type) ≠ conforming code segment)
and (CPL > DPL) or (RPL > DPL)
    THEN
        ZF ← 0;
    ELSE
        IF ((Instruction = VERR) and (Segment readable))
        or ((Instruction = VERW) and (Segment writable))
              THEN
                   ZF ← 1;
        FI;
FI;

Its operation is partly based on the GDT or LDT registers. As you already know these registers cannot be sufficiently simulated by most emulators (including VMware). This is why it fails but in any case, resulting a SIGSEGV is probably some bug of the VMware implementation of these instructions.
Anyway, as the title says.. just another VMM detection technique. I’d be really happy to hear what’s the reaction of different emulators apart from VMware, so if you test this and you’d like to share it feel free to contact me or leave a comment! :)

UPDATE:

I just finished reading a must-read paper (A Comparison of Software and Hardware Techniques for x86 Virtualization) and it seems like the problem with the above instruction is because of the lack of traps on privileged instructions, the papers says:

Lack of traps when privileged instructions run at user-level. For example, in privileged code popf (“pop flags”) may change both ALU flags (e.g., ZF) and system flags (e.g., IF, which controls interrupt delivery). For a deprivileged guest, we need kernel mode popf to trap so that the VMM can emulate it against the virtual IF. Unfortunately, a deprivileged popf, like any user-mode popf, simply suppresses attempts to modify IF; no trap happens.

Written by xorl

March 23, 2009 at 16:23

One Response

Subscribe to comments with RSS.

  1. Hi! It appears that this trick might be VMWare specific only.

    I have just tested this trick under debian5/virtualbox and it seems that for virtualbox (OSE edition) the trick is not working i.e. I get the same results for my native ubuntu box. (eflags is either 0×200286 (most of the time) of 0×200282 (in a few cases).

    Keep up the good work :)

    thanasisk

    April 12, 2009 at 13:04


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s