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

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

我在 一篇文章中找到了一些关于这个主题的有用信息。同一篇文章出现在多个地方,我不确定原始来源。VMware实现一个特定的无效 x86指令来返回关于它自己的信息,而 虚拟电脑使用一个带有 IN 指令的神奇数字和 I/O 端口。

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

类似地,是否有检测 XenVirtualBox的方法?

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

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

85066 次浏览

在 Linux 下,您可以在/proc/cpuinfo 上进行报告。如果是在 VMware 中,通常会出现不同于裸机的情况,但也不总是如此。Virtuozzo 显示了到底层硬件的传递。

尝试读取 SMBIOS结构,特别是包含 BIOS信息的结构。

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

没有。这是不可能完全准确地探测到的。有些虚拟化系统,如 QEMU,模拟整个机器到硬件寄存器。让我们反过来想想,你到底想干什么?也许我们能帮上忙。

你听说过 蓝色药丸,红色药丸?吗。这是一种用于查看是否在虚拟机内运行的技术。这个术语的起源源于 黑客帝国电影,在这里 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。

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

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

例如,使用 sidt 指令(但是这个指令也可以通过动态转换变得透明) ,或者将 cpuid 的运行时与其他非虚拟化指令进行比较。

在安装新的 Ubuntu 时,我发现了一个叫做 imvirt 的软件包

VMware 有一篇 确定软件是否在 VMware 虚拟机中运行的机制知识库文章,其中包含一些源代码。

微软也有一个关于 “确定是否安装了 Hypervisor”的页面。MS 在其 “服务器虚拟化验证测试”文档的“ IsVM TEST”部分阐明了虚拟机监控程序的这一要求

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

RHEL bug 跟踪器有一个用于 ”应该为 CPUID 叶0x00000001设置 ISVM 位(ECX: 31)在 Xen 内核下设置寄存器 ECX 位31的 bug 跟踪器。

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

在 Linux 下我使用了命令: 中密码(我在 CentOS 和 Ubuntu 上都有它)

来自一个男人:

Dmidecode 是转储 计算机的 DMI (有人说 SMBIOS)表 内容采用人类可读的格式。

所以我搜索了输出结果找到了可能的微软

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/

如果它返回微软,vmware 等,那么它可能是一个虚拟服务器。

检查工具 虚拟什么。它使用前面提到的 dmidecode 来确定您是否在虚拟主机上以及类型。

在 viralbox 上,假设您可以控制 VM 客户机,并且具有 dmidecode,那么您可以使用以下命令:

dmidecode -s bios-version

它会回来的

VirtualBox

这个 C 函数将检测 VM Guest OS:

(在 Windows 上测试,用 VisualStudio 编译)

#include <intrin.h>


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

我使用这个 C#类来检测 Guest OS 是否在虚拟环境(只有窗户)中运行:

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

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

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

(Windows 在真正的 CPU 上运行) 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

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

命令:
$ systemd-detect-virt

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

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

$ systemd-detect-virt
kvm

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

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

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

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

背景资料

我研究了好几个月,做了很多测试,我发现: Win32 _ portconnect 在 VM 上始终为 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://learn.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

给我看代码

基于这些测试,我编写了一个小程序,可以检测窗口虚拟机。

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

你可以选择 读取代码或者 编译的可执行文件

稳定

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

  • 探测虚拟机
  • 检测 Vmware
  • 检测 Windows 服务器
  • 检测 RDP
  • 检测病毒
  • 检测 < a href = “ https://app.any.run/asks/874cd411-5996-4e93-83d8-fdc72e95215a”rel = “ nofollow norefrer”> any.run 等等。