It is no secret that the Information Security industry takes advantage of virtualization software in order to research security threats. VMWare, Sandboxie, Virtual PC, Anubis, CWSandbox, JoeBox, VirtualBox, Parallels, QEMU are just just of few of these virtual machines. The cornucopia of virtual environments gives the security professional the opportunity to observe and analyze malicious software in a convenient and easily reproducible manner. This presents an issue for malware writers and because of this, they often include code in their binaries to make it more difficult for computer security professionals to analyze their executables in those virtual environments. Here are some of the most frequent anti-virtualization techniques:
Check for the presence of virtualized hardware:
Virtual environments have virtual network interfaces. Just like any network interface, they are assigned a unique MAC address that usually includes the manufacturer's identification number. For example, a network interface for VMware Workstation will have a MAC address that starts with 00:50:56 or 00:0C:29 (VMware has more than one organizationally unique identifier or OUI). Malware can check for the presence of certain OUIs and choose to behave differently or not to display any malignant behavior whatsoever in a virtual machine.
It is also possible to check for the presence of GUIDs that give away the fact that it's being run in a virtual environment. Eg: MD5: 0151c5afde070a7b194f492d26e9b3ef (Trojan.Agent-124243 by ClamAV):
.text:004012EA jz short loc_40130E
.text:004012EC push 104h ; size_t
.text:004012F1 push offset a76487644317703 ; "76487-644-3177037-23510"
.text:004012F6 lea ecx, [ebp+var_104]
.text:004012FC push ecx ; char *
.text:004012FD call _strncmp
.text:00401302 add esp, 0Ch
.text:00401305 test eax, eax
.text:00401307 jnz short loc_40130E
The presence of HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\ProductId 76487-644-3177037-23510
shows that the host environment is CWSandbox.
Each virtual machine is associated with specific device drivers, registry values that give away their nature. For instance:
Hard drive driver (VMware):
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\IDE\DiskVMware_Virtual_IDE_Hard_
Drive___________00000001\3030303030303030303030303030303030303130\FriendlyName VMware Virtual IDE Hard Drive
Video driver (VMware):
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{4D36E968-E325-11CE-BFC1-08002BE10318}\0000\DriverDesc VMware SVGA II
Mouse driver (VMware):
%WINDIR%\system32\drivers\vmmouse.sys
Any of these can be used by a malware writer to detect the presence of a virtual machine.
Descriptor Table Registers check:
There is only one Interrupt Descriptor Table Register (IDTR), one Global Descriptor Table Register (GDTR) and one Local Descriptor Table Register (LDTR) per processor. Since there are two operating systems running at the same time (the host and the guest), the virtual machine needs to relocate the IDTR, GDTR and LDTR for the guest OS to different locations in order to avoid conflicts. This will cause inconsistencies between the values of these registers in a virtual machine and in the native machine. The instructions SIDT, SGDT and SLDT are assembly instructions that can respectively be used to retreive the values of IDTR, GDTR and LDTR.
Eg: MD5: b27d73bfcbaec49a95f23b45e9cf9310 (W32.Virut-54 by ClamAV)
UPX2:3142A03A loc_3142A03A: ; CODE XREF: sub_3142A02E+2 j
UPX2:3142A03A push eax
UPX2:3142A03B sidt fword ptr [esp+var_6+4]
UPX2:3142A040 pop eax
UPX2:3142A041 mov eax, [eax+6]
UPX2:3142A044 shl eax, 10h
UPX2:3142A047 jns short sub_3142A021
The IDT is at:
0x80ffffff in Windows
0xe8XXXXXX in Virtual PC
0xffXXXXXX in VMware
Backdoor I/O port:
VMware uses the I/O port 0x5658
("VX" in ASCII) to communicate with the virtual machine. A piece of malware could detect the presence of that port by doing the following:
mov EAX, 564D5868h ; VMXh
xor EBX, EBX ; set EBX to anything but 0x564D5868 (in this case 0)
mov CX, 0Ah ; Backdoor command. 10: Get VMware version
mov DX, 5658h ; VX
in EAX, DX ; Read from port VX into EAX
cmp EBX, 564D5868h ; EBX should have the magic number VX is VMware is present. If not, EBX=0
Basically, the magic number 0×564D5868
("VMXh") is copied to EAX and EBX is set to anything but 0x564D5868
. A backdoor command is loaded into CX and finally the I/O port number 0x5658
("VX") is loaded into DX. Then the "in" instruction is used to read from port 0x5658
into EAX. Outside of VMware (on a native host), a privilege error occurs. Under VMware, the magic number 0x564D5868
is returned to EBX (yes, in this case EBX is affected by in EAX, DX) hence the CMP instruction.
Exit if being debugged:
While this is not, per se, a anti-virtualization technique, it remains a a popular check performed by malware to see if a user-land debugger is present on the operating system. That's because more often than not a debugger will be installed in a virtual image used for malware analysis.
Eg: MD5: 74ab05d1ebdba509fd68711b360c1235 (Trojan.IRCBot-3475 by ClamAv)
.text:004050F8 push offset aZwquerysystemi ; "ZwQuerySystemInformation"
.text:004050FD push [ebp+hModule] ; hModule
.text:00405100 call ds:GetProcAddress
.text:00405106 mov [ebp+var_4], eax
.text:00405109 push offset aZwqueryinforma ; "ZwQueryInformationProcess"
.text:0040510E push [ebp+hModule] ; hModule
.text:00405111 call ds:GetProcAddress
.text:00405117 mov [ebp+var_14], eax
.text:0040511A cmp [ebp+var_4], 0
.text:0040511E jz short loc_405147
.text:00405120 push 0
.text:00405122 push 2 ; SystemInformationLength
.text:00405124 lea eax, [ebp+var_8]
.text:00405127 push eax ; SystemKernelDebuggerInformation
.text:00405128 push 23h
.text:0040512A call [ebp+var_4] ; ZwQueryInformationProcess
.text:0040512D test eax, eax
.text:0040512F jnz short loc_405147 ; process is being debugged
For the Windows API function ZwQuerySystemInformation, setting the value of SystemInfoClass to 2 (SystemKernelDebuggerInformation) retrieves system information on the presence of a user-land debugger.
NTSTATUS WINAPI ZwQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
For the Windows API function ZwQueryInformationProcess, setting the value of ProcessInformationClass to 7 (ProcessDebugPort) retrieves the port number for the debugger of the process. A value other than 0 indicates that the process is being run through a user-land debugger.
NTSTATUS WINAPI ZwQueryInformationProcess(
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);
How to thwart virtual machine detection:
For starters, do not install tools provided by the virtual machine in your guest OS. For example, VMware provides a set of tools called VMware Tools that enhances the overall user experience with the guest OS. The drawback is that installing VMware Tools in a Windows guest OS will leave many clues easily detectable by a piece malware that it is being run in a virtual machine.
The next step is to edit your VMware .vmx file. When you create a new virtual image with VMware, settings about it are stored in a configuration file with the .vmx extension. The file contains information about networking, disk size, devices attached to the virtual machine, etc...and is usually located in the directory where you created your virtual image. With your guest OS stopped, edit the .vmx file and append the following:
isolation.tools.setPtrLocation.disable = "TRUE"
isolation.tools.setVersion.disable = "TRUE"
isolation.tools.getVersion.disable = "TRUE"
monitor_control.disable_directexec = "TRUE"
monitor_control.disable_chksimd = "TRUE"
monitor_control.disable_ntreloc = "TRUE"
monitor_control.disable_selfmod = "TRUE"
monitor_control.disable_reloc = "TRUE"
monitor_control.disable_btinout = "TRUE"
monitor_control.disable_btmemspace = "TRUE"
monitor_control.disable_btpriv = "TRUE"
monitor_control.disable_btseg = "TRUE"
Now start your virtual machine. This will allow you to run (with very little effort) more vmware-aware malware than before.
I'll point out that:
monitor_control.disable_directexec = "TRUE"
will usually thwart descriptor table registers checks. This setting will make VMware interpret each assembly instruction instead of executing them directly on the processor. Therefore a the result of a sidt instruction will not be an address in the0xffXXXXXX
range as one would get without this setting.isolation.tools.getVersion.disable = "TRUE"
will thwart the backdoor I/O check.
Now, what if after all this, your piece of malware still detects that it is being run in a virtual machine? I would go through the code, find where virtual machine checks are being performed and patch the code with NOPs (0x90).
Finally, if that's too hard or not possible for whatever reason, run your sample on a native system! :-) (you can always use system backup and restore software to quickly revert the machine to its original state without reinstalling the OS)