上篇《Anti-VM之CPUID指令》 ,通过CPUID指令获取CPU信息,来判断环境是否是虚拟的。这篇从时间角度判断环境是否是虚拟的。
Intel和AMD为处理器增加了虚拟化扩展(Intel VT-x , AMD AMD-V ),使得操作系统不做修改就可虚拟化。以Intel VT-x为例,VMM(Virtual Machine Monitor)运行在root模式,虚拟机运行在非root模式,在非root模式下,一些指令如RDMSR,WRMSR,CPUID需要在VMM才能执行,即会触发 VM exit , 从而带来时间上的开销,通过统计时间,就可以判断当前环境是否是虚拟的。
The Time Stamp Counter (TSC) is a 64-bit register present on all x86 processors since the Pentium. It counts the number of cycles since reset. The instruction RDTSC returns the TSC in EDX:EAX. In x86-64 mode, RDTSC also clears the higher 32 bits of RAX and RDX. Its opcode is 0F 31.
TSC是一个64位寄存器,统计CPU时钟周期,可以用来高精度统计时间。RDTSC指令读取TSC值。
RDTSC和CPUID都是非特权(unprivileged)指令,可以在用户态调用。
检测代码 rdtsc.c :
#include <stdio.h> #include <unistd.h> #define TRUE 1 #define FALSE 0 static inline unsigned long long rdtsc_diff () { unsigned long long ret, ret2; unsigned eax, edx; __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)) ; ret = ((unsigned long long )eax) | (((unsigned long long )edx) << 32 ); __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)) ; ret2 = ((unsigned long long )eax) | (((unsigned long long )edx) << 32 ); printf ("(%llu - %llu) " , ret, ret2); return ret2 - ret; } static inline unsigned long long rdtsc_diff_vmexit () { unsigned long long ret, ret2; unsigned eax, edx; __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)) ; ret = ((unsigned long long )eax) | (((unsigned long long )edx) << 32 ); __asm__ volatile ("cpuid" : : "a" (0x00 )) ; __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)) ; ret2 = ((unsigned long long )eax) | (((unsigned long long )edx) << 32 ); printf ("(%llu - %llu) " , ret, ret2); return ret2 - ret; } int cpu_rdtsc () { int i; unsigned long long avg = 0 , sub; for (i = 0 ; i < 10 ; i++) { sub = rdtsc_diff(); avg = avg + sub; printf ("rdtsc difference: %d\n" , sub); usleep(500 ); } avg = avg / 10 ; printf ("difference average is: %d\n" , avg); return (avg < 1000 && avg > 0 ) ? FALSE : TRUE; } int cpu_rdtsc_force_vmexit () { int i; unsigned long long avg = 0 , sub; for (i = 0 ; i < 10 ; i++) { sub = rdtsc_diff_vmexit(); avg = avg + sub; printf ("rdtsc_force_vmexit difference: %d\n" , sub); usleep(500 ); } avg = avg / 10 ; printf ("difference average is: %d\n" , avg); return (avg < 1000 && avg > 0 ) ? FALSE : TRUE; } int main () { printf ("cpu_rdtsc: %d\n" , cpu_rdtsc()); printf ("cpu_rdtsc_force_vmexit: %d\n" , cpu_rdtsc_force_vmexit()); return 0 ; }
在物理机上运行结果:
(2724639288020470 - 2724639288020494) rdtsc difference: 24 (2724639289813128 - 2724639289813156) rdtsc difference: 28 (2724639291344684 - 2724639291344708) rdtsc difference: 24 (2724639292869608 - 2724639292869668) rdtsc difference: 60 (2724639294412600 - 2724639294412628) rdtsc difference: 28 (2724639295888716 - 2724639295888744) rdtsc difference: 28 (2724639297385732 - 2724639297385760) rdtsc difference: 28 (2724639298878740 - 2724639298878768) rdtsc difference: 28 (2724639300371292 - 2724639300371320) rdtsc difference: 28 (2724639301864924 - 2724639301864952) rdtsc difference: 28 difference average is: 30 cpu_rdtsc: 0 (2724639303466468 - 2724639303466608) rdtsc_force_vmexit difference: 140 (2724639304950316 - 2724639304950440) rdtsc_force_vmexit difference: 124 (2724639306452456 - 2724639306452576) rdtsc_force_vmexit difference: 120 (2724639307949500 - 2724639307949624) rdtsc_force_vmexit difference: 124 (2724639309446084 - 2724639309446208) rdtsc_force_vmexit difference: 124 (2724639310963224 - 2724639310963344) rdtsc_force_vmexit difference: 120 (2724639312455892 - 2724639312456012) rdtsc_force_vmexit difference: 120 (2724639313952608 - 2724639313952728) rdtsc_force_vmexit difference: 120 (2724639315444756 - 2724639315444880) rdtsc_force_vmexit difference: 124 (2724639316941332 - 2724639316941452) rdtsc_force_vmexit difference: 120 difference average is: 123 cpu_rdtsc_force_vmexit: 0
在VMware虚拟机上运行结果:
(2201234633835839 - 2201234633835857) rdtsc difference: 18 (2201234638344307 - 2201234638344325) rdtsc difference: 18 (2201234641440343 - 2201234641440361) rdtsc difference: 18 (2201234645264790 - 2201234645264814) rdtsc difference: 24 (2201234648970696 - 2201234648970714) rdtsc difference: 18 (2201234652584847 - 2201234652584865) rdtsc difference: 18 (2201234655954692 - 2201234655954710) rdtsc difference: 18 (2201234660290766 - 2201234660290790) rdtsc difference: 24 (2201234662928102 - 2201234662928126) rdtsc difference: 24 (2201234666890620 - 2201234666890638) rdtsc difference: 18 difference average is: 19 cpu_rdtsc: 0 (2201234670145762 - 2201234670148696) rdtsc_force_vmexit difference: 2934 (2201234674344607 - 2201234674347196) rdtsc_force_vmexit difference: 2589 (2201234677321168 - 2201234677322647) rdtsc_force_vmexit difference: 1479 (2201234681439262 - 2201234681441659) rdtsc_force_vmexit difference: 2397 (2201234684594947 - 2201234684596750) rdtsc_force_vmexit difference: 1803 (2201234689163149 - 2201234689165630) rdtsc_force_vmexit difference: 2481 (2201234693566946 - 2201234693568884) rdtsc_force_vmexit difference: 1938 (2201234699323186 - 2201234699325493) rdtsc_force_vmexit difference: 2307 (2201234702590461 - 2201234702592354) rdtsc_force_vmexit difference: 1893 (2201234706444177 - 2201234706446514) rdtsc_force_vmexit difference: 2337 difference average is: 2215 cpu_rdtsc_force_vmexit: 1
参考: