鱼知道吗?

(一)哲学家与鱼

“子非鱼”是《庄子》中一个非常有名的辩论,展示了庄子与惠施两种截然不同的世界观,出自《秋水》篇。原文如下:

“庄子与惠子游于濠梁之上。庄子曰:‘鯈鱼出游从容,是鱼之乐也。’惠子曰:‘子非鱼,安知鱼之乐?’庄子曰:‘子非我, 安知我不知鱼之乐?’惠子曰:‘我非子,固不知子矣;子固非鱼也,子之不知鱼之乐全矣!’庄子曰:‘请循其本。子曰‘汝安知鱼乐’云者,既已知吾知之而问我,我知之濠上也。’”

翻译也很简单:庄子和朋友惠施在濠水的一座桥梁上散步。庄子看着水里的鱼说:“鱼在水里悠然自得,这是鱼的快乐啊。”

惠子说:“你不是鱼,哪里知道鱼的快乐呢?”

庄子说:“你不是我,怎么知道我不知道鱼的快乐呢?”

惠子说:“我不是你,本来就不知道你;你本来就不是鱼,你不知道鱼儿的快乐,也是完全可以断定的。”

庄子说:“请回到我们开头的话题。你说:‘你哪里知道鱼的快乐’等等,就是已经知道了我知道鱼的快乐而问我,我是在濠水河边上知道的。”

作家王蒙却指出庄子不过是在诡辩,他说:

“我越看越感觉庄子是太诡辩了,我是非常喜欢庄子的,庄子的文字好啊,但是这种诡辩这种讹,北京话叫讹搅,第一个他循环论证,‘子非我,安知我不知鱼之乐’,惠子就说,我非子,安知我不知汝不知鱼之乐’是不是?这个两个人就一块辩论一下,辩论到2005年也辩论不完,这是第一点。”

“第二点呢,你们看全文的话,这个庄子更不讲道理,人家安知鱼之乐,这个‘安’的意思是为什么,你怎么会知道鱼之乐,为什么和怎么的意思,why和how是这个,但是庄子理解成了Where do you know the happiness of the fish?你问的是where,既然是where,就是你知道我已经知道鱼之乐了,我告诉你我就是在濠上知道的,利用一个‘安’字,因为这个安字既可以当how讲,也可以当why讲,也可以当where讲,是不是?这是讹的把戏。”

王蒙还感慨到:

“我就弄不懂了,为什么古往今来那么多人在这注释啊……怎么就没有人指出来庄子在这儿诡辩呢?这一点啊他在讹搅,没有人指出这个,类似的一些东西啊非常多。”

那么庄子是在“讹搅”吗?其实,如果真正把《庄子》读上一遍,就会知道他不是在诡辩。他在“子非我,安知我不知鱼之乐?”这一反问中,就已经指出了惠施“非鱼”就不知鱼之乐的逻辑错误之处。

如果惠施在这里懂了,他也就不会再有下一问了,所以庄子只能无奈再把自己的层次拉低一些,用名家的套路来制服同属名家的惠施罢了。

名家是什么套路呢?“白马非马”,在概念名词上下功夫,于是庄子就也玩了一把概念,不但把“哪里”与“怎么”混淆,而且更进一步:

你既然能问出“你哪里知道鱼的快乐”,那么首先你就要知道“我知道鱼的快乐”,然后才能问出“哪里知道”这个问题。如果你并不知道“我知道鱼的快乐”,那么也就不会问我怎么知道的,哪里知道的,这个问题也就不存在了。

这说明了什么呢?“不知道”也是一种“知道”。《庄子》中有过论述:能把自己病情说清楚的人,就不算是生了重病;自己都不知道自己生了什么病,那才是真正的重病。

为了更好地说明这个问题,我们来做一个问答实验:第一个问题,哪些东西是你知道的?第二个问题,哪些东西是你不知道的?第三个问题,哪些东西是你不知道自己不知道的?

第一个问题,我们很好回答;第二个问题,我们也能说出个一二三来;但第三个问题,就真的是没法回答了。一旦回答,就与这个问题本身相违背了。

所以“不知”,也是一种“知”;真正的“无知”,是你并不知道自己不知道。因此在科学界,提出问题远远比解答问题要重要,一个问题被提出来,哪怕没有答案,也已经是一种进步,一种“知”了。

(二)物理学家与鱼

物理学家加来道雄写过《一名物理学家的教育历程》,摘录如下。

记得那时我的父母不时带我去旧金山游览著名的日本茶园。我蹲在那里的一个小池边,为慢慢畅游在水底睡莲之中五彩斑斓的鲤鱼所陶醉。这是我最快乐的童年记忆之一。

在那静静的时刻,我充满了无限的遐想。我常常给自己提一些只有小孩才问的问题,比如水池中鲤鱼怎样观察它们周围的世界。我想,它们的世界一定奇妙无比!

鲤鱼们的一生就在这浅浅的水池中度过。它们相信它们的“宇宙”就由阴暗的池水和睡莲构成。它们大部分时间在池底漫游,因此它们只模糊地意识到在水面之上存在有另一个外部世界。我的世界的本质超过了它们的理解能力。我喜欢坐在距离鲤鱼仅仅几十厘米的地方,然而,我们之间却如距深渊。鲤鱼和我生活在两个截然不同的宇宙之中,从来不进入对方的世界,我们之间被水面这一薄薄的“栅栏”分隔开来。

我曾想:在水底的鱼群中可能有一些鲤鱼“科学家”。我想这个鲤鱼“科学家”会对那些提出在睡莲之外还存在有另外一个平行世界的鱼冷嘲热讽。他们认为,唯一真实存在的事物就是鱼儿们看得见摸得着的。水池就是一切。水池之外看不见的世界没有科学意义。

有一次,我遇到了一场暴雨。我注意到成千上万的小雨滴轰击在池水的表面。池水变得混乱,水中的睡莲在汹涌不息的水波冲刷下摇摆不定。在躲避风雨之时,我想弄清楚周围发生的一切将会以怎样的形式呈现在鲤鱼们的眼中。在它们看来,睡莲似乎是自己在运动,没有任何东西冲刷它们。因为就像我们看不见我们周围的空气和空间一样,鲤鱼们也看不见它们赖以生存的水,它们为睡莲自己能够运动而困惑不解。

我想,鲤鱼“科学家们”将会聪明地杜撰某种虚构的东西——它被称为“力”,来掩盖自己的无知。由于不能理解在看不见的水面上存在的水波,它们将得出这样一个结论:睡莲之所以能够不被触摸而运动,是因为有一种看不见的神秘力在对它起作用。它们可能给这种错觉起一个高深莫测的名称(如超距作用,或没有任何接触睡莲即会运动的能力)。

我曾想,如果在池水中抓出一个鲤鱼“科学家”,事情将会怎么样呢?放回池水之前,它可能随着我的查看而狂乱挣扎。那么别的鲤鱼又将怎样看待这件事呢?对于它们而言,这确实是一件可怖的事情。它们第一次意识到有一位鲤鱼“科学家”从它们的宇宙中消失了。就那么简简单单,没有留下任何踪迹。不管在它们的宇宙中怎么寻找,就是没有这条丢失的鲤鱼的踪影。然而,就那么几秒钟,当我把它放回池水之后,这位鲤鱼“科学家”便突然冒了出来。对于别的鲤鱼而言,这真是一个奇迹。

待神智镇定之后,这位鲤鱼“科学家”就会讲述一个真正令它们惊诧不已的传奇故事。它说:“突然之间,不知怎的我就被拉出了咱们的宇宙(池水),投进了一个冥冥世界,那里有令人目眩的强光和我从未见过的奇形怪状的物体。最奇怪的是那个抓住我的生物竟然一点也不像鱼。更使我震惊的是,无论如何也看不到它的鳍,但是没有鳍它还是能够运动。我感觉到熟悉的自然规律不再适合于这个冥冥世界。随后,我发现自己突然又被扔回了咱们的世界。”(当然,这个到宇宙之外一游的故事对于鲤鱼是怪诞的,大多数鱼都认为这完全是胡说八道。)

我常想,我们就像自鸣得意地在池中游动的鲤鱼。我们的一生就在我们自己的“池子”里度过,以为我们的宇宙只包含那些看得见摸得着的事物。就像鲤鱼一样。

(三)操作系统与虚拟机

目前虚拟机环境检测有两个“金标准”,分别是Al-khaserPafish。这两个开源项目几乎一网打尽了所有公开常见的VM检测技术。下面简要分析一下它们的技术原理。

3.1、硬件信息检测

首先大概说说操作系统是怎么知道这台计算机安了哪些设备的。计算机启动的时候,主板固件会给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地址等容易带有虚拟机特征的地方。

3.2、CPU信息检测

x86 CPU本身有一条指令叫CPUID,用于探测该CPU所支持的功能,例如是否支持SSE指令集等。有些功能虚拟机无法模拟,就会屏蔽掉相关功能的信息,这是第五个容易露馅的地方

早期虚拟化技术不完善的时候,虚拟机软件需要挪动一些重要数据结构的位置,例如中断表(IDT)等。著名的Red Pill程序就是靠读取这些结构的地址来判定虚拟环境。但是后来有了Intel VT-x等硬件虚拟化技术,以及KVM以后,这些检测方法就基本被淘汰了。

基于KVM的客机,如果将EAX寄存器置为0x40000000,并执行CPUID指令,会在EBX、ECX、EDX寄存器中读取到字符串“KVMKVMKVM”,这是第六个容易露馅的地方

3.3、驱动信息检测

在有Linux KVM之前,各虚拟机软件用的几乎都是半虚拟化(Paravirtualization),也就是必须对客机软件做一定修改才能在虚拟机中正常运行。例如VMWare虚拟机需要在客机中安装一些驱动程序,这些驱动的信息中都带有VMWare标识,这是第七个容易露馅的地方

KVM实现的是全虚拟化,不需要对客机做任何修改,所以不必担心这些问题。但是,按默认配置的QEMU虚拟机会带有很多VirtIO接口的设备,这些设备的驱动也会留下虚拟机的痕迹,需要当心。

3.4、计时检测

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那边做了改进。

(四)我们都是阴沟里的虫子

在科幻作家刘慈欣大名鼎鼎的作品《三体》里,女主角叶文洁有一句台词非常有震撼力,那就是:我们都是阴沟里的虫子,但是总还有人仰望星空

阴沟里的虫子自然没有鱼在水中的那种灵活性。

越来越多的人开始怀疑我们的宇宙是一个虚拟系统。

既然操作系统有可能检测出虚拟机,我们是不是可以比鱼知道得更多?

《银河系漫游指南》(The Hitchhiker's Guide to the Galaxy)是英国作家道格拉斯·亚当斯(Douglas Adams)的著名科幻小说系列的第一部。

这个系列一共5部,分别是:

1.银河系漫游指南 (The Hitchhiker's Guide to the Galaxy)

2.宇宙尽头的餐馆 (The Restaurant at the End of the Universe)

3.生命,宇宙及一切 (Life The Universe and Everything)

4.再见,谢谢所有的鱼 (So Long and thanks for all the Fish)

5.基本无害 (Mostly Harmless)

站务

全部专栏