错误检查 0x139:KERNEL_SECURITY_CHECK_FAILURE

KERNEL_SECURITY_CHECK_FAILURE bug 检查的值为 0x00000139,并指示内核检测到关键数据结构的损坏。

重要

这篇文章适合程序员阅读。 如果你是使用计算机时收到蓝屏错误代码的客户,请参阅 “排查蓝屏错误”。

错误检查 0x139 KERNEL_SECURITY_CHECK_FAILURE 参数

参数 说明
1 损坏的类型。 有关详细信息,请参阅下表。
2 导致错误检查的异常的陷阱帧的地址
3 导致错误检查的异常的异常记录的地址
4 已预留

下表对参数 1 的可能值进行了说明。

参数 1 说明
0 基于堆栈的缓冲区溢出(旧版 /GS 冲突)。
1 VTGuard 检测代码检测到使用非法虚拟函数表的尝试。 通常,C++对象已损坏,然后虚拟方法调用尝试使用损坏对象的 指针。
2 堆栈 Cookie 检测代码检测到基于堆栈的缓冲区溢出(/GS 违规)。
3 LIST_ENTRY已损坏(例如,双重删除)。 有关详细信息,请参阅以下“原因”部分。
4 已预留
5 将无效参数传递给一个将无效参数视为致命参数的函数。
6 加载程序未正确初始化堆栈 Cookie 安全 Cookie。 此 bug 检查的原因是生成驱动程序仅在 Windows 8 上运行,并尝试在早期版本的 Windows 上加载驱动程序映像。 若要避免此问题,必须生成要在早期版本的 Windows 上运行的驱动程序。
7 请求了致命程序退出。
8 编译器插入的数组边界检查检测到非法数组索引作。
9 RtlQueryRegistryValues 的 调用是在不使用RTL_QUERY_REGISTRY_TYPECHECK的情况下指定RTL_QUERY_REGISTRY_DIRECT,并且目标值不在受信任的系统配置单元中。
10 间接呼叫临界检查检测到无效的控制传输。
11 写入临界检查检测到无效的内存写入。
12 尝试切换到无效的纤程上下文。
13 已尝试分配无效的寄存器上下文。
14 对象的引用计数无效。
18 尝试切换到无效的 jmp_buf 上下文。
19 对只读数据进行了不安全的修改。
20 加密自我测试失败。
21 检测到无效的异常链。
22 发生加密库错误。
23 在 DllMain 中进行了无效的调用。
24 检测到无效的映像基址。
25 保护延迟加载导入时遇到无法恢复的失败。
26 已调用不安全的扩展。
27 调用了已弃用的服务。
28 检测到超出边界的缓冲区访问。
29 RTL_BALANCED_NODE RBTree 条目已损坏。
37 调用了超出范围的开关跳转项。
38 longjmp 尝试到无效的目标。
39 无法将导出禁止调用目标作为有效的呼叫目标。

原因

使用参数 1 表和转储文件,可以缩小此类型的许多 bug 检查的原因。

LIST_ENTRY腐败可能很难跟踪。 此 bug 检查指示将不一致引入到一个双重链接列表中(在向列表中添加或删除单个列表条目元素时检测到)。 遗憾的是,在损坏发生时不一定检测到不一致,因此可能需要一些侦探工作来确定根本原因。

列表项损坏的常见原因包括:

  • 驱动程序损坏了内核同步对象,例如 KEVENT(例如,当线程仍在等待同一 KEVENT 时对 KEVENT 进行双重初始化,或者允许基于堆栈的 KEVENT 在另一个线程使用该 KEVENT 时超出范围)。 这种类型的错误检查通常发生在 nt!Ke* 或 nt!Ki* 代码。 当线程完成等待同步对象或代码尝试将同步对象置于信号状态时,可能会发生这种情况。 通常,要发出信号的同步对象是已损坏的同步对象。 有时,具有特殊池的驱动程序验证程序可以帮助跟踪罪魁祸首(如果损坏的同步对象位于已释放的池块中)。
  • 驱动程序损坏了定期 KTIMER。 这种类型的错误检查通常发生在 nt!Ke* 或 nt!Ki* 代码,并涉及向计时器发出信号,或者插入或删除计时器表中的计时器。 正在作的计时器可能是损坏的计时器,但可能需要使用 !timer 检查计时器表(或手动行走计时器列表链接),以确定哪个计时器已损坏。 有时,具有特殊池的驱动程序验证程序可以帮助跟踪罪魁祸首(如果损坏的 KTIMER 位于已释放的池块中)。
  • 驱动程序管理了内部LIST_ENTRY样式的链接列表。 典型的示例是在同一列表条目上调用 RemoveEntryList 两次,而无需重新插入两个 RemoveEntryList 调用之间的列表项。 其他变体可行,例如将条目插入到同一列表中。
  • 驱动程序释放了包含LIST_ENTRY的数据结构,而不会从其相应的列表中删除数据结构,导致在重新使用旧池块后检查列表后检测到损坏。
  • 驱动程序以并发方式使用LIST_ENTRY样式的列表,而无需进行适当的同步,从而导致对列表进行撕裂更新。

在大多数情况下,可以通过向前和向后走链接列表(dldlb 命令可用于此目的)和比较结果来确定损坏的数据结构。 如果列表在向前和向后走之间不一致,通常是损坏的位置。 由于链接列表更新操作可以修改相邻元素的列表链接,因此应仔细查看损坏的列表条目的邻居,因为它们可能是基础罪魁祸首。

由于许多系统组件在内部利用 LIST_ENTRY 列表,因此使用系统 API 的驱动程序进行各种类型的资源管理不当可能会导致系统管理的链接列表损坏。

解决方法

确定列表项损坏问题的原因通常需要使用调试器来收集其他信息。 应检查多个转储文件,以确定停止代码是否具有类似的特征,例如在停止代码出现时运行的代码。

有关详细信息,请参阅使用 Windows 调试器 (WinDbg) 进行崩溃转储分析使用 !analyze 扩展!analyze

使用事件日志查看是否存在导致停止代码的更高级别事件。

这些常规故障排除提示可能会有所帮助。

  • 如果最近向系统添加了硬件,请尝试删除或替换它。 或与制造商联系,查看是否有可用的修补程序。

  • 如果最近添加了新的设备驱动程序或系统服务,请尝试删除或更新它们。 尝试确定系统中导致新错误检查代码出现的原因。

  • 检查事件查看器中的系统日志是否有其他错误消息,这些错误消息可能有助于查明导致错误的设备或驱动程序。 在系统日志中查找与蓝屏同时出现的严重错误。

  • 设备管理器中查看是否有任何设备标有感叹号 (!)。 查看驱动程序属性中显示的事件日志,以查找任何故障驱动程序。 请尝试更新相关驱动程序。

  • 运行病毒检测程序。 病毒可感染针对 Windows 格式化的所有类型的硬盘,由此导致的磁盘损坏可能会生成系统错误检查代码。 确保病毒检测程序检查主启动记录是否存在感染。

  • 有关更常规的故障排除信息,请参阅 “分析 Bug 检查蓝屏数据”。

另请参阅

使用 Windows 调试器 (WinDbg) 进行故障转储分析

使用 WinDbg 分析内核模式转储文件