Back to main page

Contents

Global objects detection methods
1. Check for specific global mutexes
2. Check for specific virtual devices
3. Check for specific global pipes
4. Check for specific global objects
5. Check for specific object directory (Sandboxie only)
6. Check if virtual registry is present in system (Sandboxie only)
Countermeasures
Credits

Global objects detection methods

The principle of all the global objects detection methods is the following: there are no such objects in usual host; however they exist in particular virtual environments and sandboxes. Virtual environment may be detected if such an artifact is present.


1. Check for specific global mutexes

This method checks for particular mutexes which are present in virtual environments but not in usual host systems.

Functions used:

  • CreateMutexA/W
  • OpenMutexA/W

Code sample

// usage sample:
supMutexExist(L"Sandboxie_SingleInstanceMutex_Control"); // sample value from the table below


BOOL supMutexExist(_In_ LPWSTR lpMutexName)
{
    DWORD dwError;
    HANDLE hObject = NULL;
    if (lpMutexName == NULL) {
        return FALSE;
    }

    SetLastError(0);
    hObject = CreateMutex(NULL, FALSE, lpMutexName); // define around A or W function version
    dwError = GetLastError();

    if (hObject) {
        CloseHandle(hObject);
    }

    return (dwError == ERROR_ALREADY_EXISTS);
}

Credits for this code sample: VMDE project


Signature recommendations

If the following function contains 3rd argument from the table column `Name`:

  • CreateMutexA/W(..., ..., registry_path)
  • OpenMutexA/W(..., ..., registry_path)

then it’s an indication of application trying to use the evasion technique.


Detections table

Check if the following global mutexes exist:
Detect Name
DeepFreeze Frz_State
Sandboxie Sandboxie_SingleInstanceMutex_Control
SBIE_BOXED_ServiceInitComplete_Mutex1
VirtualPC MicrosoftVirtualPC7UserServiceMakeSureWe'reTheOnlyOneMutex


Note: DeepFreeze is an application restoring the system on each reboot.


2. Check for specific virtual devices

This method checks for particular virtual devices which are present in virtual environments but not in usual host systems.

Function used:

  • NtCreateFile

Code sample

// usage sample:
HANDLE hDummy = NULL;
supOpenDevice(L"\\Device\\Null", GENERIC_READ, &hDummy); // sample values from the table below


BOOL supOpenDevice(
    _In_ LPWSTR lpDeviceName,
    _In_ ACCESS_MASK DesiredAccess,
    _Out_opt_ PHANDLE phDevice)
{
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK iost;
    UNICODE_STRING uDevName;
    HANDLE hDevice;
    NTSTATUS Status;

    if (phDevice) {
        *phDevice = NULL;
    }
    if (lpDeviceName == NULL) {
        return FALSE;
    }

    hDevice = NULL;
    RtlSecureZeroMemory(&uDevName, sizeof(uDevName));
    RtlInitUnicodeString(&uDevName, lpDeviceName);
    InitializeObjectAttributes(&attr, &uDevName, OBJ_CASE_INSENSITIVE, 0, NULL);

    Status = NtCreateFile(&hDevice, DesiredAccess, &attr, &iost, NULL, 0,
        0, FILE_OPEN, 0, NULL, 0);
    if (NT_SUCCESS(Status)) {
        if (phDevice != NULL) {
            *phDevice = hDevice;
        }
    }

    return NT_SUCCESS(Status);
}

Credits for this code sample: VMDE project


Signature recommendations

If the following function contains 3rd argument with its field `ObjectName->Buffer` from the table column `Name`:

  • NtCreateFile(..., ..., attr, ...)

then it’s an indication of application trying to use the evasion technique.


3rd argument is of the following type:

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;

Detections table

Check if the following virtual devices exist:
Detect Path
VirtualBox \\.\VBoxMiniRdDN
\\.\VBoxMiniRdrDN
\\.\VBoxGuest
\\.\VBoxTrayIPC
\\.\VBoxMouse
\\.\VBoxVideo
VMWare \\.\HGFS
\\.\vmci


3. Check for specific global pipes

Pipes are just a particular case of virtual devices, please refer to the previous section for code sample and signature recommendations.


Detections table

Check if the following global pipes exist:
Detect String
VirtualBox \\.\pipe\VBoxMiniRdDN
\\.\pipe\VBoxTrayIPC


4. Check for global objects

This method checks for particular global objects which are present in virtual environments but not in usual host systems.

Functions used:

  • NtOpenDirectoryObject
  • NtQueryDirectoryObject

Code sample

// usage sample:
supIsObjectExists(L"\\Driver", L"SbieDrv"); // sample values from the table below


typedef struct _OBJECT_DIRECTORY_INFORMATION {
    UNICODE_STRING Name;
    UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;

BOOL supIsObjectExists(
    _In_ LPWSTR RootDirectory,
    _In_ LPWSTR ObjectName)
{
    OBJSCANPARAM Param;
    if (ObjectName == NULL) {
        return FALSE;
    }

    Param.Buffer = ObjectName;
    Param.BufferSize = (ULONG)_strlen_w(ObjectName);

    return NT_SUCCESS(supEnumSystemObjects(RootDirectory, NULL, supDetectObjectCallback, &Param));
}

NTSTATUS NTAPI supDetectObjectCallback(
    _In_ POBJECT_DIRECTORY_INFORMATION Entry,
    _In_ PVOID CallbackParam)
{
    POBJSCANPARAM Param = (POBJSCANPARAM)CallbackParam;
    if (Entry == NULL) {
        return STATUS_INVALID_PARAMETER_1;
    }
    if (CallbackParam == NULL) {
        return STATUS_INVALID_PARAMETER_2;
    }
    if (Param->Buffer == NULL || Param->BufferSize == 0) {
        return STATUS_MEMORY_NOT_ALLOCATED;
    }
    if (Entry->Name.Buffer) {
        if (_strcmpi_w(Entry->Name.Buffer, Param->Buffer) == 0) {
            return STATUS_SUCCESS;
        }
    }

    return STATUS_UNSUCCESSFUL;
}

NTSTATUS NTAPI supEnumSystemObjects(
    _In_opt_ LPWSTR pwszRootDirectory,
    _In_opt_ HANDLE hRootDirectory,
    _In_ PENUMOBJECTSCALLBACK CallbackProc,
    _In_opt_ PVOID CallbackParam)
{
    BOOL cond = TRUE;
    ULONG ctx, rlen;
    HANDLE hDirectory = NULL;
    NTSTATUS status;
    NTSTATUS CallbackStatus;
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING sname;
    POBJECT_DIRECTORY_INFORMATION objinf;

    if (CallbackProc == NULL) {
        return STATUS_INVALID_PARAMETER_4;
    }
    status = STATUS_UNSUCCESSFUL;
    
    __try {
        // We can use root directory.
        if (pwszRootDirectory != NULL) {
            RtlSecureZeroMemory(&sname, sizeof(sname));
            RtlInitUnicodeString(&sname, pwszRootDirectory);
            InitializeObjectAttributes(&attr, &sname, OBJ_CASE_INSENSITIVE, NULL, NULL);

            status = NtOpenDirectoryObject(&hDirectory, DIRECTORY_QUERY, &attr);
            if (!NT_SUCCESS(status)) {
                return status;
            }
        }
        else {
            if (hRootDirectory == NULL) {
                return STATUS_INVALID_PARAMETER_2;
            }
            hDirectory = hRootDirectory;
        }

        // Enumerate objects in directory.
        ctx = 0;
        do {
            rlen = 0;
            status = NtQueryDirectoryObject(hDirectory, NULL, 0, TRUE, FALSE, &ctx, &rlen);
            if (status != STATUS_BUFFER_TOO_SMALL)
                    break;
            objinf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, rlen);
            if (objinf == NULL)
                break;
                
            status = NtQueryDirectoryObject(hDirectory, objinf, rlen, TRUE, FALSE, &ctx, &rlen);
            if (!NT_SUCCESS(status)) {
                HeapFree(GetProcessHeap(), 0, objinf);
                break;
            }

            CallbackStatus = CallbackProc(objinf, CallbackParam);
            HeapFree(GetProcessHeap(), 0, objinf);
            if (NT_SUCCESS(CallbackStatus)) {
                status = STATUS_SUCCESS;
                break;
            }
        } while (cond);

        if (hDirectory != NULL) {
            NtClose(hDirectory);
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        status = STATUS_ACCESS_VIOLATION;
    }

    return status;
}

Credits for this code sample: VMDE project


Detections table

Check if the following global objects exist:
Detect Path Object
Hyper-V VmGenerationCounter \Device
Parallels prl_pv \Device
prl_tg \Device
prl_time \Device
Sandboxie SandboxieDriverApi \Device
SbieDrv \Driver
SbieSvcPort \RPC Control
VirtualBox VBoxGuest \Device
VBoxMiniRdr \Device
VBoxVideo \Driver
VBoxMouse \Driver
VirtualPC VirtualMachineServices \Device
1-driver-vmsrvc \Driver
VMWare vmmemctl \Device


5. Check for object directory (Sandboxie only)

This method checks for particular object directory which is present in Sandboxie virtual environment but not in usual host systems.

Function used:

  • GetFileAttributes

Code sample

#define DIRECTORY_QUERY (0x0001)
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define DIRECTORY_SANDBOXIE L"\\Sandbox"

int check_if_obj_dir_present() {
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING ustrName;
    HANDLE hObject = NULL;

    RtlSecureZeroMemory(&ustrName, sizeof(ustrName));
    RtlInitUnicodeString(&ustrName, DIRECTORY_SANDBOXIE);
    InitializeObjectAttributes(&attr, &ustrName, OBJ_CASE_INSENSITIVE, NULL, NULL);

    if (NT_SUCCESS(NtOpenDirectoryObject(&hObject, DIRECTORY_QUERY, &attr))) {
        NtClose(hObject);
        return TRUE;
    }
    
    return FALSE;
}

Credits for this code sample: VMDE project


Signature recommendations

If the following function contains 3rd argument with its field "ObjectName->Buffer" from the table column `Name`:

  • NtOpenDirectoryObject(..., ..., attr, ...)

then it’s an indication of application trying to use the evasion technique.


3rd argument is of the following type:

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;

Detections table

Check if the following object directory exists:
Detect Path
Sandboxie \Sandbox


6. Check if virtual registry is present in OS (Sandboxie only)

This method checks for virtual registry which is present in Sandboxie virtual environment but not in usual host systems.

Application opens registry key \REGISTRY\USER. It uses the following function in order to check real object name:

NtQueryObject(
    hUserKey,
    ObjectNameInformation,
    oni, // OBJECT_NAME_INFORMATION object
    Size,
    NULL);

If received OBJECT_NAME_INFORMATION object name does not equal to the "\REGISTRY\USER", then application assumes that it runs inside Sandboxie environment.


Signature recommendations

If the following function is used for opening \REGISTRY\USER:

  • NtOpenKey

and is followed by the call of the following function with its 1st argument being the handle of \REGISTRY\USER key:

  • NtQueryObject(hUserKey, ...)

then it’s an indication of application trying to use the evasion technique.


Countermeasures

Hook target functions and return appropriate results if indicators (objects from tables) are triggered. In some cases stopping appropriate device may help — but it’s not a universal counter-action: not all global objects are devices.


Credits

Credits go to open-source project from where code samples were taken:

Though Check Point tool InviZzzible has them all implemented, due to modular structure of the code it would require more space to show a code sample from this tool for the same purposes. That’s why we’ve decided to use other great open-source projects for examples throughout the encyclopedia.


Back to main page