Global OS object H FileSystem Registry Generic OS Queries Global OS object UI artifacts OS Features Processes Network CPU Hardware Firmware tables Hooks Timing WMI Human-like behavior macOS
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.
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.
This method checks for particular virtual devices which are present in virtual environments but not in usual host systems.
Function used:
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
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
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
This method checks for particular object directory which is present in Sandboxie virtual environment but not in usual host systems.
Function used:
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
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 :
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.
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 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.