全局操作系统对象

描述

全局操作系统对象检测方法的原理是普通主机中不存在此类对象,因为此类对象只存在于特定的虚拟环境和沙箱中。如果存在这样的对象,则证明是虚拟环境。

1.热键

恶意软件可以设置热键,如果用户没有触发热键则不运行,以避免被虚拟机或沙盒环境检测。
以RegisterHotKey函数为例:
#include <windows.h>
#include <stdio.h>

// 定义一个常量存储热键的标识符
const int HOTKEY_ID = 1;

// 定义一个常量存储规定时间(毫秒)
const DWORD TIME_LIMIT = 5000;

// 定义一个窗口过程函数,用于处理WM_HOTKEY消息
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // 判断是否为WM_HOTKEY消息
    if (uMsg == WM_HOTKEY)
    {
        // 判断是否为指定的热键
        if (wParam == HOTKEY_ID)
        {
            // 如果是指定的热键,运行恶意代码
            printf("The hotkey 'ALT+B' is pressed, executing.\n");
            // 这里插入恶意代码,比如显示一个弹窗消息
            MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
            return 0;
        }
    }

    // 调用默认的窗口过程函数处理其他消息
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int main()
{
    // 注册一个窗口类
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"HotKeyWindowClass";
    RegisterClass(&wc);

    // 创建一个隐藏的窗口,用于接收WM_HOTKEY消息
    HWND hWnd = CreateWindowEx(0, L"HotKeyWindowClass", L"HotKeyWindow", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);

    // 如果成功,继续执行
    if (hWnd != NULL)
    {
        // 调用RegisterHotKey函数注册热键“Alt+b”,并使用MOD_NOREPEAT标志避免重复触发
        BOOL result = RegisterHotKey(hWnd, HOTKEY_ID, MOD_ALT | MOD_NOREPEAT, 0x42); // 0x42 is 'b'

        // 如果成功,继续执行
        if (result)
        {
            // 打印提示信息
            printf("Hotkey 'ALT+B' registered, using MOD_NOREPEAT flag\n");
            // 定义一个变量存储开始时间
            DWORD startTime = GetTickCount();

            // 定义一个变量存储结束时间
            DWORD endTime;

            // 定义一个变量存储是否触发的标志
            BOOL triggered = FALSE;

            // 循环处理消息
            MSG msg = { 0 };
            while (GetMessage(&msg, NULL, 0, 0) != 0)
            {
                // 转换和分发消息
                TranslateMessage(&msg);
                DispatchMessage(&msg);

                // 判断是否为WM_HOTKEY消息
                if (msg.message == WM_HOTKEY)
                {
                    // 如果是WM_HOTKEY消息,设置触发标志为真,并退出循环
                    triggered = TRUE;
                    break;
                }

                // 获取当前时间
                endTime = GetTickCount();

                // 判断是否超过规定时间
                if (endTime - startTime > TIME_LIMIT)
                {
                    // 如果超过规定时间,退出循环
                    break;
                }
            }
            // 判断是否触发了热键
            if (triggered)
            {
                // 如果触发了热键,打印提示信息,并注销热键
                printf("The hotkey was triggered within %d milliseconds.\n", TIME_LIMIT);
                UnregisterHotKey(hWnd, HOTKEY_ID);
            }
            else
            {
                // 如果没有触发热键,不运行恶意代码,并注销热键
                printf("The hotkey was not triggered within %d milliseconds, aborting.\n", TIME_LIMIT);
                UnregisterHotKey(hWnd, HOTKEY_ID);
                return 0;
            }
        }
        else
        {
            // 如果失败,打印错误信息
            printf("RegisterHotKey failed with error %d\n", GetLastError());
            return -1;
        }
    }
    else
    {
        // 如果失败,打印错误信息
        printf("CreateWindowEx failed with error %d\n", GetLastError());
        return -1;
    }
}

2.检查特定的全局互斥体

恶意软件可以检查是否存在特定的全局互斥体,如果存在则不运行,以避免被虚拟机或沙盒环境检测。
检查以下互斥体是否存在:
探测互斥体
DeepFreezeFrz_State
SandboxieSandboxie_SingleInstanceMutex_Control
SBIE_BOXED_ServiceInitComplete_Mutex1
VirtualPC MicrosoftVirtualPC7UserServiceMakeSureWe'reTheOnlyOneMutex
以CreateMutexA/W函数为例:
#include <windows.h>
#include <stdio.h>

int main()
{
// 定义一个常量存储要检查的全局互斥体的名称
const char* MUTEX_NAME = "Global\\Sandboxie_SingleInstanceMutex_Control";

    // 调用CreateMutexA函数创建或打开全局互斥体
    HANDLE hMutex = CreateMutexA(NULL, FALSE, MUTEX_NAME);

    // 如果成功,继续执行
    if (hMutex != NULL)
    {
        // 打印提示信息
        printf("CreateMutexA succeeded\n");

        // 获取错误代码
        DWORD dwError = GetLastError();
        // 判断是否为ERROR_ALREADY_EXISTS
        if (dwError == ERROR_ALREADY_EXISTS)
        {
            // 如果是ERROR_ALREADY_EXISTS,说明全局互斥体已经存在,不运行恶意代码,并关闭句柄
            printf("The mutex '%s' already exists, aborting.\n", MUTEX_NAME);
            CloseHandle(hMutex);
            return 0;
        }
        else
        {
            // 如果不是ERROR_ALREADY_EXISTS,说明全局互斥体不存在,运行恶意代码,并关闭句柄
            printf("The mutex '%s' does not exist, executing.\n", MUTEX_NAME);
            // 这里插入恶意代码,比如显示一个弹窗消息
            MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
            CloseHandle(hMutex);
        }
    }
    else
    {
        // 如果失败,打印错误信息
        printf("CreateMutexA failed with error %d\n", GetLastError());
        return -1;
    }
}
以OpenMutexA/W函数为例:
#include <windows.h>
#include <stdio.h>

int main() {
    // 定义一个常量存储要检查的全局互斥体的名称
    const char* MUTEX_NAME = "Global\\Sandboxie_SingleInstanceMutex_Control";

    // 调用OpenMutexA函数打开全局互斥体
    HANDLE hMutex = OpenMutexA(SYNCHRONIZE, FALSE, MUTEX_NAME);

    // 如果成功,继续执行
    if (hMutex != NULL)
    {
        // 打印提示信息
        printf("OpenMutexA succeeded\n");
        // 说明全局互斥体已经存在,不运行恶意代码,并关闭句柄
        printf("The mutex '%s' already exists, aborting.\n", MUTEX_NAME);
        CloseHandle(hMutex);
        return 0;
    }
    else
    {
        // 如果失败,获取错误代码
        DWORD dwError = GetLastError();

        // 判断是否为ERROR_FILE_NOT_FOUND
        if (dwError == ERROR_FILE_NOT_FOUND)
        {
            // 如果是ERROR_FILE_NOT_FOUND,说明全局互斥体不存在,运行恶意代码
            printf("The mutex '%s' does not exist, executing.\n", MUTEX_NAME);
            // 这里插入恶意代码,比如显示一个弹窗消息
            MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
        }
        else
        {
            // 如果不是ERROR_FILE_NOT_FOUND,打印错误信息
            printf("OpenMutexA failed with error %d\n", dwError);
            return -1;
        }
    }
}

3.检查特定的虚拟设备

恶意软件可以检查主机系统是否存在特定的虚拟设备,例如VMware或VirtualBox的驱动程序或硬件标识符。如果存在,恶意软件可以选择不运行或执行其他的逃逸或免杀技术。
检查是否存在以下虚拟设备:
探测路径
VirtualBox\\.\VBoxMiniRdDN
\\.\VBoxMiniRdrDN
\\.\VBoxGuest
\\.\VBoxTrayIPC
\\.\VBoxMouse
\\.\VBoxVideo
VMware\\.\HGFS
\\.\vmci
以NtCreateFile函数为例:
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include <ntstatus.h>
// 定义NtCreateFile函数的类型
typedef NTSTATUS(WINAPI* NTCREATEFILE)(
    PHANDLE FileHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PIO_STATUS_BLOCK IoStatusBlock,
    PLARGE_INTEGER AllocationSize,
    ULONG FileAttributes,
    ULONG ShareAccess,
    ULONG CreateDisposition,
    ULONG CreateOptions,
    PVOID EaBuffer,
    ULONG EaLength
    );

// 定义一些常量
#define FILE_OPEN 0x00000001
#define FILE_NON_DIRECTORY_FILE 0x00000040
#define OBJ_CASE_INSENSITIVE 0x00000040L
// 定义一个结构体来存储虚拟设备的名称和标识符
typedef struct _VIRTUAL_DEVICE {
    LPCWSTR DeviceName; // 设备名称,如"\\Device\\VBoxMiniRdrDN"
    LPCWSTR DeviceID; // 设备标识符,如"VBOX"
} VIRTUAL_DEVICE, * PVIRTUAL_DEVICE;

// 定义一个数组来存储要检测的虚拟设备
VIRTUAL_DEVICE VirtualDevices[] = {
    {L"\\Device\\VBoxMiniRdrDN", L"VBOX"},
    {L"\\Device\\vmci", L"VMWARE"},
    {L"\\Device\\HGFS", L"VMWARE"},
    {L"\\Device\\QEMUVP", L"QEMU"},
    {NULL, NULL} // 结束标志
};

// 获取NtCreateFile函数的地址
NTCREATEFILE NtCreateFile = (NTCREATEFILE)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateFile");

// 检查虚拟设备是否存在
BOOL CheckVirtualDevice(PVIRTUAL_DEVICE vd)
{
    HANDLE hFile;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING us;
    IO_STATUS_BLOCK isb;

    // 初始化UNICODE_STRING结构体
    RtlInitUnicodeString(&us, vd->DeviceName);

    // 初始化OBJECT_ATTRIBUTES结构体
    oa.Length = sizeof(oa);
    oa.RootDirectory = NULL;
    oa.ObjectName = &us;
    oa.Attributes = OBJ_CASE_INSENSITIVE;
    oa.SecurityDescriptor = NULL;
    oa.SecurityQualityOfService = NULL;
    // 调用NtCreateFile函数尝试打开虚拟设备
    NTSTATUS status = NtCreateFile(&hFile, SYNCHRONIZE | FILE_READ_DATA, &oa, &isb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);

    // 如果成功打开,则关闭句柄并返回TRUE,否则返回FALSE
    if (status == STATUS_SUCCESS)
    {
        CloseHandle(hFile);
        return TRUE;
    }

    return FALSE;
}

// 主函数
int main()
{
    // 遍历要检测的虚拟设备数组
    for (int i = 0; VirtualDevices[i].DeviceName != NULL; i++)
    {
        // 如果检测到虚拟设备,则输出其名称和标识符,并退出程序
        if (CheckVirtualDevice(&VirtualDevices[i]))
        {
            wprintf(L"Detected virtual device: %s (%s)\n", VirtualDevices[i].DeviceName, VirtualDevices[i].DeviceID);
            ExitProcess(0);
        }
    }

    // 如果没有检测到虚拟设备,则输出正常信息,并继续运行
    wprintf(L"No virtual device detected.\n");
    // 这里插入恶意代码,比如显示一个弹窗消息
    MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);

    return 0;
}

4.检查特定全局管道

管道只是虚拟设备的一种特殊情况,通常为VirtualBox特有的两个路径:
\.\pipe\VBoxMiniRdDN
\.\pipe\VBoxTrayIPC

以NtCreateFile函数为例:
// 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);
}

5.检查全局对象

恶意软件可以检查主机系统是否存在特定的全局对象,例如VMware或VirtualBox的虚拟机标识符。如果存在,恶意软件可以选择不运行或执行其他的逃逸或免杀技术。
需要检查的全局对象如下:
探测路径
Hyper-VVmGenerationCounter
Parallelsprl_pv
prl_tg
prl_time
SandboxieSandboxieDriverApi
SbieDrv
SbieSvcPort
VirtualBoxVBoxGuest
VBoxMiniRdr
VBoxVideo VBoxMouse
VirtualPC VirtualMachineServices
1-driver-vmsrvc
VMwarevmmemctl
以NtOpenDirectoryObject函数为例:
#include <windows.h>
#include <winternl.h>
#include <stdio.h>

// 定义NtOpenDirectoryObject函数的类型
typedef NTSTATUS(WINAPI* NTOPENDIRECTORYOBJECT)(
    PHANDLE DirectoryHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes
    );

// 定义一些常量
#define DIRECTORY_QUERY 0x0001
#define OBJ_CASE_INSENSITIVE 0x00000040L

// 定义一个结构体来存储全局对象的名称和标识符
typedef struct _GLOBAL_OBJECT {
    LPCWSTR ObjectName; // 全局对象名称,如"\\GLOBAL??\\VBoxMiniRdrDN"
    LPCWSTR ObjectID; // 全局对象标识符,如"VBOX"
} GLOBAL_OBJECT, * PGLOBAL_OBJECT;
// 定义一个数组来存储要检测的全局对象
GLOBAL_OBJECT GlobalObjects[] = {
    {L"\\GLOBAL??\\VBoxMiniRdrDN", L"VBOX"},
    {L"\\GLOBAL??\\vmci", L"VMWARE"},
    {L"\\GLOBAL??\\HGFS", L"VMWARE"},
    {L"\\GLOBAL??\\QEMUVP", L"QEMU"},
    {NULL, NULL} // 结束标志
};

// 获取NtOpenDirectoryObject函数的地址
NTOPENDIRECTORYOBJECT NtOpenDirectoryObject = (NTOPENDIRECTORYOBJECT)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtOpenDirectoryObject");

// 检查全局对象是否存在
BOOL CheckGlobalObject(PGLOBAL_OBJECT go)
{
    HANDLE hDir;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING us;

    // 初始化UNICODE_STRING结构体
    RtlInitUnicodeString(&us, go->ObjectName);

    // 初始化OBJECT_ATTRIBUTES结构体
    oa.Length = sizeof(oa);
    oa.RootDirectory = NULL;
    oa.ObjectName = &us;
    oa.Attributes = OBJ_CASE_INSENSITIVE;
    oa.SecurityDescriptor = NULL;
    oa.SecurityQualityOfService = NULL;

    // 调用NtOpenDirectoryObject函数尝试打开全局对象
    NTSTATUS status = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &oa);
    // 如果成功打开,则关闭句柄并返回TRUE,否则返回FALSE
    if (status == STATUS_SUCCESS)
    {
        CloseHandle(hDir);
        return TRUE;
    }

    return FALSE;
}

// 主函数
int main()
{
    // 遍历要检测的全局对象数组
    for (int i = 0; GlobalObjects[i].ObjectName != NULL; i++)
    {
        // 如果检测到全局对象,则输出其名称和标识符,并退出程序
        if (CheckGlobalObject(&GlobalObjects[i]))
        {
            wprintf(L"Detected global object: %s (%s)\n", GlobalObjects[i].ObjectName, GlobalObjects[i].ObjectID);
            ExitProcess(0);
        }
    }

    // 如果没有检测到全局对象,则输出正常信息,并继续运行
    wprintf(L"No global object detected.\n");
    // 这里插入恶意代码,比如显示一个弹窗消息
    MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);

    return 0;
}
以NtQueryDirectoryObject函数为例:
#include <windows.h>
#include <winternl.h>
#include <stdio.h>

// 定义NtQueryDirectoryObject函数的类型
typedef NTSTATUS(WINAPI* NTQUERYDIRECTORYOBJECT)(
    HANDLE DirectoryHandle,
    PVOID Buffer,
    ULONG Length,
    BOOLEAN ReturnSingleEntry,
    BOOLEAN RestartScan,
    PULONG Context,
    PULONG ReturnLength
    );

// 定义一些常量
#define DIRECTORY_QUERY 0x0001
#define OBJ_CASE_INSENSITIVE 0x00000040L

// 定义一个结构体来存储全局对象的名称和标识符
typedef struct _GLOBAL_OBJECT {
    LPCWSTR ObjectName; // 全局对象名称,如"\\GLOBAL??\\VBoxMiniRdrDN"
    LPCWSTR ObjectID; // 全局对象标识符,如"VBOX"
} GLOBAL_OBJECT, * PGLOBAL_OBJECT;
// 定义一个数组来存储要检测的全局对象
GLOBAL_OBJECT GlobalObjects[] = {
    {L"\\GLOBAL??\\VBoxMiniRdrDN", L"VBOX"},
    {L"\\GLOBAL??\\vmci", L"VMWARE"},
    {L"\\GLOBAL??\\HGFS", L"VMWARE"},
    {L"\\GLOBAL??\\QEMUVP", L"QEMU"},
    {NULL, NULL} // 结束标志
};

// 获取NtQueryDirectoryObject函数的地址
NTQUERYDIRECTORYOBJECT NtQueryDirectoryObject = (NTQUERYDIRECTORYOBJECT)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryDirectoryObject");

// 检查全局对象是否存在
BOOL CheckGlobalObject(PGLOBAL_OBJECT go)
{
    HANDLE hDir;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING us;

    // 初始化UNICODE_STRING结构体
    RtlInitUnicodeString(&us, go->ObjectName);

    // 初始化OBJECT_ATTRIBUTES结构体
    oa.Length = sizeof(oa);
    oa.RootDirectory = NULL;
    oa.ObjectName = &us;
    oa.Attributes = OBJ_CASE_INSENSITIVE;
    oa.SecurityDescriptor = NULL;
    oa.SecurityQualityOfService = NULL;

    // 调用NtOpenDirectoryObject函数尝试打开全局对象
    NTSTATUS status = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &oa);

    // 如果成功打开,则继续查询目录对象内容
    if (status == STATUS_SUCCESS)
    {
        // 定义一个缓冲区结构体来存储目录对象信息
        typedef struct _OBJECT_DIRECTORY_INFORMATION {
            UNICODE_STRING Name;
            UNICODE_STRING TypeName;
        } OBJECT_DIRECTORY_INFORMATION, * POBJECT_DIRECTORY_INFORMATION;

        // 分配一个缓冲区大小为1024字节
        POBJECT_DIRECTORY_INFORMATION buffer = (POBJECT_DIRECTORY_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024);

        // 定义一些变量来控制查询过程
        ULONG context = 0; // 查询上下文,第一次为0,后续为返回值
        ULONG returnLength; // 返回长度
        BOOL restartScan = TRUE; // 是否重新扫描,第一次为TRUE,后续为FALSE

        // 循环查询目录对象内容,直到返回STATUS_NO_MORE_ENTRIES
        while (TRUE)
        {
            // 调用NtQueryDirectoryObject函数查询目录对象内容
            status = NtQueryDirectoryObject(hDir, buffer, 1024, TRUE, restartScan, &context, &returnLength);

            // 如果返回STATUS_NO_MORE_ENTRIES,表示查询结束,退出循环
            if (status == STATUS_NO_MORE_ENTRIES)
            {
                break;
            }

            // 如果返回STATUS_SUCCESS,表示查询成功,继续判断
            if (status == STATUS_SUCCESS)
            {
                // 比较目录对象的名称和类型是否与全局对象的标识符相同,如果相同,表示检测到全局对象,返回TRUE
                if (wcscmp(buffer->Name.Buffer, go->ObjectID) == 0 || wcscmp(buffer->TypeName.Buffer, go->ObjectID) == 0)
                {
                    return TRUE;
                }

                // 设置restartScan为FALSE,继续查询下一个目录对象
                restartScan = FALSE;
            }
        }

        // 释放缓冲区
        HeapFree(GetProcessHeap(), 0, buffer);

        // 关闭目录对象句柄
        NtClose(hDir);
    }

    // 如果没有检测到全局对象,返回FALSE
    return FALSE;
}

// 主函数
int main()
{
    // 遍历要检测的全局对象数组
    for (int i = 0; GlobalObjects[i].ObjectName != NULL; i++)
    {
        // 调用CheckGlobalObject函数检查全局对象是否存在
        BOOL result = CheckGlobalObject(&GlobalObjects[i]);
        // 打印检测结果
        printf("Checking %S: %s\n", GlobalObjects[i].ObjectName, result ? "Detected" : "Not detected");
    }

    return 0;
}

6.检查对象目录

恶意软件可以检查主机系统是否存在特定的对象目录,例如某些安全软件或虚拟机的安装目录。如果存在,恶意软件可以选择不运行或执行其他的逃逸或免杀技术。
以GetFileAttributes函数为例:
#include <windows.h>
#include <stdio.h>

#define UNICODE

// 定义一个结构体来存储对象目录的名称和属性
typedef struct _OBJECT_DIRECTORY {
    LPCWSTR DirectoryName; // 对象目录名称,如"C:\\Program Files\\VMware"
    DWORD DirectoryAttributes; // 对象目录属性,如FILE_ATTRIBUTE_DIRECTORY
} OBJECT_DIRECTORY, * POBJECT_DIRECTORY;
// 定义一个数组来存储要检测的对象目录
OBJECT_DIRECTORY ObjectDirectories[] = {
    {"C:\\Program Files\\VMware", FILE_ATTRIBUTE_DIRECTORY},
    {"C:\\Program Files\\Oracle\\VirtualBox", FILE_ATTRIBUTE_DIRECTORY},
    {"C:\\Program Files\\QEMU", FILE_ATTRIBUTE_DIRECTORY},
    {NULL, 0} // 结束标志
};
// 检查对象目录是否存在
BOOL CheckObjectDirectory(POBJECT_DIRECTORY od)
{
    // 调用GetFileAttributes函数获取对象目录的属性
    DWORD attributes = GetFileAttributes(od->DirectoryName);

    // 如果返回值为INVALID_FILE_ATTRIBUTES,表示获取失败,可能对象目录不存在或者无法访问
    if (attributes == INVALID_FILE_ATTRIBUTES)
    {
        return FALSE;
    }

    // 如果返回值与对象目录的属性相同,表示检测到对象目录,返回TRUE
    if (attributes == od->DirectoryAttributes)
    {
        return TRUE;
    }

    // 否则返回FALSE
    return FALSE;
}

7.检查虚拟注册表

此方法检查 Sandboxie 虚拟环境中存在但通常主机系统中不存在的虚拟注册表。需要检测注册表项\REGISTRY\USER,并使用NtQueryObject函数来检查真实对象名称:
NtQueryObject(
    hUserKey,
    ObjectNameInformation,
    oni, // OBJECT_NAME_INFORMATION object
    Size,
    NULL);
如果返回的OBJECT_NAME_INFORMATION对象名称不等于”\REGISTRY\USER”,则假定恶意软件在 Sandboxie 环境中运行。