代码之家  ›  专栏  ›  技术社区  ›  DGentry

从应用程序检测虚拟化操作系统?

  •  62
  • DGentry  · 技术社区  · 16 年前

    我需要检测我的应用程序是否在虚拟化操作系统实例中运行。

    我找到了 an article 提供一些关于该主题的有用信息。同一篇文章出现在多个地方,我不确定原始来源。 VMware 实现特定的无效x86指令以返回有关其自身的信息,而 VirtualPC 使用带IN指令的幻数和I/O端口。

    类似地,有没有一种方法可以检测到 Xen VirtualBox ?

    我不关心平台故意隐藏自己的情况。例如,蜜罐使用虚拟化,但有时会掩盖恶意软件用来检测它的机制。我不在乎我的应用程序会认为它在这些蜜罐中没有虚拟化,我只是在寻找一个“尽力而为”的解决方案。

    14 回复  |  直到 3 年前
        1
  •  75
  •   Bergi    9 年前

    你听说了吗 blue pill, red pill? . 这是一种用于查看您是否在虚拟机中运行的技术。这个词起源于 the matrix movie

    以下代码将检测您是否在“矩阵”中运行:
    (代码借用自 this site 其中还包含一些关于当前主题的好信息):

     int swallow_redpill () {
       unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3";
       *((unsigned*)&rpill[3]) = (unsigned)m;
       ((void(*)())&rpill)();
       return (m[5]>0xd0) ? 1 : 0;
     } 
    

    在虚拟机内运行时,函数将返回1,否则返回0。

        2
  •  24
  •   Michael Ben-Nes Niyas Nazar    13 年前

    解码 (我在CentOS和Ubuntu上都有)

    男人说:

    dmidecode是一种用于转储 计算机的DMI(有人说是SMBIOS)表

    所以我搜索了输出,发现它可能是微软的Hyper-V

    Handle 0x0001, DMI type 1, 25 bytes
    System Information
        Manufacturer: Microsoft Corporation
        Product Name: Virtual Machine
        Version: 5.0
        Serial Number: some-strings
        UUID: some-strings
        Wake-up Type: Power Switch
    
    
    Handle 0x0002, DMI type 2, 8 bytes
    Base Board Information
        Manufacturer: Microsoft Corporation
        Product Name: Virtual Machine
        Version: 5.0
        Serial Number: some-strings
    

    另一种方法是搜索eth0的MAC地址与哪个制造商相关: http://www.coffer.com/mac_find/

    如果它返回Microsoft、vmware&等那么它可能是一个虚拟服务器。

        3
  •  14
  •   David    14 年前

    VMware有一个 Mechanisms to determine if software is running in a VMware virtual machine 有一些源代码的知识库文章。

    微软也有一个关于 "Determining If Hypervisor Is Installed" . MS在其手册的“IsVM测试”部分中详细说明了虚拟机监控程序的这一要求 "Server Virtualization Validation Test"

    VMware和MS文档都提到使用CPUID指令检查虚拟机监控程序的当前位(寄存器ECX的第31位)

    RHEL bugtracker有一个 "should set ISVM bit (ECX:31) for CPUID leaf 0x00000001" 在Xen内核下设置寄存器ECX的第31位。

    因此,在不涉及供应商详细信息的情况下,您似乎可以使用CPUID检查来了解您是否在虚拟运行。

        4
  •  12
  •   Kirk Strauser    16 年前

    QEMU ,模拟整个机器,直至硬件寄存器。让我们扭转这个局面:你想做什么?也许我们能帮上忙。

        5
  •  12
  •   jakobengblom2    16 年前

    我认为,在未来,依靠像破碎的SIDT虚拟化这样的技巧并不能真正起到帮助作用,因为硬件填补了奇怪而混乱的x86体系结构留下的所有漏洞。最好的办法是游说虚拟机提供商提供一种标准的方式来判断您是否在虚拟机上——至少在用户明确允许的情况下是这样。但是如果我们假设显式地允许检测VM,那么我们也可以在其中放置可见的标记,对吗?我建议用一个文件来更新虚拟机上的磁盘,告诉您在虚拟机上——例如,文件系统根目录中的一个小文本文件。或者检查ETH0的MAC,并将其设置为给定的已知字符串。

        6
  •  8
  •   icasimpan    10 年前

    dmidecode -s bios-version
    

    它会回来的

    VirtualBox
    
        7
  •  7
  •   ZelluX    15 年前

    我想推荐一篇发表在Usenix HotOS'07上的论文, 兼容性不是透明性:VMM检测神话与现实 ,它总结了几种判断应用程序是否在虚拟化环境中运行的技术。

        8
  •  6
  •   Pavlo Svirin    14 年前

    在安装newes Ubuntu时,我发现了一个名为imvirt的包。请看一看 http://micky.ibh.net/~liske/imvirt.html

        9
  •  6
  •   user2242746    9 年前

    此C函数将检测VM来宾操作系统:

    #include <intrin.h>
    
        bool isGuestOSVM()
        {
            unsigned int cpuInfo[4];
            __cpuid((int*)cpuInfo,1);
            return ((cpuInfo[2] >> 31) & 1) == 1;
        }
    
        10
  •  6
  •   AVX-42    3 年前

    在linux上,systemd提供了一个命令,用于检测系统是否作为虚拟机运行。

    命令:
    $ systemd-detect-virt

    如果系统是虚拟化的,则会输出虚拟化软件/技术的名称。 如果没有,则输出 none

    例如,如果系统正在运行KVM,则:

    $ systemd-detect-virt
    kvm
    

    你不需要像sudo那样运行它。

        11
  •  5
  •   warren    16 年前

    在Linux下,您可以在/proc/cpuinfo上报告。如果是在VMware中,它的表现通常与在裸机上不同,但并不总是如此。Virtuozzo展示了对底层硬件的传递。

        12
  •  5
  •   Jonas Engström Jenrik    16 年前

    试着通过阅读 SMBIOS BIOS 信息

    dmidecode 用于浏览信息的实用程序。

        13
  •  4
  •   Rickard von Essen    12 年前

    virt-what . 它使用前面提到的dmidecode来确定您是否在虚拟化主机上以及类型。

        14
  •  4
  •   Mohit Dabas    8 年前

    我尝试了朋友建议的另一种方法。在VMWARE上运行的虚拟机没有CPU温度属性。i、 它们不显示CPU的温度。我正在使用CPU温度计应用程序检查CPU温度。

    (在VMWARE中运行的Windows) enter image description here

    (在真正的CPU上运行的Windows) enter image description here

    所以我编写了一个小的C程序来检测温度传感器

    #include "stdafx.h"
    
    #define _WIN32_DCOM
    #include <iostream>
    using namespace std;
    #include <comdef.h>
    #include <Wbemidl.h>
    
    #pragma comment(lib, "wbemuuid.lib")
    
    int main(int argc, char **argv)
    {
        HRESULT hres;
    
        // Step 1: --------------------------------------------------
        // Initialize COM. ------------------------------------------
    
        hres = CoInitializeEx(0, COINIT_MULTITHREADED);
        if (FAILED(hres))
        {
            cout << "Failed to initialize COM library. Error code = 0x"
                << hex << hres << endl;
            return 1;                  // Program has failed.
        }
    
        // Step 2: --------------------------------------------------
        // Set general COM security levels --------------------------
    
        hres = CoInitializeSecurity(
            NULL,
            -1,                          // COM authentication
            NULL,                        // Authentication services
            NULL,                        // Reserved
            RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
            RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
            NULL,                        // Authentication info
            EOAC_NONE,                   // Additional capabilities 
            NULL                         // Reserved
            );
    
    
        if (FAILED(hres))
        {
            cout << "Failed to initialize security. Error code = 0x"
                << hex << hres << endl;
            CoUninitialize();
            return 1;                    // Program has failed.
        }
    
        // Step 3: ---------------------------------------------------
        // Obtain the initial locator to WMI -------------------------
    
        IWbemLocator *pLoc = NULL;
    
        hres = CoCreateInstance(
            CLSID_WbemLocator,
            0,
            CLSCTX_INPROC_SERVER,
            IID_IWbemLocator, (LPVOID *)&pLoc);
    
        if (FAILED(hres))
        {
            cout << "Failed to create IWbemLocator object."
                << " Err code = 0x"
                << hex << hres << endl;
            CoUninitialize();
            return 1;                 // Program has failed.
        }
    
        // Step 4: -----------------------------------------------------
        // Connect to WMI through the IWbemLocator::ConnectServer method
    
        IWbemServices *pSvc = NULL;
    
        // Connect to the root\cimv2 namespace with
        // the current user and obtain pointer pSvc
        // to make IWbemServices calls.
        hres = pLoc->ConnectServer(
            _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
            NULL,                    // User name. NULL = current user
            NULL,                    // User password. NULL = current
            0,                       // Locale. NULL indicates current
            NULL,                    // Security flags.
            0,                       // Authority (for example, Kerberos)
            0,                       // Context object 
            &pSvc                    // pointer to IWbemServices proxy
            );
    
        if (FAILED(hres))
        {
            cout << "Could not connect. Error code = 0x"
                << hex << hres << endl;
            pLoc->Release();
            CoUninitialize();
            return 1;                // Program has failed.
        }
    
        cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
    
    
        // Step 5: --------------------------------------------------
        // Set security levels on the proxy -------------------------
    
        hres = CoSetProxyBlanket(
            pSvc,                        // Indicates the proxy to set
            RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
            RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
            NULL,                        // Server principal name 
            RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
            RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
            NULL,                        // client identity
            EOAC_NONE                    // proxy capabilities 
            );
    
        if (FAILED(hres))
        {
            cout << "Could not set proxy blanket. Error code = 0x"
                << hex << hres << endl;
            pSvc->Release();
            pLoc->Release();
            CoUninitialize();
            return 1;               // Program has failed.
        }
    
        // Step 6: --------------------------------------------------
        // Use the IWbemServices pointer to make requests of WMI ----
    
        // For example, get the name of the operating system
        IEnumWbemClassObject* pEnumerator = NULL;
        hres = pSvc->ExecQuery(
            bstr_t("WQL"),
            bstr_t(L"SELECT * FROM Win32_TemperatureProbe"),
            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
            NULL,
            &pEnumerator);
    
        if (FAILED(hres))
        {
            cout << "Query for operating system name failed."
                << " Error code = 0x"
                << hex << hres << endl;
            pSvc->Release();
            pLoc->Release();
            CoUninitialize();
            return 1;               // Program has failed.
        }
    
        // Step 7: -------------------------------------------------
        // Get the data from the query in step 6 -------------------
    
        IWbemClassObject *pclsObj = NULL;
        ULONG uReturn = 0;
    
        while (pEnumerator)
        {
            HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
                &pclsObj, &uReturn);
    
            if (0 == uReturn)
            {
                break;
            }
    
            VARIANT vtProp;
    
            // Get the value of the Name property
            hr = pclsObj->Get(L"SystemName", 0, &vtProp, 0, 0);
            wcout << " OS Name : " << vtProp.bstrVal << endl;
            VariantClear(&vtProp);
            VARIANT vtProp1;
            VariantInit(&vtProp1);
            pclsObj->Get(L"Caption", 0, &vtProp1, 0, 0);
            wcout << "Caption: " << vtProp1.bstrVal << endl;
            VariantClear(&vtProp1);
    
            pclsObj->Release();
        }
    
        // Cleanup
        // ========
    
        pSvc->Release();
        pLoc->Release();
        pEnumerator->Release();
        CoUninitialize();
    
        return 0;   // Program successfully completed.
    
    }
    

    Vmware计算机上的输出 enter image description here

    在真实Cpu上的输出 enter image description here

        15
  •  3
  •   Pedro Lobito    9 年前

    我用这个 C# 类来检测来宾操作系统是否在虚拟环境中运行( 仅限窗口 ):

    sysInfo.cs

    using System;
    using System.Management;
    using System.Text.RegularExpressions;
    
    namespace ConsoleApplication1
    {
        public class sysInfo
        {
                public static Boolean isVM()
                {
                    bool foundMatch = false;
                    ManagementObjectSearcher search1 = new ManagementObjectSearcher("select * from Win32_BIOS");
                    var enu = search1.Get().GetEnumerator();
                    if (!enu.MoveNext()) throw new Exception("Unexpected WMI query failure");
                    string biosVersion = enu.Current["version"].ToString();
                    string biosSerialNumber = enu.Current["SerialNumber"].ToString();
    
                    try
                    {
                        foundMatch = Regex.IsMatch(biosVersion + " " + biosSerialNumber, "VMware|VIRTUAL|A M I|Xen", RegexOptions.IgnoreCase);
                    }
                    catch (ArgumentException ex)
                    {
                        // Syntax error in the regular expression
                    }
    
                    ManagementObjectSearcher search2 = new ManagementObjectSearcher("select * from Win32_ComputerSystem");
                    var enu2 = search2.Get().GetEnumerator();
                    if (!enu2.MoveNext()) throw new Exception("Unexpected WMI query failure");
                    string manufacturer = enu2.Current["manufacturer"].ToString();
                    string model = enu2.Current["model"].ToString();
    
                    try
                    {
                        foundMatch = Regex.IsMatch(manufacturer + " " + model, "Microsoft|VMWare|Virtual", RegexOptions.IgnoreCase);
                    }
                    catch (ArgumentException ex)
                    {
                        // Syntax error in the regular expression
                    }
    
                        return foundMatch;
                }
            }
    
    }
    

    用法:

            if (sysInfo.isVM()) { 
                Console.WriteLine("VM FOUND");
            }
    
        16
  •  1
  •   Gray Programmerz    3 年前

    我想出了一种通用的方法,只需一行代码就可以检测每种类型的windows虚拟机。它支持win7--10(xp尚未测试)。

    为什么我们需要通用的方法?

    出身背景

    我为此工作了好几个月。我做了很多测试,观察到: win32_端口连接器 在虚拟机上始终为null和空。请参阅完整报告

    //asked at: https://stackoverflow.com/q/64846900/14919621
    what win32_portconnector is used for ? This question have 3 parts.
    1) What is the use case of win32_portconnector ?    //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-portconnector
    2) Can I get state of ports using it like Mouse cable, charger, HDMI cables etc ?
    3) Why VM have null results on this query : Get-WmiObject Win32_PortConnector ?
    

    PS C:\Users\Administrator> Get-WmiObject Win32_PortConnector
    

    PS C:\Users\Administrator> Get-WmiObject Win32_PortConnector
    Tag                         : Port Connector 0
    ConnectorType               : {23, 3}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 2
    
    Tag                         : Port Connector 1
    ConnectorType               : {21, 2}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 9
    
    Tag                         : Port Connector 2
    ConnectorType               : {64}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 16
    
    Tag                         : Port Connector 3
    ConnectorType               : {22, 3}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 28
    
    Tag                         : Port Connector 4
    ConnectorType               : {54}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 17
    
    Tag                         : Port Connector 5
    ConnectorType               : {38}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 30
    
    Tag                         : Port Connector 6
    ConnectorType               : {39}
    SerialNumber                :
    ExternalReferenceDesignator :
    PortType                    : 31
    

    给我看代码

    基于这些测试,我制作了一个可以检测windows虚拟机的小程序。

    //@graysuit
    //https://graysuit.github.io
    //https://github.com/Back-X/anti-vm
    using System;
    using System.Windows.Forms;
    
    public class Universal_VM_Detector
    {
        static void Main()
        {
            if((new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_PortConnector")).Get().Count == 0)
            {
                MessageBox.Show("VM detected !");
            }
            else
            {
                MessageBox.Show("VM NOT detected !");
            }
        }
    }
    

    read code 或者 compiled executable .

    稳定性

    它在许多环境中经过测试,非常稳定。

    • 虚拟仪器
    • 检测Vmware
    • 检测Windows服务器
    • 检测RDP
    • 检测病毒总数
    • 察觉 any.run