问题:

公司之前有一套文件过滤驱动,但是在实施过程中经常出现问题,现在交由我维护。于是在边看代码的过程中,一边查看官方资料,进行整理。

这套文件过滤驱动的目的只要是根据应用层下发的策略来控制对某些特定文件的控制,例如根据后缀名来决定是否允许查看,是否允许查看指定目录啊之类的功能。

介绍:

MSDN上对可安装的文件系统驱动介绍http://msdn.microsoft.com/en-us/library/windows/hardware/ff548143(v=vs.85).aspx:其中树形结构菜单可以看出可安装的文件驱动类型种类:

文件系统驱动那说的应该就是最基本的驱动了,过滤驱动则是完全基于文件驱动中的操作进行手动过滤,可以理解成你hook了系统的create函数,然后如果你要拦截这个操作你就按要求返回不允许,否则就传给系统下一层去继续就好了。

而minifilter驱动则是通过向过滤管理器(Filter Manager)驱动进行注册自己需要过滤的一些操作,提供指定格式的回调函数让过滤管理器来进行调用即可。对于每一种操作,minifilter都可以注册一个“过滤前”和“过滤后”被调用的回调函数。(有点类似于Linux内核上probe调试技术)。(preCreate和postCreate用来作为后面“过滤前”和“过滤后”被调用的回调函数的例子)。

要注意minifilter的加载顺序是根据一个Altitude来决定的,可以理解成驱动所处的维度。例如,当FilterManager检测到要执行create的时候,就去调用注册了对该操作进行过滤的minifilter的回调函数,根据Altitude的值从大到小的顺序先调用preCreate函数。而FilterManager检测到create执行完成后,便按照Altitude的值从小到大的顺序去调用postCreate函数。

minifilter是基于FilterManager所提供的类似插件一样的模块,它可以调用FilterManager所提供很多功能:http://msdn.microsoft.com/en-us/library/windows/hardware/ff541613(v=vs.85).aspx

加载和卸载:

FilterLoad和FilterUnload可用于在用户态程序控制minifilter驱动的加载和卸载。

这里要注意的是minifilter还存在一个instance的概念,这个instance应该就是指某个特定的minifilter,比如有三个minifilter A、B、C。就代表三个minifilter,每一个instance有特定的名字、altitude和flags。当在instance里面调用FltStartFiltering的时候就会去通知FilterManager去将这个insance关联到磁盘以及相关的I/0操作过滤表上。如果在FLtStartFiltering返回之前,FilterManager检测新挂上的磁盘的话,就会自动通知这个instance(通过调用回调函数InstanceSetupCallBack),所以minifilter注册时提供的Instance开头的回调函数,主要是用于FilterManager对这个驱动的一些反馈操作。(比如关联磁盘啊、取消关联啊之类的)。

此外,minifilter自己主动去卸载的话,当然是调用FltUnregisterFilter函数了。

资料:

英语能力确实不太好,在看后面的I/O操作的介绍的时候看的实在费解。幸好有搜到中文资料:http://blog.csdn.net/jununfly/article/category/517002。还是挺感慨很多高深底层的东西都只有英文资料。我就不多做口舌甚至好有可能误导了。

WDK示例:在WDK开发包示例中的IFSK Samples类别下。源码目录是src/filesys/minifilter。中文介绍:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=24504987&id=208208

可能根据我的需求,比较拥有的应该是以上三个例子了,其中swapBuffers那个,用来做加解密比较适合参考。

记录:

记录下我自己遇到的问题:

1、想要做个最简单的测试,通过vs来直接调试,于是简单的仅仅过滤IRP_MJ_CREATE操作,并且在Pre函数里得到操作的文件名,然后输出。而对于FLT_REGISTRATION结构体中,其他可选的回调函数全部置NULL。效果是根本不会进入到的我的pre函数中,原因是我压根没有attach我的驱动的instance到相关卷标上。(这里可以增进对instance这概念的理解,也就是说必须在相关卷标上attach了对应的instance才会生效)。所以如果在系统启动通过fltmc load命令或者FilterLoad和FltLoadFilter来手动加载驱动的,需要手动去关联minifilter到本地磁盘上。可以用fltmc attach命令、FilterAttach、FltAttachVolume、FilterAttachAtAltitude、FltAttachVolumeAtAltitude来手动加载。

2、原来的过滤驱动代码中,是在InstanceSetup中根据需要关联的卷来获取磁盘信息等,保存到Instance的上下文中。如果开启了磁盘控制,还要对USB类型的磁盘设备名称进行记录。话说这里为什么不在磁盘驱动里面记录呢??

3、原来的代码里创建上下文的地方,既调用了FltAllocateContext也调用了FltSet***Context函数的,如果都成功的话,需要调用两次FltReleaseContext,而实际只调用了一次。

上下文(context):

流上下文(stream context):为文件流所设置的上下文,需要和打开了的文件对象关联,所以不能在pre-create回调函数中直接关联,但是可以在pre-create中创建,然后通过pre-create的最后一个参数传递到post-create中进行调用FltSetStreamContext进行关联。

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操作所处的线程上下文)。

Buffer传输方式

注意IRP_MJ_READ和IRP_MJ_WRITE可以是基于IRP或fast I/O的操作.当它们基于IRP时,buffering方法由以上描述的设备对象标记决定.当它们是fast I/O,它们总是使用neither I/O.更多关于可以是基于IRP或fast I/O的操作的I/O操作的信息,参考可以是IRP-I/O或Fast I/O的操作. 

总结:

很遗憾直接写上了总结,事实上上面的内容已经是半个多月前写的了,一方面是有其他事情,一方面发现有点滥竽充数的感觉,没有内容可写,写出来也比较肤浅。在调试的过程中不断出现问题,不断的更改,很多东西改好了也未必能解释出来。

主要原因还是对windows的文件系统本身就不怎么了解,在这个前提下去做过滤操作,就难上加难了。

File System Minifilter Drivers(文件系统微型过滤驱动)入门的更多相关文章

  1. 基于Minifilter框架的文件过滤驱动理解

    概述 Minifilter即File System Minifilter Drivers,是Windows为了简化第三方开发人员开发文件过滤驱动而提供的一套框架,这个框架依赖于一个称之为Filter ...

  2. File System 之本地文件系统

    上一篇文章提到了,最近做一个基于 File System/IndexedDB的应用,上一篇是定额和使用的查询. 因为LocalFileSystem只有chrome支持,有点尴尬,如果按需加载又何来尴尬 ...

  3. [LeetCode] Design In-Memory File System 设计内存文件系统

    Design an in-memory file system to simulate the following functions: ls: Given a path in string form ...

  4. chattr lsattr linux file system attributes - linux 文件系统扩展属性

    我们使用 linux 文件系统扩展属性,能够对linux文件系统进行进一步保护:从而给文件 赋予一些额外的限制:在有些情况下,能够对我们的系统提供保护: chattr命令用来改变文件属性.这项指令可改 ...

  5. GFS(Google File System,谷歌文件系统)----(1)文件系统简介

    分布式文件系统 系统是构建在普通的.廉价的机器上,因此故障是常态而不是意外 系统希望存储的是大量的大型文件(单个文件size很大) 系统支持两种类型读操作:大量的顺序读取以及小规模的随机读取(larg ...

  6. GFS(Google File System,谷歌文件系统)----(1)读写一致性

    GFS副本控制协议--中心化副本控制协议 对于副本集的更新操作有一个中心节点来协调管理,将分布式的并发操作转化为单点的并发操作,从而保证副本集内各节点的一致性.在GFS中,中心节点称之为Primary ...

  7. HDFS(Hadoop Distributed File System )

    HDFS(Hadoop Distributed File System ) HDFS(Hadoop Distributed File System )Hadoop分布式文件系统.是根据google发表 ...

  8. Fast File System

    不扯淡了,直接来写吧,一天一共要写三篇博客,还有两篇呢. 1. 这篇博客讲什么? Fast File System(FFS)快速文件系统,基本思想已经在在上一篇博客File System Implem ...

  9. File System Implementation 文件系统设计实现

    先来扯淡吧,上一篇文章说到要补习的第二篇文章介绍文件系统的,现在就来写吧.其实这些技术都已经是很久以前的了,但是不管怎么样,是基础,慢慢来学习吧.有种直接上Spark源码的冲动.. 1. 这篇博客具体 ...

随机推荐

  1. 移动端网站或APP点击后出现闪动或灰色背景

    隐藏文本框阴影 input, textarea{-webkit-appearance: @none;} 取消手机点击屏幕时,会出现的灰块 html,body{-webkit-text-size-adj ...

  2. Linq101-Set

    using System; using System.Collections.Generic; using System.Linq; namespace Linq101 { class Set { / ...

  3. 从一个SVN下载的导入另一个SVN里面

    如果项目是你从个一个SVN下载的,你想存入另一个SVN里面 那么问题来了 你用eclipse的team的时候会发现没有Team share 这个选项,那么就等于是没有上传的选项了 解决办法,把项目删掉 ...

  4. c - 折半查找(二分法检索)

    #include <stdio.h> #define LEN 10 /* 折半查找(二分法检索). */ int index_of(int *a, int k) { ; ; int m; ...

  5. Oracle11G安装

    1.安装Oracle 记住要设置好密码 不要忘了 解锁scott(注意一定要解锁)账户, 去掉前面的绿色小勾,输入密码.同样可以输入平常用的短小的密码,不必非得按oracle建议的8位以上大小写加数字 ...

  6. Mac下配置node.js 和react-native

    最近对JS挺感兴趣的,就琢磨着在mac上配置下环境学习学习,正巧看到了Facebook的react-native,顺便配置了一下. 安装Homebrew 终端输入: ruby -e "$(c ...

  7. ajax页面数据的传递

    在上一篇文章中,简单提到了ajax的工作流程,那么在这里我们就得实战一回了,真正将ajax的用途展现出来,这一整套流程就是在页面上触发一个ajax事件,然后发送请求,紧接着到数据库读取数据,返回值,然 ...

  8. 通过dbcp链接池对数据库操作报 Cannot create PoolableConnectionFactory (Could not create connection to database server. Attempted reconnect 3 times. Giving up.)--解决方案

    org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for ...

  9. ajax无刷新方式收集表单并提交表单

    ajax无刷新方式收集表单有两种方式, 一个是使用html5的FormData.一个是传统的方式. 一,FormData,在主流的浏览器中可以用,IE不好用啊. 另外,FormData使用有两个条件, ...

  10. hdu1230火星A+B (大数题)

    Problem Description 读入两个不超过25位的火星正整数A和B,计算A+B.需要注意的是:在火星上,整数不是单一进制的,第n位的进制就是第n个素数.例如:地球上的10进制数2,在火星上 ...