目前虚拟机环境检测有两个“金标准”,分别是Al-khaser和Pafish。这两个开源项目几乎一网打尽了所有公开常见的VM检测技术。下面简要分析一下它们的技术原理。
一、硬件信息检测
首先大概说说操作系统是怎么知道这台计算机安了哪些设备的。计算机启动的时候,主板固件会给OS传两个信息表,分别是ACPI和SMBIOS。ACPI表有很多部分,其中硬件信息主要集中在DSDT和SSDT这两部分。
ACPI表的每个部分开头都有一个OEM ID和OEM Table ID,这是第一个容易露馅的地方,例如QEMU默认将OEM ID写为BOCHS,将OEM Table ID写为BXPC + 部分名称,如DSDT部分就写成“BXPCDSDT”。
虚拟机的ACPI表中往往会存在一些现实中不存在的硬件,用于主客机间通讯,这是第二个容易露馅的地方,例如QEMU的DSDT表中会有DBUG和FWCF这两个硬件。
计算机中大部分设备的信息并不写在ACPI和SMBIOS表中。像显卡、声卡、网卡、USB这些都属于PCI设备,与PCI控制器相连。PCI控制器本身提供一个接口,可以列出所有检测到的PCI设备。每个PCI设备有四个用来亮明身份的代号,分别是Vendor ID, Device ID, Subsystem ID, Class ID。一般来说,OS检测到PCI设备时,会首先根据Vendor ID和Device ID搜索驱动;如果搜不到驱动,则会根据Class ID查找是否有这一类设备的通用驱动。
虚拟机模拟出的PCI设备,其身份代号往往采用特定数字,这是第三个容易露馅的地方,例如QEMU模拟出的VirtIO设备,其Vendor ID多为0x1AF4。
相比于ACPI,SMBIOS对系统的正常运行没有那么重要。但是Windows的“系统信息”工具显示的内容,多半都来自SMBIOS表,这是第四个容易露馅的地方,例如目前主流的虚拟机固件是OVMF,那么虚拟机里面“系统信息”就会显示出OVMF的信息。
有些恶意软件会通过检测系统是否有风扇和热区域(Thermal Zone)来判断是否处于虚拟环境。目前所有版本的Windows,都是从SMBIOS表中读取风扇信息,从ACPI表中读取Thermal Zone信息。但是正常的商业软件一般不使用此方法判定,因为很多正常的笔记本电脑也没有在SMBIOS表中写入风扇信息。
此外还有硬盘产品名、序列号、声卡ID、网卡MAC地址等容易带有虚拟机特征的地方。
二、CPU信息检测
x86 CPU本身有一条指令叫CPUID,用于探测该CPU所支持的功能,例如是否支持SSE指令集等。有些功能虚拟机无法模拟,就会屏蔽掉相关功能的信息,这是第五个容易露馅的地方。
早期虚拟化技术不完善的时候,虚拟机软件需要挪动一些重要数据结构的位置,例如中断表(IDT)等。著名的Red Pill程序就是靠读取这些结构的地址来判定虚拟环境。但是后来有了Intel VT-x等硬件虚拟化技术,以及KVM以后,这些检测方法就基本被淘汰了。
基于KVM的客机,如果将EAX寄存器置为0x40000000,并执行CPUID指令,会在EBX、ECX、EDX寄存器中读取到字符串“KVMKVMKVM”,这是第六个容易露馅的地方。
三、驱动信息检测
在有Linux KVM之前,各虚拟机软件用的几乎都是半虚拟化(Paravirtualization),也就是必须对客机软件做一定修改才能在虚拟机中正常运行。例如VMWare虚拟机需要在客机中安装一些驱动程序,这些驱动的信息中都带有VMWare标识,这是第七个容易露馅的地方。
KVM实现的是全虚拟化,不需要对客机做任何修改,所以不必担心这些问题。但是,按默认配置的QEMU虚拟机会带有很多VirtIO接口的设备,这些设备的驱动也会留下虚拟机的痕迹,需要当心。
四、计时检测
x86 CPU中有一个精度极高的计时器,称为TSC计时器,可以精确到CPU时钟周期数。那么可以执行一段CPU指令,并将消耗的时间与正常CPU上消耗的时间进行对比,如果明显高于正常值,就可判定处于虚拟机环境。
目前最常用的方法是,在两次读取TSC计时器之间,执行一次CPUID指令。前文说到,虚拟机软件一般会特殊处理CPUID指令,屏蔽掉一些无法模拟的功能的信息,执行这些操作所需的时间远多于正常CPU上执行一次CPUID所需的时间,这是第八个容易露馅的地方。
目前没有简单的办法可以骗过计时检测,所有已知方案都需要用特制的Linux内核和特制的QEMU软件配合。
但是近几年来,虚拟机环境检测已经没那么重要了。这是因为微软在Windows 10上大力推广Hyper-V技术,有相当数量的用户自己都不知道自己处于虚拟机环境。例如,只要在Windows 10 Home的Windows Defender中开启Memory Integrity或Core Isolation功能,就等同于开启Hyper-V,并让Windows运行在虚拟机环境下。
于是有很多网游反作弊系统,只要检测到开启了Hyper-V,就放弃检测虚拟机环境。于是在Linux界就有了一种神奇的操作,先用KVM开Windows虚拟机,然后在Windows中开启Hyper-V,这样就能愉快地玩各种3A巨作了。
当然这种操作需要CPU和Hypervisor支持Nested Virtualization,然而Windows的Hyper-V长期以来不支持AMD的Nesting,会在启动时卡死。直到2020年6月,微软才宣布Windows 10 Insider的Hyper-V开始支持嵌套虚拟化。最近国外Reddit上有人报告使用5.11.6版本的Linux内核(无需打补丁),配合4.2版本的QEMU,可以在AMD系统上正常启动Windows 10 20H2并开启Hyper-V,可能是Linux KVM那边做了改进。
既然这么多人看我就再写一写怎么绕开这些虚拟机检测方法。我日常电脑装的是Linux,平时用Linux KVM + QEMU方案跑Windows虚拟机。QEMU是开源的虚拟机Hypervisor,命令行参数非常灵活,有另一个开源项目libvirt专门帮助配置QEMU的参数。下面的内容都是基于KVM + QEMU + libvirt。我从简单的操作写起,比较难隐藏的东西放到后面。
1)CPU信息:打开libvirt的XML配置,找到<cpu>段落,将mode设为host-passthrough,然后段落里面添加一行
<feature policy="disable" name="hypervisor"/>
找到<os>段落,里面添加一行
<smbios mode="host"/>
2)KVM Hypervisor信息:XML配置中找到<features>段落,里面添加几行
<hyperv> <vendor_id state="on" value="random"/> </hyperv> <kvm> <hidden state="on"/> </kvm>
3)硬盘产品名、序列号:将Disk bus设为SCSI,Serial随便填写,添加一个SCSI Controller,Model填为saslsi1068,然后在XML配置中找到<disk>段落,在里面添加几行
<vendor>Samsung</vendor> <product>20GB Harddisk</product>
此处Vendor和Product可随便填写
4)网卡:NIC Device Model选rtl8139,然后用这个网站随机生成一个MAC地址填进去。
5)QEMU硬编码的ID信息:修改这些ID有两种方法,一种是下载QEMU源代码,修改硬编码ID后重新编译;另一种是直接用radare2等二进制修改工具,在QEMU可执行文件上打补丁。下面列出应当隐藏的硬编码ID对应的代码位置。(QEMU源代码见github)
ACPI OEM ID:见hw/acpi/aml-build.c中的build_header函数
ACPI DSDT中的FWCF设备:见hw/i386/acpi-build.c中的build_dsdt函数
ACPI DSDT中的DBUG设备:见hw/i386/acpi-build.c中的build_dbg_aml函数
常规PCI设备ID:见hw/pci/pci.c中的pci_set_default_subsystem_id函数
VGA设备ID:见hw/display/vga-pci.c中的vga_pci_class_init函数
声卡ID:见hw/audio/hda-codec-common.h中所有含有QEMU_HDA_ID_*宏的数据结构
VirtIO Serial设备ID:见hw/virtio/virtio-serial-pci.c中的virtio_serial_pci_class_init函数
6)风扇和热区域:利用QEMU的-acpitable参数,伪造一个ACPI SSDT表,里面填入一个Thermal Zone的信息;再利用QEMU的-smbios参数,伪造一个SMBIOS Entry Type 27,里面填入一个风扇的信息。
ACPI标准第11.7节提供了ACPI Thermal Zone的例子
SMBIOS标准第7.28节提供了SMBIOS Entry Type 27的格式说明
7)计时检测:这个绕过很麻烦,需要重新编译Linux内核,主要原理是每当遇到CPUID这种需要Hypervisor专门处理的指令时,都把TSC计时器的当前值减掉一定量,这样就抵消掉处理这些指令花掉的时间。
详见Reddit上相关讨论:
https://www.reddit.com/r/VFIO/comments/g4pqkq/rdtsc_detection_workarounds/
https://www.reddit.com/r/VFIO/comments/i071qx/spoof_and_make_your_vm_undetectable_no_more/
https://www.reddit.com/r/VFIO/comments/i1xbue/here_is_my_take_on_rdtsc_offsetting/
我从网络安全的角度作答。
“如何防止操作系统或软件知道自己处于虚拟机中?”
答案很简单:不使用虚拟机!
想象这样一种情境:我想从网上下载某个免费软件,但我被杀毒软件警告,该免费软件包含病毒。由于我非常需要这个免费软件,遂决定冒险一试。为防止病毒对主机造成伤害,我利用 Oracle VM 创建了一个虚拟机,希望在虚拟机中测试这个免费软件。
请注意:在虚拟机中测试软件无法100%保证主机安全。
原因是有些恶意软件具备从虚拟机中逃逸的能力,即“反虚拟机技术(anti-virtual machine techniques)”。
唯一安全的办法是使用另一台物理隔离的计算机进行测试。该计算机不联网,不保存任何个人信息或重要文件,不做任何其他用途,只用于测试。
另外,不要依赖系统还原,那样做依然存在感染风险。
根据软硬等价原理,如果虚拟机刻意这么做,一定可以骗过os。
但似乎没有虚拟机去费这劲做这些无聊的事情。
一大早起来真是笑死我了。
由于老头环空前的热潮,以及B站特有的UP主靠制作视频吸引流量转直播的模式,导致很多有人气但完全没有魂系列经验的主播在播这款游戏。比如某幻、瓶子。
(就是一开始制作视频是主业,直播是兼职,甚至是乐趣兴趣,到直播为主,制作视频反倒成了兼职。这种现象在游戏区特别明显。)
这就很有节目效果了,我看几个有名气的主播,都是重复被虐,平均活不过5分钟。真正是在哪里跌倒就从哪里跌倒。
很多在我们这些老玩家看来常识性的东西,对于他们来说完全不存在的。
盾反这种就不提了(其实我也不会),连二人转、回合制、推图都不懂。在大型地牢里不想打小怪,一个劲往前跑,结果变成开火车;当着怪物的面喝药=白喝;开宝箱被怪物背刺;以为学了法术就是法爷了,结果被几只鸟打得抱头鼠窜。
然后另一边,那些原本有魂系列经验的主播,就吃了刻板印象的亏。觉得自己有技术有实力,也不练级就顺着主线硬钢。就比如一上来的野外精英太阳骑士,要么你死要么我亡,绕路是不可能绕路的。
太阳骑士都还好,毕竟王老菊都能杀。
但没有等级,没有血量,没有伤害,硬钢噩兆。
真当噩兆快慢刀是假的,自己打几次就能盾反了?而且老头环这次砍了盾反在BOSS战中的作用,要反三次(二次)才能触发处决。
结果被虐3000遍,又不好意思去练级,尬在那了。
老头环是不是玩家的盛宴我还不知道(买了游戏,昨天也预下载了,结果今天起来发现那个盘满了……正在重新下载,下载完了又发现,我的电脑只有8G内存……),但肯定是不少主播的灾难、观众的盛宴。
当然,我也知道有些主播直播受罪是搞节目效果,但我也是真看到有主播被气到下播了。
另外一点,老头环这次其实是以探索为主要玩法。
B站UP主老戴今天专门做了一期视频讲解,想要玩好、玩轻松,就是尽可能的探索地图,拿物品、刷等级。而不是走到哪杀到哪,打不过硬去打。
就比如第一个剧情BOSS前,大地图上有的是小型地牢,野外精英,要把图清完了再去打噩兆,真跟打弟弟一样。(收回我的话,40级30血20耐20敏+3打刀7瓶奶,打了7次才过。前三次就是纯背板,后三次有点贪,经常血瓶白喝,最后一次基本掌握出手时机,就硬耗过去了。)
其实魂系列游戏特别吃角色强度(等级、装备),一些小怪你一刀砍死和一刀残血,完全就是两种难度。打BOSS,你挨一下就要喝药,和挨两下才需要喝药也是两倍的差距。
不过按照这么个玩法,的确没有什么节目效果。
讲真,还真就是看那些新手主播无能狂怒最有节目效果。
至于游戏本体,如今我也的确是玩上了,总体上来说符合我的期待。
作为一个中年人,我其实是在看了老头环试玩视频后才接触魂系列的。
原因有2,一是手残反映慢,玩这种游戏非常苦手;二是,我其实不太喜欢魂系列那种压抑的黑暗风格。
但老头环作为开放世界,虽然依旧以压抑阴郁为主,但也有光明广阔的场景。比如一开始做完新手指引推门而出的那一刻。
至于在难度与操作方面,远程技能的实用化,召唤物的存在,以及跳砍与伪盾反的出现,真的能够解决很多问题。
只是看你愿不愿意当一个“卑鄙的褪色者”。
远程技能包括法术与射击。我玩的武士,初始给的长弓非常给力。尤其记得推一座城堡图的时候,一开始不清楚套路,进入城堡被满地的炸药桶与两个放火球的法师直接秒了。复活后掏出长弓,一剑封喉,解决掉法师无伤过了。
还有初期的一个地牢,一个场景墙上爬着的与左右墙角蹲着的类似地精的怪物,近战5-6刀才能砍死。
第一次去直接围殴致死。
第二次,用弓箭一只只引过来,很轻松就过了。
至于近战武器,我是非常推荐初期见完老婆就能开箱子拿到的君王大剑。
这把武器虽然攻速低,成长性也低,但在初期真的非常实用。
尤其是在跳劈方面。
这一作跳劈虽然强但也看武器,比如武士上来给的打刀就属于跳劈对空,跳起来横着劈一刀,有时候都打不到站着的怪。而大剑则是竖着往地上砸,范围极大。
我举一个例子,就是我开地图第一次遇到红灵。就是等对方打完一套跳劈就完了。
我的战斗策略就是,遇事不决,举盾防御,然后跳劈。
至于BOSS战,依旧有难度,也许跳劈和法术都没啥作用,依靠的依旧是精准的闪躲后普攻(排除盾反)。
但我觉得这算是魂系列的乐趣之一。
如果随便什么BOSS战都能逃课,那也就没意思了。