一直在用虚拟机学习linux,突然来了个这个问题


虚拟化分为完全虚拟化(full virtualization)和准虚拟化(para-virtualization)两种,完全虚拟化意思是,guest OS不需要进行任何定制,就可以在hypervisor中运行,例如KVM、VirtualBox;准虚拟化则表示guest OS必须进行定制,把一些硬体操作替换成对VMM的调用,例如XEN。

准虚拟化环境中,guest OS一定知道自己在虚拟机中,如果不知道就没法正常运行了。在x86引入硬体虚拟化之前,XEN一直是x86虚拟化的唯一方案。

而在完全虚拟化环境中,并没有100%可靠的办法,因为这种虚拟化的目的就是模拟真实机器,让guest OS感觉不到差别。

但是,也存在一些办法可以进行猜测。例如OS可以探测pci汇流排上的外设,如果发现某些外设的vendor是VMware、VirtualBox这类,那么很有可能是在虚拟机里面。此外还可以获取硬碟驱动器的product string。

在x86架构下,还可以使用cpuid(eax=1)辅助判断。Intel文档中说,ecx最高比特「not used, always returns 0」并没有规定edx最高位比特的含义,但是微软将这个空闲的bit利用了起来,HyperV环境可以用这个比特来判断。

上面这些方法都是虚拟机故意留下一些痕迹,让OS可以发现。如果虚拟机不想被发现,就只能借助外部时钟源进行timing attack。例如,有一种rootkit叫做Blue Pill(蓝色药丸),本身就是一个轻量级的hypervisor,处在硬体和操作系统之间,可以拦截操作系统的全部硬体交互。检测这类的恶意软体,常规方法显然是不行的。


有能让 Guest 完全区分不出来的虚拟机——即 Cycle-accurate Emulator,不过这个太慢了,正常软体不会做到这么极端


感谢网友 @sindorei 指正。看了下Windows确实能默认识别是否在虚拟机中:

放在这个位置展示,猜测是CPU虚拟化的时候给Guest系统传了什么识别参数进去。

这样的话其实只要系统自己做个识别,就可以识别正常虚拟机了。(虚拟机有意让你识别不出来肯定还是很容易的)

=====================原回答分割线=====================

如果你问的是目前的操作系统原生有没有这个功能,那大多应该是没有的。

但如果你问的是是否可以通过第三方软体的功能识别当前的系统是否是运行在虚拟机中的——方法有的是。要知道「虚拟机检测技术」在恶意软体对抗和破解对抗中是非常常用也是非常成熟的一项技术。

实现方法非常的多,具体的不说了,网上一搜一大把,还有开源代码供使用。咱就说几个不懂技术都能看得懂的方法,让你了解一下这东西可以做的多简单粗暴:

  • 检测虚拟机工具主流的虚拟机软体(如VMware)都会在你装好系统之后要求在虚拟机系统中安装一个虚拟机工具(如VMware Tools),用来实现很多快捷的功能(比如自动调整屏幕尺寸啊、虚拟机内外直接拖拽啊、虚拟机内外剪切板共享啊之类的)。然后,你完全可以暴力搜索当前系统的进程列表,看有没有这个工具的进程名——有,那就是在虚拟机里面了,简单不简单?粗暴不粗暴?

  • 检测MAC地址任何网卡,都有一个物理地址,叫做MAC地址。这个MAC地址是按照区段分配给各个网卡生产商的。而虚拟机软体的开发公司,某种意义上讲,其实也是网卡生产商——他们生产的是虚拟网卡。所以,比如VMware虚拟机的网卡,也是有专门的区段的。

  • 检测硬碟信息

    这个原理其实和上面的MAC地址类似,我就截个图你就明白了(类似的其实还有其他的一些其虚拟硬体,很多都能找到虚拟机开发商的痕迹)。

以上举的三个例子都是最简单粗暴的,更高阶的还有的是,比如对某些特权指令的检测、对IO通信埠的检测、对指令运行速度的检测等等,五花八门。

同时,也都有对应的反检测机制,你检测什么数值,我就把数值给你改的和物理机一样就完了。检测于反检测,识别与反识别。

RED PILL and BLUE PILL……


Kernel是不知道的,不过Ubuntu、Redhat这种发行版本,在安装的时候,会自己检测下是不是在虚拟机中(CPU、bios属性中都有一些值会标识,除非Hypervisor故意伪装)然后做一些设置以更好的适应虚拟环境(没深入研究过做些啥设置)


通常来说,子操作系统都是能知道是否在虚拟机中的。

为了便于子操作系统的运行,通常来说虚拟机都会主动通知子操作系统,设定一些标识,或者在子操作系统中安装一些对接软体,从而让子操作系统在这种较为复杂的环境下正常工作。但就算是这些标识被主动隐藏,作为子操作系统,通常来说也能以足够的置信度判断自己是否被虚拟化。看题目的意思,可能更倾向于这种,因为略有了解,就来说几句。

这个需求在软体安全行业中不算冷门,通常称为虚拟机检测,通常是指一个应用程序,判断自身是否运行在被虚拟化的系统中。虽然一个是被虚拟系统本身,一个是被虚拟系统中的程序,但技术基本上是共通的。这种需求有很多的用途,比如说防止一个有时限授权的软体,被存为虚拟机快照从而反复还原使用;防止网路游戏运行在虚拟机上从而实现一机多开;防止软体授权被绑定在虚拟机上从而可以在多个物理机上使用等等。

而实现虚拟机检测,可以从多方面下手,每种方法都各有利弊,综合起来结果,就能大概估算出是否在虚拟机中。从理论来说,完美模拟是不可能检测出来的,但实践中,只要让模拟成本足够高,就够了。

首先是其他答案提过的,检测硬体信息。

大部分普通虚拟机,硬体信息上都会有相关信息,比如说硬碟、网卡等设备名,通常都会带有VMwareRed Hat等提供商的名字,同理还有网卡MAC和一些硬体序列号等。

设备名中包含VMware字样

除了这些显而易见的文本,我们还可以核对一些其他的特征。虚拟机的很多硬体配置是非常奇怪的,比如说CPU信息是1核1线程的i7、内存大小是9GB、没有插入显示器等等,还有温度感测器一般也无法访问。这些情况是物理机上非常少见的,可以作为一个判断指标。

软体相关的检测

上面提到过,为了便于虚拟机的运行,通常会在虚拟系统中安装一些软体来协调工作。可以检测这些软体的痕迹来判断,比如说是否存在相关的进程、文件、注册表等。

VMware Tools相关的进程

系统环境相关

这些东西不好区分是软体还是硬体,算都有吧,就单列出来了。

有一些机器指令可以直接或者间接的获取到一些信息,常见的比如说cpuid指令,该指令用以查询cpu相关的信息,很多虚拟机会在里面记录是否为虚拟cpu,推测其他答主提到的任务管理器显示虚拟的信息来源于此。还有部分指令可以读取一些底层信息,比如说GDT和IDT表等,这些内容由于一些比较难以解决的问题,通常都没有完全虚拟,得到的结果跟物理机是有差异的。

还有一些操作,由于虚拟机和物理机的差异,运行速度会有较大的差异,可以通过性能分析获得一些信息。

网路相关

如果可以访问网路,有些事情会变得容易很多。我们可以方便的知道真实的时间,也可以向伺服器汇报程序的情况,伺服器可以就使用频率、访问地点等信息,分析出软体被恶意使用的可能性。


这些是比较容易想到的,还有一些比较生涩的不提也罢,这些是虚拟机中的应用程序都能做到的,稍微有点偏题。但如果是一个操作系统,能做的只多不少,所以也还好吧……


虚拟机底层可以把介面做处理,操作系统不会知道。

比如设置光速有限,存在时间有限,控制虚yu拟zhou机中信息总存量等方式,让操作系统及其中程序发现不了被虚拟的现实。


为了实际使用而开发的VMM一定会提供某些「后门」机制让guest识别出自己处于VM中,因为要给guest充分利用虚拟硬体本身的特性来加速嘛。

反过来说,如果不介意guest性能,只是为了论证这个问题而做实验,只要把VM的硬体规格降得足够老旧,一定有办法让guest识别不出来,以为自己是真机。


硅基生物版的缸中之脑吗?

大部分情况下是能知道的,因为现在的虚拟机没有完美模拟硬体的执行环境,可能是没必要。


除非虚拟机告诉它,你是虚拟机,否则不行。

不过啊……虚拟机往往都会告诉系统它是在虚拟机里的。


理论上不行,实践中可以

虚拟机这个东西有好几种实现方式,一个最朴素的实现就是模拟一台计算机的运行过程,用程序读取代码以后解释执行

执行这个模拟的不一定是软体,也可以是硬体(那就是真实的计算机了),也可以是人脑+纸+笔,我自己写玩具内核的时候,就经常对著汇编脑内运行,你说这个在人脑中执行的操作系统是否知道它自己处于虚拟机中呢?

目前的x86 CPU有通过VMX加速虚拟化的方案,而VMX指令集的文档是明确写明指令集层面是不向Guest暴露「是否处于虚拟机中」的信息的

但实践中可以的原因是,完全模拟一台计算机过于复杂了,很多虚拟机软体提供的虚拟硬体要么就是虚构的型号和虚构的硬体介面(为啥要装客户机增强工具),要么就是很古老、实际上已经没人用的硬体型号(功能简单方便软体模拟),以及缺少GPGPU这一类想模拟也根本不知道从哪下手的功能超复杂的硬体的模拟实现(但是真实的桌面计算机不会没有显卡)。结果就是只要用心找找常用虚拟机软体留下的特征,总还是能判断出来的。


当然可以,虚拟机和底层的hypervisor之间的主动交互远比你想像的多,大多是为了性能。linux已经把很多这类功能整合到kernel里了,你甚至都不用额外装驱动,Windows我相信应该也有类似功能。

即使不考虑这些,现在硬体的虚拟化也是不支持原生的嵌套的,你只要在虚拟机里开一下虚拟化模式看能不能成功就知道自己是不是虚拟机了。


能. 而且是host故意让guest知道的.

你也可以去看看virt-what的代码.


曾运行过一个软体,提示探测出在虚拟机中运行,自动结束了。所以虚拟机是有可能被识别出来的。也许有更牛的虚拟机让探测方法失效。


这个根据具体情况来决定,主要取决于两个方面,一个是Hypervisor,另外一个是Guest OS。

Hypervisor主要实现计算机的模拟,常见的Hypervisor包括VMware,Virtualbox,QEMU,Xen等。这些Hypervisor在模拟计算机的时候,经常会提供某些特定的介面让运行于Hypervisor内的虚拟机能够调用,获取当前运行的环境的相关信息。

Guest OS,以目前的两大主流操作系统Windows和Linux,由于现在云计算应用很普遍,所以这些操作系统经常也会针对虚拟机环境做一些具体的优化,所以操作系统其实是有知道自己是否运行在虚拟机中的需求的。

操作系统一方面可以通过之前提到的Hypervisor提供的一些特定介面来判定自己是否运行在虚拟机中,另一方面,其实有些设备是只有在虚拟机环境中才存在的,有时候操作系统可以根据自己看到的设备来判断自己是否运行在虚拟机环境。

所以,操作系统知道自己是否运行在虚拟机环境其实是个趋势,目前主流的操作系统大部分都能够知道自己是否运行在虚拟机环境。


这是个「协同进化」的问题。

有些虚拟机,可以模拟「真实」的CPU、IDE控制器、显卡等设备。我用Everest看了一下,没看出来这是个虚拟机。

假如,有一个程序,要检测这是不是一个虚拟机:运行某些指令,得到的与物理机结果不同。

然而,虚拟机也可以增加这条特殊的指令,得到更加精确的模拟结果。

好比兔子和猫这两种动物:猫为了不至于饿死,跑得最快的活下来;兔子为了不至于被猫吃掉,也是跑得最快的活下来。


应该能知道。

我头几天和我爸讨论,用收费软体的时候,可不可以先装个试用版,到期了删掉,然后再装个试用版,到期了再重装,就这样没完没了地装试用版,从而能够一直免费用这个软体?我爸说行,但有些软体,你装过一次之后,他会识别出你的电脑,然后就不给你装了。

我又问,那可不可以不停地开虚拟机,然后在虚拟机里装?我爸说有些软体在虚拟机里装不了。

所以我想既然软体在安装的时候都能检测出你用的是虚拟机了,系统应该也能吧。


可以。在虚拟机里面再安装虚拟机时 会有提示


小白亲自测试过,vmware workstation pro15环境允许deepin会直接告诉你「检测到虚拟机环境,建议使用xx模式」


根据软硬等价原理,如果虚拟机刻意这么做,一定可以骗过os。

但似乎没有虚拟机去费这劲做这些无聊的事情。


你问这个只是出于好奇,有些人问这个是为了对抗,比如那些反外挂系统开发者、逆向反外挂系统的外挂作者、恶意软体分析师、软体版权保护破解者等等。

嗯,偏题了,题主问的是操作系统,这些人问的是应用程序。

比如这篇:

e1knot:那些年病毒用过的损招——反虚拟机技术?

zhuanlan.zhihu.com图标

还有这个VBoxHardenedLoader,是几个小脚本+内核驱动+教程组合起来的大杂烩,可以帮你设定出一个不容易被检测出来的虚拟机:

https://github.com/hfiref0x/VBoxHardenedLoader?

github.com

不过,它实现的手段很歪,是直接在内核里挂钩子,而且这样只是为了修补VirtualBox的几个dll文件,而且为了进Ring0,还载入了另一个带漏洞的老版本VBox内核驱动(先让新版VBox驱动从内核里卸载,然后载入带漏洞的旧版,用完了再卸载旧版,把新版载入回去),用这个办法来绕过内核驱动强制签名(DSE)。

即便折腾到如此地步,我觉得离「完全无法被检测出来是虚拟机」应该还有相当的距离,只能说是hypervisor bit/主板/网卡/硬碟这些容易被直接拿来检测(应该说这些地方本来就很憨憨,无意隐藏自己是个虚拟机)的地方做了伪装而已。

另外,我记得这种绕过DSE的办法在新版Win10上会蓝屏;如果利用带漏洞的旧版VBox驱动直接关闭DSE(也就是这个作者的另一个项目DSEFix),那又会触发PatchGuard,还是蓝屏。

所以,结论就是要在Windows启动前就修补内核、把PatchGuard和DSE有关的代码干掉——这个作者以前也做过这种工具UPGDSED,原理简单粗暴——直接修改内核文件和引导器文件。他当初还夸下海口diss微软,结果Win10更新节奏太快、让他感觉吃不消了,就停更了……好在,要实现这个目的,还有更优雅(以bootkit的形式在启动时挂钩来进行修改,不需要修改文件)的替代品EfiGuard。


推荐阅读:
相关文章