Operating system 我可以依靠TSC增量频率进行VM检测吗?

Operating system 我可以依靠TSC增量频率进行VM检测吗?,operating-system,virtualization,Operating System,Virtualization,我需要检测我的代码是否在虚拟机上运行,因为我知道我的一些用户会试图伪造代码,假装代码在真正的机器上运行,而实际上并没有。另外,依赖供应商或设备名称不是一个好主意,因为它可以通过更改VM设置或更换BIOS固件来覆盖。问题是,我可以依赖TSC频率吗 问题是,我可以依赖TSC频率吗 简短回答:不(可能) 用于以文字方式使用TSC频率(如“此CPU的TSC频率应为2345 MHz,但TSC频率测量为1234 MHz”);通常(对于其他人安装在未知计算机上的软件),无法知道CPU的TSC频率应该是多少;鉴

我需要检测我的代码是否在虚拟机上运行,因为我知道我的一些用户会试图伪造代码,假装代码在真正的机器上运行,而实际上并没有。另外,依赖供应商或设备名称不是一个好主意,因为它可以通过更改VM设置或更换BIOS固件来覆盖。问题是,我可以依赖TSC频率吗

问题是,我可以依赖TSC频率吗

简短回答:不(可能)

用于以文字方式使用TSC频率(如“此CPU的TSC频率应为2345 MHz,但TSC频率测量为1234 MHz”);通常(对于其他人安装在未知计算机上的软件),无法知道CPU的TSC频率应该是多少;鉴于“hyper visor”可以告诉您任何感觉
cpuid
(如果不以某种方式依赖于
cpuid
,就无法确定TSC频率应该是多少)

对于简单的HyperVisor,您可以使用TSC来检测导致“HyperVisor陷阱”的原因(因为这比在裸机上花费的时间要长得多)

但是,更复杂的HyperVisor可以通过虚拟化TSC来隐藏其时间消耗。这可能包括一种“橡皮筋”技术——例如,告诉客人“虚拟TSC频率”比实际TSC频率慢一点,然后在“虚拟TSC”超前太远时引入短暂暂停。或者,HyperVisor可以告诉客人“虚拟TSC频率”与真实TSC频率相同,通过减少“TSC偏移量”来隐藏“陷阱到HyperVisor”的额外时间消耗,然后随着时间的推移平滑TSC偏移量,以便客人不知道时间去了哪里(并且不知道时间是否被其他东西占用,比如系统管理模式或稍慢的RAM或..)

最重要的是,你最终得到的是一种竞争——当你找到检测虚拟机的新方法时,虚拟机开发人员就会找到改进虚拟化和防止检测的新方法

问题是,我可以依赖TSC频率吗

简短回答:不(可能)

用于以文字方式使用TSC频率(如“此CPU的TSC频率应为2345 MHz,但TSC频率测量为1234 MHz”);通常(用于其他人安装在未知计算机上的软件)无法知道CPU的TSC频率应该是多少;因为hyper visor可以通过告诉您它感觉到的任何东西。
cpuid
(如果不以某种方式依赖
cpuid
,也无法确定TSC频率应该是多少)

对于简单的HyperVisor,您可以使用TSC来检测导致“HyperVisor陷阱”的原因(因为这比在裸机上花费的时间要长得多)

然而,更复杂的hyper visor可以通过虚拟化TSC来隐藏其时间消耗。这可以包括一种“橡皮筋”技术-例如,告诉客人“虚拟TSC频率”比真实TSC频率稍慢,然后在“虚拟TSC”出现时引入短暂暂停或者,hyper visor可以告诉客人“虚拟TSC频率”与真实TSC频率相同,通过减少“TSC偏移量”来隐藏“陷阱到hyper visor”的额外时间消耗,然后随时间平滑TSC偏移量,以便客人不知道时间到了哪里(并且不知道时间是否被其他东西占用,比如系统管理模式或稍慢的RAM或..)


大多数情况下,你最终会遇到一种竞争——当你找到检测虚拟机的新方法时,虚拟机开发人员会找到改进虚拟化和防止检测的新方法。

你需要一起比较多个时间源。如果可以,你应该一起比较多个核心

基于TSC的检测最简单的解决方法是执行Brendan提到的橡皮绑定。但是,当涉及多个核心时,欺骗TSC更难。TSC偏移/乘数是每个核心的。如果VMM试图隐藏自身,每个VMEXIT都会导致TSC倾斜

现在,VMM可以尝试在任何单个核心退出时退出其他VCPU,以便它们可以同步TSC,但这非常昂贵(而且可能存在其他可检测的问题,因为很难同步VCPU重新进入)

总之,您至少需要两个内核:

  • 一个内核应该设置一个原子变量,调用RDTSC,然后调用一组带有强制vmexit的指令(例如CPUID),调用RDTSC,然后取消设置原子变量
  • 另一个内核应该监视该原子变量,然后调用rdtsc,然后再次监视它,最后在它未设置时调用rdtsc
  • 这需要一些校准。对于这样的事情,计时可能会非常挑剔。
    此外,您可以使用循环递增变量来充当rdtsc的代理,但这方面的校准可能更为挑剔(但值得一试,因为TSC可以普遍存在,包括在上面提到的第二个核心中).

    您需要一起比较多个时间源。如果可以,您应该一起比较多个核心

    基于TSC的检测最简单的解决方法是执行Brendan提到的橡皮绑定。但是,当涉及多个核心时,欺骗TSC更难。TSC偏移/乘数是每个核心的。如果VMM试图隐藏自身,每个VMEXIT都会导致TSC倾斜

    现在,VMM可以尝试在任何单个核心退出时退出其他VCPU,以便它们可以同步TSC,但这非常昂贵(而且可能存在其他可检测的问题,因为很难同步VCPU重新进入)

    总之,您至少需要两个内核:

  • 一个内核应该设置一个原子变量,调用RDTSC,然后调用一组指令