Windows 10任务管理器如何检测虚拟机?

时间:2018-07-16 14:57:21

标签: windows windows-10 virtual-machine reverse-engineering virtualization

Windows 10任务管理器(taskmgr.exe)知道它是在物理机还是虚拟机上运行。

如果您在 Performance 标签中看到,“处理器数量”标签将显示为逻辑处理器:虚拟处理器:

此外,如果在虚拟机中运行,则还会有标签虚拟机:是

请参见以下两个屏幕截图:

taskmgr locical processors

taskmgr virtual processors

我的问题是,是否存在记录在案的API调用taskmgr用于进行这种检测?

我对反汇编进行了很短的了解,检测代码似乎与GetLogicalProcessorInformationEx和/或IsProcessorFeaturePresent和/或NtQuerySystemInformation相关。

但是,我不知道如何(至少不花费更多时间来分析汇编代码)。

而且:此问题与IMO不相关,例如如何检测我的程序是否在虚拟机中运行?等其他现有问题,因为我没有看到任何代码试图比较smbios表字符串或cpu供应商字符串以及具有虚拟机管理程序典型的现有已知字符串(“ qemu”,“ virtualbox”,“ vmware”)。我不排除较低级别的API实现可以做到这一点,但在taskmgr.exe中看不到这种代码。

更新:我还可以排除taskmgr.exe使用CPUID指令(EAX = 1,并检查ECX中的 hypervisor 位31)来检测矩阵。

更新:仔细查看反汇编,发现确实检查了第31位,只是显然没有这样做。

我会在下面亲自回答这个问题。

1 个答案:

答案 0 :(得分:9)

我已通过追溯对在虚拟机:是标签处查询的内存位置的写入,来分析Windows 10 1803(操作系统内部版本17134.165)中的x64 taskmgr.exe。已设置。

该变量的值是函数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地址或其他一些复杂的技术,而只是检查管理程序位(CPUID叶子0x01 ECX位31)是否已设置。 / p>

由于例如将-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;
}