i have a question regarding a stack overflow in C.
I wrote a little testing program, so when i start it with 8 As, i get what i expect, i write over the borders of the second buf and therefor buf1 is empty, because the trailing zero is first element in buf1 now.
So far so good, if i try it with 16 As it also works, event with 17 As. But i would expect a segfault here … the segfault comes up after 24 As. Why is that? I tested on x86-32 ubuntu, debian and suse. Always segfault after 24 Byte…
On an AMD64 System with same code i get segfault after 32 As, just as i expected it …
But why on x86-32 after 24????
include
#include <string.h>
/*
* $ gcc -O0 -Wall -fno-stack-protector buffer.c -o buffer
*
* $ ./buffer AAAAAAAA
* buf1: test
* buf2: test
* buf1:
* buf2: AAAAAAAA
*
* $ ./buffer AAAAAAAAAAAAAAAAAAAAAAAA
* buf1: test
* buf2: test
* buf1: AAAAAAAAAAAAAAAA
* buf2: AAAAAAAAAAAAAAAAAAAAAAAA
* Segmentation fault (core dumped)
*/
static void exploit(const char *InputString)
{
char buf1[8];
char buf2[8];
strcpy(buf1, "test");
strcpy(buf2, "test");
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
strcpy(buf2, InputString);
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
}
int main(int argc, const char *argv[])
{
if (argc > 1)
exploit(argv[1]);
return 0;
}
You are trying to guess the memory layout generated by the compiler. The compiler is free to layout the code in any way it seems fit. However, the stack frame must contain:
There are eight bytes between the local variables and the return address on the x86 machines you tested and sixteen bytes on the x64 machines. If the registers are saved by the callee, they are going to be stored in this space:
http://en.wikipedia.org/wiki/Calling_convention#x86
So, the space right after the return address contains the stored frame pointer BP. This overwrite will be unnoticed if the caller never uses the base pointer again. A function uses its base pointer to return, but if the function exits through a system call (I remember the main method being “special” in this sense, but I cannot source my claim), the corrupted base pointer is never used and the corruption will go unnoticed).
To test if it is the base pointer:
Other possible causes:
thispointer. Should not be present for ordinary functions.Other things to try:
Make a memory dump in the callee before and after the corruption to see the layout. The stored base pointer should point to the stack space (caller’s stack frame). The return address should point to the code space (near the current IP). The char* argument is a pointer. Flanking it with two other arguments (“>>>” and “<<<” as
char[4]) will help recognition.