调试器数据模型、JavaScript与x64异常处理
引言
本文主要展示最新版WinDbg(现称为“WinDbg Preview”)及其时间旅行调试(TTD)工具的强大功能。自2017年cppcon会议后发布以来,这些工具在安全与逆向工程领域的应用尚未广泛普及,因此笔者在假期期间撰文介绍。
WinDbg最显著的变化是全新的用户界面,但本文不讨论此内容。第二大改进是引入了完善的脚本引擎!以往只能依赖pyKD编写自动化脚本,虽然多年表现良好,但如今可以转向WinDbg提供的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的读者建议查阅《Basic LINQ query operations》。
首次查询
假设您想查找当前@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实例提供的。该类型暴露了多种方法