This month’s virtual machine detection trick involves detecting the presence of the Hyper-V RAW network protocol. This protocol is a special type of winsock protocol that is utilized by many of the guest features, allowing the guest and hypervisor to communicate directly. Importantly, this protocol driver is always present on guest systems even if the guest services are disabled or removed. The protocol can be detected via WMI or the registry.

WMI detection

The WMI class Win32_NetworkProtocol will have an entry named “Hyper-V RAW” on any machine where Hyper-V is installed as a feature, including both hosts and guests.

A screenshot showing WMI information for the Win32_NetworkProtocol class. The left pane shows instances of the class. The Hyper-V RAW instance is selected. The right panel shows the properties of this class instance. The instance name is Hyper-V. The minimum and maximum address sizes are shown as 36. Protocol flags for Guarantees Delivery, Guarantees Sequencing, and Supports Graceful Closing are set. All other protocol flags are false.

Registry Detection

The registry-based detection approach is to enumerate the subkeys of the following registry path:

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries

Each subkey contains a ProtocolName value. Systems with Hyper-V installed will have an entry whose protocol name is “Hyper-V RAW”.

A screenshot of regedit, showing one of the subkeys of protocol catalog entries. The protocol name is Hyper-V RAW. The key also contains a REG_BINARY value named PackedCatalogItem.

Another approach is to instead search the PackedCatalogItem values inside the subkeys. These are binary packed descriptors for protocols. Inside, the string “Hyper-V RAW” can be found, encoded in UTF-16.

A screenshot of the binary data inside PackedCatalogItem. The Hyper-V RAW string can be seen in the data.

If you want to get particularly fancy, you could avoid heuristics that look for VM-related strings by instead looking for a protocol with a minimum and maximum address size of 36, and with only the Guarantees Delivery, Guarantees Sequencing, and Supports Graceful Closing flags set.

Use in the wild

The trick itself is as simple as that. Things got interesting, however, when I went to check if anyone had documented this trick before. A search for the “Hyper-V RAW” string with various keywords like detection, malware, etc. returned no such articles on the matter, but instead uncovered a pair of malware samples that had been submitted to a sandbox:

A screenshot showing a pair of Google results from Joe Sandbox. Both results show that "Hyper-V" was detected as an in-memory string during analysis.

The first result is for an Emotet dropper, and the second is for a Shade (Troldesh) dropper. It would be particularly interesting if both malware families had utilized the same unique trick within just a month or two of each other, right as Shade was winding down and Emotet was scaling up.

Some digging through the reports showed that the string “Hyper-V RAW” was found in the process memory of dropped executables from both submissions.

A screenshot showing the Hyper-V RAW string being detected in memory. In the Emotet sample the string was detected in startedradar.exe. In the Shade sample the string was detected in csrss.exe

After far too much reverse engineering, though, I was able to show that neither of the samples actually used this as a detection trick.

The Emotet dropper produced a file with the following hash:

5650da013b1258df9e3b8e4364b857dbbd064c25

This file utilizes wininet.dll in order to make HTTP requests. The InternetOpenW API call initializes winsock, which iterates through the protocol catalog registry keys. We can see this in the list of captured registry operations:

Key Address Caller
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000001 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000002 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000003 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000004 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000005 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000006 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000007 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000008 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000009 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000010 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000011 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000012 0x31766 InternetOpenW
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000013 0x31766 InternetOpenW

The enumeration of these keys is coming from the InternetOpenW call, not application code. Searching for any of the registry key names and the Hyper-V RAW string produced no results elsewhere in the report. This indicates that there’s no actual detection going on here, and the in-memory string is simply an artifact left over from winsock’s own enumeration.

The Shade/Troldesh sample is a slightly less straightforward case. Again, the dropper produces a malicious executable and executes it, and that process somehow ends up with the Hyper-V RAW string in memory. The relevant registry operations are as follows:

Key Address Caller
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000001 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000002 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000003 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000004 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000005 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000006 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000007 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000008 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000009 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000010 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000011 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000012 0x772C2FBA RtlUserThreadStart
HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000013 0x772C2FBA RtlUserThreadStart

The fact that these come from RtlUserThreadStart might seem to indicate that this is part of user code. However, it is not uncommon for stack unwinding analysis to show RtlUserThreadStart as a false positive for the caller name. The address of 0x772C2FBA is helpful, though, since the main module is unlikely to have been loaded at such a high address, nor are RWX memory allocations from VirtualAlloc usually seen in that address range. The high address is likely to be associated with an API call into a Windows DLL.

Looking further back in the registry activity history confirms these suspicions:

Key Address Caller
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ 0x413402 RegOpenKeyExW
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\ 0x41AB2B RegOpenKeyExW
HKLM\SOFTWARE\WOW6432Node\System32\Configuration\ 0x41AB2B RegOpenKeyExW
HKLM\Software\WOW6432Node\Policies\Microsoft\Windows NT\Rpc 0x449146 NetStatisticsGet
HKLM\SOFTWARE\WOW6432Node\Microsoft\Cryptography\Defaults\Provider Types\Type 001 0x772C2FBA RtlUserThreadStart
HKLM\SOFTWARE\WOW6432Node\Microsoft\Cryptography\Defaults\Provider\Microsoft Strong Cryptographic Provider 0x772C2FBA RtlUserThreadStart
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ 0x413402 RegOpenKeyExW
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\ 0x41AB2B RegOpenKeyExW
HKLM\SOFTWARE\WOW6432Node\System32\Configuration\ 0x41AB2B RegOpenKeyExW
HKLM\Software\WOW6432Node\Policies\Microsoft\Windows NT\Rpc 0x449146 NetStatisticsGet
HKLM\SOFTWARE\WOW6432Node\Microsoft\Cryptography\Defaults\Provider Types\Type 001 0x772C2FBA RtlUserThreadStart
HKLM\SOFTWARE\WOW6432Node\Microsoft\Cryptography\Defaults\Provider\Microsoft Strong Cryptographic Provider 0x772C2FBA RtlUserThreadStart

The application’s main module, loaded with a base address of 0x400000, makes a number of calls to RegOpenKeyExW, in relation to persistence and detection of software on the system. It then calls NetStatisticsGet in netapi32.dll. This causes winsock to be initialized asynchronously, in a new thread created by RtlUserThreadStart, leading to the protocol catalog registry keys being enumerated.

In both cases the sandbox analysis’ VM detection heuristics produced false positives, due to winsock accessing the protocol catalog registry keys during initialisation, causing the strings to be loaded into the process memory. This likely only gets picked up in sandboxes that analyse the entire process memory rather than just the standard heap.

Links to the sandbox reports are below. Please be aware that the full analysis pages are extremely large and may slow down your browser.

If sandbox authors wish to detect this trick, they should look to identify that the enumeration of the protocol catalog registry keys is coming directly from application code, and not via a call stack that includes an API in a library such as winsock, wininet, or netapi32.

About this series

In this series we’re documenting a novel and as-yet undocumented VM detection trick once per month, throughout all of 2021. These detection tricks are focused on 64-bit Windows 10 or Windows Server 2019 guests, targeting a variety of VM platforms.

Previous articles in this series: