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

78
我需要检测我的应用程序是否在虚拟化的操作系统实例中运行。
我发现了一篇关于这个主题的有用信息的文章。同一篇文章出现在多个地方,我不确定原始来源。VMware使用特定的无效x86指令返回有关自身的信息,而VirtualPC使用一个神奇的数字和一个IN指令的I/O端口。
这是可行的,但似乎在两种情况下都是未记录的行为。我想VMWare或VirtualPC的未来版本可能会更改机制。有更好的方法吗?这些产品是否有支持的机制?
类似地,有没有办法检测Xen或VirtualBox?
我不关心平台故意试图隐藏自己的情况。例如,蜜罐使用虚拟化,但有时会模糊恶意软件用于检测它的机制。我不介意我的应用程序在这些蜜罐中认为它没有被虚拟化,我只是在寻找“尽力而为”的解决方案。
应用程序大部分是Java,但我希望为这个特定的功能使用本地代码加JNI。Windows XP/Vista支持最重要,尽管引用文章中描述的机制是x86的通用功能,不依赖于任何特定的操作系统设施。

5
在虚拟化环境中运行时,没有可靠的方法来确定。我在此处提供了有关RedPill、NoPill、Scoopy Doo、Jerry、DMI、OUI等流行的“技术”的详细信息,包括源代码以及它们为什么无法使用:http://charette.no-ip.com:81/programming/2009-12-30_Virtualization/index.html。 - Stéphane
@Stéphane 除了少数情况下,假设虚拟机或虚拟机操作员没有故意欺骗程序,描述的技术很可能有效。可能会有误报,但我想您必须定义“可靠”。 - Schilcote
在Linux机器上(使用systemd),似乎下面的答案是正确的方法。它不需要root权限。 - zrajm
16个回答

78

你听说过蓝色药丸、红色药丸吗?它是一种用于检测您是否在虚拟机内运行的技术。该术语源于《黑客帝国》电影,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。


12
更正:当您在今天可用的某些虚拟机上运行时,在某些硬件位上它将返回1。 - Kirk Strauser
1
是的,它确实利用了虚拟机不是真实电脑的完全准确表示这一事实。如果是这样的话,就没有(好的)方法来检测您是否在运行虚拟机。 - sven
10
@erik:它利用虚拟化操作系统是计算机上的“第二个”操作系统这一事实。这意味着需要共享资源。在这段代码中,将检查IDTR(中断描述符表寄存器:请查看维基百科),如果不在通常位置,则说明我们是虚拟的。 - sven
2
仅做记录。在运行于OSX 10.5上的VMWare Fusion(版本2.0(116369))中的Windows XP Pro中,此代码会失败。 - epochwolf
25
请注意,RedPill和scoopy_doo技术在多核CPU上会出现误报。例如,在原生运行的四核系统上,它会75%的时间告诉你它正在运行在虚拟机中。搜索“NoPill”等内容以获取更多细节。 - Stéphane
显示剩余5条评论

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等,则可能是虚拟服务器。


@BlackMamba 这取决于您是否具有对 /dev/mem 的读取权限。 - Schwern

14

VMware提供了一个关于如何检测软件是否在虚拟机中运行的知识库文章。其中包含一些源代码。

Microsoft也有一篇关于检测是否安装了Hypervisor的页面“确定是否安装了 Hypervisor”。MS在其“服务器虚拟化验证测试”文档的“IsVM TEST”部分中详细说明了这个 hypervisor 的要求。

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

RHEL bugtracker上有一个关于在Xen内核下设置ECX寄存器的第31位(ISVM位)的bug报告

因此,不需要涉及各个厂商的具体情况,看起来可以使用CPUID检查来判断是否在虚拟环境中运行。


1
每个人都逐渐接受了“同唱一首歌”的理念。 - JdeBP

13

不行,这是不可能完全准确地检测出来的。一些虚拟化系统,比如QEMU,会模拟整个机器,包括硬件寄存器。反过来问:你想做什么?也许我们可以帮忙。


这是可能的。虽然您可以模拟虚拟机执行的每个指令,但应用程序仍然可以通过资源限制等方式发现真相。 - ZelluX
1
如果我们在新的强大硬件上模拟旧PC,我们可以模拟延迟和资源。 - Eugene Mala
那是模拟而不是虚拟化。最难隐藏的是时间信息,特别是如果客户端有网络访问并且可以使用外部时钟。 - Matthew Sharp

12

我认为,未来依赖像破损的SIDT虚拟化这样的技巧已经不再有帮助了,因为硬件正在堵塞所有怪异和混乱的x86架构留下的漏洞。最好的方法是向Vm提供者游说,为用户明确允许使用的情况下制定一种标准方法来检测是否在VM上运行。但是,如果我们假设我们明确允许检测到VM,则同样可以在其中放置可见标记,对吗? 我建议只需在您的VM上更新磁盘,并使用文件告诉您正在VM上运行 - 例如,在文件系统的根目录中放置一个小文本文件。 或者检查ETH0的MAC,并将其设置为特定的已知字符串。


2
如果您无法控制正在运行的虚拟机,那么您在段落末尾提供的解决方案将无法奏效。 =\ - Erik Forbes
4
不过,如果您无法控制虚拟机,那么所有的赌注都将打翻。这时它很可能会故意隐藏起来。因此,问题实际上是为什么、何时以及在哪种情况下您想要这样做。 - jakobengblom2

10
在Linux中,systemd提供了一种命令来检测系统是否在虚拟机上运行。
命令:
$ systemd-detect-virt 如果系统是虚拟化的,则输出虚拟化软件/技术的名称。 否则,输出none
例如,如果系统正在运行KVM,则输出:
$ systemd-detect-virt
kvm

您不需要以sudo身份运行它。


9

在虚拟机中,假设您对VM客户端具有控制权并且拥有dmidecode,则可以使用以下命令:

dmidecode -s bios-version

并且它将返回
VirtualBox

7
我想推荐一篇发表在Usenix HotOS '07上的论文,题为《兼容性不等于透明度:虚拟机检测的神话和现实》,该论文总结了几种技术来判断应用程序是否在虚拟化环境中运行。
例如,使用类似redpill的sidt指令(但是这个指令也可以通过动态转换来变得透明),或者比较cpuid的运行时间与其他非虚拟化指令。

6

6
这个C函数可以检测虚拟机的客户操作系统:
(在Windows上测试,使用Visual Studio编译)
#include <intrin.h>

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

这是一个从 CPU 获取一些信息的程序吗?请添加一些信息。 - Sorry IwontTell
我缺乏判断其他地方发布的代码的知识。以下是两个有趣的评论:澄清一下,这段代码使用cpuid指令来检测是否设置了特征位,该特征位指示代码正在运行在虚拟机监视器上。当然,并不要求实际的虚拟机监视器总是设置此位,特别是对于软件虚拟机监视器而言。我不会使用这个。在我的电脑上测试出现了误报(Windows 10,VS)。我已经在BIOS中启用了虚拟化支持,但没有在虚拟机中运行,所以可能是这个原因(?)。 - marsh-wiggle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接