System Resources layout as a potential VM detection vector
I was reading XPN's article about a TotalMeltdown exploit and saw that they had updated their code to check which physical addresses were mapped when doing their search for an _EPROCESS struct, to avoid BSOD. They do this via the RESOURCEMAP registry key, which has some REG_RESOURCE_LIST type values. I hadn't come across that registry value type before and it turns out that it's a fairly in-depth struct that describes hardware resources.
This got me thinking - do the physical memory maps change between a host and a VM, and are VM maps generally the same on every box? I can answer the first one: yes. I wrote a tool to dump the address lists and here are the results:
Host box 1 (Win10, 32GB RAM):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
--> Memory region found: 00000000cb52d000 - 00000000cb98c000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 00000000cb526000 - 00000000cb52d000
--> Memory region found: 00000000fec00000 - 00000000fec01000
Host box 2 (Win10, 32GB RAM, Hyper-V enabled):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
--> Memory region found: 00000000001f5000 - 00000000001fe000
--> Memory region found: 00000000002fe000 - 00000000003fe000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 00000000001f5000 - 00000000001fe000
--> Memory region found: 0000000000293000 - 0000000000297000
--> Memory region found: 0000000000875000 - 000000000095a000
--> Memory region found: 000000000364c000 - 0000000003675000
--> Memory region found: 000000006929d000 - 000000007fa00000
VirtualBox VM on host 1 (Win8.1 x64, 2GB RAM assigned):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009f000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000000e000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 000000000000e000
--> Memory region found: 00000000000f0000 - 0000000000100000
VirtualBox VM on host 1 (Win8.1 x64, 10GB RAM assigned):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009f000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000000e000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 000000000000e000
--> Memory region found: 00000000000f0000 - 0000000000130000
Hyper-V VM on host 2 (Win10, dynamic RAM):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 000000007eee9000 - 000000007ef1b000
HyperV VM on host 2 (Win10, 2GB RAM assigned):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 000000007eee9000 - 000000007ef1b000
There are patterns here that we can probably exploit, although I'd like more data samples to be sure.
A preliminary test would be:
- If
Reserved\.Translatedhas anything other than 1 entry, skip test. - If
Loader Reserved\.Rawhas anything other than 2 entries, skip test. - Detect VirtualBox if
Reserved\.Translatedis0000000000000000 - 000000000000e000andLoader Reserved\.Rawcontains an entry equal to0000000000000000 - 000000000000e000. - Detect HyperV if
Reserved\.Translatedis0000000000001000 - 00000000000a0000andLoader Reserved\.Rawcontains an entry equal to0000000000000000 - 00000000000a0000.
I could do with more data points before I write this up, so @LordNoteworthy it'd be great if you could try this on your side with various VM solutions.
Here's the code for the test utility: PhysMemResourceList.c.txt
If you're feeling lazy and don't wanna compile the above you can use my compiled binary (requires VC Runtime 14 x86): PhysMemResourceList.zip
Let me know what results you get :)
Aside: there are other REG_RESOURCE_LIST values in the registry and they contain all sorts of hardware information that we can probably fingerprint in various ways. My code only dumps the memory entries from the lists and ignores everything else. See CM_RESOURCE_LIST and related structs for more info.
@LordNoteworthy Can you run the PhysMemoryResourceList tool above on a few platforms and paste the results please? Once I've got data samples I can write this up as a check.
@gsuberland
VirtualBox VM (Windows 7 x64, 4GB assigned)
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009f000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 0000000000008000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 0000000000008000
--> Memory region found: 0000000000110000 - 0000000000140000
VirtualBox VM (Windows 7 x86, 2GB assigned)
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Tra
nslated
--> Memory region found: 0000000000001000 - 000000000009f000
--> Memory region found: 0000000000100000 - 000000007fff0000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 0000000000005000
--> Memory region found: 0000000000030000 - 0000000000040000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 0000000000005000
--> Memory region found: 0000000000030000 - 0000000000040000
--> Memory region found: 000000000009f000 - 00000000000a0000
--> Memory region found: 00000000000f0000 - 0000000000100000
--> Memory region found: 000000007fff0000 - 0000000080000000
--> Memory region found: 00000000fec00000 - 00000000fec01000
--> Memory region found: 00000000fee00000 - 00000000fee01000
--> Memory region found: 00000000fffc0000 - 0000000100000000
VirtualBox VM (Windows 10 x64, 4GB assigned)
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009f000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 0000000000017000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 0000000000017000
--> Memory region found: 0000000000102000 - 0000000000103000
My host is linux, I will post more about VMWare.
I ended up doing some more research into this at work. Writeup here.
https://labs.nettitude.com/blog/vm-detection-tricks-part-1-physical-memory-resource-maps/
I'll port the code into here when I get chance.