自动检查
驱动程序验证程序在验证一个或多个驱动程序时执行以下检查。 无法激活或停用这些检查。 从 Windows 10 版本 1709 开始,这些自动检查已移动到相关的标准标志中。 因此,使用标准标志启用驱动程序验证程序的用户应看到检查不会减少。
监视 IRQL 和内存例程
驱动程序验证程序监视所选驱动程序的以下禁止操作:
通过调用 KeLowerIrql 提高 IRQL
通过调用 KeRaiseIrql 降低 IRQL
请求大小为零的内存分配
使用 IRQL > APC_LEVEL分配或释放分页池
使用 IRQL > DISPATCH_LEVEL分配或释放非分页池
尝试释放未从以前的分配返回的地址
尝试释放已释放的地址
使用 IRQL > APC_LEVEL获取或释放快速互斥体
使用 IRQL 获取或释放旋转锁不等于DISPATCH_LEVEL
双重释放旋转锁。
将分配请求标记为MUST_SUCCEED。 不允许此类请求。
如果驱动程序验证程序未处于活动状态,这些冲突可能不会在所有情况下都立即导致系统崩溃。 驱动程序验证程序监视驱动程序的行为,并在发生任何这些冲突时检查 0xC4发出 bug。 有关 bug 检查参数的列表,请参阅 bug 检查0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION) 。
监视堆栈切换
驱动程序验证程序监视正在验证的驱动程序的堆栈使用情况。 如果驱动程序切换其堆栈,并且新堆栈既不是线程堆栈也不是 DPC 堆栈,则会发出 bug 检查。 (这是第一个参数等于 0x90 的 bug 检查 0xC4。) KB 调试器命令显示的堆栈通常会显示执行此操作的驱动程序。
检查驱动程序卸载
正在验证的驱动程序卸载后,驱动程序验证程序将执行多次检查,以确保驱动程序已清理。
具体而言,驱动程序验证程序查找:
未删除的计时器
挂起的延迟过程调用 (DPC)
未删除的旁视列表
未删除的工作线程
未删除的队列
其他类似资源
此类问题可能会导致在驱动程序卸载后一段时间发出系统 bug 检查,并且很难确定这些 bug 检查的原因。 驱动程序验证程序处于活动状态时,此类冲突将导致在卸载驱动程序后立即发出 bug 检查 0xC7。 有关 bug 检查参数的列表,请参阅 bug 检查0xC7 (TIMER_OR_DPC_INVALID) 。
监视内存描述符列表 (MDL) 使用情况
在 Windows Vista 中,驱动程序验证程序还会监视所选驱动程序的以下禁止操作:
在没有相应标志的 MDL 上调用 MmProbeAndLockPages 或 MmProbeAndLockProcessPages。 例如,为使用 MmBuildMdlForNonPagedPool 创建的 MDL 调用 MmProbeAndLockPages 不正确。
在没有相应标志的 MDL 上调用 MmMapLockedPages 。 例如,为已映射到系统地址的 MDL 或未锁定的 MDL 调用 MmMapLockedPages 不正确。
在部分 MDL 上调用 MmUnlockPages 或 MmUnmapLockedPages ,即使用 IoBuildPartialMdl 创建的 MDL。
在未映射到系统地址的 MDL 上调用 MmUnmapLockedPages 。
如果驱动程序验证程序未处于活动状态,这些冲突可能不会导致系统在所有情况下立即停止响应。 驱动程序验证程序监视驱动程序的行为,并在发生任何这些冲突时检查 0xC4发出 bug。 有关 bug 检查参数的列表,请参阅 bug 检查0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION) 。
NonPagedPoolSession 内存中的同步对象分配
从 Windows 7 开始,驱动程序验证程序会从会话内存中检查同步对象。
同步对象必须是不可分页的。 它们还必须位于全球系统范围的虚拟地址空间中。
图形驱动程序可以通过调用 EngAllocMem 等 API 来分配会话内存。 与全局地址空间不同,会话地址空间是针对每个终端服务器会话虚拟化的。 这意味着,在两个不同会话的上下文中使用的同一虚拟地址引用两个不同的对象。 Windows 内核必须能够从任何终端服务器会话访问同步对象。 尝试从其他会话引用会话内存地址会产生不可预知的结果,例如系统崩溃或另一个会话的数据无提示损坏。
从 Windows 7 开始,当已验证的驱动程序通过调用 API(如 KeInitializeEvent 或 KeInitializeMutex)初始化同步对象时,驱动程序验证程序会检查该对象的地址是否位于会话虚拟地址空间内。 如果驱动程序验证程序检测到此类地址不正确,则会发出 bug 检查0xC4:DRIVER_VERIFIER_DETECTED_VIOLATION,参数 1 值为 0xDF。
对象引用计数器更改从 0 更改为 1
从 Windows 7 开始,驱动程序验证程序会检查错误对象引用的其他类。
当 Windows 内核对象管理器创建对象(如 File 对象或 Thread 对象)时,新对象的引用计数器设置为 1。 引用计数器通过调用 API(如 ObReferenceObjectByPointer 或 ObReferenceObjectByHandle)递增。 对同一对象的每个 ObDereferenceObject 调用都会递减引用计数器。
引用计数器达到 0 值后,对象将有资格被释放。 对象管理器可能会立即释放它,也可能稍后释放它。 调用 ObReferenceObjectByPointer 或 ObDereferenceObject 并将引用计数器从 0 更改为 1 意味着递增已释放对象的引用计数器。 这始终不正确,因为它可能会导致损坏其他人的内存分配。
系统关闭阻止或延迟
从 Windows 7 开始,如果系统在启动 20 分钟后系统关闭未完成,驱动程序验证程序会中断内核调试器。 驱动程序验证程序在 Windows 内核开始关闭其各种子系统(如注册表、即插即用或 I/O 管理器子系统)时分配系统关闭的开始时间。
如果未将内核调试器附加到系统,驱动程序验证程序 会发出 bug 检查0xC4:DRIVER_VERIFIER_DETECTED_VIOLATION,参数 1 值为 0x115,而不是此断点。
系统关闭通常不能在 20 分钟内完成,表明在该系统上运行的驱动程序之一出现故障。 从内核调试器运行 !analyze -v 会显示负责关闭的系统工作线程的堆栈跟踪。 应检查该堆栈跟踪,并确定正在测试的某个驱动程序是否阻止了关闭线程。
有时,系统无法关闭,因为它受到繁重的压力测试,即使所有驱动程序都正常运行。 用户可以选择在此驱动程序验证程序断点后继续执行,并检查系统最终是否关闭。