我正在我的系统编程类中进行练习,处理缓冲区溢出。由于我无法正确格式化问题陈述,我只想解释一下。我们有一个大小为512个字符的缓冲区。调用名为getbufn的函数来分配此缓冲区,然后调用Gets()函数来接收输入。输入以文本文档中的十六进制值的形式出现,由空格分隔,空格通过另一个提供的程序运行以生成输入。一旦输入通过gets输入缓冲区,getbufn设置eax = 1并返回测试函数,检查堆栈是否已损坏。
现在我已经让这个工作了。在最后一个问题中,缓冲区大小为32,并且堆栈已设置。现在堆栈可以移动。调用getbufn的代码首先在堆栈上分配一个随机存储量,这样如果你在两次连续执行getbufn期间对%ebp的值进行采样,你会发现它们相差±240。所以我们需要使用NOP底座来使我们的代码工作。
首先,这是getbufn函数:
80491e8: 55 push %ebp
80491e9: 89 e5 mov %esp,%ebp
80491eb: 81 ec 18 02 00 00 sub $0x218,%esp
80491f1: 8d 85 f8 fd ff ff lea -0x208(%ebp),%eax
80491f7: 89 04 24 mov %eax,(%esp)
80491fa: e8 db fa ff ff call 8048cda <Gets>
80491ff: b8 01 00 00 00 mov $0x1,%eax
8049204: c9 leave
8049205: c3 ret
8049206: 90 nop
8049207: 90 nop
我发现了一些事情。当在地址0x8049205处调用ret时,esp = 0x556832F4。所以我知道返回地址就在那里。在lea之后的mov指令中,ebp总是等于0x556832F0(所以我不知道我的prof通过它移动了240),而eax总是等于0x556830e8。对我来说,这意味着我的数组从0x556830e8开始,到0x556832E8结束。然后为了获得返回地址,我需要再写12个字节才能到达0x556832F4。然后最后的4个字节应该是NOP底座中间的地址。
所以现在我所拥有的是~500 NOP OPS然后我的代码在缓冲区的末尾 - 这使得总大小512填满了数组。然后我有12个字节的十六进制,在缓冲区溢出之前与这些地址上最初的堆栈相匹配。然后,当在getbufn结束时执行返回指令时,我还有4个字节指向NOP底座中间的地址。这不是出于某种原因。如果我在我的数组和返回地址之间放入5个字节的垃圾,我就知道堆栈已损坏。如果我在我的数组和返回值之间放入6个字节的垃圾,我会遇到分段错误。在我的计算中,我认为我需要12个字节才能从我的数组到返回地址,所以我在这里做错了什么?
答案 0 :(得分:0)
这听起来很像来自Bryant和O'Hallaron的CS:APP缓冲区溢出实验室,它听起来也像是最后一级。
让我给你一些指示:
$ebp
的差异不会超过+/- 240个字节。知道这一切你可以做到以下几点:
$esp
的shell代码,并将{512}字节(或者是缓冲区的实际大小)添加到$esp
,这样就可以获得价值被覆盖的已保存的$ebp
。然后,您可以执行一些计算,并将垃圾ebp
替换为您刚刚计算的正确垃圾。进一步解释一些事情。为什么我们需要缓冲区中的NOP(\x90
)?由于基址被随机化+/- 240字节,缓冲区大小为512字节,因此您可以进行计算并确定性地始终返回缓冲区中的某个位置。当你返回缓冲区的某个地方时,它会点击NOPS(\x90
)并滑入你的shell代码。
如果您有任何其他问题,请随时提出。