You seem to have the general idea of what happens when you overflow a buffer, but I see you making a lot of assumptions and doing a lot of guessing. Also, there's the issue that b49P23TIvg has already pointed out, which is that the details of how local variables are organized is arbitrary and entirely up to the compiler, just so long as the end result complies with the C language standard.
So why guess? Why not just look directly at how your compiler organizes those local variables? The printf flag for an address is %p. Here is a short program I just wrote which shows you where those arrays are actually located on my system (WinXP, compiled with MinGW gcc version 2.95.3-6:
Code:
#include <stdio.h>
int main( void )
{
char firstname[20];
char lastname[20];
char age[3];
char serialnumber[32];
printf("firstname starts at %p\n", firstname);
printf(" firstname[0] at %p\n firstname[19] at %p\n",
&firstname[0], &firstname[19]);
printf("lastname starts at %p\n", lastname);
printf(" lastname[0] at %p\n lastname[19] at %p\n",
&lastname[0], &lastname[19]);
printf("age starts at %p\n", age);
printf(" age[0] at %p\n age[2] at %p\n",
&age[0], &age[2]);
printf("serialnumber starts at %p\n", serialnumber);
printf(" serialnumber[0] at %p\n serialnumber[31] at %p\n",
&serialnumber[0], &serialnumber[31]);
return 0;
}
Here is what it output on my system:
Code:
C:TEST>a
firstname starts at 0022FF60
firstname[0] at 0022FF60
firstname[19] at 0022FF73
lastname starts at 0022FF40
lastname[0] at 0022FF40
lastname[19] at 0022FF53
age starts at 0022FF30
age[0] at 0022FF30
age[2] at 0022FF32
serialnumber starts at 0022FF10
serialnumber[0] at 0022FF10
serialnumber[31] at 0022FF2F
C:TEST>
Originally Posted by dcforeman
IF the memory address starts at 0x1000 in my computer for whatever reason, then if I create a 20 character array I'm going to start writing the data at 0x1020 backwards towards 0x1000.
And yet you see that the first character in firstname is at 0022FF60 while the last possible character is at 0022FF73, meaning that the string progresses forward through memory, not backwards as you had assumed. This demonstratess the advantage of looking at what's really happening instead of making guesses. Though, of course, mileage will vary so you will need to see what addresses you get with your compiler on your system.
You will also see that my compiler organized all the local variables backwards with the last one appearing first and the first one last, just like in the Bible:
serialnumber starts at 0022FF10
age starts at 0022FF30
lastname starts at 0022FF40
firstname starts at 0022FF60
You will also notice that lastname ends at 0022FF53 but firstname starts 13 bytes later at 0022FF60. A reason for that is that the compiler can leave padding between some variables in order to place them on a word boundary that's more efficient to access; you will see this a lot in structs. So when you overflow lastname by one character, you won't see it affect firstname.
However, we don't know what's following firstname. Remember, these local variables are on the stack along with variables and pointers that are needed to make the function work, including the return address from the function. Overwriting one of those can easily cause the program to crash. Until we learn exactly how your compiler organizes that stack frame, we cannot predict what will happen when you overflow firstname.
So the secret is to not overflow any buffer.