基于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如何派发且无需要考虑兼容性问题,微过滤驱动使 ...
随机推荐
- Android(java)学习笔记215:多线程断点下载的原理(JavaSE实现)
1. 为什么需要多线程下载? 服务器的资源有限,同时的平均地分配给每个客户端.开启的线程越多抢占的服务的资源就越多,下载的速度就越块. 2. 下载速度的限制条件? (1)你的电脑手机宽带的带宽 ...
- 有向图的欧拉路径POJ2337
每个单词可以看做一条边,每个字母就是顶点. 有向图欧拉回路的判定,首先判断入度和出度,其实这个题判定的是欧拉通路,不一定非得构成环,所以可以有一个点的顶点入度比出度大1,另外一个点的出度比入度大1,或 ...
- python 全栈开发之路 day1
python 全栈开发之路 day1 本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...
- Android开发--WIFI实现
wifi的基本结构 在Android的官方文档中定义了如下五种状态: WIFI_STATE_DISABLING WIFI网卡正在关闭 0 WIFI_STATE_DISABLED WIFI网卡不 ...
- 学习JAVA第一部分总结
把自己这几天的学习情况记录下来. 第一章,认识JAVA,了解JAVA的运行机制,虚拟机. 第二章,了解java的注释,标识符,关键字.. 第三章,基本的数据类型,byte short int long ...
- My.Ioc 代码示例——注册项的注销和更新
当您需要从 Ioc 容器中注销/删除一个注册项的时候,您会怎么做呢? 有人曾经在 stackoverflow 上提问“如何从 Unity 中注销一个注册项”.对于这个问题,有人的回答是“有趣.你为什么 ...
- 佛祖保佑 永无BUG(网转 by atkfc)
// _ooOoo_ // o8888888o // 88" . ...
- java中的IO二
java中流分为节点流和处理流,IO一中的案例都是节点流 一.处理流的使用实例 二.装饰者模式 以上BufferReader的用法就是装饰者模式 Decorator就是动态地给对象增添行为 如果要实现 ...
- break、continue和goto 三者作用介绍
跳跃语句 由于break.continue和goto语句有助于跳跃到代码中的某个特定语句,因此它们属于跳跃语句.下面是这三个语句的介绍. ①break语句 这个语句常与switch语句联合使用:但是, ...
- java学习——网络编程UDP
UDP 将数据及源和目的封装成数据包中,不需要建立连接 每个数据报的大小限制在64k内 因无连接,是不可靠协议 不需要建立连接,速度快 TCP 建立连接,形成传输数据的通道 在连接中进行大数据量传输 ...