如何检查我的Java程序是否在虚拟机中运行?

5
我有一款需要向客户授权的Java软件。我创建了一个许可模块,只允许该软件在激活的特定硬件上运行。
但我不希望客户在虚拟机中激活软件,因为这意味着单个许可证可以使用多份软件副本。
如何防止我的软件在虚拟机中安装?
注意:
1.我已经对此进行了研究并找到了解决方案。我在这里发布它,以便对其他开发人员有用。
2.它仅适用于VmWare和Virtual PC,而不适用于Parallels或VirtualBox。
3.我找不到一个纯Java解决方案。它依赖本地代码。
如果您知道更好的解决方案,请将其发布为答案。

技术上来说,这是一个有趣的问题,但为什么要让付费用户使用软件比那些盗版版本中已经去除了DRM的非付费用户更加困难呢?或者更重要的是,为什么要因此吓跑潜在的客户呢?由于某些破损的DRM认为他们没有许可证(请记住,每个程序都有漏洞,DRM也不例外),从而增加支持成本以帮助用户运行其许可程序。 - Thilo
@Thilo 我们的产品大小并不是很大。你在互联网上找不到我们软件的盗版副本。我们的目标不是设计一个100%防抄袭的方法,而是确保使用我们的软件不像复制粘贴那么简单。 - Kshitiz Sharma
一个简单的许可密钥解决方案不能达到相同的效果吗? - Thilo
@Thilo 如果他们使用虚拟机,那就不行了,现在每个人都在用。我们想做的就是让破解我们软件变得更加困难,直到客户不再费心去破解并支付许可费用,这也会为他们提供支持。据我所知,即使像微软和Adobe这样的大公司也是这么做的。 - Kshitiz Sharma
2
只有当他们使用虚拟机并自觉违反您的许可协议时,才不适用。另一方面,如果现在每个人都在使用虚拟机,那么强制他们不再这样做,他们会非常高兴。 - Thilo
1个回答

9

检查虚拟机是否存在的一些方法包括:

  1. 查找由VM Guest工具创建的进程、文件、注册表条目等VM工件的存在
  2. 使用虚拟化软件公开的非标准x86指令

如果想了解更多信息,可以在此处查看一个很好的演示文稿。

由于第二种方法最简单和直接,我们将使用它。

以下代码片段可用于检查代码是否在VMware虚拟机中运行 -

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

这是从Code Project上发布的一个项目中提取的代码部分。它旨在演示,因此不包括检查Microsoft Virtual PC存在的代码。您可以访问主站点获取Virtual PC代码和预编译演示。该站点还提供了一个DLL,但具有讽刺意味的是,函数并没有被导出,这破坏了DLL的目的,因为您无法在程序中调用它。因此,我不得不自己编译上述代码并创建DLL。 __try__catch是微软特定的C++扩展。您需要在Windows上使用Visual Studio进行编译,而不能使用gcc
下载并安装以下组件 -
  1. Visual Studio 2005(或更高版本)
  2. Microsoft Platform SDK 2003
创建一个新的DLL项目,并将上述代码粘贴到主CPP文件中。
将此添加到您的代码中以导出函数。如果没有这个,您的DLL将被编译,但是从外部无法调用函数。
extern "C" __declspec(dllexport) 
bool IsInsideVMWare()
{
  //Code
}

现在通过构建Visual Studio项目来编译DLL。如果您遇到像找不到windows.h或其他错误的问题,请参考以下stackoverflow问题 - 要检查函数是否已导出到DLL中,可以使用DLL Export Viewer查看DLL导出(即公开)的函数列表。
现在我们有了一个检查VM存在的组件。我们所需要做的就是从Java中调用它。
下载JNA库,该库需要从Java中调用本机代码。 创建一个Eclipse项目,并将DLLJNA添加到类路径中。
创建以下文件 -

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.");
    }
}

这是一张屏幕截图,显示最终代码在虚拟机上运行 - enter image description here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接