74

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

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

这是可行的,但在这两种情况下似乎都是未记录的行为。我想 VMWare 或 VirtualPC 的未来版本可能会改变机制。有没有更好的办法?这两种产品是否有受支持的机制?

同样,有没有办法检测XenVirtualBox

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

该应用程序主要是 Java,尽管我希望为这个特定功能使用本机代码和 JNI。Windows XP/Vista 支持是最重要的,尽管参考文章中描述的机制是 x86 的通用特性并且不依赖于任何特定的操作系统工具。

4

16 回答 16

75

你听说过蓝色药丸,红色药丸吗?. 这是一种用于查看您是否在虚拟机中运行的技术。该术语的起源源于向Neo 提供蓝色或红色药丸的矩阵电影(留在矩阵内 = 蓝色,或进入“真实”世界 = 红色)。

以下是一些代码,可以检测您是否在“矩阵”内运行:(从该站点
借用的代码还包含有关手头主题的一些不错的信息):

 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。

于 2008-09-30T17:59:12.380 回答
24

在 Linux 下我使用了命令:dmidecode(我在 CentOS 和 Ubuntu 上都有)

来自男人:

dmidecode 是一种以人类可读格式转储计算机的 DMI(有人说是 SMBIOS)表内容的工具。

所以我搜索了输出,发现它可能是 Microsoft 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 等,那么它可能是一个虚拟服务器。

于 2010-11-28T22:36:45.587 回答
14

VMware 有一种机制来确定软件是否在 VMware 虚拟机知识库文章中运行,该文章有一些源代码。

微软还有一个关于“确定是否安装了管理程序”的页面。MS 在其“服务器虚拟化验证测试”文档的“ IsVM 测试”部分中详细说明了虚拟机管理程序的这一要求

VMware 和 MS 文档都提到使用 CPUID 指令来检查管理程序存在位(寄存器 ECX 的第 31 位)

RHEL bugtracker 有一个用于“应为 CPUID 叶 0x00000001 设置 ISVM 位 (ECX:31)”以设置 Xen 内核下寄存器 ECX 的第 31 位。

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

于 2010-08-16T18:32:49.970 回答
12

不,这是不可能完全准确地检测到的。一些虚拟化系统,比如QEMU,模拟整个机器到硬件寄存器。让我们扭转局面:你想做什么?也许我们可以提供帮助。

于 2008-09-30T17:52:44.750 回答
12

我认为继续前进,依靠像坏掉的 SIDT 虚拟化这样的技巧并没有真正的帮助,因为硬件填补了奇怪和混乱的 x86 架构留下的所有漏洞。最好的办法是游说 Vm 提供者以一种标准的方式告诉您您在 VM 上——至少在用户明确允许的情况下是这样。但是,如果我们假设我们明确允许检测到 VM,我们也可以在其中放置可见标记,对吗?我建议只用一个文件更新你的虚拟机上的磁盘,告诉你你在一个虚拟机上——例如,文件系统根目录中的一个小文本文件。或者检查 ETH0 的 MAC,并将其设置为给定的已知字符串。

于 2008-10-02T06:58:56.117 回答
8

在 virtualbox 上,假设您可以控制 VM 来宾并且您有 dmidecode,您可以使用以下命令:

dmidecode -s bios-version

它会回来

VirtualBox
于 2014-04-30T15:41:54.613 回答
7

我想推荐一篇发表在 Usenix HotOS '07 上的论文,Comptibility is Not Transparency: VMM Detection Myths and Realities,它总结了几种判断应用程序是否在虚拟化环境中运行的技术。

例如,使用 sidt 指令,就像 redpill 一样(但这条指令也可以通过动态翻译变得透明),或者将 cpuid 的运行时间与其他非虚拟化指令进行比较。

于 2009-05-28T13:21:14.977 回答
6

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

于 2010-01-14T23:34:09.757 回答
6

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

(在 Windows 上测试,使用 Visual Studio 编译)

#include <intrin.h>

    bool isGuestOSVM()
    {
        unsigned int cpuInfo[4];
        __cpuid((int*)cpuInfo,1);
        return ((cpuInfo[2] >> 31) & 1) == 1;
    }
于 2015-08-14T14:39:13.940 回答
6

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

命令:
$ systemd-detect-virt

如果系统是虚拟化的,那么它会输出虚拟化软件/技术的名称。如果不是,则输出none

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

$ systemd-detect-virt
kvm

您不需要将其作为 sudo 运行。

于 2019-03-06T04:16:14.230 回答
5

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

于 2008-09-30T17:45:18.123 回答
5

尝试读取SMBIOS结构,尤其是带有BIOS信息的结构。

在 Linux 中,您可以使用dmidecode实用程序来浏览信息。

于 2008-09-30T17:48:55.947 回答
4

检查工具virt-what。它使用前面提到的 dmidecode 来确定您是否在虚拟主机上和类型。

于 2012-08-09T08:44:38.257 回答
4

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

(在 VMWARE 中运行的 Windows) 在此处输入图像描述

(在真实 CPU 上运行的 Windows) 在此处输入图像描述

所以我编写了一个小 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 机器上输出 在此处输入图像描述

真实 CPU 上的输出 在此处输入图像描述

于 2016-10-12T09:18:10.897 回答
3

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

系统信息.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");
        }
于 2015-09-07T02:22:40.737 回答
2

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

为什么我们需要通用方式?

最常用的方法是从 win32 搜索和匹配供应商值。但是如果有 1000 多家虚拟机制造商呢?那么您将不得不编写一个代码来匹配 1000 多个 VM 签名。但它的时间浪费。即使过了一段时间,也会有新的其他虚拟机启动,你的脚本也会被浪费掉。

背景

我为此工作了好几个月。我做了很多测试,观察到: win32_portconnector在虚拟机上总是为空且为空。请查看完整报告

//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 VM 的小程序。

//@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 !");
        }
    }
}

您可以阅读代码或获得编译的可执行文件

稳定

它在许多环境中进行了测试,并且非常稳定。

  • 检测到 Visrtualbox
  • 检测 Vmware
  • 检测 Windows 服务器
  • 检测 RDP
  • 检测到 Virustotal
  • 检测any.run 等...
于 2021-03-13T17:12:22.070 回答