基于Minifilter框架的文件过滤驱动理解
概述
Minifilter即File System Minifilter Drivers,是Windows为了简化第三方开发人员开发文件过滤驱动而提供的一套框架,这个框架依赖于一个称之为Filter Manager(后面简写为FltMgr)的传统文件系统过滤驱动。这套框架应用到内核中的结构如下图所示:
FltMgr以传统文件过滤驱动的形式插入到I/O处理队列中去接收不同的I/O请求,然后将这个请求遍历发布到它所维护的Minifilter对象中,然后根据各个Minifilter对这个I/O请求的处理结果来决定后续的操作。
这种模式在很多软件架构中使用,类似于插件一样,每一个Minifilter遵守一定的接口规范插入到FltMgr中,然后就能执行过滤控制。
上面是对整个Minifilter框架进行描述,实际内部需要注意的细节牵涉到很多内核知识,比如中断级别、I/O请求被封装成IRP包和fast I/O请求等相对复杂的概念。这里不做深究,主要以研究Minifilter的开发过程和相应注意的地方为主。此外还有FltMgr在内核中的位置等相关知识,也只在必要的地方提及一下。
Minifilter流程
Minifilter通过注册并启动后,根据在注册表中设置的相应值,插入到对应的FltMgr实例(Frame)队列中,然后关联上需要过滤的卷。FltMgr会根据Minifilter所注册的I/O操作类型,调用对应的pre和post操作函数,并根据对应的返回值执行不同的流程。这里假设有A、B、C三个Minifilter从上往下挂载在FltMgr实例上,那么当接收到I/O请求时,执行的步骤为A-pre、B-pre、C-pre,一旦某个Minifilter返回了FLT_PREOP_COMPLETE,即表明这个I/O请求被它完成处理了,则立即按照相反的顺序调用对应的post函数(不再继续往下调)。
注册和关联
Minifilter根据FltRegisterFilter函数介绍说明,为响应操作设置对应的回调函数和数据结构后,就可以在DriverEntry中调用FltRegisterFilter进行注册了,然后调用FltStartFiltering来通知FltMgr当前Minifilter已经准备好关联到要过滤的卷了。
FltMgr会在系统启动时或者接收到手动关联命令时,调用Minifilter的InstanceSetupCallback回调函数,当然前提是Minifilter在注册的时候增设置了这个函数的地址,这个回调函数会传入要关联的卷标信息,FltMgr会根据这个函数的返回值判断是否关联成功。这里和对应卷相关联的Minifilter实例叫做instance。一个卷上可以挂多个instance。只有对指定卷进行关联后,才能过滤其I/O请求。
取消关联的过程可以理解成释放实例的过程,释放后就无法继续过滤对应卷了。
Pre回调函数(PFLT_PRE_OPERATION_CALLBACK)
FLT_PREOP_COMPLETE:表示当前的过滤驱动完成了本次I/O操作,过滤管理器就不再往下发送本次I/O请求,而是依次向上调用post回调函数。这种情况下IoStatus.Status的值就是最终I/O操作的执行结果(不能是STATUS_PENDING)。
FLT_PREOP_SUCCESS_NO_CALLBACK/FLT_PREOP_SUCCESS_WITH_CALLBACK:这个返回值表示处理成功,让过滤管理器去做自己的事,区别在于WITH_CALLBACK的返回值会标明需要回调post函数。而NO_CALLBACK的则标明不需要。
FLT_PREOP_PENDING:顾名思义,表明当前过滤驱动将本次I/O操作挂起了,过滤管理器需要等待当前驱动调用FltCompletePendedPreOperation函数后才会继续本次I/0操作处理流程。注意只有对于基于IRP中断的I/O操作(用FLT_IS_IRP_OPERATION宏测试)才可以挂起。
FLT_PREOP_DISALLOW_FASTIO:只有操作是fast I/O操作(用FLT_IS_FASTIO_OPERATION(Data)进行测试)时才可以返回这个值,表明过滤驱动不允许fast I/O操作继续执行。因此过滤管理器不会再下发该请求,而是依次向上调用post回调函数。这种情况下不需要设置IoStatus.Status的值,过滤管理器会自动设置这个值。
FLT_PREOP_SYNCHRONIZE:这个返回值表明处理未完成,保持当前过滤驱动上下文线程环境,交由过滤管理器继续下发后调用post回调函数后继续处理。也只对基于IRP中断的操作有效,并且必须有post函数,如果不是基于IRP中断的,就会和FLT_PREOP_SUCCESS_WITH_CALLBACK一样。注意:对于Create操作,不应该返回这个值,因为文件管理器已经为这个操作进行同步了。此外对于同步的读和写操作,如果返回这个值会严重影响驱动和系统性能。
如果在pre和post函数中更改了Data的内容,必须调用FltSetCallbackDataDirty函数(更改IoStatus除外)。
Post回调函数(PFLT_POST_OPERATION_CALLBACK)
这个回调函数执行的中断等级为IRQL <= DISPATCH_LEVEL。所以需要注意以下几点:1、不能安全调用必须低于IRQL级别的任何内核模式的派遣函数。2、在这个函数内开辟的任何数据结构必须位于非页内存。3、该函数不可分页。4、不能请求资源(resource)、信号量(mutextes)和快速信号量(fast mutexes),只能获取互斥锁(spin lock)。5、不能获取、设置或者删除上下文,但可以释放上下文。
相对于Pre回调函数多了最后一个参数Flags,这个参数如果存在FLTFL_POST_OPERATION_DRAINING标记位,则表明当前过滤驱动实例正在被取消关联,本次调用是为了清理pre回调函数传入的completion context,返回值必须是FLT_POSTOP_FINISHED_PROCESSING,并且这个回调是在IRQL<=APC_LEVEL执行的。
FLT_POSTOP_FINISHED_PROCESSING:表明本过滤驱动完成了对I/0操作的处理并将控制交还给过滤管理器。
FLT_POSTOP_MORE_PROCESSING_REQUIRED:只有当微过滤驱动将本次I/O操作发送到工作队列中时,才能返回这个值,微过滤驱动最后必须负责完成这个I/O操作。过滤管理器会继续等待FltCompletePendedPostOperation函数被调用后才继续执行控制。注意:这个返回值也必须对基于IRP中断的操作执行。
任何要被执行在IRQL<DISPATCH_LEVEL的I/O完成处理都不能在这个回调函数内直接执行。取而代之,可以使用FltDoCompletionRpocessingWhenSafe或者FltQueueDeferredIoWorkItem之类的函数发送到工作队列中。
除了以下情况外,要确保在Flags参数没有FLTFL_POST_OPERATION_DRAINING标记位的时候才能调用FltDoCompletionRpocessingWhenSafe函数:
1、如果微过滤驱动的pre回调函数为一个基于IRP中断的操作返回FLT_PREOP_SYNCHRONIZE,那么对应的post回调要保证和pre回调都处在IRQL<=APC_LEVEL的线程上下文中。
2、对于create操作的post回调要保证中断级别为IRQL_PASSIVE_LEVEL(原始IRP_MJ_CREATE操作所处的线程上下文)。
基于Minifilter框架的文件过滤驱动理解的更多相关文章
- 文件过滤驱动实现目录重定向(一)good
文件过滤驱动拦截的IRP主要包括以下几个:IRP_MJ_CREATE,文件创建操作,文件的任何操作,都是从这里开始的.IRP_MJ_CLEANUP,文件的HANDLE句柄全部关闭会触发这个消息IRP_ ...
- [转载]文件过滤驱动 文件系统激活通知 IoRegisterFsRegistrationChange函数实现
IoRegisterFsRegistrationChange 注册一个文件系统变动回调函数,用来被通知文件系统的激活和注销,激活是指第一次加载文件系统,当一个文件系统已经加载后,当加载一个同种文件系统 ...
- Windows 文件过滤驱动经验总结
Windows 文件过滤驱动经验总结作者:sinister 本文转载自驱动开发网 看了 ChuKuangRen 的第二版<文件过滤驱动开发教程>后,颇有感触.我想,交流都是建立在平等的基础 ...
- 文件过滤驱动框架Minispy解析一
因工作需要,研究minispy文件过滤框架,上图为我整理出的其内核部分代码的逻辑.
- Struts2内建校验器(基于校验框架的文件校验)
位于xwork-2.0.4.jar压缩包中( com.opensymphony.xwork2.validator.validators)有个文件default.xml ,该文件中定义了Struts2框 ...
- 【转】NodeJS教程--基于ExpressJS框架的文件上传
本文是翻译的一篇文章,原文地址:Handle File Uploads in Express (Node.js). 在NodeJS发展早期上传文件是一个较难操作的功能,随后出现了formidable. ...
- 基于SSM框架的文件上传
我整理了一下,这个办法在Servlet上应该也用得上.其实文件上传主要的问题是在于存储路径的拼接. 这里我是把东西存在Web项目的WebContent目录下的 下面贴一些代码 目标应该是这样一个格式 ...
- File System Minifilter Drivers(文件系统微型过滤驱动)入门
问题: 公司之前有一套文件过滤驱动,但是在实施过程中经常出现问题,现在交由我维护.于是在边看代码的过程中,一边查看官方资料,进行整理. 这套文件过滤驱动的目的只要是根据应用层下发的策略来控制对某些特定 ...
- 驱动开发:内核枚举Minifilter微过滤驱动
Minifilter 是一种文件过滤驱动,该驱动简称为微过滤驱动,相对于传统的sfilter文件过滤驱动来说,微过滤驱动编写时更简单,其不需要考虑底层RIP如何派发且无需要考虑兼容性问题,微过滤驱动使 ...
随机推荐
- [转] Form表单中method="post/get'的区别
Form提供了两种数据传输的方式——get和post.虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响.虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一 ...
- linux sysvinit与upstart [转]
linux sysvinit与upstart(1) linux sysvinit与upstart(2) linux sysvinit与upstart(3)
- PHP: 深入pack/unpack <转> [链接]
PHP: 深入pack/unpack PHP: chr和pack.unpack那些 PHP: pack/unpack补遗
- HDU 5033 Building(单调栈维护凸包)
盗张图:来自http://blog.csdn.net/xuechelingxiao/article/details/39494433 题目大意:有一排建筑物坐落在一条直线上,每个建筑物都有一定的高度, ...
- 使用phpmailer发送邮件(以QQ邮箱为例)
<?php include("class/class.phpmailer.php"); //下载phpmailer并include两个文件 include(" ...
- windows服务安装(System.ComponentModel.Win32Exception:远程过程调用失败)
“安装”阶段发生异常.System.ComponentModel.Win32Exception:远程过程调用失败 附上提示信息C:\Windows\Microsoft.NET\Framework\v4 ...
- mac 查找当前目录下所有同一类型文件,并执行命令行
以TexturePacker举例 MAC下用TexturePacker命令行打包当前目录下所有的 *.tps文件 1.配置好tps文件需要配置好路径.参数等.(也可不配置,用命令行实现.具体参考:ht ...
- 关于C#编程中引用与值类型赋值的一些容易犯错的地方
值类型与引用类型的区别在于:值类型在赋值的时候是拷贝值,引用类型在赋值的时候的拷贝引用.记住这一个原则,我们再来分析一些具体情况: PointStruct pt1 = ,); PointStruct ...
- 【USACO 1.2.5】双重回文数
[题目描述] 如果一个数从左往右读和从右往左读都是一样,那么这个数就叫做“回文数”.例如,12321就是一个回文数,而77778就不是.当然,回文数的首和尾都应是非零的,因此0220就不是回文数. 事 ...
- PHP Countable接口
实现该接口可以使用count()方法来获取集合的总数
