C++如何检测应用程序运行的虚拟机是一个焦点

k0pti3hp  于 2023-05-30  发布在  其他
关注(0)|答案(2)|浏览(112)

我有两个应用程序,每个程序都运行在各自独立的MS Windows 7虚拟机(VM)上。我不能为主机编写软件作为解决方案的一部分。我用C++编写Qt代码。
这可能是不可能的,但我希望能够检测VM窗口何时具有焦点(不是应用程序窗口,而是VM)。这两个应用程序都是全屏应用程序(至少在VM中是全屏),它们始终具有应用程序窗口焦点,但我希望能够在用户按键之前检测到用户的键盘输入将要转到哪个VM。
有什么想法吗

4ioopgfo

4ioopgfo1#

没有100%的方法来识别VM。但有一些“指标”:

  • 特定的“设备”、驱动程序、服务(vmouse.sys、vmci、VBoxService.exe等)
  • 特定的注册表项、Windows产品ID、MAC地址

所有这些方法都不可靠,但被广泛使用。
VMware提供了正式记录的VM检测方法is here, (with code snippets)。有一种方法是基于使用虚拟机管理程序端口0x5658(“VX”)和虚拟机管理程序魔术DWORD 0x564D5868,它代表“VMXh”

bool IsVMWare()
{
  bool res = true;

  __try
  {
    __asm
    {
      push   edx
      push   ecx
      push   ebx

      mov    eax, 'VMXh'
      mov    ebx, 0 
      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' // compare with target
      setz   [res] // set return value

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

  return res;
}

另一种方法是测试CPUID管理程序(HV)存在位和HV供应商的名称:

bool IsVM()
{
    int cpuInfo[4] = {};

    //
    // Upon execution, code should check bit 31 of register ECX
    // (the “hypervisor present bit”). If this bit is set, a hypervisor is present.
    // In a non-virtualized environment, the bit will be clear.
    //
    __cpuid(cpuInfo, 1);
    

    if (!(cpuInfo[2] & (1 << 31)))
        return false;
    
    //
    // A hypervisor is running on the machine. Query the vendor id.
    //
    const auto queryVendorIdMagic = 0x40000000;
    __cpuid(cpuInfo, queryVendorIdMagic);

    const int vendorIdLength = 13;
    using VendorIdStr = char[vendorIdLength];

    VendorIdStr hyperVendorId = {};
    
    memcpy(hyperVendorId + 0, &cpuInfo[1], 4);
    memcpy(hyperVendorId + 4, &cpuInfo[2], 4);
    memcpy(hyperVendorId + 8, &cpuInfo[3], 4);
    hyperVendorId[12] = '\0';

    static const VendorIdStr vendors[]{
    "KVMKVMKVM\0\0\0", // KVM 
    "Microsoft Hv",    // Microsoft Hyper-V or Windows Virtual PC */
    "VMwareVMware",    // VMware 
    "XenVMMXenVMM",    // Xen 
    "prl hyperv  ",    // Parallels
    "VBoxVBoxVBox"     // VirtualBox 
    };

    for (const auto& vendor : vendors)
    {
        if (!memcmp(vendor, hyperVendorId, vendorIdLength))
            return true;
    }

    return false;
}

实现的一些硬件检测方法依赖于VM如何模拟CPU行为的事实。例如,使用缓存指令,如 wbinvdinvd,但它们是特权的。
一些链接阅读更多:
这里有一篇有趣的文章about VM & Sandbox detection,里面有一些代码示例。
我发现了一个repository,其中一些方法是用C实现的。其中一些只能在Windows上使用,但也有一些跨平台的

zengzsys

zengzsys2#

这段代码应该可以完成这项工作

BOOL IsVMRunning()
{
#if _WIN64
    UINT64 time1 = __rdtsc();
    UINT64 time2 = __rdtsc();
    return ((time2 - time1) > 500);
#else
    unsigned int time1 = 0;
    unsigned int time2 = 0;
    __asm
    {
        RDTSC
        MOV time1, EAX
        RDTSC
        MOV time2, EAX
    }
    return ((time2 - time1) > 500);
#endif
}

相关问题