【问题标题】:How does Windows 10 task manager detect a virtual machine?Windows 10 任务管理器如何检测虚拟机?
【发布时间】:2018-12-24 04:06:54
【问题描述】:

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

如果您查看 性能 选项卡,您会注意到处理器数量标签显示为 逻辑处理器:虚拟处理器: .

另外,如果在虚拟机内部运行,还有标签Virtual machine: Yes

请看以下两个屏幕截图:

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

我对反汇编进行了简短的查看,似乎检测代码与GetLogicalProcessorInformationEx和/或IsProcessorFeaturePresent和/或NtQuerySystemInformation有关。

但是,我不知道如何(至少在没有花费更多时间分析汇编代码的情况下不会)。

而且:这个问题是 IMO 与其他现有问题无关,例如 我如何检测我的程序是否在虚拟机中运行? 因为我没有看到任何尝试比较 smbios 表字符串的代码或 cpu 供应商字符串,其中包含现有的已知字符串(“qemu”、“virtualbox”、“vmware”)。我不排除较低级别的 API 实现会这样做,但我在 taskmgr.exe 中看不到这种代码。

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

更新:仔细查看反汇编表明确实检查了第 31 位,但显然没有这样做。

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

【问题讨论】:

  • @CodeCaster 我不这么认为。至少我没有在代码中看到任何提示,它试图匹配 smbios 表数据,或供应商字符串与已知的虚拟化字符串(qemu、vmware、...)
  • Taskmgr 在函数 __int64 WdcMemoryMonitor::CheckVirtualStatus() 中使用 CPUID 来检查状态。
  • @magicandre1981 是和否。 CheckVirtualStatus() 将 CPUID 用于多个检测任务(例如签名、制造商 ID 字符串),但只有一次 EAX=1,在这种情况下,只分析 ECX 的第 5 位以检查 VMX 扩展。并且缺少 VMX 标志不是虚拟机的合适指标。
  • 好的,我只用 IDA 看了一眼,还没有检查 EAX 值的含义
  • @magicandre1981 不过你是对的。我错过了它,因为我专注于 eax 位移并且没有注意到在该函数中第一次使用 CPUID 之后是 test ecx,ecx 的 jns,它与测试位 31 相同;)跨度>

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


【解决方案1】:

我已经分析了 Windows 10 1803(OS Build 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 位(CPUIDleaf 0x01 ECX 位 31)是否已设置。

结果当然是假的,因为例如在 qemu 的 cpu 参数中添加 -hypervisor 会禁用管理程序 cpuid 标志,这会导致任务管理器不再显示 Virtual machine: yes

最后是一些示例代码(在 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;
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-07
  • 1970-01-01
  • 2021-06-20
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多