What address can I print?

advertisements

In this example C program,

int main (int argc, char* argv[]) {
    printf("%p\n");
    return 0;
}

I am confused as to what exactly I'm printing. The address it prints changes every time I run the program, so I assume the address has something to do with the stack, like maybe where it starts or something, but I am not sure.

EDIT: The above program comes from a more elaborate example of a simple buffer overflow attack from "Writing Secure Code" (2nd edition) by Michael Howard and David LeBlanc (2003). In the foo method, the first printf says "My stack looks like: \n%p... etc. so I was wondering how that was possible because there's no argument passed to the printf function, but I asked here because maybe there was something I was missing. My apologies for not including it in the original post.

#include <stdio.h>
#include <string.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[])
{
    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;
}


So we have covered that this is undefined behavior. You cannot make any guarantees about code that invokes undefined behavior. So the code you have posted likely does not work except for a very specific implementation (e.g., gcc 4.3 on x86 with no extra compiler flags or optimizations, let's say).

But let's have fun and guess how the code was intended to work on a specific platform with a specific compiler with specific flags at a specific optimization level.

The main idea that will help you here is that the compiler must generate some code to give a function its arguments, and the function must have some code to be able to access those arguments. And then someone, either the caller or the function, must have code to clean up the arguments so that memory (if used at all) is not leaked.

But here's the rub: the compiler generating code to call the function may not be the same as the compiler that compiled the function.

So the platform architects and compiler writers and various other stakeholders got together and came up with some calling conventions. The calling convention is part of the platform's ABI, and as long as every compiler implements to the same ABI, then their compiled libraries will be compatible.

Because of the ABI, I can implement a function using my compiler and give you the generated object file. You can write code to call this function, and link with my object file (library). If our compilers both generate code that adheres to the proper calling conventions and ABI, then it will all work out.

As you can guess, the calling convention for every platform is different. The calling convention on x86 processors for variadic functions like printf is called the cdecl calling convention. In this calling convention, the caller pushes all arguments onto the stack (in reverse order) and once the function is done, the caller pops the arguments off the stack.

So what you're seeing is that you've called printf and provided 1 argument, which is your format string. This is what happens (for cdecl):

  1. Your code pushes a pointer to the format string onto the stack and calls the function printf.

  2. printf reads the format string, which is on the top of the stack.

  3. printf sees %p in the format string. You have told it that there is another argument on the stack, this argument is a pointer, and that printf should print the value of this pointer.

  4. But there is no other argument on the stack. printf interprets whatever arbitrary garbage is on the stack as a pointer and prints it.

And so the more %p's you give it, the more stack data it will print.

What garbage it prints is (you guessed it) undefined. You'll have to study your platform and compiler to know and understand what's there.