我是使用插入例程(pin)得到了错误的ebp,还是这里遗漏了什么



所以交易是这样的。我正在使用pin工具和我所连接的进程中的dwarf信息进行调试。pin是一个框架,可以让你为已经运行的进程创建检测工具,我连接到进程,然后从中解析dwarf信息。

显然,pin让我在连接到程序的精确时刻获取寄存器。我可以获得ebpespeip。但是堆栈中的信息与DWARF信息中的信息不匹配。

例如:

Pin告诉我ebp是:bfe0abe8我假设这是寄存器的实际地址,而不是寄存器内部的值

如果我去堆栈,我有这个:

bfe0abb5 -> 00000020   \this is esp
bfe0abb6 -> 0804855d
bfe0abb7 -> 08048720
bfe0abb8 -> 0000000a
bfe0abb9 -> bfe0abe8    \this is what I think is ebp, but according to pin is not
bfe0abba -> 0015711f
bfe0abbb -> bfe0ac28
bfe0abbc -> 4236b852     \this is a local float variable named jos
bfe0abbd -> 42c0947b     \this is a local float variable named tib
bfe0abbe -> 0000000a
bfe0abbf -> 08048724
bfe0abc0 -> bfe0abf8
bfe0abc1 -> bfe0ac28
bfe0abc2 -> 08048612
bfe0abc3 -> 00000000
bfe0abc4 -> 0000000a
bfe0abc5 -> 00006680
bfe0abc6 -> 08048689
bfe0abc7 -> 00266324
bfe0abc8 -> 00265ff4
bfe0abc9 -> 936498a8
bfe0abca -> 4072464d
bfe0abcb -> 0013f4a5
bfe0abcc -> 424ab852    \this is another local variable
bfe0abcd -> 42bc947b    \this is another local variable
bfe0abce -> 0000000a
bfe0abcf -> 08048670
bfe0abd0 -> 00000000
bfe0abd1 -> bfe0aca8

更重要的是,我不知道堆栈的底部到底是什么,所以我只展示了一点

如果我转到DWARF信息,这是堆栈顶部当前所在的函数,也是ebp应该指向的函数:

<1><  962>  DW_TAG_subprogram
DW_AT_external              yes(1)
DW_AT_name                  add
DW_AT_decl_line             36
DW_AT_prototyped            yes(1)
DW_AT_low_pc                0x8048513
DW_AT_high_pc               0x804855f
DW_AT_frame_base            <loclist with 3 entries follows>
[ 0]<lowpc=0x2f><highpc=0x30>DW_OP_breg4+4
[ 1]<lowpc=0x30><highpc=0x32>DW_OP_breg4+8
[ 2]<lowpc=0x32><highpc=0x7b>DW_OP_breg5+8

我知道这一点是因为我在堆栈上看到的局部变量在这个函数中。这些局部变量是:

<2>< 1029> DW_TAG_variable
DW_AT_name                  tib
DW_AT_decl_line             38
DW_AT_type                  <837>
DW_AT_location              DW_OP_fbreg -24
<2>< 1043> DW_TAG_variable
DW_AT_name                  jos
DW_AT_decl_line             39
DW_AT_type                  <837>
DW_AT_location              DW_OP_fbreg -28

我知道,根据DWARF(以及:如何查看存储在带有GDB的堆栈上的变量),该函数中的ebp应该是当前的ebp+8(因为我使用DWORD,所以应该是+2)。然后我应该减去-24到8,使其成为ebp-16(实际上是ebp-4)。从纸面上看,这应该有效,但当进入堆栈时,我遇到了很多问题:

  • 我甚至没有在堆栈顶部附近看到该引脚返回给我的当前ebp的地址
  • 假设bfe0abb9是当前ebp,并且该引脚实际上返回的是寄存器的值,而不是地址,如果我从该寄存器中减去4,我将不会得到tib的值,因为根据我对堆栈的理解,我将向上而不是向下。即使我在尝试获得jos(ebp-28+8 = ebp -20 = ebp -5)时会摔倒,我也肯定不会获得jos,而是获得000000a

我是不是遗漏了什么?我是否对堆栈和/或寄存器或DWARF信息有错误的理解?还是Pin把我搞砸了,提供了错误的信息?

有什么建议吗?

我将忽略堆栈转储,因为我不确定您要在那里显示什么。

你引用的DWARF说,函数的帧基最初是$esp + 4,然后它变为$esp + 8,然后它变成$ebp + 8。这是打开大多数i386函数的标准"push $ebp; mov $esp, $ebp"指令序列。在函数条目中,帧基础是esp的值加4。一旦我们在堆栈上保存了调用方的ebp寄存器,帧基现在是esp加8,因为esp由于push而发生了更改。最后,esp中的值被复制到ebp中,并且该值将在函数的其余部分保持不变(而esp通常被进一步调整)。

您在这里看到的——"帧基"——在debug_frame部分也被称为规范帧地址或CFA。CFA是堆栈上的一个地址,在函数的整个持续时间内都是相同的。在i386上,CFA地址是调用方执行call指令以调用您正在查看的函数之前的esp

DWARF表示,变量tib位于帧基-24处。函数的帧基是ebp + 8,所以是的,ebp寄存器的值减去16就是堆栈上的一个地址。变量存储在该地址。

如果DWARF不清楚,假设您对汇编语言有合理的理解,我经常发现阅读函数的实际汇编代码很有帮助。你也可以在程序中执行一步指令,在执行过程中检查寄存器和堆栈地址。对真实代码进行少量的动手实验几乎总能回答任何问题。

这很奇怪,因为它不像堆栈寻址,bfe0abb5bfe0abb6bfe0abb7bfe0abb8bfe0abb9bfe0abba
它应该在32位机器中以4字节对齐。根据您提供的堆栈地址,即使您提供了正确的DWARF信息,我也无法计算实际地址。

最新更新