0%

Chapter 10 文件系统微过滤器

过滤驱动开发程序可以修改已有驱动程序功能,也可以对数据进行过滤加密。上层过滤驱动是指附加在FDO下面的过滤驱动程序,下层反之。

文件过滤驱动将挂载在磁盘驱动之上,将所有发往磁盘驱动的IRP拦截,并有选择的过滤这些IRP。

文件系统是访问文件的I/O操作的目标。Windows支持多个文件系统,最著名的是NTFS,其本机文件系统。文件系统过滤是驱动程序可以拦截发送到文件系统的调用的机制。

image-20220606210155856

加载和卸载

微过滤驱动的加载与加载一个标准的微软驱动一样,但是卸载不同。加载使用用户模式下的FilterLoad函数,将驱动名字作为参数传递,内部调用的是内核FltLoadFilter函数。

下载操作调用的函数用户模式下是FilterUnload,内核模式下FltUnloadFilter,此操作需要与加载驱动有用样的权限,但不能保证成功,因为调用了微过滤器的过滤器卸载回调函数,这可能会使请求失败,从而使驱动程序保留在系统中。

在开发的时候一般采用fltmc.exe实现过滤驱动的加载与卸载(fltmc load/unload myfilter

image-20220607095246931

除此之外,还包括很多的命令,比如fltmc instances可以查看每个驱动的实例详情

image-20220607095703336

初始化

文件系统微过滤驱动同样有一个DriverEntry,驱动需要调用FltRegisterFilter注册为一个微过滤驱动,然后调用FltStartFiltering启动过滤操作。该驱动是不需要设置自己的派遣函数的,因为驱动程序不是直接在I/O路径中。

下面是FltRegisterFilter这个函数的详细信息,其中参数二详细结构如第二张图(这里只截取了前三个参数,其余的具体使用的时候再找资料)

image-20220607104559411

image-20220607104638920

image-20220607104705085

还有一个参数很重要。这是一个指向FLT_OPERATION_REGISTRATION结构数组的指针,每个结构都指定感兴趣的操作以及驱动程序希望调用的前/后回调。

image-20220607145341769

管道和邮件槽

命名管道是一种从服务器到一个或多个客户端的单向或双向通信机制,它被实现为一个文件系统(npfs.sys)。WindowsAPI提供了创建管道服务器和客户端的特定功能。CreateNamedPipe函数可用于创建一个命名的管道服务器,客户端可以使用普通的CreateFileAPI以这个形式:\\<server>\pipe\<管道名>的文件名进行连接。

直接访问卷(DAS/DAX)

直接访问卷是windows10 1607添加的一个新特性,它提供了对一种基于直接访问底层字节数据的新型存储的支持。这被被称为存储类内存的新型存储硬件所支持——这是一种具有类似RAM性能的非易失性存储介质。

操作回调注册(Operation callback register)

一个微过滤器驱动程序必须指示它想要执行的操作。这是在微过滤器注册时间提供的,带有一个FLT_OPERATION_REGISTRATION结构的数组,定义如下:

image-20220607111509648

该操作本身就被定义为一个Major Function(和IRP_MJ_CREATE等一样),但是它并没有一个真正的Major Function的派遣函数。过滤器管理器提供的这个抽象有助于将微过滤器与知道操作的确切来源隔离开来。它可以是一个真正的IRP,也可以是另一个被抽象为IRP的操作。此外,文件系统还支持另一种接收请求的机制,称为Fast I/O。快速I/O用于具有缓存文件的同步I/O。快速I/O请求直接在用户缓冲区和系统缓存之间传输数据,从而绕过了文件系统和存储驱动程序堆栈,从而避免了不必要的开销。例如,NTFS文件系统驱动程序支持快速I/O。

快速I/O的初始化方法是通过分配一个FAST_IO_DISPATCH结构(包含一长串回调),填充它,然后将DRIVER_OBJECTFastIoDispatch成员设置为这个结构。

高度

文件系统微过滤器必须有一个高度,指示它们在文件系统过滤器层次结构中的相对“位置”。一个微过滤器的高度值是非常重要的。首先,高度的值不是作为微过滤器注册的一部分提供的,而是从注册表中读取的。安装驱动程序时,其高度被写入注册表的适当位置。

关于文件加密

文件系统过滤驱动在I/O操作到达文件系统之前拦截I/O操作(来自应用程序和系统本身)。这允许他们在文件系统捕获它们之前监控、跟踪、管理、操作甚至允许或拒绝I/O操作。

文档加密软件的核心逻辑:在数据写入到磁盘之前,被透明加密了,从磁盘中读取返回到用户程序之前,又被透明解密了。

对于杀毒软件的文件过滤驱动,通常会拦截文件的打开请求并挂起他们,同时过滤驱动或者应用层运行的相关程序扫描正在打开的文件是否有病毒。如果发现任何病毒,可以取消打开请求。如果没有发现病毒,则可以允许打开请求正常完成。

标准minifilter

标准minifilter是Windows文件系统常见的过滤驱动,往往用来监控或跟踪文件系统数据。大多数杀毒软件都会使用标准微过滤驱动。

隔离minifilter

隔离minifilter也是Windows文件系统的过滤驱动,它将文件数据的视图与相关文件的底层真实数据隔离开。隔离minifilter的典型使用场景是文档加密产品的透明加密和透明解密的实现。隔离minifilter使用“相同堆栈”的概念,并通过为每个视图提供独特的缓存来提供不同的视图。

minifilter的回调

当minifilter向过来管理器注册时,除了一些基本的设置,它还可以选择接收指定的I/O操作的PreOperation和PostOperation回调。PreOperation回调在指定类型的每个I/O操作被传递到文件系统之前被调用。PostOperation则在文件系统处理特定类型的I/O操作后调用。

Pre回调函数

1
2
3
4
FLT_PREOP_CALLBACK_STATUS SomePreOperation (
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Outptr_ PVOID *CompletionContext);

几个返回值如下:

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/O操作处理流程。注意只有对于基于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操作,不应该返回这个值,因为文件管理器已经为这个操作进行同步了。此外对于同步的读和写操作,如果返回这个值会严重影响驱动和系统性能。