Reputation: 5207
I was reading Tim Newsham's white paper on format string exploits and found some parts in the beginning difficult to understand.
The following program was being discussed.
/*
* fmtme.c
* Format a value into a fixed-size buffer
*/
#include <stdio.h>
int
main(int argc, char **argv)
{
char buf[100];
int x;
if(argc != 2)
exit(1);
x = 1;
snprintf(buf, sizeof buf, argv[1]);
buf[sizeof buf - 1] = 0;
printf("buffer (%d): %s\n", strlen(buf), buf);
printf("x is %d/%#x (@ %p)\n", x, x, &x);
return 0;
}
Author says "All examples in this document were actually performed on an x86 BSD/OS 4.1", a little-endian machine.
The program is executed like
% ./fmtme "%x %x %x %x"
buffer (15): 1 f31 1031 3133
x is 1/0x1 (@ 0x804745c)
The paper says:
"A quick analysis of the program will reveal that the stack layout of the
program when the snprintf function is called is:
Address Contents Description
fp+8 Buffer pointer 4-byte address
fp+12 Buffer length 4-byte integer
fp+16 Format string 4-byte address
fp+20 Variable x 4-byte integer
fp+24 Variable buf 100 characters
The four values output in the previous test were the next four arguments on
the stack after the format string: the variable x, then three 4-byte
integers
taken from the uninitialized buf variable."
What is fp
here? File pointer?
And why does it start from fp+8 and not fp+4 when the increments are by 4 everwhere else (4-byte address)?
Here, does larger address mean the value is higher up or lower down the stack?
What does the names given under 'Contents' mean?
And when I run the above program, the value of x
, ie, 1
, is not being printed. Maybe because of different architecture?
I get like this
./fmtme "%x %x %x %x"
buffer (34): cd512860 b3356d80 b3356d80 8247ee8
x is 1/0x1 (@ 0x7ffc08247d8c)
Can anyone help?
Upvotes: 0
Views: 130
Reputation: 239021
fp
stands for "frame pointer".
The arguments start at fp+8
because fp+4
is the return address and fp+0
is the saved frame pointer.
In a conventional grows-down stack as x86 uses, higher addresses are deeper in the stack (items that were pushed earlier).
The Contents
is a little bit unclear - it's trying to describe what's in that stack slot but some of them don't have names. This might be clearer:
Address Contents Description
fp+8 First snprintf argument pointer 4-byte address
fp+12 Second snprintf argument length 4-byte integer
fp+16 Third snprintf argument string 4-byte address
fp+20 Variable x in main 4-byte integer
fp+24 Variable buf in main 100 characters
You don't see the same result because these kinds of things - formally undefined behaviour - are highly sensitive to the architecture, compiler and compiler version you're using. It appears from the pointer value printed with %p
that you're using a 64 bit architecture - if you're using x86-64, then then first 6 integral arguments to a function are passed in registers, not on the stack, so that's where your bogus %x
formats are going to start looking. You could try compiling for x86 with the -m32
compiler option, but there's no guarantees.
Upvotes: 2