飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2832|回复: 2

[病毒分析] [翻译]规避技术:全局操作系统对象

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2021-5-19 14:46:52 | 显示全部楼层 |阅读模式
    本帖最后由 梦幻的彼岸 于 2021-5-20 10:10 编辑

    备注
    原文地址:https://evasions.checkpoint.com/techniques/global-os-objects.html
    原文标题:Evasions: Global OS Objects
    更新日期:2021年5月19日
    此文后期:根据自身所学进行内容扩充
    因自身技术有限,只能尽自身所能翻译国外技术文章,供大家学习,若有不当或可完善的地方,希望可以指出,用于共同完善这篇文章。


    目录
    • 全局目标检测方法
    • 1.检查特定的全局互斥体
    • 2.检查特定的虚拟设备
    • 3.检查特定的全局管道
    • 4.检查特定的全局对象
    • 5.检查特定对象目录(仅限于沙盒)
    • 6.检查系统中是否存在虚拟注册表(仅限于沙盒)
    • 反制措施
    • 归功于

    全局目标检测方法
    所有全局对象检测方法的基本原理是:在通常的主机上没有这样的对象,但它们存在于特定的虚拟环境和沙盒中。如果存在这样的伪装,则可以检测虚拟环境。
    1.检查特定的全局互斥体
    此方法检查虚拟环境中存在但通常主机系统中不存在的特定互斥体。
    使用的函数:
    • CreateMutexA/W
    • OpenMutexA/W

    代码样本
    [C++] 纯文本查看 复制代码
    // 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);
    }

    该代码样本归功于:VMDE project
    识别标志
    如果以下函数包含表列“名称”的第3个参数:
    • CreateMutexA/W(..., ..., registry_path)
    • OpenMutexA/W(..., ..., registry_path)

    那么这就表明应用程序试图使用规避技术。
    检测表
    检查是否存在以下全局互斥体:
    检测
    名称
    DeepFreeze
    Frz_State
    Sandboxie
    Sandboxie_SingleInstanceMutex_Control
    SBIE_BOXED_ServiceInitComplete_Mutex1
    VirtualPC
    MicrosoftVirtualPC7UserServiceMakeSureWe'reTheOnlyOneMutex

    注意:DeepFreeze是一个在每次重启时恢复系统的应用程序。
    2. 检查特定的虚拟设备
    这种方法检查特定的虚拟设备,这些设备存在于虚拟环境中,但不在常规的主机系统中。
    使用的函数:
    • NtCreateFile

    代码样本
    [C++] 纯文本查看 复制代码
    // 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);
    }

    该代码样本归功于:VMDE project
    识别标志
    如果下面的函数包含第三个参数,它的字段' ObjectName->Buffer '来自表列' 名称 ':
    • NtCreateFile(..., ..., attr, ...)

    那么这就表明应用程序试图使用规避技术。
    第三个参数的类型如下:
    [C++] 纯文本查看 复制代码
    typedef struct _OBJECT_ATTRIBUTES {
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
    } OBJECT_ATTRIBUTES;

    检测表
    检查是否存在以下虚拟设备:
    检测
    路径
    VirtualBox
    \\.\VBoxMiniRdDN
    \\.\VBoxMiniRdrDN
    \\.\VBoxGuest
    \\.\VBoxTrayIPC
    \\.\VBoxMouse
    \\.\VBoxVideo
    VMware
    \\.\HGFS
    \\.\vmci

    3.检查特定的全局管道
    管道只是虚拟设备的一个特殊情况,请参考上一节的代码样本和识别标志。
    检测表
    检查是否存在以下全局管道:
    检测
    字符串
    VirtualBox
    \\.\pipe\VBoxMiniRdDN
    \\.\pipe\VBoxTrayIPC

    4.检查特定的全局对象

    这种方法检查特定的全局对象,这些对象存在于虚拟环境中,但不存在于常规的主机系统中。
    使用的函数:
    • NtOpenDirectoryObject
    • NtQueryDirectoryObject

    代码样本
    [C++] 纯文本查看 复制代码
    // 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;
    }

    该代码样本归功于:VMDE project
    检测表
    检查是否存在以下全局对象:
    检测
    路径
    对象
    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.检查特定对象目录(仅限于沙盒)
    该方法检查特定的对象目录,该目录存在于Sandboxie虚拟环境中,但不存在于常规的主机系统中。
    使用的函数:
    • GetFileAttributes

    代码样本
    [C++] 纯文本查看 复制代码
    #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;
    }

    该代码样本归功于:VMDE project
    识别标志
    如果下面的函数包含第3个参数,其字段 "ObjectName->Buffer "来自表列`名称`。
    • NtOpenDirectoryObject(..., ..., attr, ...)

    那么这就表明应用程序试图使用规避技术。
    第三个参数的类型如下:
    [C++] 纯文本查看 复制代码
    typedef struct _OBJECT_ATTRIBUTES {
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
    } OBJECT_ATTRIBUTES;

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

    6.检查系统中是否存在虚拟注册表(仅限于沙盒)
    此方法检查Sandboxie虚拟环境中存在的虚拟注册表,但在通常的主机系统中不存在。
    应用程序打开注册表项\注册表\用户。它使用以下函数来检查真实的对象名:
    [C++] 纯文本查看 复制代码
    NtQueryObject(
        hUserKey,
        ObjectNameInformation,
        oni, // OBJECT_NAME_INFORMATION object
        Size,
        NULL);

    如果接收到的OBJECT_NAME_INFORMATION对象名称不等于“"\REGISTRY\USER",则应用程序假定它运行在沙箱环境中。
    识别标志
    如果使用以下函数来打开\REGISTRY\USER:
    • NtOpenKey

    后面是调用下面的函数,其第一个参数是 \REGISTRY\USER键的句柄:
    • NtQueryObject(hUserKey, ...)

    那么这就表明应用程序试图使用规避技术。
    反制措施
    拦截目标函数,如果指标(表格中的对象)被触发,返回适当的结果。在某些情况下,停止适当的设备可能会有帮助--但这并不是一个普遍的反击行动:不是所有的全局对象都是设备。
    归功于
    归功于开源项目,代码样本来自该项目。
    尽管Check Point工具InviZzzible已经实现了所有这些功能,但由于代码的模块化结构,需要更多的空间来展示这个工具的代码样本,以达到相同的目的。这就是为什么我们决定在整个百科全书中使用其他伟大的开源项目作为例子。
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2023-5-13 23:22
  • 签到天数: 853 天

    [LV.10]以坛为家III

    发表于 2021-5-19 23:58:29 | 显示全部楼层
    感谢楼主分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    昨天 14:36
  • 签到天数: 194 天

    [LV.7]常住居民III

    发表于 2021-8-30 11:17:05 | 显示全部楼层
    感谢翻译 mark  



    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表