70

I need to detect whether my application is running within a virtualized OS instance or not.

I've found an article with some useful information on the topic. The same article appears in multiple places, I'm unsure of the original source. VMware implements a particular invalid x86 instruction to return information about itself, while VirtualPC uses a magic number and I/O port with an IN instruction.

This is workable, but appears to be undocumented behavior in both cases. I suppose a future release of VMWare or VirtualPC might change the mechanism. Is there a better way? Is there a supported mechanism for either product?

Similarly, is there a way to detect Xen or VirtualBox?

I'm not concerned about cases where the platform is deliberately trying to hide itself. For example, honeypots use virtualization but sometimes obscure the mechanisms that malware would use to detect it. I don't care that my app would think it is not virtualized in these honeypots, I'm just looking for a "best effort" solution.

The application is mostly Java, though I'm expecting to use native code plus JNI for this particular function. Windows XP/Vista support is most important, though the mechanisms described in the referenced article are generic features of x86 and don't rely on any particular OS facility.

wjandrea
  • 16,334
  • 5
  • 30
  • 53
DGentry
  • 15,552
  • 7
  • 48
  • 65
  • 5
    There is no reliable way to determine when running in a virtualized environment. I have details including source code on RedPill, NoPill, Scoopy Doo, Jerry, DMI, OUI, ...all of the popular "techniques" and why they don't work here: http://charette.no-ip.com:81/programming/2009-12-30_Virtualization/index.html – Stéphane Jan 15 '10 at 10:50
  • @Stéphane Except a handful of the techniques described *will* likely work assuming the VM or VM operator is not intentionally trying to deceive the program. There can be false negatives, but I suppose you have to define 'reliable' – Schilcote Apr 23 '15 at 01:28

16 Answers16

74

Have you heard about blue pill, red pill?. It's a technique used to see if you are running inside a virtual machine or not. The origin of the term stems from the matrix movie where Neo is offered a blue or a red pill (to stay inside the matrix = blue, or to enter the 'real' world = red).

The following is some code that will detect wheter you are running inside 'the matrix' or not:
(code borrowed from this site which also contains some nice information about the topic at hand):

 int swallow_redpill () {
   unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3";
   *((unsigned*)&rpill[3]) = (unsigned)m;
   ((void(*)())&rpill)();
   return (m[5]>0xd0) ? 1 : 0;
 } 

The function will return 1 when you are running inside a virutal machine, and 0 otherwise.

Bergi
  • 513,640
  • 108
  • 821
  • 1,164
sven
  • 17,326
  • 10
  • 48
  • 62
  • 11
    Correction: it will return 1 when you are running inside some of the virtual machines that are available today, on some bits of hardware. – Kirk Strauser Sep 30 '08 at 18:05
  • yes, it indeed uses the fact that the virtual machine is not an entirely accurate representation of a real pc. If it was then there is no (good) way to detect you are running virtual – sven Sep 30 '08 at 18:14
  • 7
    @erik: it uses the fact that a virutalised OS is a 'second' OS on a machine. This means that resources needs to be shared. In this code it's the IDTR (Interrupt descriptor table register: check wikipedia) that will be checked against, if it is not in the usual place, then we know that we are virtual – sven Oct 02 '08 at 15:17
  • 1
    Just to note. This code fails in Windows XP Pro running in VMWare Fusion (Version 2.0 (116369)) on OSX 10.5 – epochwolf Nov 10 '08 at 04:40
  • Is there a reason this code is so cryptic? Why isn't just some asm code in a c function? – vanja. Feb 12 '09 at 12:10
  • Is there a standard (cross compiler) way of writing asm inside a C function? – Martin Beckett Feb 17 '09 at 18:32
  • 22
    Note that RedPill and the initial scoopy_doo techniques will return false positives on multi-core CPUs. For example: on a quad-core system running natively, 75% of the time it will tell you it is running in a VM. Google for things like "NoPill" to get additional details. – Stéphane Dec 30 '09 at 08:33
  • is there a way to understand it through a Java program?? – Thanasis Petsas Jun 11 '13 at 15:28
  • This is interesting, mainly on what Stephane said, some software I use here are accusing my native windows 10 x64 of being a VM, i tried running that code and it just crashes with access violation (even with UAC elevation). – Felype Jan 04 '16 at 16:43
  • Is this working on modern Virtual machines? And why? – LotoLo Jun 21 '18 at 09:25
24

Under Linux I used the command: dmidecode ( I have it both on CentOS and Ubuntu )

from the man:

dmidecode is a tool for dumping a computer's DMI (some say SMBIOS) table contents in a human-readable format.

So I searched the output and found out its probably Microsoft Hyper-V

Handle 0x0001, DMI type 1, 25 bytes
System Information
    Manufacturer: Microsoft Corporation
    Product Name: Virtual Machine
    Version: 5.0
    Serial Number: some-strings
    UUID: some-strings
    Wake-up Type: Power Switch


Handle 0x0002, DMI type 2, 8 bytes
Base Board Information
    Manufacturer: Microsoft Corporation
    Product Name: Virtual Machine
    Version: 5.0
    Serial Number: some-strings

Another way is to search to which manufacturer the MAC address of eth0 is related to: http://www.coffer.com/mac_find/

If it return Microsoft, vmware & etc.. then its probably a virtual server.

michaelbn
  • 6,313
  • 1
  • 29
  • 42
14

VMware has a Mechanisms to determine if software is running in a VMware virtual machine Knowledge base article which has some source code.

Microsoft also has a page on "Determining If Hypervisor Is Installed". MS spells out this requirement of a hypervisor in the IsVM TEST" section of their "Server Virtualization Validation Test" document

The VMware and MS docs both mention using the CPUID instruction to check the hypervisor-present bit (bit 31 of register ECX)

The RHEL bugtracker has one for "should set ISVM bit (ECX:31) for CPUID leaf 0x00000001" to set bit 31 of register ECX under the Xen kernel.

So without getting into vendor specifics it looks like you could use the CPUID check to know if you're running virtually or not.

David
  • 4,116
  • 1
  • 14
  • 5
  • 1
    Everyone is gradually coming around to the idea of [singing from the same songsheet](http://homepage.ntlworld.com./jonathan.deboynepollard/FGA/detecting-x86-virtual-machines.html). – JdeBP Nov 22 '11 at 22:34
12

No. This is impossible to detect with complete accuracy. Some virtualization systems, like QEMU, emulate an entire machine down to the hardware registers. Let's turn this around: what is it you're trying to do? Maybe we can help with that.

Kirk Strauser
  • 27,753
  • 5
  • 45
  • 62
  • This is possible. Although you can emulate every instructions a virtual machine executes, the application can still discover the truth by resourse limitation, etc,. – ZelluX May 28 '09 at 13:24
  • If we emulate old PC on a new powerful hardware - we can emulate latencies and resources. – Eugene Mala May 14 '17 at 22:22
  • Well that's emulation rather than virtualization. The hardest to hide is timing information, especially if the guest has network access and can use an external clock. – Matthew Sharp May 22 '19 at 06:22
12

I think that going forward, relying on tricks like the broken SIDT virtualization is not really going to help as the hardware plugs all the holes that the weird and messy x86 architecture have left. The best would be to lobby the Vm providers for a standard way to tell that you are on a VM -- at least for the case when the user has explicitly allowed that. But if we assume that we are explicitly allowing the VM to be detected, we can just as well place visible markers in there, right? I would suggest just updating the disk on your VMs with a file telling you that you are on a VM -- a small text file in the root of the file system, for example. Or inspect the MAC of ETH0, and set that to a given known string.

jakobengblom2
  • 4,806
  • 2
  • 23
  • 30
  • 2
    Your solution (at the end of your paragraph) won't work if you don't have control over the VM you're running in. =\ – Erik Forbes Oct 02 '08 at 07:04
  • 3
    No, but if you do not have control over the VM, all bets are off anyway. Then it might well deliberately hide. So the question is really why and when and in which situation you want to do this. – jakobengblom2 Oct 02 '08 at 07:38
8

On virtualbox, assuming you have control over the VM guest and you have dmidecode, you can use this command:

dmidecode -s bios-version

and it will return

VirtualBox
icasimpan
  • 1,093
  • 3
  • 13
  • 28
7

This C function will detect VM Guest OS:

(Tested on Windows, compiled with Visual Studio)

#include <intrin.h>

    bool isGuestOSVM()
    {
        unsigned int cpuInfo[4];
        __cpuid((int*)cpuInfo,1);
        return ((cpuInfo[2] >> 31) & 1) == 1;
    }
user2242746
  • 361
  • 4
  • 6
  • add little info, Is this one gets some info from cpu ? – Sorry IwontTell Jun 06 '20 at 13:57
  • I lack the knowledge to judge the code which was also posted in other places. Here are two interesting comments from there: `To clarify, this piece of code uses the cpuid instruction to detect if the feature bit is set that indicates the code is running on a hypervisor. There is, of course, no requirement that an actual hypervisor always sets this bit, especially for software hypervisors.` and `I would not use this. Tested false positive (Windows 10, VS) on my PC. I have virtualization support turned on in BIOS, but not running in VM, so it might be that (?).` – marsh-wiggle Jan 29 '21 at 14:43
7

I'd like to recommend a paper posted on Usenix HotOS '07, Comptibility is Not Transparency: VMM Detection Myths and Realities, which concludes several techniques to tell whether the application is running in a virtualized environment.

For example, use sidt instruction as redpill does(but this instruction can also be made transparent by dynamic translation), or compare the runtime of cpuid against other non-virtualized instructions.

ZelluX
  • 57,940
  • 18
  • 67
  • 104
5

Under Linux, you can report on /proc/cpuinfo. If it's in VMware, it usually comes-up differently than if it is on bare metal, but not always. Virtuozzo shows a pass-through to the underlying hardware.

warren
  • 28,486
  • 19
  • 80
  • 115
5

Try by reading the SMBIOS structures, especially the structs with the BIOS information.

In Linux you can use the dmidecode utility to browse the information.

Jonas Engström
  • 4,825
  • 2
  • 35
  • 36
  • 2
    `dmidecode` needs super-user (root) permission to run, so it's not that useful from an application. – Raedwald Apr 17 '13 at 14:15
5

While installing the newes Ubuntu I discovered the package called imvirt. Have a look at it at http://micky.ibh.net/~liske/imvirt.html

Pavlo Svirin
  • 460
  • 3
  • 8
4

Check the tool virt-what. It uses previously mentioned dmidecode to determine if you are on a virtualized host and the type.

Rickard von Essen
  • 3,554
  • 2
  • 18
  • 22
4

I Tried A Different approach suggested by my friend.Virtual Machines run on VMWARE doesnt have CPU TEMPERATURE property. i.e They Dont Show The Temperature of the CPU. I am using CPU Thermometer Application For Checking The CPU Temperature.

(Windows Running In VMWARE) enter image description here

(Windows Running On A Real CPU) enter image description here

So I Code a Small C Programme to detect the temperature Senser

#include "stdafx.h"

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

int main(int argc, char **argv)
{
    HRESULT hres;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        cout << "Failed to initialize COM library. Error code = 0x"
            << hex << hres << endl;
        return 1;                  // Program has failed.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres = CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities 
        NULL                         // Reserved
        );


    if (FAILED(hres))
    {
        cout << "Failed to initialize security. Error code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                    // Program has failed.
    }

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    IWbemLocator *pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID *)&pLoc);

    if (FAILED(hres))
    {
        cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    IWbemServices *pSvc = NULL;

    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
        NULL,                    // User name. NULL = current user
        NULL,                    // User password. NULL = current
        0,                       // Locale. NULL indicates current
        NULL,                    // Security flags.
        0,                       // Authority (for example, Kerberos)
        0,                       // Context object 
        &pSvc                    // pointer to IWbemServices proxy
        );

    if (FAILED(hres))
    {
        cout << "Could not connect. Error code = 0x"
            << hex << hres << endl;
        pLoc->Release();
        CoUninitialize();
        return 1;                // Program has failed.
    }

    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;


    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
        pSvc,                        // Indicates the proxy to set
        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
        NULL,                        // Server principal name 
        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
        NULL,                        // client identity
        EOAC_NONE                    // proxy capabilities 
        );

    if (FAILED(hres))
    {
        cout << "Could not set proxy blanket. Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----

    // For example, get the name of the operating system
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"),
        bstr_t(L"SELECT * FROM Win32_TemperatureProbe"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator);

    if (FAILED(hres))
    {
        cout << "Query for operating system name failed."
            << " Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------

    IWbemClassObject *pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
            &pclsObj, &uReturn);

        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        // Get the value of the Name property
        hr = pclsObj->Get(L"SystemName", 0, &vtProp, 0, 0);
        wcout << " OS Name : " << vtProp.bstrVal << endl;
        VariantClear(&vtProp);
        VARIANT vtProp1;
        VariantInit(&vtProp1);
        pclsObj->Get(L"Caption", 0, &vtProp1, 0, 0);
        wcout << "Caption: " << vtProp1.bstrVal << endl;
        VariantClear(&vtProp1);

        pclsObj->Release();
    }

    // Cleanup
    // ========

    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();

    return 0;   // Program successfully completed.

}

Output On a Vmware Machine enter image description here

Output On A Real Cpu enter image description here

Mohit Dabas
  • 2,233
  • 1
  • 14
  • 12
  • There is more easier way in powershell. `Get-WMIObject MSAcpi_ThermalZoneTemperature -Namespace root/wmi`. But it requires admin rights. – Gray Programmerz Mar 13 '21 at 17:25
4

On linux systemd provides a command for detecting if the system is running as a virtual machine or not.

Command:
$ systemd-detect-virt

If the system is virtualized the it outputs name of the virtuslization softwarwe/technology. If not then it outputs none

For instance if system is running KVM then:

$ systemd-detect-virt
kvm

You don't need to run it as sudo.

Avm-x
  • 569
  • 1
  • 9
  • 19
3

I use this C# class to detect if the Guest OS is running inside a virtual environment (windows only):

sysInfo.cs

using System;
using System.Management;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    public class sysInfo
    {
            public static Boolean isVM()
            {
                bool foundMatch = false;
                ManagementObjectSearcher search1 = new ManagementObjectSearcher("select * from Win32_BIOS");
                var enu = search1.Get().GetEnumerator();
                if (!enu.MoveNext()) throw new Exception("Unexpected WMI query failure");
                string biosVersion = enu.Current["version"].ToString();
                string biosSerialNumber = enu.Current["SerialNumber"].ToString();

                try
                {
                    foundMatch = Regex.IsMatch(biosVersion + " " + biosSerialNumber, "VMware|VIRTUAL|A M I|Xen", RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    // Syntax error in the regular expression
                }

                ManagementObjectSearcher search2 = new ManagementObjectSearcher("select * from Win32_ComputerSystem");
                var enu2 = search2.Get().GetEnumerator();
                if (!enu2.MoveNext()) throw new Exception("Unexpected WMI query failure");
                string manufacturer = enu2.Current["manufacturer"].ToString();
                string model = enu2.Current["model"].ToString();

                try
                {
                    foundMatch = Regex.IsMatch(manufacturer + " " + model, "Microsoft|VMWare|Virtual", RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    // Syntax error in the regular expression
                }

                    return foundMatch;
            }
        }

}

Usage:

        if (sysInfo.isVM()) { 
            Console.WriteLine("VM FOUND");
        }
Pedro Lobito
  • 75,541
  • 25
  • 200
  • 222
1

I came up with universal way to detect every type of windows virtual machine with just 1 line of code. It supports win7--10 (xp not tested yet).

Why we need universal way ?

Most common used way is to search and match vendor values from win32. But what if there are 1000+ VM manufacturers ? then you would have to write a code to match 1000+ VM signatures. But its time waste. Even after sometime, there would be new other VMs launched and your script would be wasted.

Background

I worked on it for many months. I done many tests upon which I observed that: win32_portconnector always null and empty on VMs. Please see full report

//asked at: https://stackoverflow.com/q/64846900/14919621
what win32_portconnector is used for ? This question have 3 parts.
1) What is the use case of win32_portconnector ?    //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-portconnector
2) Can I get state of ports using it like Mouse cable, charger, HDMI cables etc ?
3) Why VM have null results on this query : Get-WmiObject Win32_PortConnector ?

On VM:

PS C:\Users\Administrator> Get-WmiObject Win32_PortConnector

On Real environment:

PS C:\Users\Administrator> Get-WmiObject Win32_PortConnector
Tag                         : Port Connector 0
ConnectorType               : {23, 3}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 2

Tag                         : Port Connector 1
ConnectorType               : {21, 2}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 9

Tag                         : Port Connector 2
ConnectorType               : {64}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 16

Tag                         : Port Connector 3
ConnectorType               : {22, 3}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 28

Tag                         : Port Connector 4
ConnectorType               : {54}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 17

Tag                         : Port Connector 5
ConnectorType               : {38}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 30

Tag                         : Port Connector 6
ConnectorType               : {39}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 31

Show me Code

Based upon these tests, I have made an tiny program which can detect windows VMs.

//@graysuit
//https://discord.com/invite/Hu5XPGMTuk
//https://github.com/Back-X/Universal-VM-Detector
using System;
using System.Windows.Forms;

public class Universal_VM_Detector
{
    static void Main()
    {
        if((new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_PortConnector")).Get().Count == 0)
        {
            MessageBox.Show("VM detected !");
        }
        else
        {
            MessageBox.Show("VM NOT detected !");
        }
    }
}

You can read code or get compiled executable.

Stability

It is tested on many environments and is very stable.

  • Detects Visrtualbox
  • Detects Vmware
  • Detects Windows Server
  • Detects RDP
  • Detects Virustotal
  • Detects any.run etc...