This malware uses vulnerable x86 instructions to determine if it is running in a VM.
The script finds three potential anti-VM instructions and highlights them in red: sidt, str, and sldt.
The malware will delete itself if either sidt or str detects VMware. If the sldt
instruction detects malware, the malware will exit without creating its main thread, but it will
create the malicious service MalService.
On our machine running VMware Workstation 7 on an Intel Core i7, none of the techniques succeeded. Your results will vary depending on the hardware and software you use.
See the detailed analysis for an explanation of why each technique did or didn’t work.
You can NOP-out the sidt and str instructions or flip the jump flags live while debugging the malware.
Because this malware is the same as Lab07-01.exe except with added
anti-VM techniques, a good place to begin your analysis is with Lab 7-1 Solutions.
Scanning the malware for new functions, we find two: sub_401000,
a self-deletion method, and sub_401100, which appears to call the
sldt instruction. We can run Lab17-01.exe in
a VM and see what happens differently from Lab 7-1 Solutions. The dynamic analysis
results vary from system to system and might be identical to Lab 7-1 Solutions on
your machine.
We can automatically search for vulnerable x86 instructions using IDA Pro’s Python scripting capability (available in the commercial version). Create your own script using Example 17-4 in Chapter 17, or use the script named findAntiVM.py provided with the labs. To run the script in IDA Pro, select File ▸ Script File and open findAntiVM.py. You should see the following in IDA Pro’s output window:
Number of potential Anti-VM instructions: 3
This output indicates that the script detected three vulnerable instruction types. Scrolling
through the disassembly window in IDA Pro, we see three instructions highlighted in red: sidt, str, and sldt. (If you don’t have the commercial version of IDA Pro, search for these
instructions using Search ▸ Text.)
We’ll analyze each vulnerable instruction, focusing on what happens if the VM technique succeeds, how to defeat it, and why it does or doesn’t work on our machine.
The sidt instruction (also known as Red Pill) is the
first vulnerable instruction we encounter in this malware, as shown in Example C-156 at ❶. This
instruction stores the most significant 4 bytes of the sidt
result var_420 at ❷
for later use in the code.
Example C-156. Red Pill being used in Lab 17-1 Solutions
004011B5 sidt fword ptr [ebp+var_428] ❶ 004011BC mov eax, dword ptr [ebp+var_428+2] 004011C2 mov [ebp+var_420], eax ❷
The malware checks for a VM a few instructions later in the binary, as you can see in Example C-157.
Example C-157. Comparison and conditional jump checking after using the sidt instruction
004011DD mov ecx, [ebp+var_420] 004011E3 shr ecx, 18h ❶ 004011E6 cmp ecx, 0FFh 004011EC jz loc_40132F ❷
The most significant 4 bytes of the sidt result (var_420) are shifted at ❶,
since the sixth byte of sidt (fourth byte of var_20) contains the start of the base memory address. That fifth byte is
compared to 0xFF, the VMware signature. If the jump is taken at ❷, the malware detected a virtual environment, and will call the function at 0x401000 to
terminate it and remove it from disk.
The check fails in our test environment, probably because we are on a multiprocessor machine.
When we set a breakpoint at 0x4011EC, we see that ECX isn’t 0xFF (the signature for VMware).
If Red Pill is effective in your environment, NOP-out the sidt
instruction or force the jz at ❷ to not jump in a debugger.
The str instruction is the second vulnerable instruction in
this malware, as seen at line 0x401204:
00401204 str word ptr [ebp+var_418]The str instruction loads the task state segment (TSS) into
the 4-byte local variable var_418. The malware doesn’t use
this local variable again until just after the call to GetModuleFileName.
If the str instruction succeeds, the malware will not
create the MalService service. Example C-158 shows the
check against the first 2 bytes, which must equal 0 ❶
and 0x40 ❷ in order to match the signature for
VMware.
Example C-158. Checking the results of the str instruction
00401229 mov edx, [ebp+var_418] 0040122F and edx, 0FFh 00401235 test edx, edx ❶ 00401237 jnz short loc_40124E 00401239 mov eax, [ebp+var_418+1] 0040123F and eax, 0FFh 00401244 cmp eax, 40h ❷ 00401247 jnz short loc_40124E 00401249 jmp loc_401338
This check failed in our environment. When we set a breakpoint at 0x40122F, we saw that
var_418 contained 0x28, not 0x4000, the signature for
VMware.
If the str instruction check succeeds in your environment,
NOP-out the str instruction or force the jnz at 0x401237 to jump in a debugger at runtime.
The sldt instruction (also known as No Pill) is the final
anti-VM technique used in this malware. This technique is found in the function labeled sub_401100 by IDA Pro. Example C-159 shows the sldt usage within sub_401100.
Example C-159. Setup and execution of the sldt instruction
00401109 mov eax, dword_406048 ;0xDDCCBBAA 0040110E mov [ebp+var_8], eax ❶ ... 00401121 sldt word ptr [ebp+var_8] 00401125 mov edx, [ebp+var_8] 00401128 mov [ebp+var_C], edx 0040112B mov eax, [ebp+var_C] ❷
As you can see, var_8 is set to EAX at ❶, and EAX was set to dword_406048 in the previous instruction. dword_406048
contains an initialization constant (0xDDCCBBAA). The result of the sldt instruction is stored in var_8 and is ultimately
moved into EAX at ❷.
After this function returns, the result is compared to see if the low-order bits of the initialization constant are set to zero, as shown in Example C-160 at ❸. If the low-order bytes are not zero, the jump will be taken, and the malware will terminate without creating the thread.
Example C-160. Checking the result of the sldt instruction
execution
004012D1 call sub_401100
004012D6 cmp eax, 0DDCC0000h ❸
004012DB jnz short loc_40132BThis check failed in our environment. When we set a breakpoint at 0x4012D6, we found that EAX was equal to 0xDDCC0000, which meant that the check for a VM failed.
If No Pill is effective in your environment, you will need to NOP-out the three instructions
in Example C-160 or force the jnz to not jump in a debugger.