Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Windows 10 task manager detect a virtual machine?

The Windows 10 task manager (taskmgr.exe) knows if it is running on a physical or virtual machine.

If you look in the Performance tab you'll notice that the number of processors label either reads Logical processors: or Virtual processors:.

In addition, if running inside a virtual machine, there is also the label Virtual machine: Yes.

See the following two screen shots:

taskmgr locical processors

taskmgr virtual processors

My question is if there is a documented API call taskmgr is using to make this kind of detection?

I had a very short look at the disassembly and it seems that the detection code is somehow related to GetLogicalProcessorInformationEx and/or IsProcessorFeaturePresent and/or NtQuerySystemInformation.

However, I don't see how (at least not without spending some more hours of analyzing the assembly code).

And: This question is IMO not related to other existing questions like How can I detect if my program is running inside a virtual machine? since I did not see any code trying to compare smbios table strings or cpu vendor strings with existing known strings typical for hypervisors ("qemu", "virtualbox", "vmware"). I'm not ruling out that a lower level API implementation does that but I don't see this kind of code in taskmgr.exe.

Update: I can also rule out that taskmgr.exe is using the CPUID instruction (with EAX=1 and checking the hypervisor bit 31 in ECX) to detect a matrix.

Update: A closer look at the disassembly showed that there is indeed a check for bit 31, just not done that obviously.

I'll answer this question myself below.

like image 685
gollum Avatar asked Jul 16 '18 14:07

gollum


People also ask

How does Windows know its a virtual machine?

The Windows 10 task manager (taskmgr.exe) knows if it is running on a physical or virtual machine. If you look in the Performance tab you'll notice that the number of processors label either reads Logical processors: or Virtual processors:.

How are virtual machines detected?

VM Threat Detection is built into Google Cloud's hypervisor, a secure platform that creates and manages all Compute Engine VMs. The service periodically performs scans from the hypervisor into the guest VM's live memory without pausing operation of the guest.

Can you be tracked if you use a virtual machine?

Short answer: yes, as any regular computer would. A little more detail: VMs are computers like any other. VMs can have one IP address, public or private. VMs can even have more than one IP address.


1 Answers

I've analyzed the x64 taskmgr.exe from Windows 10 1803 (OS Build 17134.165) by tracing back the writes to the memory location that is consulted at the point where the Virtual machine: Yes label is set.

Responsible for that variable's value is the return code of the function WdcMemoryMonitor::CheckVirtualStatus

Here is the disassembly of the first use of the cpuid instruction in this function:

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

So taskmgr is not using any hardware strings, mac addresses or some other sophisticated technologies but simply checks if the hypervisor bit (CPUID leaf 0x01 ECX bit 31)) is set.

The result is bogus of course since e.g. adding -hypervisor to qemu's cpu parameter disables the hypervisor cpuid flag which results in task manager not showing Virtual machine: yes anymore.

And finally here is some example code (tested on Windows and Linux) that perfectly mimics Windows task manager's test:

#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;
}
like image 111
gollum Avatar answered Oct 12 '22 11:10

gollum