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