如何检测程序运行在虚拟机中?

版权声明:所有博客文章除特殊声明外均为原创,允许转载,但要求注明出处。

最近在网络上看到有人提出一个有趣的问题:程序能否知道自己是在虚拟机中运行的?如果能,是怎么做到的?

之前并没有深入考虑过这个问题,不过我知道这确实是可能的。比如说,国内比较有知名度的深度操作系统在安装时就会检查自己所在的运行环境,如果发现是从虚拟机运行的,就会主动关闭一些比较消耗资源的动画与特效。

深度安装屏幕

除此之外,也听说过这样一种说法:对于某些来源不明、可能携带病毒或有流氓行为,但仍然有用处的软件,部分高级用户会在虚拟机里安装它们,以防止它们影响实际的系统。后来这些流氓软件的开发者也学乖了,如果发现自己是从虚拟机中运行的,就可以推断出系统用户可能属于那种警觉性比较高的人,也有可能通过一些技术手段去观测程序的行为,所以这些流氓软件在虚拟机中反而表现得比较“老实”。当然,这只是听说,我并没有实际验证过。

既然知道这是可行的,接下来的问题就是:如何办到?我们已经看到深度操作系统有检查虚拟机的功能,并且它也是开源的,我们不妨看看它是如何实现的。

一番查找之后,我在 deepin-installer-reborn 项目中发现了具体代码:

深度安装源码

这个方法非常简单,相信你即便不熟悉 C++ 或者 Qt 也很容易看明白:运行 cat /proc/cpuinfo,输出结果如果包含 hypervisor 字样,就说明程序是运行在虚拟机中。显然这是一个系统级别的虚拟文件,也就是说,Linux 已经帮助我们实现了这个功能。你可以去命令行自己运行一下试试看。因为输出内容很长,要防止看花眼,最好用期望的结果去过滤一下:

cat /proc/cpuinfo | grep hypervisor

以上是检测虚拟机最简单、不需要其他外部依赖的办法。当然,除此之外还有很多其他方法,总体说来,不外乎这么几种思路:

  • 使用系统内置支持,比如前述的方法
  • 检查硬件信息。这是因为虚拟机模拟出来的硬件通常都有明显标志,比如名字中包含 vmware/vbox/qemu/kvm 等等,基本上就可以断定是虚拟机;
  • 此外还有一种较为罕见的做法:故意制造特定错误,并观察系统的处理机制。关于该方法有一篇较早的文章 Detect if your program is running inside a Virtual Machine。但是这个路线过于底层、通用性差且有可能失效,在实践中应用很少。

如果你不喜欢前述方法的话,这里有一篇老外写的较为全面的文章,总结了判断虚拟机的 10 种不同方法。这些方法大多走的用硬件信息的路子,其中有些依赖于特定的系统命令,在实际使用中应该结合 Linux 发行版的具体情况来选择。如果你仔细看过上面的代码注释,应该会发现深度的开发者也考虑到了调用外部命令(dmidecode 以及 virt-what 都是该文章提到过的方法),但最终还是选择了第一种方式。当然,这个实现以后也可能会改变。

How to Check if Linux Server is Physical or Virtual