驱动程序与内存完整性和 VBS 的兼容性

内存完整性一种基于虚拟化的安全 (VBS) 功能,可用于Windows 10、Windows 11、Windows Server 2016及更高版本。 内存完整性和 VBS 改进了 Windows 的威胁模型,并针对试图利用 Windows 内核的恶意软件提供更强大的保护。 VBS 使用 Windows 虚拟机监控程序创建独立的虚拟环境,该环境成为假定内核可能遭到入侵的 OS 的信任根。 内存完整性是一个关键组件,它通过在 VBS 的隔离虚拟环境中运行内核模式代码完整性来保护和强化 Windows。 内存完整性还限制可用于危害系统的内核内存分配,确保内核内存页仅在安全运行时环境中传递代码完整性检查后才成为可执行文件,并且可执行页本身永远不会可写。

备注

内存完整性有时称为 虚拟机监控程序保护的代码完整性 (HVCI) 虚拟机监控程序强制实施的代码完整性,最初作为 Device Guard 的一部分发布。 除了在 组策略 或 Windows 注册表中查找内存完整性和 VBS 设置外,不再使用 Device Guard。

默认情况下,在 S 模式下全新安装 Windows 10 时,内存完整性处于打开状态,并在兼容硬件上Windows 11,如启用内存完整性中所述。 在不符合内存完整性自动启用要求的其他系统上,客户可以选择使用 如何启用内存完整性中所述的任何方法。

应用程序兼容性

尽管自 Windows 10 周年更新 (1607) 以来,所有驱动程序都要求与内存完整性兼容,但某些应用程序和硬件设备驱动程序可能仍不兼容。 这种不兼容可能会导致设备或软件发生故障,在极少数情况下,可能导致蓝屏) (启动失败。 在启用内存完整性保护后或启用过程本身期间,可能会出现此类问题。 如果你是应用程序开发人员,并且想要验证驱动程序和软件包是否与内存完整性兼容,请按照以下步骤操作。

我们观察到内存完整性不兼容的一些示例包括:

  • 游戏反作弊解决方案
  • 第三方输入方法
  • 第三方银行密码保护

我们努力缓解受影响的体验,因此,如果启动关键驱动程序存在不兼容问题,如果已自动启用内存完整性保护,则会以无提示方式关闭内存完整性保护。 如果与其他应用不兼容,建议在关闭内存完整性保护之前,检查特定应用和遇到问题的版本的更新。

如何生成兼容的驱动程序

由于内存页和节永远都不能写入和执行,因此第一步是确保数据和代码明确分离,而不是尝试直接修改代码页。

  • 默认选择启用 NX
  • 使用 NX API/标志进行内存分配 - NonPagedPoolNx
  • 不要使用既可写又可执行的节
  • 不要尝试直接修改可执行系统内存
  • 不要在内核中使用动态代码
  • 不要将数据文件加载为可执行文件
  • 节对齐必须是 0x1000 (PAGE_SIZE) 的倍数。 例如,DRIVER_ALIGNMENT=0x1000

使用默认设置时,使用最新版本的 WDKVisual Studio 生成兼容的驱动程序。

如何验证驱动程序与内存完整性的兼容性

验证驱动程序兼容性有三个步骤:

  1. 使用驱动程序验证程序 (请参阅下面的部分,) 启用了代码完整性兼容性检查。
  2. 在启用了内存完整性的系统上测试驱动程序。
  3. 在 Windows HLK 中运行虚拟机监控程序代码完整性就绪情况测试

驱动程序验证工具兼容性检查

驱动程序验证程序具有代码完整性选项标志 (0x02000000) ,用于启用额外的检查来验证内存完整性。 若要从命令行启用此标志,请使用以下命令:

verifier.exe /flags 0x02000000 /driver <driver.sys>

若要在使用验证工具 GUI 时选择此选项,请选择“创建自定义设置(适用于代码开发人员)”,选择“下一步”,然后选择“代码完整性检查”。

如果成功,则没有输出。 下面是失败输出的示例。

Driver Verifier: Enabled for DvCi.sys, flags 0x2000000, build 16299, key o4Dbg8OVJqaBYlqWQ2QvRH

\*\*\*\*\*\*\*\*\*\*\* Verifier Detected a Code Integrity Issue \*\*\*\*\*\*\*\*\*\*\*\*

\*\* The caller 0xFFFFF8094B9852F0 specified an executable page protection 0x40.

\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

\*\*\* Verifier assertion failed \*\*\*

(B)reak, (I)gnore, (W)arn only, (R)emove assert? B

在启用内存完整性的情况下测试驱动程序

尽管 Windows 默认会为大多数系统启用内存完整性,但有多种原因可能会阻止这种情况发生。 若要启用内存完整性,请参阅 如何打开内存完整性。 然后,测试驱动程序的功能。 请务必练习驱动程序中的所有代码路径,以确保驱动程序在运行时不会执行与内存完整性不兼容的操作。

HLK 测试(桌面和服务器)

HLK 测试 HyperVisor 代码完整性就绪性测试 必须通过才能批准驱动程序进行 Microsoft 签名。 桌面版和服务器版都需要内存完整性兼容的驱动程序。 HLK 测试是一项基本测试,旨在确保操作系统正确加载和运行与内存完整性兼容的驱动程序。

尽管只需通过 HLK 测试即可获得驱动程序的 Microsoft 签名,但我们强烈建议在启用内存完整性的情况下进行彻底的功能测试。 例如,可能存在错误编码的内存分配违反 NX 保护,从而导致测试无法捕获的故障。 驱动程序作者应全面测试驱动程序,同时保持内存完整性。

在驱动程序开发和 HLK 测试期间,可能需要禁用内存完整性,因为它可能会阻止驱动程序加载。

HLK 虚拟机监控程序代码完整性就绪性测试是 Windows Server 保障 AQ 的一部分所必需的,在其他 HLK 测试期间启用驱动程序验证程序时,还会设置启用代码完整性检查的标志。

常见问题

现有驱动程序怎么办? 是否需要重新生成这些驱动程序以使其在 Windows 10 上工作?

视情况而定。 许多驱动程序已经具备兼容性。 如果对旧版 WDK 和 Visual Studio 使用标准设置,则会出现一个已知问题,即 INIT 节标记为 RWX。 但是,在 Windows 10 中,W 将被自动去除,所以如果这是唯一的问题,驱动程序将具备兼容性。

如何实现验证是否启用了内存完整性?

最简单的方法是 (msinfo32) 运行系统信息应用。 查找以下行:“基于虚拟化的安全服务正在运行”。 它应报告为:“虚拟机监控程序强制执行了代码完整性”。 还有一个 WMI 接口,用于使用管理工具进行检查,请参阅 验证已启用的 VBS 和内存完整性功能

还可以在设置>更新&安全性>>Windows 安全中心设备安全>核心隔离详细信息>内存完整性Windows 安全中心应用中检查内存完整性。 有关详细信息,请参阅 KB4096339

是否可以验证是否已从内核以编程方式启用内存完整性以更改驱动程序行为?

是的,你可以使用 NtQuerySystemInformation:https://msdn.microsoft.com/library/windows/desktop/ms724509(v=vs.85).aspx

SYSTEM_CODEINTEGRITY_INFORMATION 结构公开了0x400值,指示内存完整性处于打开状态。

如何解决兼容性问题?

除了仔细检查是否没有 W+X 页面以及驱动程序节是否正确对齐(如上所述)外,最可能的问题是内存分配不当。 若要了解与内存分配相关的代码分析警告,请参阅 MSDN 上的以下页面:

驱动程序的代码分析警告

以下 MSDN 链接显示了一些导致分配可执行内存的常用 API 示例,以及一些修复示例:

使用下表解释输出,以确定需要更改哪些驱动程序代码来解决不同类型的 HVCI 不兼容问题。

警告 解决方法
执行池类型 调用方指定了一个可执行池类型。 调用请求可执行内存的内存分配函数。 确保所有池类型都包含非可执行 NX 标志。
执行页面保护 调用方指定了一个可执行页面保护。 指定“不执行”页面保护掩码。
执行页面映射 调用方指定了一个可执行内存描述符列表 (MDL) 映射。 确保使用的掩码包含 MdlMappingNoExecute。 有关详细信息,请参阅 MmGetSystemAddressForMdlSafe
执行-写入节 映像包含可执行和可写节。
节对齐失败 映像包含未对齐页面的节。 节对齐必须是 0x1000 (PAGE_SIZE) 的倍数。 例如,DRIVER_ALIGNMENT=0x1000
不支持的重定位 在 Windows 10 版本 1507 到版本 1607 中,由于使用地址空间布局随机化 (ASLR),地址对齐和内存重定位可能会出现问题。 操作系统需要将链接器从其设置默认基址的地址重定位到 ASLR 分配的实际位置。 此重定位不能跨越页面边界。 例如,假设有一个 64 位地址值,该值在页面中从偏移量 0x3FFC 开始。 该地址值在偏移量 0x0003 处与下一页重叠。 在 Windows 10 版本 1703 之前,不支持这种重叠重定位。

当全局结构类型变量初始值设定项具有指向另一个全局变量的未对齐指针时,可能会发生这种情况,其布局方式使得链接器无法移动变量以避免跨页重定位。 链接器将尝试移动变量,但在某些情况下它可能无法移动,例如大型未对齐结构或未对齐结构的大型数组。 在适当的情况下,应使用 /Gy (COMDAT) 选项组装模块,以允许链接器尽可能对齐模块代码。

#include <pshpack1.h>

typedef struct _BAD_STRUCT {
      USHORT Value;
      CONST CHAR *String;
} BAD_STRUCT, * PBAD_STRUCT;

#include <poppack.h>

#define BAD_INITIALIZER0 { 0, "BAD_STRING" },
#define BAD_INITIALIZER1 \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0

#define BAD_INITIALIZER2 \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1

#define BAD_INITIALIZER3 \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2

#define BAD_INITIALIZER4 \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3

BAD_STRUCT MayHaveStraddleRelocations[4096] = { // as a global variable
      BAD_INITIALIZER4
};

在其他涉及使用汇编程序代码的情况下,也可能出现此问题。

可执行节中的 IAT 导入地址表 (IAT) 不应是内存的可执行节。

当 IAT 位于内存的只读和执行 (RX) 节时,会出现此问题。 这意味着 OS 将无法写入 IAT 来为引用的 DLL 设置正确的地址。

在代码链接中使用 /MERGE(合并节)选项时可能会出现这种情况。 例如,如果 .rdata(只读初始化数据)与 .text 数据(可执行代码)合并,IAT 可能最终位于内存的可执行节中。

哪些 API 可能受到影响?

以下列表中这些未保留供系统使用的 API 可能会受到影响:

   
API 名称 说明
ExAllocatePool https://msdn.microsoft.com/library/windows/hardware/ff544501(v=vs.85).aspx
ExAllocatePoolWithQuota https://msdn.microsoft.com/library/windows/hardware/ff544506(v=vs.85).aspx
ExAllocatePoolWithQuotaTag https://msdn.microsoft.com/library/windows/hardware/ff544513(v=vs.85).aspx
ExAllocatePoolWithTag https://msdn.microsoft.com/library/windows/hardware/ff544520(v=vs.85).aspx
ExAllocatePoolWithTagPriority https://msdn.microsoft.com/library/windows/hardware/ff544523(v=vs.85).aspx
ExInitializeNPagedLookasideList https://msdn.microsoft.com/library/windows/hardware/ff545301(v=vs.85).aspx
ExInitializeLookasideListEx https://msdn.microsoft.com/library/windows/hardware/ff545298(v=vs.85).aspx
MmAllocateContiguousMemory https://msdn.microsoft.com/library/windows/hardware/ff554460(v=vs.85).aspx
MmAllocateContiguousMemorySpecifyCache https://msdn.microsoft.com/library/windows/hardware/ff554464(v=vs.85).aspx
MmAllocateContiguousMemorySpecifyCacheNode https://msdn.microsoft.com/library/windows/hardware/ff554464(v=vs.85).aspx
MmAllocateContiguousNodeMemory https://msdn.microsoft.com/library/windows/hardware/jj602795(v=vs.85).aspx
MmCopyMemory https://msdn.microsoft.com/library/windows/hardware/dn342884(v=vs.85).aspx
MmMapIoSpace https://msdn.microsoft.com/library/windows/hardware/ff554618(v=vs.85).aspx
MmMapLockedPages https://msdn.microsoft.com/library/windows/hardware/ff554622(v=vs.85).aspx
MmMapLockedPagesSpecifyCache https://msdn.microsoft.com/library/windows/hardware/ff554629(v=vs.85).aspx
MmProtectMdlSystemAddress https://msdn.microsoft.com/library/windows/hardware/ff554670(v=vs.85).aspx
ZwAllocateVirtualMemory https://msdn.microsoft.com/library/windows/hardware/ff566416(v=vs.85).aspx
ZwCreateSection https://msdn.microsoft.com/library/windows/hardware/ff566428(v=vs.85).aspx
ZwMapViewOfSection https://msdn.microsoft.com/library/windows/hardware/ff566481(v=vs.85).aspx
NtCreateSection https://msdn.microsoft.com/library/windows/hardware/ff556473(v=vs.85).aspx
NtMapViewOfSection https://msdn.microsoft.com/library/windows/hardware/ff556551(v=vs.85).aspx
StorPortGetDataInBufferSystemAddress https://msdn.microsoft.com/library/windows/hardware/jj553720(v=vs.85).aspx
StorPortGetSystemAddress https://msdn.microsoft.com/library/windows/hardware/ff567100(v=vs.85).aspx
DxgkCbMapMemory https://msdn.microsoft.com/library/windows/hardware/ff559533(v=vs.85).aspx
IMiniportDMus::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536701(v=vs.85).aspx
FltAllocatePoolAlignedWithTag https://msdn.microsoft.com/library/windows/hardware/ff541762(v=vs.85).aspx
FltAllocateContext https://msdn.microsoft.com/library/windows/hardware/ff541710(v=vs.85).aspx
ChangerClassAllocatePool https://msdn.microsoft.com/library/windows/hardware/ff551402(v=vs.85).aspx
IMiniportMidi::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536710(v=vs.85).aspx
IMiniportWaveCyclic::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536723(v=vs.85).aspx
IPortWavePci::NewMasterDmaChannel https://msdn.microsoft.com/library/windows/hardware/ff536916(v=vs.85).aspx
IMiniportWavePci::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536735(v=vs.85).aspx
PcNewDmaChannel https://msdn.microsoft.com/library/windows/hardware/ff537712(v=vs.85).aspx
PcNewResourceList https://msdn.microsoft.com/library/windows/hardware/ff537717(v=vs.85).aspx
PcNewResourceSublist https://msdn.microsoft.com/library/windows/hardware/ff537718(v=vs.85).aspx
VideoPortAllocatePool https://msdn.microsoft.com/library/windows/hardware/ff570180(v=vs.85).aspx
ClfsCreateMarshallingArea https://msdn.microsoft.com/library/windows/hardware/ff541520(v=vs.85).aspx
WdfLookasideListCreate https://msdn.microsoft.com/library/windows/hardware/ff548694(v=vs.85).aspx
WdfMemoryCreate https://msdn.microsoft.com/library/windows/hardware/ff548706(v=vs.85).aspx
WdfDeviceAllocAndQueryProperty https://msdn.microsoft.com/library/windows/hardware/ff545882(v=vs.85).aspx
WdfDeviceAllocAndQueryPropertyEx https://msdn.microsoft.com/library/windows/hardware/dn265599(v=vs.85).aspx
WdfFdoInitAllocAndQueryProperty https://msdn.microsoft.com/library/windows/hardware/ff547239(v=vs.85).aspx
WdfFdoInitAllocAndQueryPropertyEx https://msdn.microsoft.com/library/windows/hardware/dn265612(v=vs.85).aspx
WdfIoTargetAllocAndQueryTargetProperty https://msdn.microsoft.com/library/windows/hardware/ff548585(v=vs.85).aspx
WdfRegistryQueryMemory https://msdn.microsoft.com/library/windows/hardware/ff549920(v=vs.85).aspx
NdisAllocateMemory https://msdn.microsoft.com/library/windows/hardware/ff550762(v=vs.85).aspx