Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / ASM

Detect if your program is running inside a Virtual Machine

Rate me:
Please Sign up or sign in to vote.
4.86/5 (102 votes)
4 Apr 2005CPOL5 min read 701.4K   8.4K   160   103
An article showing how you can programmatically check if your code is running inside a virtual machine (such as VPC or VMWare).

Sample Image

Introduction

This article will demonstrate how an application can detect if it is being run from inside a virtual machine software.

The code in this article will detect two well known machine virtualization software:

  • Microsoft's Virtual PC (formally from Connectix).
  • VMWare from VMWare.com

Other virtual machine software such as Bochs or Plex86 are not covered in this article.

It is best that the readers have a general idea about the Intel x86 assembly language to better understand how the code works, however I will do my best to explain the techniques in layman's terms.

Please note that whenever I use the term "Virtual Machine Software", this means I am referring to a software such as Virtual PC or VMWare. When the term "Virtual Machine" is used, this means the emulated machine, usually running an operating system.

A little about virtual machine software

Virtual machine software are software that emulate a given machine's architecture using software (code) instead of relying on hardware, thus allowing a code to be executed in that virtual machine as if it is being run from a real machine.

Till today, these software are far from being perfect, and emulating a given real machine still poses many challenges due to complexities involved when trying to emulate every component of a given machine.

Both Virtual PC and VMWare allow you to install "add-in"s to accelerate emulation, allow drag-n-drop from your real desktop to your virtual desktop, and allow file sharing between your real machine and the virtual machine.

In order to accomplish this task, a communication mechanism between the virtual machine software and the virtual machine itself must exist.

This sort of interfacing is called a "backdoor interfacing", since, using a special/undocumented mechanism, certain commands can be carried and interpreted in a different manner (by the virtual machine software) unlike having them interpreted by the real machine.

Next, I'll be covering how you can tell whether your software is being executed using a real machine or a virtual machine software (covering both Virtual PC and VMWare).

How to detect Virtual PC

As you may already know, every machine has a defined set of instructions commonly referred to as Instruction Set Architecture (ISA).

When an invalid instruction (that is not present in the ISA) is encountered, the machine raises an exception of the type "Invalid Opcode". The software can either handle the exception (using the usual try/catch mechanism), let the operating system handle the exception, or crash the machine in worst cases.

Virtual PC uses a bunch of invalid instructions to allow the interfacing between the virtual machine and the Virtual PC software.

Here's what happens when Virtual PC's virtual machine wants to talk with Virtual PC:

  1. The program sets exception handlers (try/catch blocks).
  2. Set needed parameters before calling the VM software.
  3. Issue a special "Invalid Opcode" instruction.
  4. VM software will recognize this invalid opcode and act accordingly, causing no exception if VPC was present, and an exception if VPC isn't present.
  5. The program's "catch" block will handle the exception and examine the returned parameters for the presence/absence of VM software.

In short, Virtual PC uses the "Invalid Opcode" mechanism as a backdoor.

The following code shows how to detect Virtual PC's presence:

MC++
// IsInsideVPC's exception filter
DWORD __forceinline IsInsideVPC_exceptionFilter(LPEXCEPTION_POINTERS ep)
{
  PCONTEXT ctx = ep->ContextRecord;

  ctx->Ebx = -1; // Not running VPC
  ctx->Eip += 4; // skip past the "call VPC" opcodes
  return EXCEPTION_CONTINUE_EXECUTION;
  // we can safely resume execution since we skipped faulty instruction
}

// High level language friendly version of IsInsideVPC()
bool IsInsideVPC()
{
  bool rc = false;

  __try
  {
    _asm push ebx
    _asm mov  ebx, 0 // It will stay ZERO if VPC is running
    _asm mov  eax, 1 // VPC function number

    // call VPC 
    _asm __emit 0Fh
    _asm __emit 3Fh
    _asm __emit 07h
    _asm __emit 0Bh

    _asm test ebx, ebx
    _asm setz [rc]
    _asm pop ebx
  }
  // The except block shouldn't get triggered if VPC is running!!
  __except(IsInsideVPC_exceptionFilter(GetExceptionInformation()))
  {
  }

  return rc;
}

More details on the code:

  1. Install exception handlers.
  2. Prepare input registers "eax" and "ebx".
  3. Issue invalid instruction 0x0F 0x3F 0x07 0x0B. This invalid instruction is like a function designator, it tells Virtual PC what to do exactly. For other functionality, Virtual PC uses another invalid instruction.
  4. Inside the exception handler -> modify registers so to mark VPC's absence (EBX is set to -1 if exception is triggered -> VPC is absent).
  5. Return from exception and resume execution (only if VPC was absent).
  6. Inspect returned registers accordingly.

How to detect VMWare

The Intel x86 provides two instructions to allow you to carry I/O operations, these instructions are the "IN" and "OUT" instructions. These two instructions are privileged instructions and cannot be used in a user-mode (while in protected mode) process unless the necessary privileges are enabled, so using them in normal cases will cause an exception of the type: "EXCEPTION_PRIV_INSTRUCTION".

VMWare uses the "IN" instruction to read from a special port. This port does not effectively exist, however when VMWare is present, that port will be the interface between the virtual machine and VMWare.

Here's the code:

MC++
bool IsInsideVMWare()
{
  bool rc = true;

  __try
  {
    __asm
    {
      push   edx
      push   ecx
      push   ebx

      mov    eax, 'VMXh'
      mov    ebx, 0 // any value but not the MAGIC VALUE
      mov    ecx, 10 // get VMWare version
      mov    edx, 'VX' // port number

      in     eax, dx // read port
                     // on return EAX returns the VERSION
      cmp    ebx, 'VMXh' // is it a reply from VMWare?
      setz   [rc] // set return value

      pop    ebx
      pop    ecx
      pop    edx
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    rc = false;
  }

  return rc;
}
  1. The program sets exception handlers (in case VMWare isn't present, we just discard its presence).
  2. Set up into the EAX register the magic number 0x564D5868 (or 'VMXh').
  3. Set EBX register to any value but the magic number.
  4. Set ECX register to the "function number" value. The value 10 means Get VMWare version, other codes means other functionality.
  5. Set into DX the magic port number 0x5658 (or 'VX'), this special port number allows interfacing with VMWare when it is present.
  6. Read from that port into EAX.
    1. When VMWare is not present, an exception will occur and we discard VMWare's presence.
    2. Otherwise, the code flow continues.
  7. EBX should now read the magic number value.
  8. If so, then VMWare is present.

Using the code

This article comes with a sample GUI written in C#/VB.NET and VC++, allowing you to detect the presence of either VMWare or Virtual PC.

The C++ code uses "DetectVM.cpp/.h" which exports the following functions:

bool IsInsideVPC();
bool IsInsideVMWare();

The C#/VB.NET code uses the following read-only properties:

System::Boolean IsInsideVPC
System::Boolean IsInsideVMWare

Closing words

Hope you enjoyed and learned from reading this article and using the code. Thanks to CodeProject members for their continuous support and quality articles/code.

Special thanks goes to Mr. Ken Kato, for his work that enabled me to learn about VMWare's backdoor interface.

History

  • 03/14/2005 - Initial version of article packed with only VC++ sample code.
  • 03/30/2005
    • Updated the article's IsInsideVPC explanation.
    • Rewritten both IsInsideVPC() and IsInsideVMWare() using less ASM code.
    • Added .NET samples (thanks to unruledboy for his .NET code contribution).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Elias (aka lallousx86, @0xeb) has always been interested in the making of things and their inner workings.

His computer interests include system programming, reverse engineering, writing libraries, tutorials and articles.

In his free time, and apart from researching, his favorite reading topics include: dreams, metaphysics, philosophy, psychology and any other human/mystical science.

Former employee of Microsoft and Hex-Rays (the creators of IDA Pro), was responsible about many debugger plugins, IDAPython project ownership and what not.

Elias currently works as an Anticheat engineer in Blizzard Entertainment.

Elias co-authored 2 books and authored one book:

- Practical Reverse Engineering
- The Antivirus Hacker's Handbook
- The Art of Batch Files Programming

Comments and Discussions

 
QuestionHow to remove / stop visualization if detected? Pin
Member 119580833-Sep-15 14:19
Member 119580833-Sep-15 14:19 
QuestionHow to tell if... Virtual Pin
Member 119580833-Sep-15 13:49
Member 119580833-Sep-15 13:49 
AnswerRe: How to tell if... Virtual Pin
SolarNigerija8-Jul-16 10:16
SolarNigerija8-Jul-16 10:16 
GeneralRe: How to tell if... Virtual Pin
hooger201715-May-17 17:00
hooger201715-May-17 17:00 
GeneralRe: How to tell if... Virtual Pin
SolarNigerija11-Nov-17 22:55
SolarNigerija11-Nov-17 22:55 
sorry on late answer (wierd is that I've just now noticed this q?)
Actually I did manage that code to work pretty well.
This piece of code is now part of Commercial Project used by company I work for.
Copied code for VPC, XEN, HV variants, hope it helps.

/*********************************************************************************
  method  : call non existing CPU instruction SEH filter
            read bellow function for details.
  --------------------------------------------------------------------------------
*/
DWORD __forceinline vmd_check_vpcseh_filter(LPEXCEPTION_POINTERS ep)
{
  PCONTEXT ctx = ep->ContextRecord;
  ctx->Ebx = -1; // Not running VPC
  ctx->Eip += 4; // skip past the "call VPC" opcodes
  return EXCEPTION_CONTINUE_EXECUTION;
  // we can safely resume execution since we skipped faulty instruction
}

/*********************************************************************************
  method  : VirtualPC call non existing CPU instruction 
            only properly written to include push, and pop for registers and 
            proper set of ebx register to 0 (should replace V1 of the same fn).
  --------------------------------------------------------------------------------
  accuracy: this method exploits Virtual PC inner communication.
            I haven't tried to prevent this detection method (yet).            
  --------------------------------------------------------------------------------
  returns : if hypervisor detected true, otherwise false
  --------------------------------------------------------------------------------
  notice  : ESET-NOD32 detects the name vmd_check_vpcseh() function as a variant 
            of "Win32/Packed.VMDetector.A" when exposed from a DLL.
            We might need to rewrite this.
  --------------------------------------------------------------------------------
*/
bool vmd_check_vpcseh()
{
  bool rc = false;
  __try
  {
    _asm push ebx
    _asm mov  ebx, 0 // It will stay ZERO if VPC is running
    _asm mov  eax, 1 // VPC function number

    // The except block shouldn't get triggered if VPC is running!!
    // call VPC 
    _asm __emit 0x0F
    _asm __emit 0x3F
    _asm __emit 0x07
    _asm __emit 0x0B

    _asm test ebx, ebx
    _asm setz [rc]
    _asm pop ebx
  }  
  // exception block ensures that we skip invalid instruction and 
  // continue execution like nothing happened in case of real world.
  __except(vmd_check_vpcseh_filter(GetExceptionInformation()))
  {
    // [rc] contains result (false)
  }
  return rc;
}

/*********************************************************************************
  method  : XEN call non existing CPU instruction             
  --------------------------------------------------------------------------------
  accuracy: this method exploits XEN inner communication.
            I haven't tried to prevent this detection method (yet).            
  --------------------------------------------------------------------------------
  returns : if hypervisor detected true, otherwise false
  --------------------------------------------------------------------------------
  notice  : ESET-NOD32 detects the name vmd_check_vpcseh() function as a variant 
            of "Win32/Packed.VMDetector.A" when exposed from a DLL.
            We might need to rewrite this.
  --------------------------------------------------------------------------------
*/
bool vmd_check_xenseh()
{
  bool rc = false;
  __try
  {
    _asm push ebx
    _asm mov  ebx, 0 // It will stay ZERO if XEN is running
    _asm mov  eax, 1 // XEN function number ???

    // The except block shouldn't get triggered if XEN is running!!
    // call XEN 
    _asm __emit 0x0F
    _asm __emit 0x0B
    _asm __emit 0x0F
    _asm __emit 0xA2

    _asm test ebx, ebx
    _asm setz [rc]
    _asm pop ebx
  }  
  // exception block ensures that we skip invalid instruction and 
  // continue execution like nothing happened in case of real world.
  __except(vmd_check_vpcseh_filter(GetExceptionInformation()))
  {
    // [rc] contains result (false)
  }
  return rc;
}

/*********************************************************************************
  method  : Hyper-V call non existing CPU instruction             
  --------------------------------------------------------------------------------
  accuracy: this method exploits Hyper-V inner communication.
            I haven't tried to prevent this detection method (yet).            
  --------------------------------------------------------------------------------
  returns : if hypervisor detected true, otherwise false
  --------------------------------------------------------------------------------
  notice  : ESET-NOD32 detects the name vmd_check_vpcseh() function as a variant 
            of "Win32/Packed.VMDetector.A" when exposed from a DLL.
            We might need to rewrite this.
  --------------------------------------------------------------------------------
*/
bool vmd_check_hvseh()
{
  bool rc = false;
  __try
  {
    _asm push ebx
    _asm mov  ebx, 0    // It will stay ZERO if Hyper-V is running
    _asm mov  eax, 1    // Hyper-V function number ???

    // The except block shouldn't get triggered if Hyper-V is running!!
    // call XEN     
    // vmcall C3 // VMCALL—Call to VM Monitor ???
    // IDA failure to analize SP, interesting good for code obfuscation ;)
    //
    _asm __emit 0x0F
    _asm __emit 0x01
    _asm __emit 0xC1
    _asm __emit 0xC3

    _asm test ebx, ebx
    _asm setz [rc]      // set to true if executed
    _asm pop ebx
  }  
  // exception block ensures that we skip invalid instruction and 
  // continue execution like nothing happened in case of real world.
  __except(vmd_check_vpcseh_filter(GetExceptionInformation()))
  {
    // [rc] contains result (false)
  }
  return rc;
}


modified 12-Nov-17 5:05am.

GeneralVery nice Pin
Amin Esmaeily8-Mar-15 21:45
professionalAmin Esmaeily8-Mar-15 21:45 
QuestionInteresting Pin
jfriedman12-Feb-15 14:26
jfriedman12-Feb-15 14:26 
QuestionHow can I detect VM/ VMWare in x64 bit Windows Pin
kalyani.homkar2-Sep-14 20:42
kalyani.homkar2-Sep-14 20:42 
AnswerRe: How can I detect VM/ VMWare in x64 bit Windows Pin
Michael Haephrati2-Oct-22 1:44
professionalMichael Haephrati2-Oct-22 1:44 
Questionhow about detecting proxmox ? Pin
bgsjust17-Jan-14 12:46
professionalbgsjust17-Jan-14 12:46 
Questionupdated link and correction Pin
Dio PM2-Aug-13 2:33
Dio PM2-Aug-13 2:33 
AnswerRe: updated link and correction Pin
Daniele Rota Nodari30-Jun-15 1:33
Daniele Rota Nodari30-Jun-15 1:33 
GeneralRe: updated link and correction Pin
SolarNigerija8-Jul-16 10:18
SolarNigerija8-Jul-16 10:18 
QuestionESET-NOD32 detects the name IsInsideVPC() function as a variant of "Win32/Packed.VMDetector.A" when exposed from a DLL. Pin
anony-user14-Jul-13 20:46
anony-user14-Jul-13 20:46 
QuestionHow to use this code on x64 project ?? Pin
imyoungcheol16-Jun-13 21:14
imyoungcheol16-Jun-13 21:14 
GeneralMy vote of 5 Pin
filepang22-May-13 5:07
filepang22-May-13 5:07 
QuestionCool codes.Furthermore,how to get the vmware version if it's running in vmware? Pin
Eric Yung4-Jun-12 17:11
Eric Yung4-Jun-12 17:11 
GeneralMy vote of 5 Pin
sloth771-Jun-12 9:47
sloth771-Jun-12 9:47 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey24-Feb-12 2:44
professionalManoj Kumar Choubey24-Feb-12 2:44 
QuestionProgram could not detect accurately for 64 bit processor machine Pin
Anthony_Yio2-Jan-12 22:27
Anthony_Yio2-Jan-12 22:27 
AnswerRe: Program could not detect accurately for 64 bit processor machine Pin
firehawk25-Apr-12 17:13
firehawk25-Apr-12 17:13 
BugI Can't Compile the library on windows 7 (x64 bit) Pin
Kirollos.Farouk24-Oct-11 3:49
Kirollos.Farouk24-Oct-11 3:49 
GeneralRe: I Can't Compile the library on windows 7 (x64 bit) Pin
Minh Danh Nguyen (ToughDev)6-Mar-12 3:25
Minh Danh Nguyen (ToughDev)6-Mar-12 3:25 
GeneralMy vote of 5 Pin
Kirollos.Farouk24-Oct-11 3:31
Kirollos.Farouk24-Oct-11 3:31 
Generalin case you have Hyper-V Pin
fryezz18-May-11 11:42
fryezz18-May-11 11:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.