1

我一直在 CSAPPS 的 bufbomb 实验室工作,但我陷入了其中一个阶段。

我不会深入了解该项目的血腥细节,因为我只需要朝着正确的方向轻推。我很难在给定的程序集中找到名为“buf”的数组的起始地址。

我们得到了一个名为 getbuf 的函数:

#define NORMAL_BUFFER_SIZE 32

int getbuf()
{
   char buf[NORMAL_BUFFER_SIZE];
   Gets(buf);
   return 1;
}

组装转储:

Dump of assembler code for function getbuf:
0x08048d92 <+0>:    sub    $0x3c,%esp
0x08048d95 <+3>:    lea    0x10(%esp),%eax
0x08048d99 <+7>:    mov    %eax,(%esp)
0x08048d9c <+10>:    call   0x8048c66 <Gets>
0x08048da1 <+15>:    mov    $0x1,%eax
0x08048da6 <+20>:    add    $0x3c,%esp
0x08048da9 <+23>:    ret   
End of assembler dump.


Dump of assembler code for function Gets:
0x08048c66 <+0>:    push   %ebp
0x08048c67 <+1>:    push   %edi
0x08048c68 <+2>:    push   %esi
0x08048c69 <+3>:    push   %ebx
0x08048c6a <+4>:    sub    $0x1c,%esp
0x08048c6d <+7>:    mov    0x30(%esp),%esi
0x08048c71 <+11>:    movl   $0x0,0x804e100
0x08048c7b <+21>:    mov    %esi,%ebx
0x08048c7d <+23>:    jmp    0x8048ccf <Gets+105>
0x08048c7f <+25>:    mov    %eax,%ebp
0x08048c81 <+27>:    mov    %al,(%ebx)
0x08048c83 <+29>:    add    $0x1,%ebx
0x08048c86 <+32>:    mov    0x804e100,%eax
0x08048c8b <+37>:    cmp    $0x3ff,%eax
0x08048c90 <+42>:    jg     0x8048ccf <Gets+105>
0x08048c92 <+44>:    lea    (%eax,%eax,2),%edx
0x08048c95 <+47>:    mov    %ebp,%ecx
0x08048c97 <+49>:    sar    $0x4,%cl
0x08048c9a <+52>:    mov    %ecx,%edi
0x08048c9c <+54>:    and    $0xf,%edi
0x08048c9f <+57>:    movzbl 0x804a478(%edi),%edi
0x08048ca6 <+64>:    mov    %edi,%ecx
---Type <return> to continue, or q <return> to quit---
0x08048ca8 <+66>:    mov    %cl,0x804e140(%edx)
0x08048cae <+72>:    mov    %ebp,%ecx
0x08048cb0 <+74>:    and    $0xf,%ecx
0x08048cb3 <+77>:    movzbl 0x804a478(%ecx),%ecx
0x08048cba <+84>:    mov    %cl,0x804e141(%edx)
0x08048cc0 <+90>:    movb   $0x20,0x804e142(%edx)
0x08048cc7 <+97>:    add    $0x1,%eax
0x08048cca <+100>:    mov    %eax,0x804e100
0x08048ccf <+105>:    mov    0x804e110,%eax
0x08048cd4 <+110>:    mov    %eax,(%esp)
0x08048cd7 <+113>:    call   0x8048820 <_IO_getc@plt>
0x08048cdc <+118>:    cmp    $0xffffffff,%eax
0x08048cdf <+121>:    je     0x8048ce6 <Gets+128>
0x08048ce1 <+123>:    cmp    $0xa,%eax
0x08048ce4 <+126>:    jne    0x8048c7f <Gets+25>
0x08048ce6 <+128>:    movb   $0x0,(%ebx)
0x08048ce9 <+131>:    mov    0x804e100,%eax
0x08048cee <+136>:    movb   $0x0,0x804e140(%eax,%eax,2)
0x08048cf6 <+144>:    mov    %esi,%eax
0x08048cf8 <+146>:    add    $0x1c,%esp
0x08048cfb <+149>:    pop    %ebx
0x08048cfc <+150>:    pop    %esi
0x08048cfd <+151>:    pop    %edi
---Type <return> to continue, or q <return> to quit---
0x08048cfe <+152>:    pop    %ebp
0x08048cff <+153>:    ret   
End of assembler dump.

我很难找到 buf 的起始地址在哪里(或者 buf 在这个混乱中的位置!)。如果有人可以向我指出这一点,我将不胜感激。

尝试解决方案

Reading symbols from /home/user/CS247/buflab/buflab-handout/bufbomb...(no debugging symbols found)...done.
(gdb) break getbuf
Breakpoint 1 at 0x8048d92
(gdb) run -u user < firecracker-exploit.bin
Starting program: /home/user/CS247/buflab/buflab-handout/bufbomb -u user < firecracker-exploit.bin
Userid: ...
Cookie: ...

Breakpoint 1, 0x08048d92 in getbuf ()
(gdb) print buf
No symbol table is loaded.  Use the "file" command.
(gdb) 
4

4 回答 4

2

正如其他人指出的那样, buf 在运行时分配在堆栈上。请参阅 getbuf() 函数中的这些行:

0x08048d92 <+0>:    sub    $0x3c,%esp
0x08048d95 <+3>:    lea    0x10(%esp),%eax
0x08048d99 <+7>:    mov    %eax,(%esp)

第一行从堆栈指针中减去 0x3c (60) 个字节,有效地分配了那么多空间。超过 32 的额外字节可能是 Gets 的参数(很难准确地说 Gets 的调用约定是什么,所以很难说)第二行获取 16 个字节的地址。这会在其上方留下 44 个未分配的字节。第三行将该地址放入堆栈,可能用于gets 函数调用。(记住堆栈会向下增长,因此堆栈指针将指向堆栈上的最后一项)。我不确定为什么编译器会生成如此奇怪的偏移量(60 字节,然后是 44 字节),但可能有一个很好的理由。如果我弄清楚了,我会在这里更新。

在gets函数中,我们有以下几行:

0x08048c66 <+0>:    push   %ebp
0x08048c67 <+1>:    push   %edi
0x08048c68 <+2>:    push   %esi
0x08048c69 <+3>:    push   %ebx
0x08048c6a <+4>:    sub    $0x1c,%esp
0x08048c6d <+7>:    mov    0x30(%esp),%esi

这里我们看到我们保存了一些寄存器的状态,加起来是16字节,然后Gets在栈上保留28(0x1c)字节。最后一行是关键:它从堆栈中获取 0x30 字节处的值并将其加载到 %esi 中。这个值就是getbuf入栈的buf地址。为什么?返回地址为 4 加上寄存器为 16 + 28 保留 = 48。0x30 = 48,因此它在调用 get 之前通过 getbuf() 抓取放置在堆栈上的最后一项。

要获得 buf 的地址,您必须在调试器中实际运行程序,因为每次运行程序时地址可能会有所不同,甚至为此调用函数。您可以在上面的任何这些行中设置一个断点,然后在 %eax 寄存器包含要放置在 getbuf 的第二行堆栈上的地址时转储它,或者在 %esi 寄存器被拉出时转储它堆栈。这将是指向缓冲区的指针。

于 2013-05-18T18:29:03.573 回答
0

buf在栈上分配。因此,您将无法从装配列表中找到它的地址。换句话说,只有在运行时buf输入函数时才分配(因此知道其地址)getbuf()

如果您必须知道地址,一种选择是使用 gbd(但请确保使用-g标志进行编译以启用调试支持),然后:

gdb a.out    # I'm assuming your binary is a.out
break getbuf # Set a breakpoint where you want gdb to stop
run          # Run the program. Supply args if you need to
             # WAIT FOR your program to reach getbuf and stop    
print buf

如果你想走这条路,一个好的 gdb 教程(例子)是必不可少的。您也可以放置一个printf内部getbuf并以这种方式进行调试 - 这取决于您要做什么。

另一点从您的代码中跳出来。从 返回时getbuf, 的结果Gets将被丢弃。这是因为Gets大概是将其结果写入堆栈分配的buf。当您从getbuf.

于 2013-05-18T04:39:41.817 回答
0

为了能够在使用 gdb 时查看调试信息,您必须在编译时将 -g3 开关与 gcc 一起使用。有关 -g 开关的更多详细信息,请参见 man gcc。只有这样,gcc 才会将调试信息(符号表)添加到可执行文件中。

于 2013-05-18T05:33:52.783 回答
0
0x08048cd4 <+110>:    mov    %eax,(%esp)
0x08048cd7 <+113>:    **call   0x8048820 <_IO_getc@plt>**
0x08048cdc <+118>:    cmp    $0xffffffff,%eax
0x0848cdf <+121>:    je     0x8048ce6 <Gets+128>
0x08048ce1 <+123>:    cmp    $0xa,%eax
0x08048ce4 <+126>:    jne    0x8048c7f <Gets+25>
0x08048ce6 <+128>:    movb   $0x0,(%ebx)
0x08048ce9 <+131>:    mov    0x804e100,%eax
0x08048cee <+136>:    movb   $0x0,0x804e140(%eax,%eax,2)
0x08048cf6 <+144>:    mov    %esi,%eax
0x08048cf8 <+146>:    add    $0x1c,%esp
0x08048cfb <+149>:    **pop    %ebx**
0x08048cfc <+150>:    **pop    %esi**
0x08048cfd <+151>:    **pop    %edi**
---Type <return> to continue, or q <return> to quit---
0x08048cfe <+152>:    **pop    %ebp**
0x08048cff <+153>:    ret   
End of assembler dump.

我不知道你的 asm 风格,但那里有一个可能使用起始地址的电话

程序结束弹出各种指针

那就是我开始寻找的地方

如果您可以调整这些函数的 asm,您可以输入自己的例程以在函数运行时以及在这些指针被弹出之前转储数据

于 2013-05-18T09:00:16.353 回答