我一直在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)
答案 0 :(得分:2)
正如其他人所指出的,buf在运行时分配在堆栈上。请参阅getbuf()函数中的以下几行:
0x08048d92 <+0>: sub $0x3c,%esp
0x08048d95 <+3>: lea 0x10(%esp),%eax
0x08048d99 <+7>: mov %eax,(%esp)
第一行从堆栈指针中减去0x3c(60)字节,有效地分配了那么多空间。超出32的额外字节可能是Get的参数(很难说出Get的调用约定是精确的,所以很难说)第二行获取16字节的地址。这会在其上方留下44个字节,这些字节是未分配的。第三行将该地址放入堆栈,可能用于获取函数调用。 (记住堆栈向下增长,因此堆栈指针将指向堆栈中的最后一项)。我不确定为什么编译器生成了这样奇怪的偏移量(60个字节然后是44个),但可能有一个很好的理由。如果我搞清楚,我会在这里更新。
在获取功能中,我们有以下几行:
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个字节,然后在堆栈中获取保留28(0x1c)个字节。最后一行是关键:它在堆栈的0x30字节处抓取值并将其加载到%esi中。该值是getbuf放在堆栈上的buf的地址。为什么? 4为返回地址加上16为寄存器+ 28保留= 48. 0x30 = 48,所以它在调用gets之前抓取getbuf()放在堆栈上的最后一项。
要获取buf的地址,您必须在调试器中实际运行程序,因为每次运行程序时地址可能会有所不同,甚至为此调用函数。您可以在上面的任何一行中设置一个断点,当它包含要放在getbuf第二行的堆栈上的地址时转储%eax寄存器,或者当它被取消时转储%esi寄存器。堆栈。这将是指向缓冲区的指针。
答案 1 :(得分: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教程(example)是必不可少的。
您也可以将printf
置于getbuf
内并以此方式进行调试 - 这取决于您要执行的操作。
另一点从您的代码中跳出来。从getbuf
返回后,Gets
的结果将被删除。这是因为Gets
可能将其结果写入堆栈分配的buf
。当您从getbuf
返回时,您的堆栈被烧毁,您无法可靠地访问buf。
答案 2 :(得分:0)
为了能够在使用gdb时看到调试信息,你必须在编译时使用带gcc的-g3开关。有关-g开关的详细信息,请参阅man gcc。 只有这样,gcc才会将调试信息(符号表)添加到可执行文件中。
答案 3 :(得分: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,您可以输入自己的例程来在函数运行时以及在弹出这些指针之前转储数据