首页
社区
课程
招聘
[翻译]标准和隔离型微过滤驱动介绍
发表于: 2024-2-9 23:44 10237

[翻译]标准和隔离型微过滤驱动介绍

2024-2-9 23:44
10237

标准和隔离型微过滤驱动介绍

过滤驱动是Windows I/O子系统中最强大的架构特性之一。通过简单地将自身附加到现有设备上,过滤驱动就可以给设备增加新的功能。并且,过滤设备不需要对底层设备的驱动程序进行任何更改。

 

在典型的Windows系统中,过滤驱动程序可以安装在多个层级上。例如,有标准的Windows提供的在卷层级上的过滤驱动程序,用以提供卷快照功能(用于支持备份),以及可选的完整卷加密功能(以支持Windows Bitlocker)。还有制造商特定的过滤驱动程序,例如用于鼠标或键盘的过滤驱动程序,为特定型号添加对独特按钮的支持。

 

在Windows系统中,在众多插入过滤器的地方中,其中最常见且最强大的一个地方是在文件系统上。文件系统过滤器在I/O操作(来自应用程序和系统本身)到达文件系统之前截取这些I/O操作。这使它们能够在文件系统看到它们之前监视、跟踪、管理、操作甚至接受或拒绝I/O操作。大多数人熟悉的文件系统过滤器类型可能是杀毒软件过滤器。这种类型的过滤器通常截取文件打开请求,将请求挂起,并在过滤器(或更可能是在用户模式下运行的关联服务)扫描正在打开的文件以查找病毒。如果发现任何病毒,打开请求可以被取消。如果没有发现病毒,打开请求可以继续正常完成。

 

文件系统过滤器通常用于各种用途,从如上所述的杀毒和恶意软件扫描,到软件许可证跟踪和管理,到文件的审核和更改跟踪,到透明的数据加密和解密。文件系统过滤器还可以用于其他不太明显的用途。例如,由于它们可以看到哪些文件被创建和写入,文件系统过滤器通常在备份产品和分层存储子系统中发挥关键作用。而且,因为文件系统过滤器可以成为应用程序看到的文件系统“命名空间”的第一个解释器,它们还可以执行强大的文件重定向操作,例如将远程文件(例如存储在云中的文件)显示为本地文件。

 

自Windows XP SP2引入以来,文件系统Minifilter模型已成为实现文件系统过滤器的首选机制。这是有充分理由的,因为Minifilter模型为文件系统过滤驱动程序的开发提供了出色的组织和支持框架。有了相当不错的文档和一系列重要示例(如GitHub上的示例),许多开发人员认为编写文件系统Minifilter是完全可行的。如果他们遵循一定的限制,他们是正确的。

 

本文描述了Windows文件系统Minifilter的基本架构概念。然后描述了两种不同类型的Minifilter:标准Minifilter和隔离Minifilter。最后,它描述了为开发文件系统隔离Minifilter的项目相对于开发标准Minifilter的项目而言更加复杂的原因。

 

标准Minifilters vs 隔离Minifilters

在本文中,我们澄清了Windows文件系统社区中使用的一些常见术语。

 

标准Minifilter

标准Minifilter是一个Windows文件系统Minifilter驱动程序,用于监视或跟踪文件系统数据。大多数杀毒扫描程序都是标准Minifilter。

 

隔离Minifilter

隔离Minifilter是一个Windows文件系统Minifilter驱动程序,将文件数据的视图与同一文件的实际底层数据分离开来。典型的隔离Minifilter的例子是透明加密/解密过滤器。隔离Minifilter使用“相同的堆栈”概念,并通过为每个视图提供独特的缓存区域来提供不同的视图。

 

过滤管理器和高度

文件系统Minifilter模型的基础是过滤管理器,它是一个标准的Windows组件。过滤管理器是作为传统的文件系统过滤器实现的,并过滤所有文件系统实例。因为可以在任何给定的文件系统实例上有多个过滤器(Windows 10的默认安装中包含不少于九个标准文件系统Minifilter!),过滤管理器提供了一个“高度”系统,允许开发人员决定他们的Minifilter应该安装在过滤器层级中的哪个位置。见图1。

 

图 1 – 带有三个文件系统过滤器的过滤器管理器

 

在图1中,您可以看到Windows过滤管理器(标记为FLTMGR)正在过滤作为C盘挂载的NTFS文件系统实例。在图中,过滤管理器加载了三个文件系统Minifilter:MiniFilter A、MiniFilter B和MiniFilter C。这些过滤器的顺序,MiniFilter A位于MiniFilter B之上,MiniFilter B位于MiniFilter C之上,不是随机的。相反,这是由分配给每个Minifilter的高度确定的。高度对于每个Minifilter都是唯一的,并在Minifilter安装过程中指定。

 

高度是文件系统过滤器的重要属性,因为在正确的高度进行过滤对于正常运行非常关键。例如,考虑可能安装在任意文件系统上的两个Minifilter:一个透明数据加密Minifilter和一个杀毒软件Minifilter。为了使杀毒软件Minifilter能够正常工作,它需要在文件的解密内容上进行操作。因此,杀毒软件Minifilter需要在高度上较高(即高于)数据加密Minifilter。

 

Minifilter回调函数

当Minifilter向过滤管理器注册时,除了其他事情外,它可以选择接收特定I/O操作的PreOperation和/或PostOperation回调。在将指定类型的每个I/O操作传递给被过滤的文件系统(或者实际上是下一个较低高度的Minifilter)之前,会调用PreOperation回调。在文件系统(和任何较低的Minifilter)处理特定类型的I/O操作之后,会调用PostOperation Minifilter回调。

 

过滤管理器对回调的支持非常周到。例如,当给定的Minifilter接收到PreOperation回调时,该过滤器可以:

l   完全完成操作。这将导致较低高度的Minifilter(如果有的话),甚至被过滤的文件系统都看不到此I/O操作。

l   完成操作,将其传递给较低高度的Minifilter(如果有的话)和底层文件系统,并选择在操作完成时进行回调(PostOperation回调)。

l   完成操作,将其传递给较低高度的Minifilter(如果有的话)和底层文件系统,但选择在操作完成时不进行回调(这是PostOperation回调)。

l   返回操作正在进行中。在这种情况下,Minifilter稍后会向过滤管理器报告操作的状态,包括是否需要调用任何底层实体以及是否需要PostOperation回调。

 

在其PreOperation和/或PostOperation回调中,Minifilter可以执行几乎任何操作,包括检查或修改涉及到的数据。因此,关键是理解这些操作的具体含义。

 

Win32 API vs Native Windows API

Filter Manager框架用于编写Minifilter是如此强大和周到,以至于新的Minifilter开发人员很容易被误导,认为文件系统过滤很容易。事实是:它可能很容易,但也可能会变得令人惊讶地迅速变得混乱。

 

固有的问题是,无论Filter Manager模型有多么强大或令人愉快,Windows文件系统的世界本质上是复杂的。其中一些复杂性来自于Win32 API与I/O子系统实际使用的native Windows API有时非常不同。一个简单的例子是我们在OSR经常遇到的Win32 API CopyFile。开发人员通常会惊讶地发现,这个函数没有本机的对应函数。实际上,内部的CopyFile函数打开源文件,打开目标文件,并且如果这两个操作都成功,就会从源文件读取一系列数据并将其写入目标文件,直到文件被复制完成。然后关闭源文件和目标文件。

 

一个稍微有趣一些的例子是Win32函数DeleteFile。如果你不是一个文件系统开发人员,你可能会想“删除能有多复杂?你只需要…删除文件,对吗?”在Windows中,不是这样的。本机的Windows API实际上没有一个特定的删除文件操作。相反,通过发出一个设置信息操作(ZwSetInformationFile)来指示删除文件的意图,设置文件的Disposition(FILE_DISPOSITION_INFORMATION)。这允许调用者指定当文件关闭时是否要删除文件。然而,重要的是要注意,直到文件的最后一个句柄关闭,文件才会实际上被删除。这意味着应用程序可以打开一个文件并调用Win32的DeleteFile API,但这实际上并不删除文件。它只是将文件的Disposition设置为在关闭时删除。即使应用程序随后关闭文件,这仍然不一定意味着文件会被实际删除。想象一下,如果我们的示例应用程序在另一个应用程序打开文件时打开了该文件,会发生什么。该应用程序也可以随时设置文件的Disposition。如果在我们的示例应用程序设置文件的Disposition为在关闭时删除之后,其他应用程序将文件的Disposition设置为不再标记为在关闭时删除,那么文件将不会被删除。是的…这种情况确实发生过。

 

虚拟内存系统集成

文件系统Minifilter的另一个复杂性来源于文件系统、Windows缓存管理器和Windows内存管理器之间的密切关系。我们都知道,当我们调用ReadFile时,数据从指定的数据缓冲区中读取,该数据缓冲区指示了文件句柄所表示的文件。我们中的大多数人可能也至少知道,这里通常涉及一些缓存。也就是说,我们对ReadFile的每个调用并不总是会直接从媒介中读取数据。

 

有趣的是,除非使用非缓存方式来显式打开文件,文件系统通常对处理应用程序的ReadFile调用几乎没有做太多工作,只是调用缓存管理器来处理它。在文件系统的请求下,缓存管理器将数据从与该文件打开实例相关联的缓存区复制到应用程序的数据缓冲区中。这在图2中有所说明。

图2 – 文件系统使用缓存管理器来处理读取操作


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//