|
本帖最后由 梦幻的彼岸 于 2021-5-20 10:08 编辑
备注
原文地址: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
代码样本
- // 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. 检查特定的虚拟设备
这种方法检查特定的虚拟设备,这些设备存在于虚拟环境中,但不在常规的主机系统中。
使用的函数:
代码样本
- // 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, ...)
那么这就表明应用程序试图使用规避技术。
第三个参数的类型如下:
- 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
代码样本
- // 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虚拟环境中,但不存在于常规的主机系统中。
使用的函数:
代码样本
- #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, ...)
那么这就表明应用程序试图使用规避技术。
第三个参数的类型如下:
- 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虚拟环境中存在的虚拟注册表,但在通常的主机系统中不存在。
应用程序打开注册表项\注册表\用户。它使用以下函数来检查真实的对象名:
- NtQueryObject(
- hUserKey,
- ObjectNameInformation,
- oni, // OBJECT_NAME_INFORMATION object
- Size,
- NULL);
复制代码
如果接收到的OBJECT_NAME_INFORMATION对象名称不等于“"\REGISTRY\USER",则应用程序假定它运行在沙箱环境中。
识别标志
如果使用以下函数来打开\REGISTRY\USER:
后面是调用下面的函数,其第一个参数是 \REGISTRY\USER键的句柄:
- NtQueryObject(hUserKey, ...)
那么这就表明应用程序试图使用规避技术。
反制措施
拦截目标函数,如果指标(表格中的对象)被触发,返回适当的结果。在某些情况下,停止适当的设备可能会有帮助--但这并不是一个普遍的反击行动:不是所有的全局对象都是设备。
归功于
归功于开源项目,代码样本来自该项目。
尽管Check Point工具InviZzzible已经实现了所有这些功能,但由于代码的模块化结构,需要更多的空间来展示这个工具的代码样本,以达到相同的目的。这就是为什么我们决定在整个百科全书中使用其他伟大的开源项目作为例子。 |
|