Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
105 lines (87 sloc) 4.16 KB
layout author thumbnail comments date title categories image excerpt featured-img header tags
2018-12-05 09:08:06 +0000
Detecting VMware presence on a 64-bit system [redpill respawned]
image overlay_image image_description overlay_filter cta_label cta_url
rgba(0, 0, 0, 0.3)

Hot on the heels of the latest post, I have decided to port to linux another lab example from Intermediate x86 class.
This time I will talk about the RedPill paper by Joanna Rutkowska. {: .text-justify} The main purpose of this test code is to call the SIDT instruction and save its return value inside an array: this value will tell us whether we are running it inside a vm or not. What the SIDT instruction does is simply save the Interrupt Descriptor Table Register (IDTR) value inside an operand (typically another register). The program will then check if the 6th byte of the returned value equals to 0x00 and, if it does, it means it is running inside a virtual machine. The return value size is 6 bytes on 32-bit systems (4 bytes for the address + 2 byte for the limit ) and 10 bytes on 64-bit systems instead (8 + 2 bytes). {: .text-justify}

{% highlight c hl_lines="1 3 4" %} #include <stdio.h>

int main(){ unsigned char warehouse[10];//10 bytes of storage to store the IDTR into memset(warehouse, 0, 6);//Just to make sure it's clean

__asm__ __volatile__("sidt %0" : "g="(warehouse));

printf("after SIDT instruction, storge contains:\n");

for (int i = 0; i <= 9; i++) { printf("%02X", warehouse[i]); }


if(warehouse[5] == 0x00){
	printf("This code being run in VMWare\n");
	printf("This code being run on a normal system\n");

return 0xF0551112ED;


{% endhighlight %}

We can compile it without canaries, nx or pie so the resulting assembly code will be as clean as possible by running gcc. {% highlight text hl_lines="1 3 4" %} gcc linux_verbosepill.c -o linux_verbosepill -g -fno-stack-protector -z execstack -no-pie {% endhighlight %}

The SIDT instruction provides us with valuable information from a ring0 structure, the Interrupt Descriptor Table address, via a non privileged point of view (ring3). Since the IDT is a unique entity per system, in order to avoid resource conflicts, a VM must relocate the address to a different memory region. {: .text-justify} We can then verify that under a VM we get this value.

{% highlight text hl_lines="1 3 4" %} root@kali_vm:~# ./linux_verbose_pill after SIDT instruction, warehouse contains: FF0F000000001CD7FFFF This code being run in VMWare {% endhighlight %}

On the other hand, a regular ‘bare metal’ installation, is returning a different address format.

{% highlight bash hl_lines="1 3 4" %} root@kali_bare_metal:~# ./linux_verbose_pill after SIDT instruction, warehouse contains: FF0F00C057FFFFFFFFFF This code being run on a normal system {% endhighlight %}

We can say with a fair degree of certainty that a code running on a vm has the sixth value set to zero, while it’s 0xFF on a bare metal installation. I have limited my testing to Debian and I did not manage to test this scenario extensively so fire me an email/tweet if you spot any discrepancy with any other distro.
{: .text-justify} KVM NOTE
A friend of mine tested it on KVM, guest and host, and it resulted in the following value being shown on each of them. {: .text-justify} {% highlight bash hl_lines="1 3 4" %} FF0F008052FFFFFFFFF {% endhighlight %} My guess is that KVM is either somehow sharing the IDT between host and guest or it manages to hide the rebasing on the guest system, but if you have more accurate insights, please share them :) {: .text-justify}