AlienVault R&D Labs Portal. Get the latest news from our research.
Header

Hardening Cuckoo Sandbox against VM aware malware

December 19th, 2012 | Posted by Alberto Ortega in Code | Malware | Windows - (Comments Off)

Some time ago, we wrote a post about how a lot of malware samples check the execution environment, and if it is unwanted (VM, debugger, sandbox, …) the execution unexpectedly finishes.

We use Cuckoo Sandbox in the lab for our analysis tasks, we really love how customizable it is.

Sometimes we have to deal with malware aware of the execution environment, and this is a problem when you are using public virtualization products. Let’s see how modifying some parts of cuckoo we are able to fake crucial parts of the system to the malware sample, so it will not be able to detect the VM (in this case, VirtualBox).

Pafish will help us to test our work, it is a demo tool that performs some anti(debugger/VM/sandbox) tricks, most of them often used by malware. When it is executed, it writes a log with the successful detections, so we can easily track and solve them.

To monitor the malware activity, cuckoo executes the sample with cuckoomon, the part responsible of hooking system calls to save the malware actions. With this powerful hooking system, we can modify the hooks to return fake responses if we do not like the call. For example, calls to check files / registry keys / processes to detect the VM.

When we execute pafish for the first time, it will detect VirtualBox using different tricks:

[pafish] Start
[pafish] Windows version: 5.1 build 2600
[pafish] Sandbox traced using mouse activity
[pafish] VirtualBox traced using Reg key HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0 "Identifier"
[pafish] VirtualBox traced using Reg key HKLM\HARDWARE\Description\System "SystemBiosVersion"
[pafish] VirtualBox traced using Reg key HKLM\SOFTWARE\Oracle\VirtualBox Guest Additions
[pafish] VirtualBox traced using file C:\WINDOWS\system32\drivers\VBoxMouse.sys
[pafish] End

As we can see, it has detected our VM by reading some registry keys and looking for a file.

The piece of code responsible of hook RegOpenKeyExA (the call used by the detection) is this one (hook_reg.c):

HOOKDEF(LONG, WINAPI, RegOpenKeyExA,
  __in        HKEY hKey,
  __in_opt    LPCTSTR lpSubKey,
  __reserved  DWORD ulOptions,
  __in        REGSAM samDesired,
  __out       PHKEY phkResult
) {
    LONG ret = Old_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired,
        phkResult);
    LOQ("psP", "Registry", hKey, "SubKey", lpSubKey, "Handle", phkResult);
    return ret;
}

So we can modify it:

/* Hardened */
HOOKDEF(LONG, WINAPI, RegOpenKeyExA,
  __in        HKEY hKey,
  __in_opt    LPCTSTR lpSubKey,
  __reserved  DWORD ulOptions,
  __in        REGSAM samDesired,
  __out       PHKEY phkResult
) {
    LONG ret;
    if (strstr(lpSubKey, "VirtualBox") != NULL) {
        ret = 1;
        LOQ("s", "Hardening", "Faked RegOpenKeyExA return");
    }
    else if (strstr(lpSubKey, "ControlSet") != NULL) {
        ret = 1;
        LOQ("s", "Hardening", "Faked RegOpenKeyExA return");
    }
    else {
        ret = Old_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired,
            phkResult);
    }
    LOQ("psP", "Registry", hKey, "SubKey", lpSubKey, "Handle", phkResult);
    return ret;
}

We have changed the code to check if “VirtualBox” or “ControlSet” is in the provided SubKey to read. If it is, we will log a Hardening warning in cuckoo log and fake the response.

We have to do the same with RegQueryValueExA:

HOOKDEF(LONG, WINAPI, RegQueryValueExA,
  __in         HKEY hKey,
  __in_opt     LPCTSTR lpValueName,
  __reserved   LPDWORD lpReserved,
  __out_opt    LPDWORD lpType,
  __out_opt    LPBYTE lpData,
  __inout_opt  LPDWORD lpcbData
) {
    LONG ret = Old_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType,
        lpData, lpcbData);
    LOQ("psLB", "Handle", hKey, "ValueName", lpValueName,
        "Type", lpType, "Buffer", lpcbData, lpData);
    return ret;
}

We change it to:

/* Hardened */
HOOKDEF(LONG, WINAPI, RegQueryValueExA,
  __in         HKEY hKey,
  __in_opt     LPCTSTR lpValueName,
  __reserved   LPDWORD lpReserved,
  __out_opt    LPDWORD lpType,
  __out_opt    LPBYTE lpData,
  __inout_opt  LPDWORD lpcbData
) {
    LONG ret;
    if (strstr(lpValueName, "SystemBiosVersion") != NULL) {
        ret = ERROR_SUCCESS;
        LOQ("s", "Hardening", "Faked RegQueryValueExA return");
    }
    else if (strstr(lpValueName, "Identifier") != NULL) {
        ret = ERROR_SUCCESS;
        LOQ("s", "Hardening", "Faked RegQueryValueExA return");
    }
    else if (strstr(lpValueName, "ProductId") != NULL) {
        ret = ERROR_SUCCESS;
        LOQ("s", "Hardening", "Faked RegQueryValueExA return");
    }
    else {
        ret = Old_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType,
            lpData, lpcbData);
    }
    LOQ("psLB", "Handle", hKey, "ValueName", lpValueName,
        "Type", lpType, "Buffer", lpcbData, lpData);
    return ret;
}

If the malware sample tries to read a registry key with “SystemBiosVersion“, “Identifier” or “ProductId” in the value name, it will fail.

With these two changes, we have covered the two registry keys detections done by pafish. Then we have to change the call used to access the files.

The call used is GetFileAttributesA, which is not hooked by default, so we add it (hook_file.c):

/* Hardened */
HOOKDEF(DWORD, WINAPI, GetFileAttributesA,
  __in      LPCTSTR lpFileName
) {
    BOOL ret;
    if (strstr(lpFileName, "VBox") != NULL) {
        ret = INVALID_FILE_ATTRIBUTES;
        LOQ("s", "Hardening", "Faked GetFileAttributesA return");
    }
    else {
        ret = Old_GetFileAttributesA(lpFileName);
    }
    LOQ("s", "GetFileAttributesA", lpFileName);
    return ret;
}

After that, we have to compile our new cuckoomon.dll and replace the original.

You can find it in cuckoo/analyzer/windows/dll/cuckoomon.dll, you can replace it while cuckoo is running, no need to stop it.

And we are done, we have placed some measures to disallow the samples to detect our VM by using these functions. We can execute pafish again with our new cuckoomon.dll to check the results:

[pafish] Start
[pafish] Windows version: 5.1 build 2600
[pafish] Sandbox traced using mouse activity
[pafish] End

It only traced our VM by using the mouse activity, we could hook that too. We can also take a look at cuckoo log to see the responses faked by our hardened monitor:

"pafish.exe","620","532","registry","RegOpenKeyExA","SUCCESS","0x00000000","Registry->0x80000002","SubKey->HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0","Handle->0x0000003c"
"pafish.exe","620","532","registry","RegQueryValueExA","SUCCESS","0x00000000","Hardening->Faked RegQueryValueExA return"
"pafish.exe","620","532","registry","RegQueryValueExA","SUCCESS","0x00000000","Handle->0x0000003c","ValueName->Identifier","Type->0","Buffer->0x0022f64c"
"pafish.exe","620","532","registry","RegOpenKeyExA","SUCCESS","0x00000000","Registry->0x80000002","SubKey->HARDWARE\Description\System","Handle->0x00000040"
"pafish.exe","620","532","registry","RegQueryValueExA","SUCCESS","0x00000000","Hardening->Faked RegQueryValueExA return"
"pafish.exe","620","532","registry","RegQueryValueExA","SUCCESS","0x00000000","Handle->0x00000040","ValueName->SystemBiosVersion","Type->0","Buffer->0x0022f64c"
"pafish.exe","620","532","registry","RegOpenKeyExA","FAILURE","0x00000001","Hardening->Faked RegOpenKeyExA return"
"pafish.exe","620","532","registry","RegOpenKeyExA","FAILURE","0x00000001","Registry->0x80000002","SubKey->SOFTWARE\Oracle\VirtualBox Guest Additions","Handle->0x77c05c94"
"pafish.exe","620","532","filesystem","GetFileAttributesA","FAILURE","0xffffffff","Hardening->Faked GetFileAttributesA return"
"pafish.exe","620","532","filesystem","GetFileAttributesA","FAILURE","0xffffffff","GetFileAttributesA->C:\WINDOWS\system32\drivers\VBoxMouse.sys"

It is quite difficult to cover all functions used by malware to detect VMs, but with modifications in some common functions we can cover ~90% of the cases.

You can download the modifications made in this post from here, it is a patch compatible with the last stable version of the software. You can also download the compiled library, ready to use in your cuckoo installation.

It is well known that a big amount of malware samples are aware of the execution environment. This means that a malware sample can change his behavior if it detects that the running environment is unwanted.

There are resources, public source code, and even programs that detail how to bypass automatic malware analysis systems and make things awkward for malware researchers. Of course, these resources are quite useful for both researchers and malware developers.

We are going to take a look at some of these tricks, all found in real malware samples.

Also, just as they do, we have developed some yara signatures to detect these tricks that could be useful to differently process or classify these malware samples.

We could classify anti analysis tricks in three big groups:

- Anti Virtual Machine, that tries to detect if the execution environment is a known VM or emulator.
- Anti Debugging, that tries to detect if the program is running under the surveillance of a debugger.
- Anti Sandbox, that tries to detect known sandboxing products.

It is not unusual to find all kind of tricks in just one malware sample. For example, we can take a look at the sample 9255c75de8fbc20ee67f427397e1ef82:

Quickly we can find that it is looking for sbiedll.dll (to detect Sandboxie) and dbghelp.dll

It also opens the registry key HKLM\SYSTEM\ControlSet001\Services\Disk\Enum with value 0 to read the ID of the hard disk in the machine:

Then it is compared with these three strings (VIRTUAL, VMWARE, VBOX):

Finally, it opens the registry key HKLM\Software\Microsoft\Windows\CurrentVersion with value ProductId:

And checks it against these three known MS Windows products ID from different commercial sandboxes:

If we take a look at another sample (36527d5954bf3b2af60e6efa6398ccff), we will discover a canonical function to check this:

It checks the MS Windows product ID and if it is “76487-644-3177037-23510″, the function will return 1. Else, it will return 0. It also has the same function prototype to check keys “55274-640-2673064-23950″ and “76487-337-8429955-22614″.

This sample also uses MS Windows system functions to detect debugging.

It loads the function handler for IsDebuggerPresent using the function GetProcAddress() from kernel32.dll. Hey wait! And why not use IsDebuggerPresent() directly? Because it is noisy and easily detectable.

If it can not load the function or the function returns 0 (debugger not present), it will return 0. Else, it will return nonzero.

It also looks for files (SyserDbgMsg / SyserBoot) and (SICE / NTICE) using this function:

This trick is to detect both SyserDebugger and SoftICE debuggers.

As we said, we have published a ruleset of yara signatures to detect AntiVM, AntiDebugger and AntiSandbox procedures in malware samples. You can grab it in our GitHub repository here.