Search code examples
javac++virtual-machinejna

How do I check if my Java program is running in a virtual machine?


I have a Java software that needs to be licensed to clients. I have created a licensing module that would only allow the software to be executed on a specific hardware on which it was activated.

However I don't want the client to activate the software inside a Virtual Machine which would mean that multiple copies of the software could be used with a single license.

How do I stop my software from being installed in a VM?

Note:

  1. I have done research on this and already found a solution. I'm posting it here so that it may be useful to other developers.
  2. It works only for VmWare and Virtual PC not on Parallels or VirtualBox
  3. I couldn't find a pure Java solution. It relies on native code.

If you know a better solution please post it as an answer.


Solution

  • Some methods to check presence of a VM are -

    1. Looking for presence of VM artifacts like processes, files, registry entries made by VM Guest tools
    2. Using non-standard x86 instructions exposed by Virtualization software

    If you would like to know more, there is a good presentation that discusses these topics here.

    Since method 2 is the easiest and straightforward we'd be using it.

    Following code snippet can be used to check if the code is running in VMware Virtual Machine -

    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;
    }
    

    This is a part of code taken from a project published on Code Project. Being meant for demonstration it does not include code to check presence of Microsoft Virtual PC. You can visit the main site to get code for Virtual PC and a pre-compiled demo. A DLL is also provided on that site but ironically the functions are not exported which defeats the purpose of DLL as you cannot call it in a program. Thus I had to compile the above code myself and create a DLL.

    __try and __catch are Microsoft specific C++ extensions. You'll need to compile this with Visual Studio on Windows as using gcc will not work.

    Download and install following components -

    1. Visual Studio 2005 (or higher)
    2. Microsoft Platform SDK 2003

    Create a new DLL project and paste the above code into the main CPP file.

    Add this to your code in order to export your function. Without this your DLL would get compiled but function would not be callable from outside.

    extern "C" __declspec(dllexport) 
    bool IsInsideVMWare()
    {
      //Code
    }
    

    Now compile the DLL by building the Visual Studio project. In case you get errors like windows.h not found or other errors consult these stackoverflow questions -

    To check whether the function has been exported to DLL or not you can use DLL Export Viewer to see list of functions exported (i.e. exposed) by your DLL.

    Now we have our component that checks for presence of VM. All we need to do is call it from Java.

    Download the JNA library which is needed to invoke native code from Java. Create an Eclipse Project and add the DLL and JNA to classpath.

    Create following files -

    VmCheck.java

    package in.ksharma;
    
    import com.sun.jna.Library;
    
    public interface VmCheck extends Library {
        boolean IsInsideVMWare();
        boolean IsInsideVPC();
    }
    

    Test.java

    package in.ksharma;
    
    import com.sun.jna.Native;
    
    public class Test {
        public static void main(String[] args) {
            VmCheck lib = (VmCheck) Native.loadLibrary("VmDetect.dll", VmCheck.class);
            if(lib.IsInsideVMWare() || lib.IsInsideVPC())
                System.out.println("I'm trapped in the matrix.");
            else 
                System.out.println("I'm for real.");
        }
    }
    

    Here is a screenshot showing the final code running in a VM - enter image description here