堆栈缓冲区溢出的示例汇编语言程序

时间:2018-05-25 19:20:55

标签: assembly buffer-overflow gas

我正在尝试编写一个示例程序来理解堆栈缓冲区溢出,我有以下程序。

overflow.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

我预计我会得到一些垃圾或段错误。但似乎按预期工作。所以在sum函数中,当我将堆栈指针递增4个字节时,当我从基址指针存储5个8字节的值时,我期待这是溢出的模拟。以上程序错误地使用了堆栈缓冲区溢出的示例。 ?

1 个答案:

答案 0 :(得分:2)

低于%esp的内存可能被异步破坏(通过信号处理程序 1 ),但程序的行为并不取决于您读取的值/使用addl $5, -8(%ebp)movl -8(%ebp), %eax 写入ESP正下方的4字节堆栈插槽。

在Linux上,触摸ESP下方的内存并不是错误,一直到最大堆栈大小的限制(ulimit -s,默认为8192 kiB)。如果内存尚未映射,则堆栈映射会自动扩展,以映射其中所有页面与当前映射的堆栈页面之间的最低地址。 (或者,对于线程堆栈,它已经完全分配,而不是动态增长。但是初始进程堆栈是特殊的。)

如果您在循环中运行push (没有pop或其他任何东西来平衡它),堆栈将会增长,直到ESP减少到指向未映射的页面超出内核为您增加堆栈的程度。然后,下一个push(或call或其他)会出现段错误,我们称之为堆栈溢出。

缓冲区溢出将是sub $12, %espint arr[3]保留空间,但随后写入int arr[5]:这将覆盖您的返回地址,最终ret会跳到攻击者想要你跳的地方。

 # arg in EAX: how many array elements to store into arr[3]
 vulnerable_function:
    sub  $12, %esp
    mov  %esp, %ecx
.Lloop:
    mov  %eax, (%ecx)
    add  $4, %ecx
    dec  %eax
    jnz

    add  $12, %esp
    ret

脚注1 : 您还没有安装任何信号处理程序,因此(在Linux上)没有任何东西可以异步使用堆栈内存,并且您可以在ESP下方无限

但是当你编写一个完整的程序而不使用任何库时,这是一个特例,通常你应该只是内联小函数,如果预留和释放堆栈空间的额外指令有非常重要的成本。