我试图写一个示例程序来理解堆栈缓冲区溢出,我有以下程序。
溢出。s:
.section .data
.section .text
.globl _start
_start:
call sum
movl %eax, %ebx
movl $15, %ebx
movl $1, %eax
int $0x80
.type sum, @function
sum:
pushl %ebp # save the current base pointer
movl %esp, %ebp # store current stack pointer to %ebp
subl $4, %esp # inc the stack pointer by 4 bytes for local variable
movl $5, -8(%ebp) # store value 5 from 8 bytes of %ebp 4 bytes beyond stack pointer
addl $5, -8(%ebp) # add 5 to the value store beyond of stack pointer
movl -8(%ebp), %eax # store the value in %eax
movl %ebp, %esp
popl %ebp
ret
汇编和链接程序:
as -gstabs+ overflow.s -o oveflow.o
ld overflow.o -o overflow
./overflow
echo $?
15 <============= the result
我期望要么我得到一些垃圾或segfault。但它似乎工作的预期。所以在和函数中,当我增加堆栈指针4字节,当我存储的值5 8字节从基指针,我期待这是一个溢出的模拟。上述程序是错误的使用堆栈缓冲区溢出的例子。
1条答案
按热度按时间pokxtpni1#
%esp
以下的内存可能会被异步清除(通过信号处理程序1),但**程序的行为并不取决于您在ESP正下方的4字节堆栈槽中用addl $5, -8(%ebp)
或movl -8(%ebp), %eax
**读/写的值。在Linux上,至少在同一页面内,接触ESP以下的内存不是错误。如果超过这个范围,它可能会出现segfault而不是growing the stack(对于主线程的堆栈),除非堆栈指针先被移动。(线程堆栈已经被完全分配,而不是动态增长。初始进程堆栈是特殊的。)
如果你在一个循环中运行
push
(没有pop
或其他任何东西来平衡它),堆栈将增长,直到ESP减少到指向一个未Map的页面,超出了内核将为你增长堆栈的点。然后下一个push
(或call
或其他什么)将segfault,我们称之为堆栈溢出。如果您执行
sub $12, %esp
为int arr[3]
保留空间,但随后写入int arr[5]
,则会出现缓冲区溢出:这样最终的ret
将跳转到攻击者希望您跳转的任何地方。脚注1:您还没有安装任何信号处理程序,因此(在Linux上)没有任何东西可以异步使用堆栈内存,并且您在ESP下有一个无限的red-zone。
但这是一种特殊情况,当你在编写一个完整的程序,而不使用任何库时,通常你应该只内联小函数,如果预留和释放堆栈空间的额外指令有不小的开销。
此外,如果您在GDB中执行
print foo()
或其他操作,使其在某个断点处停止时调用函数,则调试器可以使用此空间。