CPUID叶子0x40000000是最直接有效的判断依据,读取EBX/ECX/EDX拼接的vendor ID(如"VMwareVMware")可确认虚拟机,无误报风险;需先用__cpuid(0)确认支持性,再安全调用对应扩展函数。

CPUID 叶子 0x40000000 是最直接有效的判断依据,只要能读到 "VMwareVMware" 或 "VirtualBox" 字符串,基本可确认环境。
用 __cpuid 或 __cpuid_count 读取 vendor ID
主流虚拟机在 CPUID 扩展叶子 0x40000000 中硬编码厂商标识,物理 CPU 不会返回这些值,因此无误报风险。调用前必须先确认 CPUID 基础功能可用:
- 先执行
__cpuid(info, 0)(MSVC)或__cpuid_count(0, 0, a, b, c, d)(GCC/Clang),若info[0] == 0,说明不支持,跳过后续 - 再查
0x40000000:MSVC 用__cpuid(info, 0x40000000);GCC/Clang 必须用__cpuid_count(0x40000000, 0, a, b, c, d),否则子叶无效 - vendor ID 存于
info[1](EBX)、info[2](ECX)、info[3](EDX),按小端拼接为 12 字节字符串:例如info[1] == 0x6d77564d && info[2] == 0x6d77564d && info[3] == 0x6d77564d对应 "VMwareVMware" - 别用
strcmp比较字符串——寄存器值可能含 ,直接比对uint32_t更安全可靠
Linux 下读 /sys/class/dmi/id/product_name 或 sys_vendor
该路径无需 root 权限,多数发行版已开放,是 CPUID 失效时的首选 fallback。
- 读取
/sys/class/dmi/id/product_name:VMware 返回 "VMware Virtual Platform",VirtualBox 返回 "VirtualBox" - 读取
/sys/class/dmi/id/sys_vendor:常见值为 "VMware, Inc." 或 "innotek GmbH"(旧版 VirtualBox) - 注意:Google Shielded VM、AWS Nitro 等加固云实例会抹除或伪造这些字段,返回空或通用值(如 "Google")
- 若文件打开失败(ENOENT 或 EACCES),不要中断流程,继续下一检测项
Windows 下查 WMI Win32_ComputerSystem 或注册表
WMI 查询响应慢(200–500ms),且依赖服务可用性;注册表更轻量,适合快速兜底。
立即学习“C++免费学习笔记(深入)”;
- WMI 方式:查询
Win32_ComputerSystem的Manufacturer和Model属性,匹配 "VMware"、"VirtualBox"、"innotek" - WMI 初始化需调用
CoInitializeSecurity,参数错误易导致RPC_E_ACCESS_DENIED;最小化系统(如 WinPE)中可能根本连不上服务,返回WBEM_E_INVALID_NAMESPACE - 注册表 fallback:读
HKEY_LOCAL_MACHINE\SYSTEM\HardwareConfig\Current下的SystemBiosVersion,常含 "VMware" 或 "VIRTUALBOX" - 不要只依赖 WMI —— 它可被禁用、被沙箱拦截,或返回空结果
避免踩坑:为什么单点检测不可靠
现代虚拟化平台普遍具备隐藏能力,单一信号极易失效。
-
__cpuid(1, info)的 ECX[31](hypervisor bit)在 AWS EC2、Azure Gen2、GCP 都默认关闭,返回 0 不代表不是虚拟机 - VMware 可通过
hypervisor.cpuid.v0 = "FALSE"彻底隐藏0x40000000叶子;VirtualBox 也可用VBoxManage setextradata伪造 DMI 字段 - 设备名、进程名(如
vmtoolsd.exe、VBoxService.exe)容易被移除或重命名,不能作为主依据 - 真实场景中应组合使用:优先跑
0x40000000快速筛出绝大多数情况,失败后再 fallback 到 DMI/WMI/注册表
真正难处理的是那些主动隐藏所有特征的环境——比如启用了 HVCI 的 Windows 10/11 + VMware Workstation 17+,或 AWS Nitro Enclaves。这时候连 CPUID 都不可信,必须引入行为侧检测(如时钟偏移、内存延迟异常),但那已超出轻量级识别范畴。


















