I am working my way through a lab to demonstrate a buffer over flow exploit. I have it working but there's one area that I'm not quite understanding that I'm hoping someone can explain for me.
This is the code with the exploit:
/* Vunlerable program: stack.c */
/* You can get this program from the lab’s website */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(char *str)
{
char buffer[24];
/* The following statement has a buffer overflow problem */
strcpy(buffer, str); ➀
return 1;
}
int main(int argc, char **argv)
{
char str[517];
FILE *badfile;
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properly\n");
return 1;
}
One step of the lab is to determine the size of the memory allocated to the buffer[24]. To do this what I have done is run gdb on the bof function and I can see that the memory allocated on my system is 0x20 which is 32 bits.
If I change size of buffer I can run gdb and find the memory slot allocated. But should I be able to tell how much memory would be allocated to buffer[24] without gdb? If I change to buffer[8] should I know at a glance what the memory block on a 32 bit system is, or does it vary on the system? And if I should know can someone explain how.
This depends on the target platform, compiler and compile flags.
For example, GCC 7.2 x86 in debug mode (-O0
) aligns stack frames on a 16-byte boundary and allocates a frame pointer (ebp).
Example: (godbolt link)
bof(char*):
push ebp ; -4
mov ebp, esp
sub esp, 40 ; -40
sub esp, 8 ; -8
push DWORD PTR [ebp+8] ; -4
lea eax, [ebp-32] ; 32 bytes to top of stack frame
push eax ; -4
call strcpy ; stack is aligned to 16 bytes (-64)
add esp, 16
mov eax, 1
leave
ret
With optimization on (-O2
) the frame pointer is omitted but the stack is still aligned on 16 bytes (godbolt link):
bof(char*):
sub esp, 52 ; -52
push DWORD PTR [esp+56] ; -4
lea eax, [esp+20] ; 36 bytes to top of stack frame
push eax ; -4
call strcpy ; stack is aligned to 16 bytes (-64)
mov eax, 1
add esp, 60
ret
With a forced 4-byte stack alignment (-O2 -mpreferred-stack-boundary=2
) (godbolt link):
bof(char*):
sub esp, 24 ; -24
push DWORD PTR [esp+28] ; -4
lea eax, [esp+4] ; 24 bytes to top of stack frame
push eax ; -4
call strcpy
mov eax, 1
add esp, 32
ret
With stack protector on (-O2 -fstack-protector-all
) (godbolt link):
bof(char*):
sub esp, 52 ; -52
mov eax, DWORD PTR gs:20
mov DWORD PTR [esp+36], eax ; stack check value at -16 (-52+36)
xor eax, eax
push DWORD PTR [esp+56] ; -4
lea eax, [esp+16] ; 40 bytes to top of stack frame, leaving exactly 24 bytes to check value
push eax
call strcpy
add esp, 16
mov edx, DWORD PTR [esp+28]
xor edx, DWORD PTR gs:20
jne .L5
mov eax, 1
add esp, 44
ret
.L5:
call __stack_chk_fail
Other compilers might have entirely different results.
In real life, a buffer overflow is exploited in assembly mode by analyzing instructions and counting the bytes to the function's return address, so it doesn't matter what the source code was or how it was compiled (this info is often unavailable anyway).