Как определить, запущено ли мое приложение на виртуальной машине?

Как я могу определить (.NET или Win32), работает ли мое приложение на виртуальной машине?

13 ответов

Решение

Согласно сообщению в блоге Virtual PC Guy" Обнаружение виртуальных машин Microsoft", вы можете использовать WMI для проверки производителя материнской платы. В PowerShell:

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

Это то, что я использую:

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 в качестве виртуальной машины. Спасибо Эрику Фанкенбушу за указание на это.

Изменить 2017-06-29: обновлен код, чтобы он также проверял значение HypervisorPresent имущество.

Изменить 2018-02-05: удалена проверка для HypervisorPresent свойство, так как это неверно. Это свойство может возвращать значение true, если выполняется на хосте O/S на сервере Hyper-V.

Вот пример одного из способов сделать это. Он работает только с Microsoft Virtual PC и VMWare, но это только начало: http://www.codeproject.com/KB/system/VmDetect.aspx

Эта функция C обнаружит гостевую ОС VM: (протестировано в Windows, скомпилировано с Visual Studio)

#include <intrin.h>

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

Джей Абузи показал решение в PowerShell. Вот то же самое, что и функция aC#:

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

Помните, что вы должны не просто проверять популярную модель виртуальной машины, название производителя из wmi, вы также должны проверять разницу между реальностью и виртуализацией.
У ВМ не так много функций.
1) проверьте, доступна ли информация о температуре процессора

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 sandbox.

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

Для тестов нижнего уровня я рекомендую взглянуть на ScoopyNG [1]. Это коллекция известных низкоуровневых, хорошо работающих методов обнаружения виртуальных машин, хотя и немного устаревших.

Если вы действительно хотите положиться на другие вещи, такие как установленные инструменты (VM* Additions), их гораздо проще "подделать".

Это [2] сообщение в блоге также имеет довольно хороший обзор, начиная с низкоуровневого ассемблера, проверки конкретных DLL, путей к файлам и ключей реестра для проверки.

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

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

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

Этот код 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");
}

Самый простой способ выяснить, работает ли мое приложение C# на виртуальной машине VMware или нет, это проверить MAC-адрес карты (-ей) NIC. Если это VMware VM, она всегда будет: 00:50:56:XX:YY:ZZ

Вы можете перечислить через NIC, как решено здесь.

Я хотел сделать это настраиваемым, поэтому преобразовал ответ @RobSiklos в запрос WMI. Теперь я могу поместить запрос в папку конфигурации и изменить его при необходимости.

      private static bool IsVirtual()
{
    using (var searcher = new System
        .Management
        .ManagementObjectSearcher(@"SELECT * from Win32_ComputerSystem 
                                    WHERE (Manufacturer LIKE '%microsoft corporation%' AND Model LIKE '%virtual%')
                                    OR Manufacturer LIKE '%vmware%'
                                    OR Model LIKE '%VirtualBox%'"))
    {
        using (System.Management.ManagementObjectCollection items = searcher.Get())
        {
            if (items.Count > 0)
            {
                return true;
            }
        }
    }

    return false;
}

Ссылка на WQL:

https://learn.microsoft.com/en-us/windows/win32/wmisdk/wql-sql-for-wmi

От Super User вот ответ: посмотрите на графический драйвер. Это код:

      Dim driver As New ManagementObjectSearcher("Select * from Win32_PnPSignedDriver")
Dim driver_info As ManagementObject
Dim name As String
For Each driver_info In driver.Get()
    caption = driver_info("DeviceName").ToString()
    If caption.Contains("Standard") and caption.Contains("VGA") Then
        ' it's virtual machine
        ' do anything you need
    End If
Next

Я тестировал 3 типа — VirtualBox, Wmware и Huper-V.

      foreach (var mo in "Select * from Win32_ComputerSystem")
{
    var model = (string)mo["Model"];

    if (model == "VirtualBox" ||
        model == "Virtual Machine" ||
        model.StartsWith("VMware"))
    {
        return true;
    }
}
return false;
Другие вопросы по тегам