2

I am trying to get to know how buffer overflow works, so I am working on various simple examples, involving C and functions gets() and puts(). The source code for one on these programs is the following:

#include<stdio.h>
GetInput()
{
    char buffer[8];

    gets(buffer);
    puts(buffer);
}

main();
{
    GetInput();

    exit 0;
}

I am compiling this with the following line:

gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack demo.c -mpreferred-stack-boundary=2 -g -o demo

GCC version is 4.4.3, 32 bits system, and kernel 2.6.32

When calling GetInput(), the return address to main() should be pushed into de stack, then store the previous EBP record, and then it should allocate 8 bytes for the local var buffer, so to overwrite the RET address, I should input 12 bytes and the intended RET address.

But that is not the case, when I load it into GDB and dissasemble GetInput(), it says the following:

0x080483f4 <+0>:    push   %ebp
0x080483f5 <+1>:    mov    %esp,%ebp
0x080483f7 <+3>:    sub    $0xc,%esp    <------- 
0x080483fa <+6>:    lea    -0x8(%ebp),%eax
0x080483fd <+9>:    mov    %eax,(%esp)
0x08048400 <+12>:   call   0x804830c <gets@plt>
0x08048405 <+17>:   lea    -0x8(%ebp),%eax
0x08048408 <+20>:   mov    %eax,(%esp)
0x0804840b <+23>:   call   0x804832c <puts@plt>
0x08048410 <+28>:   leave  
0x08048411 <+29>:   ret

I've marked the line where it reserves 12 bytes instead of 8.

Can anyone help me get this?

GDV
  • 65
  • 5
  • Running through the program into GDB shows that the first 4 bytes of the local variable space in the stack gets a fixed value, and the function *gets(buffer)* starts writing right afer those 4 bytes. So, I guess that these 4 bytes at the top of the stack are some protection measure that I had not deactivated yet. Any clues? – GDV Dec 06 '15 at 17:48
  • 12 bytes is a strange pad length @danielruf. I'm not sure your wrong, it's just odd. – Neil Smithline Dec 06 '15 at 18:07
  • Yeah, it seems that this first word is a pointer to the start of the actual *buffer* var (it's own memory address + 4 bytes in my example). Is this the way GCC fills the "blank spaces"? Why does it behaves like this? – GDV Dec 06 '15 at 18:08
  • @NeilSmithline but compiling with -fno-stack-protector shouldn't disable canaries? And shouldn't it be a random number instead a pointer to *buffer*? – GDV Dec 06 '15 at 18:11
  • I agree. That question suggests it has something to do with buffer size. – Neil Smithline Dec 06 '15 at 18:15
  • @NeilSmithline I will try with different buffer sizes, will answer in a few hours. Thx for the answer! – GDV Dec 06 '15 at 18:17
  • I also thought about pointer + buffer var –  Dec 06 '15 at 18:25
  • Related: [Why does GCC allocate more space than necessary on the stack?](https://stackoverflow.com/a/63010237) demonstrates GCC over-allocating stack space that it doesn't need for alignment. – Peter Cordes Jul 21 '20 at 08:17

1 Answers1

2

I tried to compile your code using different version of GCC in https://gcc.godbolt.org/.

gcc 4.4.7
and
gcc 4.8.2
GetInput():
        pushl   %ebp
        movl    %esp, %ebp
        subl    $12, %esp
        leal    -8(%ebp), %eax
        movl    %eax, (%esp) <---------
        call    gets
        leal    -8(%ebp), %eax
        movl    %eax, (%esp)
        call    puts
        leave
        ret

gcc 4.9.0
GetInput():
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        leal    -8(%ebp), %eax
        pushl   %eax <---------------
        call    gets
        addl    $4, %esp
        leal    -8(%ebp), %eax
        pushl   %eax
        call    puts
        addl    $4, %esp
        leave
        ret

Notice how the address of the buffer is passed to gets(), in GCC 4.4.7 and 4.8.2, where the compiler substracts 12 bytes, the address is written into directly into the top of the stack. While for GCC 4.9.0, where only 8 bytes was subtracted, an additional PUSH is needed. So, yes, looks like the extra 4 bytes is for the address of the buffer.

xyz
  • 870
  • 2
  • 8
  • 16
  • You got it, wei. Before GCC 4.9.0, it always reserves the word at the top of the stack to store the pointer to the variable it is working with, so the space it reserves when allocating memory should be *vars + 4 bytes* (in 32bits systems). Thank you! – GDV Dec 07 '15 at 12:46
  • `push` used to be slower than a `mov` store, until Intel Pentium-M and AMD K10 introduced the stack engine. That made `push` a single-uop, even though it has to store *and* modify the stack pointer. As you say, older gcc reserved extra space and then `mov`ed into to, while newer gcc uses `push`. Looks like new gcc is dumb, and emits a useless `addl $4, %esp` right before a `leave` insn (which overwrites `%esp` with `%ebp`, and pops `%ebp`). Err, this is without optimization though. [New gcc defaults to -fomit-frame-pointer anyway, and makes good code](http://goo.gl/m2hOfp) – Peter Cordes Dec 09 '15 at 05:17
  • Actually with `-fno-omit-frame-pointer`, gcc 5.2 makes some pretty dumb code: http://goo.gl/GiOMGG. Note that it's using `pop %eax` instead of `addl $4, %esp`, but it decided to save/restore `ebx` so it has a call-preserved register to hold the address of the buffer. Maybe gcc isn't good at decision-making for functions so simple they should be inline? – Peter Cordes Dec 09 '15 at 05:25