MiniFilter 微过滤驱动是相对于SFilter
传统过滤驱动而言的,传统文件过滤驱动相对来说较为复杂,且接口不清晰并不符合快速开发的需求,为了解决复杂的开发问题,微过滤驱动就此诞生,微过滤驱动在编写时更简单,多数IRP
操作都由过滤管理器(FilterManager或Fltmgr)
所接管,因为有了兼容层,所以在开发中不需要考虑底层IRP
如何派发,更无需要考虑兼容性问题,用户只需要编写对应的回调函数处理请求即可,这极大的提高了文件过滤驱动的开发效率。
接下来将进入正题,讲解微过滤驱动的API定义规范以及具体的使用流程,并最终实现一个简单的过滤功能,首先你必须在VS上做如下配置,依次打开配置菜单,并增加驱动头文件。
- 配置属性 > 连接器 > 输入> 附加依赖 > fltMgr.lib
- 配置属性 > C/C++ > 常规 > 设置 关闭所有警告 (警告视为错误关闭)
未过滤驱动的使用非常容易,在使用之前第一件事就是要向过滤管理器宣告我们的微过滤驱动的存在,我们以DriverEntry
入口函数为例,首先在入口处需要使用FltRegisterFilter
函数注册一个过滤器组件,另外则需要通过FltStartFiltering
开启过滤功能,而当我们想要关闭时则需要调用FltUnregisterFilter
注销过滤组件,首先来看一下入口处是如何初始化的;
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
DbgPrint("Hello LyShark.com \n");
// FltRegisterFilter 向过滤管理器注册过滤器
// 参数1:本驱动驱动对象
// 参数2:微过滤驱动描述结构
// 参数3:返回注册成功的微过滤驱动句柄
status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
if (NT_SUCCESS(status))
{
// 开启过滤
status = FltStartFiltering(gFilterHandle);
DbgPrint("[过滤器] 开启监控.. \n");
if (!NT_SUCCESS(status))
{
// 如果启动失败,则取消注册并退出
FltUnregisterFilter(gFilterHandle);
DbgPrint("[过滤器] 取消注册.. \n");
}
}
return status;
}
如上代码中我们最需要关注的是FltRegisterFilter
函数的第二个参数FilterRegistration
它用于宣告注册信息,这个结构内包含了过滤器的所有信息,想要注册成功则我们必须更具要求正确的填写FLT_REGISTRATION
微过滤器注册结构,该结构体的微软定义如下所示;
typedef struct _FLT_REGISTRATION {
USHORT Size;
USHORT Version;
FLT_REGISTRATION_FLAGS Flags;
const FLT_CONTEXT_REGISTRATION *ContextRegistration;
const FLT_OPERATION_REGISTRATION *OperationRegistration;
PFLT_FILTER_UNLOAD_CALLBACK FilterUnloadCallback;
PFLT_INSTANCE_SETUP_CALLBACK InstanceSetupCallback;
PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK InstanceQueryTeardownCallback;
PFLT_INSTANCE_TEARDOWN_CALLBACK InstanceTeardownStartCallback;
PFLT_INSTANCE_TEARDOWN_CALLBACK InstanceTeardownCompleteCallback;
PFLT_GENERATE_FILE_NAME GenerateFileNameCallback;
PFLT_NORMALIZE_NAME_COMPONENT NormalizeNameComponentCallback;
PFLT_NORMALIZE_CONTEXT_CLEANUP NormalizeContextCleanupCallback;
PFLT_TRANSACTION_NOTIFICATION_CALLBACK TransactionNotificationCallback;
PFLT_NORMALIZE_NAME_COMPONENT_EX NormalizeNameComponentExCallback;
PFLT_SECTION_CONFLICT_NOTIFICATION_CALLBACK SectionNotificationCallback;
} FLT_REGISTRATION, *PFLT_REGISTRATION;
当然如上的这些字段并非都要去填充,我们只需要填充自己所需要的部分即可,例如我们代码中只填充了如下这些必要的部分,其他部分可以省略掉,当使用如下结构体注册时,只要实例发生了变化就会根据如下配置路由到不同的函数上面做处理。
// 过滤驱动数据结构
CONST FLT_REGISTRATION FilterRegistration =
{
sizeof(FLT_REGISTRATION), // 结构大小(默认)
FLT_REGISTRATION_VERSION, // 结构版本(默认)
0, // 过滤器标志
NULL, // 上下文
Callbacks, // 注册回调函数集
Unload, // 驱动卸载函数
InstanceSetup, // 实例安装回调函数
InstanceQueryTeardown, // 实例销毁回调函数
InstanceTeardownStart, // 实例解除绑定时触发
InstanceTeardownComplete, // 实例解绑完成时触发
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
如上结构中我们最需要注意的是Callbacks
字段,该字段是操作回调函数集注册,我们对文件的各种操作的回调事件都会被写入到此处,而此处我们只需要增加我们所需要的回调事件即可,以IRP_MJ_CREATE
为例,后面紧跟的是PreOperation
事前回调,以及PostOperation
事后回调,一般在要进行监控时通常在PreOperation()
回调中处理,如果时监视则一般在PostOperation()
中处理。
// 回调函数集
CONST FLT_OPERATION_RE