调试器数据模型、Javascript与x64异常处理
引言
本文主要展示最新版Windbg(现称为“WinDbg Preview”)及微软数月前发布的时间旅行调试工具(Time Travel Debugging, TTD)的新功能。Windbg最显著的变化是新UI,但本文不讨论UI。第二大改进是引入了强大的脚本引擎!过去我一直使用pyKD编写自动化脚本,虽然效果不错,但现在很高兴能转向Windbg和Javascript提供的新扩展模型(没错,是Javascript)。使用pyKD时,最大的痛点之一是需要执行多个命令并解析输出以提取所需信息。幸运的是,新的调试器数据模型解决了这个问题(至少部分解决)。第三项新功能是集成了TTD,相关讨论可参考演讲:Time Travel Debugging: Root Causing Bugs in Commercial Scale Software。
本文目标是利用所学知识,用Javascript枚举x64的try/except处理程序。请准备好咖啡,继续阅读。
目录
- 引言
- 调试器数据模型
- 概述
- 第一个查询
- 用Javascript脚本化数据模型
- Javascript整数与Int64
- 访问CPU寄存器
- 读取内存
- 执行/评估命令
- 设置断点
- TTD
- TTD.Calls
- TTD.Memory
- TTD.Utility.GetHeapAddress
- 扩展数据模型
- 步骤1:将节点附加到Process模型
- 步骤2:向节点添加第一层
- 步骤3:添加另一层和可迭代类
- 杂项
- 在命令窗口中尝试host.* API
- 如何加载扩展脚本
- 如何运行命令式脚本
- Javascript引擎是否仅限Windbg Preview?
- 如何调试脚本?
- 如何在Javascript中实现NatVis样式可视化工具?
- 从类型化对象获取值
- 评估表达式
- 如何从模块访问全局变量?
- x64异常处理与Javascript
- 关于ImageRuntimeFunctionEntries、UnwindInfos、SehScopeTables和CSpecificHandlerDatas的简要说明
- 整合所有内容
- 结束语
调试器数据模型
概述
调试器数据模型是一个对象(方法、属性、值)的层次结构,可直接从调试器命令窗口或通过Javascript API访问。调试器暴露了大量信息:线程相关信息、寄存器值、堆栈跟踪信息等。作为扩展编写者,您可以在层次结构中选择节点来暴露您的功能。一旦插入模型,其他脚本或调试器命令窗口即可使用。
这些暴露信息的一个非常有趣的特性是,它们可以通过受C# LINQ操作符高度启发的操作符进行查询。不熟悉LINQ的读者建议查看基本LINQ查询操作。
第一个查询
假设您想查找当前@rip指向的模块,可以通过LINQ操作符和数据模型轻松表达:
|
|
甚至可以点击DML链接[0x8]查看该模块的所有信息:
|
|
在前两个示例中,有几个有趣的点需要强调:
dx是访问数据模型的操作符,??和?操作符不可用。@$name用于访问调试会话中定义的变量。调试器本身定义了几个变量以便查询模型:@$curprocess等效于Javascript中的host.currentProcess,@cursession等效于host.currentSession,@$curthread等效于host.currentThread。您也可以自定义变量,例如:
|
|
- 要查询
@$curprocess层次结构中的所有节点(如果想浏览数据模型,可以使用dx Debugger并点击DML链接):
|
|
还可以检查Debugger.State.DebuggerVariables,其中包含我们刚提到的变量定义:
|
|
- 最后但同样重要的是,大多数(全部?)可迭代对象都可以通过LINQ风格的操作符进行查询。如果您从未使用过这些,一开始可能会有点奇怪,但一旦掌握,就会觉得非常方便。
以下是数据模型中可迭代对象当前可用的操作符列表:
- Aggregate
- All
- AllNonError
- Any
- Average
- Concat
- Contains
- Count
- Distinct
- Except
- First
- FirstNonError
- Flatten
- GroupBy
- Intersect
- Join
- Last
- LastNonError
- Max
- Min
- OrderBy
- OrderByDescending
- Reverse
- Select
- SequenceEqual
- Single
- Skip
- SkipWhile
- Sum
- Take
- TakeWhile
- Union
- Where
现在您可能想知道,数据模型是否适用于Windbg的所有可能配置?这里的配置是指:实时用户模式附加到进程、离线查看进程崩溃转储、实时内核模式、离线查看系统崩溃转储,或离线查看TTD跟踪。
是的,数据模型在所有上述配置中均可访问,这非常棒。总体而言,只要您挖掘/暴露的信息不依赖于特定配置,就可以编写非常通用的脚本。
用Javascript脚本化数据模型
如前所述,您现在可以通过Javascript以编程方式访问模型中暴露的所有内容。不再需要eval或字符串解析来提取所需信息,只需找到暴露所需信息的节点。如果该节点不存在,可以添加自己的节点来暴露所需信息。
Javascript整数与Int64
使用Javascript时需要注意的第一点是,整数在C双精度浮点数中编码,这意味着您的整数存储在53位中。这绝对是一个问题,因为我们处理的大多数数据都是64位整数。为了解决这个问题,Windbg向Javascript暴露了一个能够存储64位整数的本地类型。该类型称为Int64,数据模型中的大多数(全部?)信息都是通过Int64实例提供的。该类型暴露了各种方法