Reputation: 23
I have a code like this :
#include <stdio.h>
#include <string.h>
void overflow_me(char* dizi){
char buff_array[100];
strcpy(buff_array,dizi);
printf("Hosgeldin %s",buff_array);
}
int main(int argc, char *argv[]){
overflow_me(argv[1]);
return 0;
}
I compile this by using gcc -g -o overflow overflow.c -m32 -mpreferred-stack-boundary=2
this.
Then I open the overflow file with gdb and disassemble the overflow_me function.
endbr32
0x00001211 <+4>: push %ebp
0x00001212 <+5>: mov %esp,%ebp
0x00001214 <+7>: push %ebx
0x00001215 <+8>: sub $0x6c,%esp
I wonder why the stack allocates 108 bytes. I expected that would be 0x64 instead of 0x6c.
Whole disassembled function :
0x0000120d <+0>: endbr32
0x00001211 <+4>: push %ebp
0x00001212 <+5>: mov %esp,%ebp
0x00001214 <+7>: push %ebx
0x00001215 <+8>: sub $0x6c,%esp
0x00001218 <+11>: call 0x1110 <__x86.get_pc_thunk.bx>
0x0000121d <+16>: add $0x2db3,%ebx
0x00001223 <+22>: mov 0x8(%ebp),%eax
0x00001226 <+25>: mov %eax,-0x70(%ebp)
0x00001229 <+28>: mov %gs:0x14,%eax
0x0000122f <+34>: mov %eax,-0x8(%ebp)
0x00001232 <+37>: xor %eax,%eax
0x00001234 <+39>: pushl -0x70(%ebp)
0x00001237 <+42>: lea -0x6c(%ebp),%eax
0x0000123a <+45>: push %eax
0x0000123b <+46>: call 0x10b0 <strcpy@plt>
0x00001240 <+51>: add $0x8,%esp
0x00001243 <+54>: lea -0x6c(%ebp),%eax
0x00001246 <+57>: push %eax
0x00001247 <+58>: lea -0x1fc8(%ebx),%eax
0x0000124d <+64>: push %eax
0x0000124e <+65>: call 0x1090 <printf@plt>
0x00001253 <+70>: add $0x8,%esp
0x00001256 <+73>: nop
0x00001257 <+74>: mov -0x8(%ebp),%eax
0x0000125a <+77>: xor %gs:0x14,%eax
0x00001261 <+84>: je 0x1268 <overflow_me+91>
0x00001263 <+86>: call 0x1320 <__stack_chk_fail_local>
0x00001268 <+91>: mov -0x4(%ebp),%ebx
0x0000126b <+94>: leave
0x0000126c <+95>: ret
Upvotes: 0
Views: 131
Reputation: 364438
Looks like the extra space is for a stack cookie (-fstack-protector=strong
on by default, along with -fpie
also complicating the code), and from copying the stack arg from above EBP to below for no reason.
Use -fno-stack-protector -fno-pie
to simplify the asm. They're off by default on Godbolt, and newer GCC doesn't waste instructions copying from EBP+8 to another local, so https://godbolt.org/z/7bMzxGKsd illustrates that you do get only a 100 bytes of stack space reserved when you compile differently with a newer GCC. I also used -fverbose-asm
to comment the asm with var names. 32-bit PIE code sucks (PC-relative addressing was new in x86-64 64-bit mode), so it's hard to read, that's why I mention -fno-pie
even though it doesn't affect stack usage. (Other than for a moment when calling the thunk to get the current EIP into an integer register.)
I found what was going on by looking for n(%ebp)
with |n| > 0x6c, so I spotted the mov %eax,-0x70(%ebp)
(which is preceded by a load from 8(%ebp)
, i.e. the arg.) and the pushl -0x70(%ebp)
which also made it clear this was a copy of dizi
being pushed as an arg for printf.
Also, mov %gs:0x14,%eax
and call 0x1320 <__stack_chk_fail_local>
made it obvious this was compiled with some form of -fstack-protector
, so I looked and found it storing the stack cookie to mov %eax,-0x8(%ebp)
. (Right below the saved EBX, which itself is below the saved EBP, which the EBP frame pointer points at after bothering to set it up.)
Comments mentions EBX, but space for the saved EBP and EBX are allocated by push %ebp
and push %ebx
which themselves modify ESP, not part of the sub $0x6c,%esp
.
Note that GCC does sometimes allocate more stack space than it needs for locals + alignment (Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?) but that's not what it's doing here: it is using every byte of the stack space it reserves. Not usefully, but you asked it not to optimize so it made dumb code. :P
Upvotes: 1
Reputation: 17114
Looking at your disassembled code, it appears that it is checking for data overrun in the strcpy
function. At <+28> and <+34>, it writes a magic number gs:0x14
to the address just past the end of buff_array
. Then after strcpy
returns, at <+74>-<+84>,it checks that this magic number hasn't been overwritten. If it has, it knows that more than 100 bytes were copied, and it signals an error with __stack_chk_fail_local
.
Upvotes: 0