难译 | windbg 乐趣之道(上)

前言

Yarden Shafir 分享了两篇非常通俗易懂的,关于 windbg 新引入的调试数据模型的文章。链接如下:

part1:https://medium.com/@yardenshafir2/windbg-the-fun-way-part-1-2e4978791f9b

part2:https://medium.com/@yardenshafir2/windbg-the-fun-way-part-2-7a904cba5435

本文是第一部分的译文。在有道词典、必应词典、谷歌翻译的大力帮助下完成,感谢以上翻译工具,我只是一个搬运工。强烈建议英文好的朋友阅读原文,因为在翻译的过程中不可避免的按我的理解做了调整。

说明:

  1. 翻译已征得原作者同意。

4b5b7bc8be67936184f171110866f473.png
translation-permission
  1. 鸽了太久了,对不住原作者

  2. 标题实在想不到更好的翻译了

  3. 作者的 github

以下是译文!


不久前,WinDbg 添加了对新调试数据模型(debugger data model)的支持,这一变化彻底改变了我们使用 WinDbg 的方式。不再有可怕的 MASM 命令和晦涩的语法。无需再将地址或参数复制到记事本以便在后续命令中使用它们。不用再一遍又一遍地运行相同的命令(传递不同的地址)来遍历列表或数组。

这是该指南的第一部分,因为我认为实际上不会有人从头到尾读完长达 8000 字的 WinDbg 命令解释。所以,我准备了 2 篇  4000 字的文章!这样会好些,对吧?

在第一篇文章中,我们将学习如何使用这个新数据模型的基础知识 —— 使用自定义寄存器和新的内置寄存器,遍历对象,使用匿名类型来搜索、过滤、自定义对象。最后,我们将学习如何以一种比以前更好、更简单的方式解析数组和列表。

在这两篇文章中,我们将学习这个数据模型为我们提供的更复杂、更高级的方法和特性。现在我们都知道将会发生什么,准备好一杯咖啡,让我们开始吧!

这个数据模型,可以在 WinDbg 中通过 dx 命令使用,是一个极其强大的工具,能够定义自定义变量、结构体、函数并使用很多其它新功能。它还允许我们使用 LINQ(一种建立在 SQL 数据库语言之上的自然查询语言)进行查询和过滤信息。

这个数据模型已经被文档化了,甚至在 GitHub 上还有使用范例。此外,所有模块都有对应的文档,可以在调试器中通过 dx -v <method> 查看。(您也可以通过运行不带 -vdx <method> 命令获得相同的文档 ) :

dx -v Debugger.Utility.Collections.FromListEntry
Debugger.Utility.Collections.FromListEntry [FromListEntry(ListEntry, [<ModuleName | ModuleObject>], TypeName, FieldExpression) — Method which converts a LIST_ENTRY specified by the ‘ListEntry’ parameter of types whose name is specified by the string ‘TypeName’ and whose embedded links within that type are accessed via an expression specified by the string ‘FieldExpression’ into a collection object. If an optional module name or object is specified, the type name is looked up in the context of such module]

除此之外,还有一些外部文档,但我觉得有些事情需要进一步解释,并且这个特性值得更多的关注。

译注:

debugger data model 文档链接:https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/data-model-cpp-overview)

使用范例 github 链接:https://github.com/microsoft/WinDbg-Samples)

自定义寄存器(Custom Registers)

首先,NatVis 允许我们添加自定义寄存器。有点像 MASM 中的 @$t1@$t2@$t3 等。只是,现在你可以起任何想要的名字,并且可以指定类型:

dx @$myString = "My String"
dx @$myInt = 123

我们可以使用 dx @$vars 来查看所有变量,使用 dx @$vars.Remove("var name")  来移除某个变量,或者使用 @$vars.Clear() 清除所有变量。我们还可以使用 dx 来处理更复杂的结构,比如 EPROCESS。您可能知道,公共调试符号(public PDBs)中的符号不包含类型信息。使用旧调试器,这并不总是一个问题,因为在 MASM 中,反正也没有类型,我们可以使用 poi 命令对指针进行解引用。

0: kd> dt nt!_EPROCESS poi(nt!PsInitialSystemProcess)
 +0x000 Pcb : _KPROCESS
 +0x2e0 ProcessLock : _EX_PUSH_LOCK
 +0x2e8 UniqueProcessId : (null)
 ...

但当变量不是指针时,事情就变得更混乱了,比如 PsIdleProcess

0: kd> dt nt!_KPROCESS @@masm(nt!PsIdleProcess)
   +0x000 Header           : _DISPATCHER_HEADER
   +0x018 ProfileListHead  : _LIST_ENTRY [ 0x00000048`0411017e - 0x00000000`00000004 ]
   +0x028 DirectoryTableBase : 0xffffb10b`79f08010
   +0x030 ThreadListHead   : _LIST_ENTRY [ 0x00001388`00000000 - 0xfffff801`1b401000 ]
   +0x040 ProcessLock      : 0
   +0x044 ProcessTimerDelay : 0
   +0x048 DeepFreezeStartTime : 0xffffe880`00000000
   ...

我们必须先使用显式的 MASM 操作符来获取 PsIdleProcess 的地址,然后将它当作 EPROCESS 显示出来。通过使用 dx,我们可以更聪明地直接使用 C 风格的类型转换对符号进行强制转换。但是当我们尝试把 nt!Psinitialsystemprocess 转换为一个指向 EPROCESS 的指针:

dx @$systemProc = (nt!_EPROCESS*)nt!PsInitialSystemProcess
Error: No type (or void) for object at Address 0xfffff8074ef843a0

我们得到了一个错误。

就像我提到的那样,符号没有类型。我们不能转换没有类型的东西。所以我们需要获取符号的地址,并转换成一个指向我们想要的类型的指针(在当前示例中,PsInitialSystemProcess 已经是一个指向 EPROCESS 的指针,所以我们需要将其地址转换为一个指向 EPROCESS 指针的指针)。

dx @$systemProc = *(nt!_EPROCESS**)&nt!PsInitialSystemProcess

现在,我们有了一个有类型的变量,我们可以像在 C 中那样访问它的字段:

0: kd> dx @$systemProc->ImageFileName

@$systemProc->ImageFileName               [Type: unsigned char [15]]
[0]              : 0x53 [Type: unsigned char]
[1]              : 0x79 [Type: unsigned char]
[2]              : 0x73 [Type: unsigned char]
[3]              : 0x74 [Type: unsigned char]
[4]              : 0x65 [Type: unsigned char]
[5]            
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值