我需要检测我的应用程序是否在虚拟化操作系统实例中运行。
我发现an article有关于该主题的一些有用信息。同一篇文章出现在多个地方,我不确定原始来源。 VMware实现特定的无效x86指令以返回有关其自身的信息,而VirtualPC使用幻数和I / O端口和IN指令。
这是可行的,但在两种情况下似乎都是无证件行为。我想VMWare或VirtualPC的未来版本可能会改变机制。有没有更好的办法?这两种产品都有受支持的机制吗?
同样,有没有办法检测Xen或VirtualBox?
我并不担心平台故意试图隐藏自己的情况。例如,蜜罐使用虚拟化,但有时会掩盖恶意软件用来检测它的机制。我并不关心我的应用程序会认为它在这些蜜罐中没有虚拟化,我只是在寻找“尽力而为”的解决方案。
应用程序主要是Java,但我希望在这个特定的功能中使用本机代码和JNI。 Windows XP / Vista支持是最重要的,尽管参考文章中描述的机制是x86的通用功能,并且不依赖于任何特定的OS工具。
答案 0 :(得分:66)
您是否听说过blue pill, red pill?。这是一种用于查看您是否在虚拟机内运行的技术。该术语的起源源自the matrix movie,其中Neo被提供蓝色或红色药丸(留在矩阵内=蓝色,或进入'真实'世界=红色)。
以下是一些代码,可以检测您是否在“矩阵”内运行:
(从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。
答案 1 :(得分: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&等等。那么它可能是一个虚拟服务器。
答案 2 :(得分:12)
VMware有一篇Mechanisms to determine if software is running in a VMware virtual machine知识库文章,其中包含一些源代码。
Microsoft在"Determining If Hypervisor Is Installed"上也有一个页面。 MS在其"Server Virtualization Validation Test"文档的“IsVM TEST”部分中阐述了虚拟机管理程序的这一要求
VMware和MS文档都提到使用CPUID指令检查虚拟机管理程序存在位(寄存器ECX的第31位)
RHEL bugtracker有一个"should set ISVM bit (ECX:31) for CPUID leaf 0x00000001"来设置Xen内核下的寄存器ECX的第31位。
因此,如果不进入供应商细节,您似乎可以使用CPUID检查来了解您是否正在虚拟运行。
答案 3 :(得分:11)
没有。完全准确无法检测到这一点。某些虚拟化系统(如QEMU)将整个机器模拟到硬件寄存器。让我们来看看:你想做什么?也许我们可以帮忙解决这个问题。
答案 4 :(得分:11)
我认为,继续前进,依靠像破坏的SIDT虚拟化这样的技巧并没有真正帮助,因为硬件插入了奇怪而凌乱的x86架构所留下的所有漏洞。最好的方法是游说Vm提供商以标准方式告诉您在虚拟机上 - 至少在用户明确允许的情况下。但是,如果我们假设我们明确允许检测VM,我们也可以将可见标记放在那里,对吗?我建议只更新VM上的磁盘,并提供一个文件,告诉您自己在VM上 - 例如,文件系统根目录中的一个小文本文件。或者检查ETH0的MAC,并将其设置为给定的已知字符串。
答案 5 :(得分:8)
在virtualbox上,假设您可以控制VM guest虚拟机并且有dmidecode,则可以使用此命令:
dmidecode -s bios-version
它会返回
VirtualBox
答案 6 :(得分:7)
我想推荐一篇发表在Usenix HotOS '07上的论文, Comptibility is Not Transparency:VMM Detection Myths and Realities ,它总结了几种技术来判断应用程序是否在虚拟化中运行环境。
例如,使用sidt指令作为redpill(但是这条指令也可以通过动态转换使其透明),或者将cpuid的运行时与其他非虚拟指令进行比较。
答案 7 :(得分:5)
在Linux下,您可以报告/ proc / cpuinfo。如果它在VMware中,它通常与裸机上的不同,但并非总是如此。 Virtuozzo展示了底层硬件的传递。
答案 8 :(得分:5)
在安装新手Ubuntu时,我发现了名为imvirt的软件包。请在http://micky.ibh.net/~liske/imvirt.html
查看答案 9 :(得分:5)
此C函数将检测VM Guest OS:
(在Windows上测试,使用Visual Studio编译)
#include <intrin.h>
bool isGuestOSVM()
{
unsigned int cpuInfo[4];
__cpuid((int*)cpuInfo,1);
return ((cpuInfo[2] >> 31) & 1) == 1;
}
答案 10 :(得分:4)
答案 11 :(得分:4)
检查工具virt-what。它使用前面提到的dmidecode来确定您是否在虚拟主机和类型上。
答案 12 :(得分:1)
我使用此C#
类来检测来宾操作系统是否在虚拟环境中运行(仅限Windows ):
<强> 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");
}
答案 13 :(得分:1)
我想出了一种通用方法,只需 1 行代码即可检测每种类型的 Windows 虚拟机。支持win7--10(xp尚未测试)。
最常用的方法是从 win32 搜索和匹配供应商值。但是如果有 1000 多个 VM 制造商呢?那么您将不得不编写一个代码来匹配 1000 多个 VM 签名。但它的时间浪费。即使过了一段时间,也会有新的其他虚拟机启动,您的脚本也会被浪费。
我为此工作了好几个月。我做了很多测试,我观察到: win32_portconnector 在 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://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://discord.com/invite/Hu5XPGMTuk
//https://github.com/Back-X/Universal-VM-Detector
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。
在多种环境下测试过,非常稳定。
答案 14 :(得分:0)
我尝试了我朋友建议的不同方法。在VMWARE上运行的虚拟机没有CPU TEMPERATURE属性。即他们不显示CPU的温度。我正在使用CPU温度计应用程序来检查CPU温度。
所以我编写了一个小型C程序来检测Senser的温度
#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.
}
答案 15 :(得分:0)
在linux上,systemd提供了一个用于检测系统是否作为虚拟机运行的命令。
命令:
import java.util.*;
public class SomaQuadrados {
public static void main(String[] args)
{
List<Integer> numeros = new ArrayList<>();
Scanner teclado = new Scanner(System.in);
while (teclado.hasNextInt()) {
int numero = teclado.nextInt();
numeros.add(numero);
}
System.out.println(somaQuadrados(numeros));
}
public static int somaQuadrados(List<Integer> numeros)
{
int size = numeros.size();
if (size == 0)
{
return 0;
}
int numero = numeros.get(0);
return numero * numero + somaQuadrados(numeros.subList(1, size));
}
}
如果系统已虚拟化,则输出虚拟化软件/技术的名称。
如果不是,则输出$ systemd-detect-virt
例如,如果系统正在运行KVM,则:
none
您无需以sudo身份运行它。