Hardening Cuckoo Sandbox against VM aware malware

December 19, 2012  |  Alberto Ortega

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 HKLMHARDWAREDEVICEMAPScsiScsi Port 0Scsi Bus 0Target Id 0Logical Unit Id 0 "Identifier"

[pafish] VirtualBox traced using Reg key HKLMHARDWAREDescriptionSystem "SystemBiosVersion"

[pafish] VirtualBox traced using Reg key HKLMSOFTWAREOracleVirtualBox Guest Additions

[pafish] VirtualBox traced using file C:WINDOWSsystem32driversVBoxMouse.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->HARDWAREDEVICEMAPScsiScsi Port 0Scsi Bus 0Target Id 0Logical 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->HARDWAREDescriptionSystem","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->SOFTWAREOracleVirtualBox 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:WINDOWSsystem32driversVBoxMouse.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.

Share this with others

Get price Free trial