Word macro uses WMI to detect VM environments

Jul 11th 2016

We recently came across an interesting malicious Word document that used an embedded Word macro to detect whether or not it was being opened inside a VM. If no VM was detected, the macro proceeded to attempt to download a payload (executable) to infect the machine. Let’s take a look at our analysis and how VMRay’s Function logs can aid in analysing heavily obfuscated code such as the macro in this document.

SwiftOnSecurity, a well-known infosec commentator referred to the ‘Enable Content’ button in Word as the ‘Infect-my-computer-button’ with some justification as we see here.


infosecTswift tweet

In our example, a little social engineering was used to coax the potential victim to enable content, allowing the macro to run, as shown in Figure 1:


Word Macro WMI VM detection

Fig. 1 – A little social engineering by the malware author


If the user falls for it and enables content, a macro starts automatically and triggers the function Document_Open(). This leads to heavily obfuscated Visual Basic code running that will both detect if the document is open inside a VM and download an executable that will infect the system.



Fig. 2 – Document_Open() starts the obfuscated macro.



We start the analysis by uploading the document to VMRay Analyzer. The results come back a couple minutes later unambiguously malicious – 100/100 on the VTI (VMRay Threat Identifier) Threat Score. One of the main reasons for the high score is that an attempt is made to download an executable file – singularly suspicious behavior for a Word document.



Fig. 3 – Analysis generates a high VTI Threat Score


A closer look at this behavior shows something interesting. The Word macro uses WMI (Windows Management Instrumentation) to detect the presence of a VM. To extract this behavior, we have to de-obfuscate the Visual Basic code in the macro. Normally this is hard work for an analyst, but with the aid of the function log extracted by the VMRay analysis, it is much easier. This function log is created while the analysis is running. It contains in plain text every function call and associated parameter. For example, we can see in Figure 4 the download link inside the function logfile.



Fig. 4 – Malicious download link in plain text in Function Logfile


Typically, an attacker who obfuscates macros will also obfuscate the function calls. For this they use a simple trick. Visual Basic allows creation of class objects with the function CreateObject(). This function needs a string as input. For example: CreateObject(“WScript.Shell”) creates a shell-object. The attacker then encrypts this string and decrypts it on use.
As an example, first the attacker encrypts the string Wscript.Shell to lhtrWxaHLlSpcG.xS9e.iSkycrB and writes it to a list named doTNALtI at index “QJnANGYgOwW”. From then on doTNALtI.QJnANGYgOwW will point to lhtrWxaHLlSpcG.xS9e.iSkycrB which is the decrypted “Wscript.Shell. In the next step the attacker creates a subroutine for CreateObject() named WkKQhrg04 and a subroutine for the decrypt-function named kFfxtZGj54a that will decrypt the input string.
As a result, the simple call of CreateObject(“WScript.Shell”) is obfuscated to

WkKQhrg04(kFfxtZGj54a(360, doTNALtI.QJnANGYgOwW)).

This makes it very hard to reconstruct the macro.



Fig. 5 – Obfuscation of CreateObject(“WScript.Shell”)


However, with the aid of the function log, the reconstruction won’t be as hard as it looks. We only have to look for strings and functions in the function log that make sense. For example, our familiar “Wscript.Shell” will be found in the function log as follow:

CLSIDFromProgIDEx (in: lpszProgID="WScript.Shell", lpclsid=0x2130e0 | out: lpclsid=...)) returned 0x0

With this information we resolved kFfxtZGj54a(360, doTNALtI.QJnANGYgOwW) to “Wscript.Shell” without bothering to decrypt the string. This can be done for every obfuscated string in the macro, so that a complete reconstruction of the Visual Basic macro is possible. While doing this we found an interesting embedded VM detection routine.


VM detection

Before the Visual Basic macro starts its infection it tries to detect the presence of a VM environment with the VMDetectionFails method. If this method returns true, the infection will start. Otherwise the macro stops running.

Public Sub MAIN()
  if VMDetectionFails then
  end if

The VMDetectionFails method contains three detection methods with the following logic:

Private Function VMDetectionFails() As Boolean
  if Detection01 Or Detection02 then
    VMDetectionFails = Detection03
    VMDetectionFails = True
  end if

 If Detection01 or Detection02 detects a VM, Detection03 decides whether the macro should run. Otherwise if Detection01 and Detection02 detect no VM, the method returns true.


Detection01 using WMI

The first detection method has two stages. The first stage checks if the environment variable “USERNAME” is equal to “USER” and “USERDOMAIN” is equal to “HOST”. If both values are true the detection is triggered. Otherwise it proceeds to stage two.
In the second stage with the aid of WMI (Windows Management Instrumentation) the detection method calls the command: GetObject(“winmgmts:“).InstancesOf (“Win32_ComputerSystem“). This creates with the WMI command “winmgmts” an instance of “Win32_ComputerSystem”. This instance contains all the information about the System.
Now the detection method looks specifically for information about the “Manufacturer” and “Model” and checks if it contains one of the following strings: “KVM”, “QEMU”, “RED HAT”, “VIRTUAL”, “VMWARE”, “XEN”. If it does, the detection method triggers and returns true.


Detection02 using WMI

The second detection method uses WMI as well. With the following WMI command the detection method will get a list of all running processes:

GetObject("winmgmts:").ExecQuery ("Select * from Win32_Process")

With this list it will check if it contains one of the following processes:
If the detection method has a match it will return true.



This detection method checks if the string “1461591186_usa” is part of the document path. If it is, the detection method returns true, so that the infection starts. The check takes place as follows:

InStr(1, callByName(ThisDocument, "Path", 2), "1461591186_usa") <> 0

We can only speculate on the author’s intention here in using this particular string and test.



This analysis shows that VM detections can also be embedded into Visual Basic macros. Fortunately, the VMRay Analyzer environment remains undetected by the malware so it executes and we get a full analysis. This can be confirmed by the attempted download of


which starts only if no VM environment is detected.
However, at the time of our analysis the C2 (command and control) server had already been taken down, so the download was not successful in any event. The function log generated in a VMRay analysis is a very useful tool for analyzing heavily obfuscated word macros. It enables easy reconstruction of the macro, providing a clear understanding of the malware’s methods and goals.

Follow us on Twitter @VMRay to get updates on future blog posts like this.

Calculate how much malware false positives are costing your organization:
Malware False Positive Cost Calculator