写Minifilter驱动的DriverEntry例程
每一个文件系统minifilter驱动都必须有一个DriverEntry 例程.当minifilter驱动被加载时该例程会被调用.
DriverEntry例程执行全局初始化,注册minifilter驱动并初始化过滤.此例程在一个系统线程上下文中且在IRQL PASSIVE_LEVEL运行.
它的定义如下:
NTSTATUS
(*PDRIVER_INITIALIZE) (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
DriverEntry有两个入参.首先是DriverObject,它是驱动对象在minifilter驱动加载时被创建.第二个是RegistryPath, 它是包含minifilter驱动的注册key的一个路径的Unicode串.
Minifilter驱动的DriverEntry 例程必须按序执行以下步骤:
1. 执行minifilter驱动的一切所需的全局初始化.
2. 调用FltRegisterFilter注册minifilter驱动.
3. 调用FltStartFiltering发起过滤..
4. 返回一个适当的NTSTATUS 值.
本节包括:
一、注册Minifilter驱动
每一个minifilter驱动都必须从它的DriverEntry例程中调用FltRegisterFilter来添加它自己到已注册的minifilter驱动的全局列表中并向filter管理器提供一套callback例程和其他驱动相关的信息.
在MiniSpy例子中,minifilter驱动的注册过程如下:
NTSTATUS status;
status = FltRegisterFilter(
DriverObject, //Driver
&FilterRegistration, //Registration
&MiniSpyData.FilterHandle); //RetFilter
FltRegisterFilter有两个入参.第一个Driver, 是minifilter驱动在它的DriverEntry例程的入参DriverObject中收到的驱动对象的指针. 其次Registration, 是包含minifilter驱动callback例程的入口点的FLT_REGISTRATION结构的一个指针.
另外, FltRegisterFilter 有一个出参RetFilter,它接收minifilter驱动的一个不透明的过滤器指针.这个过滤器指针是许多FltXxx支持例程的一个必需的入参,包括FltStartFiltering和FltUnregisterFilter.
二、发起过滤
在调用FltRegisterFilter后,minifilter驱动的DriverEntry例程一般会调用FltStartFiltering 来开始过滤I/O操作.
每一个minifilter驱动都必须从它的DriverEntry例程中调用FltStartFiltering来通过filter管理器,该minifilter驱动已经准备好开始绑定到卷上并开始过滤I/O请求.在minifilter驱动调用了FltStartFiltering之后, filter管理器会把它当做一个完全活动的minifilter驱动,把I/O请求和要绑定的卷的通知提供给它. Minifilter驱动甚至要在FltStartFiltering返回之前就必须准备好开始接收这些I/O请求和通知.
在MiniSpy驱动例子中, FltStartFiltering 如下被调用:
status = FltStartFiltering( MiniSpyData.FilterHandle );
if( !NT_SUCCESS( status )) {
FltUnregisterFilter( MiniSpyData.FilterHandle );
}
如果对FltStartFiltering 的调用不返回STATUS_SUCCESS, minifilter驱动必须调用FltUnregisterFilter 来注销它自己.
三、从一个minifilter DriverEntry例程中返回状态
一个FSFD的DriverEntry 例程通常返回STATUS_SUCCESS.不过,如果驱动初始化失败了,DriverEntry 例程应该返回一个适当的错误状态值.
如果DriverEntry例程返回一个非正确的状态值,系统会通过卸载该驱动来做出响应.由于这个原因, DriverEntry 例程必须总是在返回一个非正确的状态值之前free一切为像设备对象这样的系统资源分配的内存.
写Minifilter驱动的FilterUnloadCallback例程
minifilter驱动可随意地注册一个 PFLT_FILTER_UNLOAD_CALLBACK类型的例程作为它的FilterUnloadCallback 例程.这个callback例程也可以说是minifilter驱动的卸载例程.
Minifilter驱动不一定要注册一个FilterUnloadCallback 例程.不过,我们强烈地推荐要注册这个callback例程,因为如果一个minifilter驱动不注册一个FilterUnloadCallback 例程,那么这个驱动就不可以被卸载.
要注册这个callback例程, minifilter驱动得在FLT_REGISTRATION结构的成员FilterUnloadCallback中存一个PFLT_FILTER_UNLOAD_CALLBACK类型的例程的地址,该结构会被minifilter驱动作为它的DriverEntry例程中的 FltRegisterFilter的一个参数.
本节包括:
一、FilterUnloadCallback例程什么时候会被调用
Filter管理器会在以下列方式之一卸载minifilter驱动之前调用该驱动的 FilterUnloadCallback 例程:
· 非强制卸载.当某个用户模式应用程序已经调用了FilterUnload或某个内核模式驱动已经调用了FltUnloadFilter时会发生这种类型的卸载. 当你在命令提示符里打fltmc unload时这种类型的卸载也会发生.
· 强制卸载. 当你通过在命令提示符里打sc stop或net stop来发出一个服务停止请求时会发生这种类型的卸载. (更多关于sc stop和net stop 命令的信息,点击开始菜单中的Help and Support .) 当某个用户模式应用程序调用了微软Win32 ControlService 函数,在参数dwControl中传SERVICE_CONTROL_STOP控制代码时它也会发生. (更多关于Win32 服务函数的信息,参考Microsoft Windows SDK documentation.)
对一个非强制卸载来说,如果minifilter驱动的FilterUnloadCallback 例程返回了一个错误或警告的NTSTATUS 值如STATUS_FLT_DO_NOT_DETACH, filter管理器就不会卸载该驱动.
对一个强制卸载来说,filter管理器在minifilter驱动的FilterUnloadCallback例程被调用之后,即使该例程返回了一个错误或警告NTSTATUS值比如STATUS_FLT_DO_NOT_DETACH这个minifilter驱动也会被卸载.
要禁用某个minifilter驱动的强制卸载,该驱动得在FLT_REGISTRATION结构的成员Flags中设置FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP标记,该结构会被minifilter驱动作为它的DriverEntry例程中的 FltRegisterFilter的一个参数.当设置了这个标记时,filter管理器通常执行非强制卸载请求.不过,强制卸载请求会失败.filter管理器为失败的卸载请求调用minifilter驱动的FilterUnloadCallback 例程.
注意如果某个minifilter驱动的DriverEntry 例程返回了一个警告或错误的 NTSTATUS 值,那么FilterUnloadCallback 例程就不会被调用;filter管理器会简单地卸载这个minifilter驱动.
FilterUnloadCallback 不会在系统关闭期间被调用.一个必须执行关闭处理的minifilter驱动应为IRP_MJ_SHUTDOWN操作注册一个pre-oper callback 例程.
二、写一个FilterUnloadCallback例程
FilterUnloadCallback 例程的定义如下:
typedef NTSTATUS
(*PFLT_FILTER_UNLOAD_CALLBACK) (
FLT_FILTER_UNLOAD_FLAGS Flags
);
FilterUnloadCallback 有一个入参Flags, 它可以是NULL或者 FLTFL_FILTER_UNLOAD_MANDATORY. Filter管理器设置这个参数为FLTFL_FILTER_UNLOAD_MANDATORY来指示卸载操作是强制的. 更多此参数的信息,参考PFLT_FILTER_UNLOAD_CALLBACK.
Minifilter驱动的FilterUnloadCallback 例程必须执行以下步骤:
· 关闭一切内核模式通信服务器端口句柄.
· 调用FltUnregisterFilter 来注册这个minifilter驱动.
· 执行一切所需的全局cleanup.
· 返回一个合适的NTSTATUS值.
本节包括:
1.关闭通信服务器端口
如果minifilter驱动之前调用FltCreateCommunicationPort打开了一个内核模式通信服务器端口,则它必须调用FltCloseCommunicationPort关闭这个端口. 为防止系统在卸载处理期间挂起,minifilter驱动的FilterUnloadCallback 例程必须在调用FltUnregisterFilter之前关闭这个端口.
如果某个用户模式应用程序对该通信服务器端口有了一个打开的连接,在FltCloseCommunicationPort返回之后该连接的一切客户端口仍被保持打开状态.不过, filter管理器会在minifilter驱动被卸载时关闭一切客户端口.
2.注销Minifilter
Minifilter驱动的FilterUnloadCallback 例程必须调用FltUnregisterFilter 来注销这个驱动.调用FltUnregisterFilter 会引起下列事情的发生:
· Minifilter驱动的callback例程被注销.
· Minifilter驱动的实例被拆卸,它的InstanceTeardownStartCallback 和InstanceTeardownCompleteCallback 例程都会为每一个minifilter驱动实例被调用.
· 如果minifilter驱动设置了卷、实例、流或流句柄上的一切上下文,这些上下文都会被删除.如果该驱动已经为某个给定的上下文类型注册了一个CleanupContext callback 例程,那么filter管理器就会在删除该上下文之前调用CleanupContext 例程.
如果minifilter驱动的不透明的过滤器指针上还有未决rundown引用, 那么FltUnregisterFilter就会进入一个等待状态直到它们被移除.未决rundown引用的发生常常是因为minifilter驱动已经调用了FltQueueGenericWorkItem来插入一个工作项到一个系统工作队列中, 且该工作项还没有被出列和处理. (filter管理器会在minifilter驱动调用FltQueueGenericWorkItem时添加rundown引用而在minifilter驱动的工作例程返回时移除该引用.)
如果minifilter驱动已经调用了任何会添加一个到其不透明的过滤器指针上的未决rundown引用的例程,比如FltObjectReference和FltGetFilterFromInstance,但后来没有调用FltObjectDereference,也会发生未决rundown引用.
3.执行全局Cleanup
Minifilter驱动的FilterUnloadCallback 例程必须执行一切所需的全局cleanup.以下是一个minifilter驱动可能执行的全局cleanup任务:
· 调用ExDeleteResourceLite 来删除一个被ExInitializeResourceLite 初始化了的全局资源变量.
· 调用ExFreePool或ExFreePoolWithTag来free被ExAllocatePoolWithTag 这样的例程分配的全局内存.
· 分别调用ExDeleteNPagedLookasideList或ExDeletePagedLookasideList来删除由ExInitializeNPagedLookasideList或ExInitializePagedLookasideList分配的一个lookaside列表.
· 调用PsRemoveCreateThreadNotifyRoutine或PsRemoveLoadImageNotifyRoutine来分别注销由PsSetCreateThreadNotifyRoutine 或PsSetLoadImageNotifyRoutine注册的一个全局callback例程.
4.从一个FilterUnloadCallback例程中返回状态
Minifilter驱动的FilterUnloadCallback 例程通常返回STATUS_SUCCESS.
要拒绝一个非强制的卸载操作,minifilter驱动应返回一个合适的警告或错误NTSTATUS值比如STATUS_FLT_DO_NOT_DETACH.强制卸载操作的详情参考写FilterUnloadCallback例程和FLT_FILTER_UNLOAD_CALLBACK.
如果FilterUnloadCallback 例程返回一个警告或错误的NTSTATUS值且卸载操作是非强制的,minifilter驱动不会被卸载.