64位进程的kb表示什么?

11

我最近在分析一个调用栈时犯了一个错误,因为我没有预料到应用程序是64位的。我使用WinDbg命令kb来显示调用栈和传递给方法的参数。

在64位上,参数不是通过堆栈传递的,而是通过寄存器(RCX、RDX、R8和R9)传递。似乎WinDbg并没有完全实现这个功能。部分原因是由于寄存器的值可能已经改变了。

然而,WinDbg帮助文档仍将kb列为User-Mode, x64 Processor下的有效命令。因此,我的问题是:

kb对64位用户模式进程显示什么?它的输出何时/如何有用?


堆栈回溯无法显示准确的函数参数值。它们被传递到寄存器中,然后在寄存器用于存储其他内容之前被溢出到内存中。如果您真的需要知道,这将非常痛苦,挖掘内存地址并不简单。上次我查看时已经过了一段时间,那时我必须学会如何应对。 - Hans Passant
2个回答

11
在WinDbg中显示的"Args to Child"输出,以kb和kv为单位,一直非常可疑,即使在x86上,这些列也不一定显示函数的参数。

在x86上,"Args to Child"仅是[EBP+0x08]、[EBP+0x0C]和[EBP+0x10](kv显示四个参数,因此最后一列是[EBP+0x14])。只有当以下条件满足时,它们才是函数的参数:

1. 函数使用EBP框架
2. 函数使用堆栈传递参数(取决于调用约定)
3. 优化器没有重复使用这些位置进行其他操作

在x64上,如您所指出的,前四个参数通过寄存器传递。然而,在调用约定的一部分中,调用方必须为每个参数在堆栈上分配“Home”(或“Spill”)空间。即使被调用的函数少于四个参数,也始终会分配这个空间。然后,被调用的函数可以自由地使用此Home Space,它可以:

1. 忽略它
2. 在其中保存非易失性寄存器
3. 将传递的寄存器参数"Home"到堆栈上

kb和kv输出按顺序显示Home Space(RCX Home、RDX Home、R8 Home、R9 Home)。最常见的情况是使用1或2,因此它实际上与传入的参数没有任何关系。然而,在Debug版本中,编译器会立即将传入的参数放到Home Space中,以使调试更容易。

例如,下面是一个有两个参数的函数的前奏曲,编译为Debug。注意,第一条指令是将参数归位:
0:000> u DriverEntry
mov     qword ptr [rsp+10h],rdx
mov     qword ptr [rsp+8],rcx
push    rdi
sub     rsp,0C0h

同样的代码编译为“Release”模式时,使用主页空间进行非易失性寄存器保存:

0:000> u DriverEntry
mov     qword ptr [rsp+8],rbx
mov     qword ptr [rsp+10h],rdi
push    rbp
lea     rbp,[rsp-57h]
sub     rsp,0B0h

这意味着Home Space通常在获取函数参数方面是无用的。但是,它仍然可以用作调试辅助工具,以在函数进入时重建非易失性寄存器值(例如,通过查看Home Space,我可以告诉您RBX或RDI的值)。


4

kb列出了堆栈回溯及其三个参数,但是参数传递机制(调用约定)使得显示的参数不可信。您必须阅读更多信息@http://www.codemachine.com/article_x64deepdive.html

dv以及所有其他变体dv /v等都可能显示垃圾值。仅在__this call的情况下,我们才可以使用rcx作为此指针,但我们必须反汇编并确保指针没有备份到其他位置,然后重新使用。除非我们有归属参数,否则反汇编是解决问题的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接