【问题标题】:How to detect if my application is running in a virtual machine?如何检测我的应用程序是否在虚拟机中运行?
【发布时间】:2010-10-04 15:28:20
【问题描述】:

如果我的应用程序在虚拟机中运行,我如何检测(.NET 或 Win32)?

【问题讨论】:

  • 前几天我运行了一个应用程序,它无法在虚拟机中运行......它说它不能。我想知道它是怎么知道的。
  • 有许多东西在 VM 中不起作用:MS SQL Server 的某些部分、用于设备模拟器的 C# 和 gasp Virtual PC/Server。能够在程序和脚本中对此进行规划是很有价值的。
  • ...因此,如果您对某些环境(即虚拟机)中不起作用的东西有依赖关系,那么您应该查询该依赖关系以查看它在当前环境中是否有效。或者我错过了你的意思?

标签: .net winapi virtualization


【解决方案1】:

这是我用的:

using (var searcher = new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem"))
{
  using (var items = searcher.Get())
  {
    foreach (var item in items)
    {
      string manufacturer = item["Manufacturer"].ToString().ToLower();
      if ((manufacturer == "microsoft corporation" && item["Model"].ToString().ToUpperInvariant().Contains("VIRTUAL"))
          || manufacturer.Contains("vmware")
          || item["Model"].ToString() == "VirtualBox")
      {
        return true;
      }
    }
  }
}
return false;

编辑 2014-12-02:更新了代码,使其不再将 Microsoft Surface Pro 检测为 VM。感谢 Erik Funkenbusch 指出这一点。

编辑 2017-06-29:更新了代码,以便它还检查 HypervisorPresent 属性的值。

编辑 2018-02-05:删除了对 HypervisorPresent 属性的检查,因为它不正确。如果在 hyper-V 服务器上的主机 O/S 上运行,此属性可能返回 true。

【讨论】:

  • 一些快速测试看起来可以将测试表达式简化(对于“简化”的某些定义)为item["Model"].ToString().ToLower().Contains("virtual")
  • 您可以将“项目”转换为 IEnumerable<ManagementBaseObjects>,如下所示:var managementItems = items.OfType<ManagementBaseObject>();IEnumerable 扩展方法一起使用。
  • 我认为这段代码会将 Microsoft 计算机硬件检测为 VM,例如 Surface Pro。
  • 此代码不会检测在 Parallels Desktop、Xen 和 KVM 下运行的虚拟机
  • 您可以通过运行命令"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" setextradata "VM_NAME" "VBoxInternal/Devices/pcbios/0/Config/DmiSystemProduct" "Latitude E5400" 在Virtualbox 中轻松伪造模型。并且在此代码不会检测到之后。
【解决方案2】:

根据Virtual PC Guy的博文“Detecting Microsoft virtual machines”,可以使用WMI查看主板厂商。在 PowerShell 中:

 (gwmi Win32_BaseBoard).Manufacturer -eq "Microsoft Corporation"

【讨论】:

  • 呃,非 MS 虚拟机呢?
  • 此外,正如评论者@ErikFunkenbusch 在我对这个问题的回答中提到的那样,此检查将错误地将 MS Surface Pro 识别为 VM。
  • 公平地说,对于 MS Virtual Machines,Surface 各种产品是在发布此答案之后发布的。
  • 所以答案不是关于公平或不公平,而是关于是否有帮助。该答案在发布时无疑很有用,但现在不再有用了,RobSiklos(更新)答案应标记为正确答案。声望点应该被视为一种乐于助人的动力,而不是成为声望百万富翁的最终目标;)
【解决方案3】:

此 C 函数将检测 VM 来宾操作系统: (在 Windows 上测试,使用 Visual Studio 编译)

#include <intrin.h>

    bool isGuestOSVM()
    {
        unsigned int cpuInfo[4];
        __cpuid((int*)cpuInfo,1);
        return ((cpuInfo[2] >> 31) & 1) == 1;
    }

【讨论】:

  • 澄清一下,这段代码使用cpuid 指令来检测是否设置了指示代码在管理程序上运行的功能位。当然,实际的管理程序并不要求总是设置这个位,尤其是对于软件管理程序。
  • 我不会用这个。在我的 PC 上测试了误报(Windows 10、VS)。我在 BIOS 中打开了虚拟化支持,但没有在 VM 中运行,所以可能是这样(?)。
【解决方案4】:

Jay Abuzi 在 powershell 中展示了解决方案。这里和c#函数一样:

   /// <summary>
    /// Detect if this OS runs in a virtual machine
    /// 
    /// http://blogs.msdn.com/b/virtual_pc_guy/archive/2005/10/27/484479.aspx
    /// 
    /// Microsoft themselves say you can see that by looking at the motherboard via wmi
    /// </summary>
    /// <returns>false</returns> if it runs on a fysical machine
    public bool DetectVirtualMachine()
    {
        bool result = false;
      const  string  MICROSOFTCORPORATION ="microsoft corporation";
        try
        {
            ManagementObjectSearcher searcher =
                new ManagementObjectSearcher("root\\CIMV2","SELECT * FROM Win32_BaseBoard");

            foreach (ManagementObject queryObj in searcher.Get())
            {
               result =  queryObj["Manufacturer"].ToString().ToLower() == MICROSOFTCORPORATION.ToLower();
            }
            return result;
        }
        catch (ManagementException ex)
        {
            return result;
        }
    }

【讨论】:

  • 遗憾的是,这种技术和类似技术在我运行 VMWare ThinApp 进行测试的 W7 系统中不起作用。 queryObj.Properties 在两种环境中是相同的。
  • @JesseChisholm - 不仅如此,这还会错误地报告 Microsoft 非虚拟机硬件是虚拟机,例如 Surface Pro。如果您的 ThinApp 正在虚拟化 WMI 数据,我建议您设置错误。
  • @ErikFunkenbusch - 虚拟化的全部意义在于代码不需要知道或关心它是实时的还是虚拟的。所以每个VM制造商都非常努力地让它无法知道。到目前为止,我发现 my 应用程序知道的唯一方法是让 VM 执行在命令行参数中传递,告诉我我正在运行虚拟。叹息。
【解决方案5】:

对于较低级别的测试,我建议查看 ScoopyNG [1]。它是已知的低级、运行良好的 vm 检测方法的集合,尽管有些过时。

如果你真的想依赖其他东西,比如安装的工具(VM* Additions),这些更容易“伪造”。

这篇 [2] 博客文章也有一个很好的概述,从低级 asm 内容到检查特定 DLL、文件路径和注册表项以检查。

[1]http://trapkit.de/research/vmm/scoopyng/index.html

[2]http://securitykitten.github.io/vm-checking-and-detecting/

【讨论】:

    【解决方案6】:

    我发现确定我的 C# 应用程序是否在 vmware VM 上运行的最简单方法是检查 NIC 卡的 MAC 地址。如果是 VMware VM,它总是:00:50:56:XX:YY:ZZ

    您可以通过网卡as resolved here.枚举

    【讨论】:

    • -1:当然,VMware 可以随时随意更改其 MAC 地址格式,无需提前告诉您
    • 根据standards.ieee.org VMWare 使用:00:05:69、00:0C:29、00:1C:14 以及 00:50:56 作为 MAC 地址的组织部分。正如@John_Saunders 所说,他们可以随时在列表中添加一个新号码。
    【解决方案7】:
    public static bool isVirtualMachine()
    {
        const string MICROSOFTCORPORATION = "microsoft corporation";
        const string VMWARE = "vmware"; 
    
        foreach (var item in new ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
        {
            string manufacturer = item["Manufacturer"].ToString().ToLower();
            // Check the Manufacturer (eg: vmware, inc)
            if (manufacturer.Contains(MICROSOFTCORPORATION) || manufacturer.Contains(VMWARE))  
            {
                return true;
            }
    
            // Also, check the model (eg: VMware Virtual Platform)
            if (item["Model"] != null)
            {
                string model = item["Model"].ToString().ToLower();
                if (model.Contains(MICROSOFTCORPORATION) || model.Contains(VMWARE)) 
                {
                    return true;
                }
            }
        }
        return false;
    }
    

    【讨论】:

    • 遗憾的是,这种技术和类似技术在我运行 VMWare ThinApp 进行测试的 W7 系统中不起作用。 queryObj.Properties 在两种环境中是相同的。
    【解决方案8】:

    此 C++ 代码将检测 Vmware 产品,例如 express、esx、fusion 或工作站

    // VMWareDetector.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "windows.h"
    #include <conio.h>
    void CheckVM(void); 
    int main()
    {
        CheckVM(); 
        _getch(); 
        return 0;
    }
    
    void CheckVM(void)
    {
        unsigned int    a, b;
    
        __try {
            __asm {
    
                // save register values on the stack
                push eax
                push ebx
                push ecx
                push edx
    
                // perform fingerprint
                mov eax, 'VMXh' // VMware magic value (0x564D5868)
                mov ecx, 0Ah // special version cmd (0x0a)
                mov dx, 'VX' // special VMware I/O port (0x5658)
    
                in eax, dx // special I/O cmd
    
                mov a, ebx // data 
                mov b, ecx // data (eax gets also modified
                           // but will not be evaluated)
    
                           // restore register values from the stack
                           pop edx
                           pop ecx
                           pop ebx
                           pop eax
            }
        }
        __except (EXCEPTION_EXECUTE_HANDLER) {}
        printf("\n[+] Debug : [ a=%x ; b=%d ]\n\n", a, b);
        if (a == 'VMXh') { // is the value equal to the VMware magic value?
            printf("Result  : VMware detected\nVersion : ");
            if (b == 1)
                printf("Express\n\n");
            else if (b == 2)
                printf("ESX\n\n");
            else if (b == 3)
                printf("GSX\n\n");
            else if (b == 4)
                printf("Workstation\n\n");
            else
                printf("unknown version\n\n");
        }
        else
            printf("Result  : Not Detected\n\n");
    }
    

    【讨论】:

    • 你也可以使用pushadpopad来代替手动推送和弹出所有寄存器
    【解决方案9】:

    请记住,您不应该只检查 流行的 VM 型号,wmi 中的制造商名称,还应该检查现实和虚拟化之间的差异。
    虚拟机没有太多功能。
    1) check-if-cpu-temperature-information-is-available

    wmic /namespace:\\root\WMI path MSAcpi_ThermalZoneTemperature get CurrentTemperature
    //On Real PC
    //CurrentTemperature
    //3147
    
    //On VM
    //Node - Admin
    //Error:
    //Description not supported
    

    在 vmware、virtualbox、windows server、app.any.run 沙箱上测试。

    2) Win32_PortConnector

    Get-WmiObject Win32_PortConnector
    //On Vm it is null
    
    //On real pc it looks something like that
    Tag                         : Port Connector 0
    ConnectorType               : {23, 3}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 2
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多