Reputation: 33
I've compiled this code with gcc (gcc -ggdb -mpreferred-stack-boundary=2 -o demo demo.c) and decompiled it to look at the assembly (I know it's using unsafe functions, this was for an exercise into buffer overflows):
#include<stdio.h>
CanNeverExecute()
{
printf("I can never execute\n");
exit(0);
}
GetInput()
{
char buffer[8];
gets(buffer);
puts(buffer);
}
main()
{
GetInput();
return 0;
}
Here is the assembly for the GetInput() Function:
(gdb) disas GetInput
Dump of assembler code for function GetInput:
0x08048432 <+0>: push ebp
0x08048433 <+1>: mov ebp,esp
0x08048435 <+3>: sub esp,0xc
=> 0x08048438 <+6>: lea eax,[ebp-0x8]
0x0804843b <+9>: mov DWORD PTR [esp],eax
0x0804843e <+12>: call 0x8048320 <gets@plt>
0x08048443 <+17>: lea eax,[ebp-0x8]
0x08048446 <+20>: mov DWORD PTR [esp],eax
0x08048449 <+23>: call 0x8048340 <puts@plt>
0x0804844e <+28>: leave
0x0804844f <+29>: ret
End of assembler dump.
Here is the assembly for the Main() Function:
(gdb) disas main
Dump of assembler code for function main:
0x08048450 <+0>: push ebp
0x08048451 <+1>: mov ebp,esp
0x08048453 <+3>: call 0x8048432 <GetInput>
0x08048458 <+8>: mov eax,0x0
0x0804845d <+13>: pop ebp
0x0804845e <+14>: ret
End of assembler dump.
I've set a breakpoint at line 13 (gets(buffer))
From Main(), I can see that the ebp value is pushed onto the stack. Then when GetInput() function is called the ret address is also pushed onto the stack. Once entered the GetInput function, the ebp value is pushed onto the stack again. Now this is where I get confused:
0x08048435 <+3>: sub esp,0xc
The buffer variable is only 8 bytes, so 8 bytes should be subtracted from esp to allow for the buffer local variable.
The stack:
(gdb) x/8xw $esp
0xbffff404: 0x08048360 0x0804847b 0x002c3ff4 0xbffff418
0xbffff414: 0x08048458 0xbffff498 0x00147d36 0x00000001
(gdb) x/x &buffer
0xbffff408: 0x0804847b
0x08048458 is the ret address, 0xbffff418 is the old value of ebp, and 4 bytes of the buffer variable is in 0x0804847b, so I guess the other 4 bytes is 0x002c3ff4. But there seems to be another 4 bytes on the stack.
So my question is, why is it subtracting 12 bytes if only 8 bytes is needed? What's the extra 4 bytes for?
Thank you
Upvotes: 3
Views: 483
Reputation: 6413
It's because of the
mov DWORD PTR [esp],eax
Apparently, your puts
and gets
implementations require the argument to be pushed onto the stack.
Value [ebp-0xc]
is actually [esp]
now, that's why that dword
is reserved ahead.
Why is it so? Doing it this way is more efficient, as you don't have to pop
and push
, but just move eax
on [esp]
, so you spare at least one instruction. However, I guess this code has gone through some optimiation, because this one is clever.
Upvotes: 5