Jeremy Huang
Jeremy Huang

Reputation: 221

Usage of %p in printf ?

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

Answers (2)

Peter Cordes
Peter Cordes

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

StilesCrisis
StilesCrisis

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

Related Questions