Windows 10 任务管理器 (taskmgr.exe) 知道它是在物理机还是虚拟机上运行。
如果您查看“性能”选项卡,您会注意到处理器数量标签显示为“逻辑处理器:”或“虚拟处理器:”。 此外,如果在虚拟机内运行,还会有标签虚拟机:是。 请参阅以下两个屏幕截图:
我的问题是,taskmgr 是否有记录的 API 调用用于进行此类检测?
我对反汇编进行了非常简短的观察,似乎检测代码在某种程度上与 GetLogicalProcessorInformationEx 和/或
IsProcessorFeaturePresent和/或
NtQuerySystemInformation有关。 但是,我不知道如何实现(至少在不花费更多时间分析汇编代码的情况下)。 并且:这个问题在我看来与其他现有问题无关,例如如何检测我的程序是否在虚拟机内运行?因为我没有看到任何代码尝试将 smbios 表字符串或 cpu 供应商字符串与现有的已知字符串进行比较虚拟机管理程序的典型字符串(“qemu”、“virtualbox”、“vmware”)。我不排除较低级别的 API 实现可以做到这一点,但我在 taskmgr.exe 中没有看到这种代码。
更新:我还可以排除taskmgr.exe正在使用CPUID指令(EAX = 1并检查ECX中的hypervisor
位31)来检测矩阵。
更新:仔细观察反汇编结果表明确实存在对位 31 的检查,只是显然没有这样做。
下面我自己来回答这个问题。
我分析了 Windows 10 1803(操作系统版本 17134.165)中的 x64 taskmgr.exe,通过追踪对设置
Virtual machine: Yes标签时查阅的内存位置的写入。
WdcMemoryMonitor::CheckVirtualStatus
以下是该函数中第一次使用
cpuid
指令的反汇编:
lea eax, [rdi+1] // results in eax set to 1
cpuid
mov dword ptr [rbp+var_2C], ebx // save CPUID feature bits for later use
test ecx, ecx
jns short loc_7FF61E3892DA // negative value check equals check for bit 31
...
return 1
loc_7FF61E3892DA:
// different feature detection code if hypervisor bit is not set
因此,taskmgr 不使用任何硬件字符串、MAC 地址或其他一些复杂的技术,而只是检查
hypervisor位(CPUID
leaf 0x01 ECX 位 31))是否已设置。
结果当然是假的,因为例如将 -hypervisor
添加到 qemu 的 cpu 参数会禁用虚拟机管理程序 cpuid 标志,从而导致任务管理器不再显示虚拟机:是。
最后这里是一些示例代码(在 Windows 和 Linux 上测试),完美模仿 Windows 任务管理器的测试:
#include <stdio.h>
#ifdef _WIN32
#include <intrin.h>
#else
#include <cpuid.h>
#endif
int isHypervisor(void)
{
#ifdef _WIN32
int cpuinfo[4];
__cpuid(cpuinfo, 1);
if (cpuinfo[2] >> 31 & 1)
return 1;
#else
unsigned int eax, ebx, ecx, edx;
__get_cpuid (1, &eax, &ebx, &ecx, &edx);
if (ecx >> 31 & 1)
return 1;
#endif
return 0;
}
int main(int argc, char **argv)
{
if (isHypervisor())
printf("Virtual machine: yes\n");
else
printf("Virtual machine: no\n"); /* actually "maybe */
return 0;
}
就KVM/QEMU而言(来自/r/VFIO的回答)
如果您对虚拟机管理程序使用功能策略禁用,它将消除 taskmgr 中的该消息。在 xml 中就像这样
或将
-cpu …,-hypervisor
添加到您的 cli。