Evasions: Global OS Objects
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:
- VMDE project on github
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.