处理 UMDF 1.x 驱动程序中的客户端模拟

警告

UMDF 2 是 UMDF 的最新版本,取代了 UMDF 1。 所有新的 UMDF 驱动程序都应使用 UMDF 2 编写。 不会向 UMDF 1 添加任何新功能,并且较新版本的 Windows 10 上对 UMDF 1 的支持有限。 通用 Windows 驱动程序必须使用 UMDF 2。

存档的 UMDF 1 示例可在 Windows 11 版本 22H2 - 2022 年 5 月驱动程序示例更新中找到。

有关详细信息,请参阅使用 UMDF 入门

UMDF 驱动程序通常在 LocalService 帐户下运行,无法访问需要用户凭据的文件或资源,例如受保护的文件或其他受保护的资源。 UMDF 驱动程序通常对在客户端应用程序和设备之间流动的命令和数据进行操作。 因此,大多数 UMDF 驱动程序不会访问受保护的资源。

但是,某些驱动程序可能需要访问受保护的资源。 例如,UMDF 驱动程序可能会从客户端应用程序提供的文件将固件加载到设备中。 该文件可能有一个访问控制列表 (ACL) ,可防止未经授权的用户修改文件并控制设备。 遗憾的是,此 ACL 还会阻止 UMDF 驱动程序访问该文件。

框架提供模拟功能,使驱动程序能够模拟驱动程序的客户端,并获取客户端对受保护资源的访问权限。

启用模拟

UMDF 驱动程序的安装包和客户端应用程序都必须启用框架的模拟功能,如下所示:

  • UMDF 驱动程序安装包的 INF 文件必须包含 UmdfImpersonationLevel 指令,并设置允许的最大模拟级别。 仅当 INF 文件包含 UmdfImpersonationLevel 指令时,才会启用模拟。 有关设置模拟级别的详细信息,请参阅 在 INF 文件中指定 WDF 指令

  • 客户端应用程序必须为每个文件句柄设置允许的模拟级别。 应用程序使用 Microsoft Win32 CreateFile 函数中的服务质量 (QoS) 设置来设置允许的模拟级别。 有关这些设置的详细信息,请参阅 Windows SDK 文档中 CreateFiledwFlagsAndAttributes 参数。

处理 I/O 请求的模拟

UMDF 驱动程序和框架按以下顺序处理 I/O 请求的模拟:

  1. 驱动程序调用 IWDFIoRequest::Impersonate 方法以指定所需的模拟级别和 IImpersonateCallback::OnImpersonate 回调函数。

  2. 框架检查请求的模拟级别。 如果请求的级别大于 UMDF 驱动程序的安装包和客户端应用程序允许的级别,则模拟请求将失败。 否则,框架将模拟客户端并立即调用 OnImpersonate 回调函数。

OnImpersonate 回调函数只能执行需要所请求模拟级别的操作,例如打开受保护的文件。

UMDF 不允许驱动程序的 OnImpersonate 回调函数调用框架的任何对象方法。 这可确保驱动程序不会向其他驱动程序回调函数或其他驱动程序公开模拟级别。

注意 在 UMDF 版本 1.0 到 1.7 中, IWDFIoRequest::Impersonate 授予客户端应用程序和 INF 文件允许的最高模拟级别,即使驱动程序请求的模拟级别较低。 在 UMDF 版本 1.9 及更高版本中, Impersonate 方法仅授予驱动程序请求的模拟级别。

将凭据向下传递驱动程序堆栈

当驱动程序收到 WdfRequestCreate 类型的 I/O 请求时,驱动程序可能会将 I/O 请求转发到内核模式驱动程序堆栈。 内核模式驱动程序没有 IWDFIoRequest::Impersonate 为基于 UMDF 的驱动程序提供的模拟功能。

因此,如果希望内核模式驱动程序接收客户端的用户凭据 (而不是驱动程序主机进程) 的凭据,驱动程序必须在调用 IWDFIoRequest::Send 时设置WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT标志,以便将创建请求发送到 I/O 目标。 如果模拟尝试失败, Send 方法将返回错误代码,除非驱动程序还设置了 WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE 标志。

驱动程序在将请求发送到 I/O 目标之前不必调用 IWDFIoRequest::Impersonate

如果较低级别的驱动程序也转发请求,则客户端的模拟级别会向下传输驱动程序堆栈。

减少安全威胁

若要降低“特权提升”攻击的可能性,应:

  • 尽量避免使用模拟。

    例如,为了避免使用模拟打开驱动程序必须使用的文件,客户端应用程序可以打开该文件并使用 I/O 操作将文件内容发送到驱动程序。

  • 使用驱动程序所需的最低模拟级别。

    将驱动程序 INF 文件中的模拟级别设置为尽可能低。 如果驱动程序不需要任何模拟,请不要在 INF 文件中包含 UmdfImpersonationLevel 指令。

  • 最大程度地减少攻击者利用你的驱动程序的机会。

    OnImpersonate 回调函数应包含一小部分代码,这些代码仅执行需要模拟的操作。 例如,如果驱动程序访问受保护的文件,则仅在打开文件句柄时需要模拟。 它不需要模拟来读取或写入文件。