Windows驱动编程之文件过滤
字数 1480 2025-08-23 18:31:18
Windows驱动编程之文件过滤技术详解
1. Minifilter框架概述
Minifilter(Mini-filter Installable File System)是微软官方推荐的文件过滤框架,具有以下优势:
- 良好的兼容性和高封装接口
- 加快开发周期,降低开发难度
- 解决早期版本驱动兼容性问题
- 统一接口规范,减少对系统的不确定因素
1.1 工作流程
用户I/O请求的处理流程:
- I/O请求转发到文件系统
- 过滤管理拦截请求并按顺序调用已注册的微型过滤器
- 文件系统驱动程序处理并转发修改后的请求
- 存储驱动程序堆栈准备硬件请求
2. Minifilter框架实现
2.1 基本结构
Minifilter主要包含四部分:注册、启动、预操作、后操作。
CONST FLT_REGISTRATION FilterRegistration = {
sizeof(FLT_REGISTRATION), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
NULL, // Context
Callbacks, // Operation callbacks
NULL, // MiniFilterUnload
FsFilter1InstanceSetup, // InstanceSetup
FsFilter1InstanceQueryTeardown, // InstanceQueryTeardown
FsFilter1InstanceTeardownStart, // InstanceTeardownStart
FsFilter1InstanceTeardownComplete, // InstanceTeardownComplete
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
NTSTATUS status;
status = FltRegisterFilter(
DriverObject, //Driver
&FilterRegistration, //Registration
&MiniSpyData.FilterHandle //RetFilter
);
2.2 操作注册结构
FLT_OPERATION_REGISTRATION是关键结构:
typedef struct _FLT_OPERATION_REGISTRATION {
UCHAR MajorFunction;
FLT_OPERATION_REGISTRATION_FLAGS Flags;
PFLT_PRE_OPERATION_CALLBACK PreOperation;
PFLT_POST_OPERATION_CALLBACK PostOperation;
PVOID Reserved1;
} FLT_OPERATION_REGISTRATION, *PFLT_OPERATION_REGISTRATION;
参数说明:
-
MajorFunction - 拦截的操作类型:
- IRP_MJ_CLEANUP
- IRP_MJ_CLOSE
- IRP_MJ_CREATE
- IRP_MJ_DEVICE_CONTROL
- IRP_MJ_FILE_SYSTEM_CONTROL
- IRP_MJ_FLUSH_BUFFERS
- IRP_MJ_INTERNAL_DEVICE_CONTROL
- IRP_MJ_PNP
- IRP_MJ_POWER
- IRP_MJ_QUERY_INFORMATION
- IRP_MJ_READ
- IRP_MJ_SET_INFORMATION
- IRP_MJ_SHUTDOWN
- IRP_MJ_SYSTEM_CONTROL
- IRP_MJ_WRITE
-
Flags - 过滤选项:
- SKIP_CACHED_IO:不过滤缓冲区读写
- SKIP_PAGING_IO:不过滤分页读写
- SKIP_NON_DASD_IO:仅对读写回调有用
-
PreOperation - 预操作回调函数
-
PostOperation - 后操作回调函数
3. Minifilter IPC通信
3.1 内核层(R0)实现
// 绑定安全描述符
FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS);
// 初始化属性对象
RtlSetDaclSecurityDescriptor(sd, TRUE, NULL, FALSE);
RtlInitUnicodeString(&EventPortName, L"\\HadesEventFltPort");
InitializeObjectAttributes(
&oa,
&EventPortName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
sd
);
// 创建通信端口
status = FltCreateCommunicationPort(
g_FltServerPortEvnet,
&g_FltServerPortEvnetPort,
&oa,
NULL,
CommunicateConnect,
CommunicateDisconnect,
NULL,
1
);
3.2 用户层(R3)实现
// 连接驱动创建的Port
Status = FilterConnectCommunicationPort(
L"\\HadesEventFltPort", // Driver CreatePortName
0,
NULL,
0,
NULL,
&g_hPort
);
if (Status == HRESULT_FROM_WIN32(S_OK)) {
// 绑定IOCP端口(异步接收)
g_comPletion = CreateIoCompletionPort(g_hPort, NULL, 0, 4);
if (nullptr == g_comPletion) {
CloseHandle(g_hPort);
g_hPort = nullptr;
continue;
}
// 获取消息分发处理
Status = FilterGetMessage(
g_hPort,
&msg->MessageHeader,
FIELD_OFFSET(COMMAND_MESSAGE, Overlapped),
&msg->Overlapped
);
}
4. 文件/目录保护技术
4.1 基本拦截方法
注册IRP_MJ_CREATE和IRP_MJ_SET_INFORMATION回调:
{ IRP_MJ_CREATE, 0, FsFilter1PreOperation, NULL },
{ IRP_MJ_SET_INFORMATION, 0, FsFilter1PreOperation, NULL }
4.2 关键信息获取
- 获取IRP类型:
const unsigned char IRP_MJ_CODE = Data->Iopb->MajorFunction;
- 获取进程PID:
const DWORD dwPID = (DWORD)PsGetCurrentProcessId();
- 获取文件路径:
PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
NTSTATUS status = FltGetFileNameInformation(
Data,
FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT,
&pNameInfo
);
- 文件操作类型判断:
Data->Iopb->Parameters.SetFileInformation.FileInformationClass;
// 重命名
case FileRenameInformation:
// 删除
case FileDispositionInformation:
4.3 访问控制
- 拒绝访问:
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
return FLT_PREOP_COMPLETE;
- 允许访问:
return FLT_PREOP_SUCCESS_NO_CALLBACK;
- 创建操作权限判断:
if (((Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff) == FILE_CREATE ||
((Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff) == FILE_OPEN_IF ||
((Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff) == FILE_OVERWRITE_IF)
{
// 处理创建/打开操作
}
5. 文件隐藏技术
5.1 注册目录控制回调
{ IRP_MJ_DIRECTORY_CONTROL, 0, FsFilterAntsDrPostFileHide, NULL }
5.2 实现细节
- 判断查询操作:
if (Data->Iopb->MinorFunction == IRP_MN_QUERY_DIRECTORY &&
(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass == FileBothDirectoryInformation) &&
Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length > 0 &&
NT_SUCCESS(Data->IoStatus.Status))
{
// 处理目录查询
}
- 获取缓冲区:
if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL) {
Bufferptr = MmGetSystemAddressForMdl(
Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
NormalPagePriority
);
} else {
Bufferptr = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
}
- 修改目录信息:
PFILE_BOTH_DIR_INFORMATION pCutFileInfo = (PFILE_BOTH_DIR_INFORMATION)Bufferptr;
PFILE_BOTH_DIR_INFORMATION pPreFileInfo = pCutFileInfo;
PFILE_BOTH_DIR_INFORMATION pNextFileInfo = 0;
ULONG uNextOffset = 0;
// 找到要隐藏的文件名并修改链表结构
if (uNextOffset == 0)
pPreFileInfo->NextEntryOffset = 0;
else
pPreFileInfo->NextEntryOffset = (ULONG)((PCHAR)pCutFileInfo - (PCHAR)pPreFileInfo + uNextOffset);
pCutFileInfo = pNextFileInfo;
6. 进程/模块拦截技术
6.1 进程拦截
- 使用PsSetCreateProcessNotifyRoutineEx:
PsSetCreateProcessNotifyRoutineEx(
(PCREATE_PROCESS_NOTIFY_ROUTINE_EX)Process_NotifyProcessEx,
FALSE
);
- 使用ObRegisterCallbacks:
NTSTATUS status = ObRegisterCallbacks(&obReg, &g_handleobj);
- 卸载回调:
PsSetCreateProcessNotifyRoutineEx(
(PCREATE_PROCESS_NOTIFY_ROUTINE_EX)Process_NotifyProcessEx,
TRUE
);
ObUnRegisterCallbacks(g_handleobj);
6.2 DLL模块拦截
- 注册IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION:
{ IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION, 0, FsFilterAntsDrvPreExe, NULL }
- 判断执行状态:
if (Data->Iopb->Parameters.AcquireForSectionSynchronization.PageProtection == PAGE_EXECUTE) {
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
- 拦截方法:
Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; // 弹出资源错误窗口
// 或
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->Iostatus.information = 0;
return FLT_PREOP_COMPLETE;
- PE文件验证:
// 通过FltReadFile读取FileObject对象,解析PE头验证是否为有效EXE/DLL
7. 总结
本文详细介绍了Windows文件过滤驱动的开发技术,重点包括:
- Minifilter框架的基本原理和实现方法
- 内核与用户态的通信机制
- 文件/目录的保护技术
- 文件隐藏的实现方法
- 进程和模块拦截技术
这些技术在安全EDR/DLP、游戏反作弊、云存储等场景中有广泛应用。开发者应根据实际需求选择合适的拦截点和实现方式,同时注意性能和稳定性问题。