I spent some time investigating how I can detect virtualization from within a user-mode application. I was looking for a solution that could fulfil the following criteria:
Unfortunately, it turns out this cannot be done. Yes, you read that correctly. Here are my findings:
This is the method that gained headlines back in late 2004. The code is often shown like this:
Details behind Joanna Rutkowska's Matrix reference can be found at Invisible Things. Basically, this takes advantage of a CPU instruction that usually does not need to be called from ring3. In a VM, this instruction returns a pointer to a different location than when running natively.
The problem with this code...is mostly that we're no longer working in 2004. Two things have happened that render this test useless:
This last problem is described in greater detail in a document [1, 2] comparing Red Pill and No Pill.
This method of virtual environment detection no longer works.
The No Pill variation by Offensive Computing [1, 2] took Red Pill's SIDT CPU instruction, and replaced it with SGDT. While SGDT returns the same information for all CPUs, I've personally observed that with modern virtualization software, the vector returned is identical regardless of whether it is running natively or virtualized. Like Red Pill, the test has been obsoleted by better virtualization software.
Just like Red Pill, the source code examples I found on the web often suffer from the segmentation fault problems.
This method of virtual environment detection no longer works.
This is yet another variation on the SIDT (Red Pill) and SGDT (No Pill) techniques. The idea behind these three tests was to find an instruction that can be called from ring3 and which returns a special value. But what I personally observed with Ubuntu 9.10-64bit is that whether running natively or through VirtualBox, SLDT was always returning a value of zero.
Of special interest, please see my comment on the segmentation fault problems.
This method of virtual environment detection no longer works.
A paper from Alfredo Andrés Omella [1, 2] describes using the SRT instruction, somewhat similar to the Red Pill/No Pill/SLDT technique. However, I've observed no discernible difference when running this natively or virtualized. I can only guess that better virtualization software has rendered this test ineffective in recent years.
This method of virtual environment detection no longer works.
The Jerry method is specific to VMWare, and thus not a valid solution for what I need. Basically, the Jerry code shows how to call into VMWare from an application running in the guest OS. Think back to the MS Windows 2.x and 3.x days where DOS INT 2Fh could be used to tell if Windows was running. (Yes, I had dig out my ancient "PC Interrupts" bible to look up the interrupt...!) Turns out that VMWare listens for I/O on port 0x5658. Depending on how registers are setup, this can be used to get things like the VMWare product, version, or the amount of (available?) memory.
This method of virtual environment detection is specific to VMWare (and may not work since there is a way to disable the VMWare back door).
Note the name, this is not a typo -- it isn't your friendly children's cartoon Scooby Doo, but actually Scoopy Doo.
Scoopy is a collection of short tests in a single .C source file that attempt to detect virtualization. [1, 2] Some of these tests are Windows-specific, some are VMWare-specific:
These methods of virtual environment detection no longer work, or are specific to VMWare.
Inspecting the MAC OUI is an oft-mentioned technique on blogs and various web sites such as StackOverflow. [1 and 2]
While the Organizationally Unique Identifier may provide insight into whether or not an environment is virtualized:
This method of virtual environment detection is strongly discouraged.
The DMI bios strings, like the MAC OUI, may indicate the presence of a virtualized environment:
However, the problems are also similar to those preventing us from using the MAC OUI:
This method of virtual environment detection is strongly discouraged.
The list of PCI devices reported by the virtualized hardware may contain names (or raw PCI device identifiers) that can be used to determine when running in a virtualized environment.
However, this suffers from some of the same problem as the MAC OUI:
This method of virtual environment detection is discouraged.
Similar to PCI devices, looking at the list of installed device drivers depends both on the device services offered by the virtualization software, and possibly also on optional installation steps ("VMWare Tools", or "VirtualBox Guest Additions") that are not guaranteed to have taken place.
This method of virtual environment detection is strongly discouraged.
Almost all of the sample code I found on the web that attempted to demonstrate how to use Red Pill and No Pill actually had one or both of the following problems:
Lastly, something else worth mentioning is that some example code of the SLDT detection method incorrectly attempts to handle the output the same way as it is done with SIDT and SGDT, as a 48-bit size+base address structure. Instead, please note that SLDT returns a single 16-bit selector regardless of whether running in i386 or AMD64. For details, see page 303 of the AMD documentation.