【发布时间】:2016-03-12 17:52:21
【问题描述】:
基本上,这与here 提出的问题相同。
在运行 Windows 7 或更早版本(使用 WinDbg 6.2 及更高版本)的机器上执行内核调试时,调试器不会在寄存器窗口中显示任何内容。按Customize... 按钮会出现一个显示Registers are not yet known 的消息框。
同时,发出r 命令会打印出完全有效的寄存器值。
这种行为的原因是什么,可以修复吗?
【问题讨论】:
基本上,这与here 提出的问题相同。
在运行 Windows 7 或更早版本(使用 WinDbg 6.2 及更高版本)的机器上执行内核调试时,调试器不会在寄存器窗口中显示任何内容。按Customize... 按钮会出现一个显示Registers are not yet known 的消息框。
同时,发出r 命令会打印出完全有效的寄存器值。
这种行为的原因是什么,可以修复吗?
【问题讨论】:
TL;DR:我写了一个扩展 DLL 来修复这个错误。可用here。
要理解这个问题,我们首先需要了解 WinDbg 基本上只是 Microsoft 的 Windows 符号调试器引擎 的前端,在 dbgeng.dll 内部实现。其他前端包括命令行kd.exe(内核调试器)和cdb.exe(用户模式调试器)。
引擎实现了我们对调试器的期望:处理符号文件、读写内存和寄存器、设置断点等。然后引擎通过类似 COM 的接口公开所有这些功能(它们实现了 IUnknown 但不是注册组件)。例如,这允许我们编写自己的调试器(就像 this person 所做的那样)。
有了这些知识,我们现在可以对 WinDbg 如何获取目标机器上的寄存器值做出有根据的猜测。
引擎公开了用于操作寄存器的IDebugRegisters 接口。该接口声明了GetValues 方法,用于一次性检索多个寄存器的值。但是 WinDbg 怎么知道有多少个寄存器呢?这就是为什么我们有 GetNumberRegisters 方法的原因。
因此,要检索目标上所有寄存器的值,我们必须执行以下操作:
IDebugRegisters::GetNumberRegisters获取寄存器总数。IDebugRegisters::GetValues,将Count参数设置为寄存器总数,Indices参数设置为NULL,Start参数设置为0。不过有一个小问题:第二次调用失败并显示E_INVALIDARG。
嗯,对不起?怎么会失败?尤其令人费解的是这个返回值的文档:
其中一个寄存器的索引值大于目标机器上的寄存器数。
但我只是问你有多少个寄存器,那么这个值怎么会超出范围呢?好吧,不管怎样,让我们继续阅读文档,也许有些事情会变得清晰:
如果返回值不是 S_OK,则可能仍会读取一些寄存器。如果目标不可访问,则返回类型为 E_UNEXPECTED 且值不变; 否则,值将包含部分结果,并且无法读取的寄存器将具有 DEBUG_VALUE_INVALID 类型。
(强调我的。)
啊哈!所以也许引擎只是无法读取其中一个寄存器!但是哪一个?结果发现引擎在xcr0 寄存器上阻塞。摘自英特尔 64 和 IA-32 架构软件开发人员手册:
扩展控制寄存器
XCR0包含一个状态组件位图,它指定软件已启用XSAVE功能集以管理的用户状态组件。如果在XCR0中清除了与状态组件对应的位,则XSAVE功能集中的指令将不会对该状态组件进行操作,无论指令掩码的值如何。
好的,所以寄存器控制XSAVE指令的操作,它保存了CPU的扩展功能(如XMM和AVX)的状态。根据this页面上的最后一条评论,该指令需要操作系统的一些支持。尽管评论指出 Windows 7(这是我正在测试的 VM 正在运行的)确实支持此指令,但似乎手头的问题无论如何都与操作系统有关,因为当目标是 Windows 8 时一切正常。
确实,不清楚该错误是在调试器引擎中,它报告的寄存器数量超过了它可以检索的值,还是在 WinDbg 中,如果引擎失败,它根本拒绝显示 任何 值生产所有个。
当然,我们可以咬紧牙关,只使用旧版本的 WinDbg 来调试旧的 Windows 版本。但其中的挑战在哪里?
相反,我向您介绍解决此问题的debugger extension。它通过挂钩(在this library 的帮助下)相关的调试器引擎方法并返回S_OK,如果唯一失败的寄存器是xcr0。否则,它会传播失败。该扩展支持运行时卸载,因此如果您遇到问题,您可以随时禁用挂钩。
就是这样,玩得开心!
【讨论】:
_NT_DEBUGGER_EXTENSION_PATH env-var 中使用它的路径并启动WinDbg。然后用.load WingDbg.dll 命令加载它。测试已加载:.chain。确实如此。然后尝试闯入Win7调试器并且寄存器窗口仍然是空的。试了几次。没有运气。如果 dll 生成任何日志,我可以将它们发送给您。有的话发邮件给我。
!regfix 命令?