My StackOverrun.cpp (Writing Secure Code 2nd Ed.)
Here is the output (see p.129 Writing Secure Code 2nd Ed. )
Address of bar = 00401070
Entering foo().
My stack looks like:
^ 04030201 (buf[3], buf[2], buf[1], buf[0]) | Lower memory address
| 08070605 (buf[7], buf[6], buf[5], buf[4]) |
Stack | 00000009 (2-byte padding, buf[9], buf[8]) |
| 0012FEE4 (saved ebp ) |
| 00401106 (Return Address in main() code) |
| 0012FE9C v Higher memory address
1234567890..EBP.p?@
My stack looks like:
^ 34333231 (All this is now ) | Lower memory address
| 38373635 (filed with the string) |
Stack | 2E2E3039 (passed as parameter,) |
| 2E504245 (overwriting the saved EBP ) |
| 00401070 (and the return address!) |
| 0012FE9C v Higher memory address
Entering bar(). Augh! I've been hacked!
and the source code, compiled with VS.NET 2003 in Release mode without /GS, optimization nor /RTC, ran on Windows XP SP2 ~RC2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void foo(const char* input)
{
printf( "\nEntering foo().\n") ;
char buf[10] = "\x1\x2\x3\x4\x5\x6\x7\x8\x9" ;
printf("My stack looks like:\n ^ %p (buf[3], buf[2], buf[1], buf[0]) | Lower memory address\n" \
" | %p (buf[7], buf[6], buf[5], buf[4]) |\n" \
"Stack | %p (2-byte padding, buf[9], buf[8]) |\n" \
" | %p (saved ebp ) |\n" \
" | %p (Return Address in main() code) |\n" \
" | %p v Higher memory address\n\n" ) ;
//Pass the user input straight to secure code public enemy #1.
strcpy(buf, input);
printf("%s\n\n", buf) ;
printf("My stack looks like:\n ^ %p (All this is now ) | Lower memory address\n" \
" | %p (filed with the string) |\n" \
"Stack | %p (passed as parameter,) |\n" \
" | %p (overwriting the saved EBP ) |\n" \
" | %p (and the return address!) |\n" \
" | %p v Higher memory address\n\n" ) ;
}
void bar()
{
printf( "\nEntering bar(). Augh! I've been hacked!\n") ;
exit(0) ; // Let's not spend time trying to return from this one, it would crash.
}
#include <strsafe.h>
void main()
{
printf( "Address of bar = %p\n\n", bar ) ;
// With the following code, we build the right buffer that would need to be infered
// and passed to our code (e.g argv, file, ...) in order to have the bar function called when
// returning from foo:
int p = reinterpret_cast<int>(bar) ;
char s[64] ; //
StringCchPrintf( s,
sizeof(s)/sizeof(s[0]),
"1234567890..EBP.%c%c%c%c", static_cast<char>(p & 0xFF),
static_cast<char>((p & 0xFF00) >> 8),
static_cast<char>((p & 0xFF0000) >> 16),
static_cast<char>((p & 0xFF000000) >> 24) ) ;
foo( s ) ; // We'll never come back from this call
}