Reputation: 221
I was reading the following code online from this link : http://www.cse.scu.edu/~tschwarz/coen152_05/Lectures/BufferOverflow.html
And I was confused about the usage of %p in this line :
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
which is taken from this snippet of code:
/*
StackOverrun.c
This program shows an example of how a stack-based
buffer overrun can be used to execute arbitrary code. Its
objective is to find an input string that executes the function bar.
*/
#pragma check_stack(off)
#include <string.h>
#include <stdio.h>
void foo(const char* input)
{
char buf[10];
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");
strcpy(buf, input);
printf("%s\n", buf);
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
}
void bar(void)
{
printf("Augh! I've been hacked!\n");
}
int main(int argc, char* argv[])
{
//Blatant cheating to make life easier on myself
printf("Address of foo = %p\n", foo);
printf("Address of bar = %p\n", bar);
if (argc != 2)
{
printf("Please supply a string as an argument!\n");
return -1;
}
foo(argv[1]);
return 0;
}
I know %p is the formatter for pointer, but why are there no values following the formatter? What values are actually printed here ? If it is printing the address of the arguments supplied to the foo function, then why there are 5 '%p' and why aren't all the '%p' formatting the same value ?
Thanks a lot.
Upvotes: 3
Views: 1636
Reputation: 364428
This code is terrible, and an extremely poor substitute for looking at the stack with a debugger. Don't waste your time with it until/unless you understand how it's abusing the calling convention and what exactly it's printing. (And also look at the compiler-generated code to see where the stack pointer is pointing at the time of the call).
It depends on a stack-args calling convention like is typical on 32-bit x86. (So the variadic printf
function will treat data on the stack as extra args). Functions "own" their args (and can modify them), but in practice most functions don't modify their stack args, and variadic functions even less so.
It also depends on the compiler not inserting a bunch of extra padding to align ESP by 16 for the call printf
, which modern versions of the i386 System V ABI require. If that happens, there will be some extra padding pointers before the real stuff that you wanted to overwrite with a strcpy
buffer overflow.
In x86-64 code, x86-64 System V passes the first 6 integer/pointer args in integer registers, so after the format string the first 5 %p
conversions are going to grab whatever garbage was in RSI, RDX, RCX, R8, and R9. (Format string in RDI). Then you'll get some qwords from the stack for the rest of the %p
conversions.
In Windows x64, the calling convention includes "shadow space": 32 bytes above RSP owned by the callee, where they can dump register args to make an array of args contiguous with the stack args. The caller has to reserve this space. That happens for strcpy
as well, so that maybe sort of balances out, but you're still going to print whatever garbage was in RDX, R8, and R9. (Format string in RCX).
In general most calling conventions for other non-x86 ISAs have some register args (often 4, e.g. ARM or MIPS), and most don't use shadow space.
Upvotes: 0
Reputation: 16290
This is leveraging undefined behavior.
By deliberately not providing values to printf, va_arg
is going to be pulling arbitrary values off of the stack to be printed. It is not correct code. And in fact it looks like this code snippet is trying to explain hacking techniques, which often take advantage of glitches that occur when undefined behavior happens.
Upvotes: 8