-3

Good day everyone!

I am trying to understand how buffer overflow works. Right now, I’m in the process of determining the address of a function’s return address which I’m supposed to change to perform a buffer overflow attack. I’ve written a simple program based from an example I’ve read in the internet. What this program does is it creates an integer pointer to store the address of the function's return address in the stack. To do this, (granted I understand how a function/program variables get organized in the stack), I add 8 to the buffer variable’s address and set it as the value of ret. I’m not doing anything here that would change the address contained in the location of func’s return address.

UPDATE: I've modified the program a bit, so it prints the stack address of func's parameter a. As you can see, the distance between a and buffer is about 8 bytes, so that would probably mean, based from the stack layout, that saved FP and old EIP (func return address) is in between. Am I right?

Here's the program:

void func( int a){
    char buffer[3];

    int *ret;

    ret = buffer + 11; // this is the configuratio which made the whole program works... This now points to the address containing func's return address

    printf (" address of a is %d\n", &a);

    printf ("address of buffer is %x\n", buffer);

    printf ("address of ret is %x\n", ret);

    printf ("value of ret is %x\n", (*ret));

}

void main(){
    int num;

    num = 0;

    func(num);

    num = 1;

    printf("Num now is %d", num);
}

Output of the program when gets excecuted:

alt text http://img20.imageshack.us/img20/2034/72783404.png

As you can see, I’m printing the address of the variables buffer and ret. I’ve added an additional statement printing the value of the ret variable (supposed location of func return address, so this should print the address of the next instruction which will get executed after func returns from execution).

Here is the dump which shows the supposed address of the instruction to be executed after func returns. (Underlined in green) As you can see, that value is way different from the value printed contained in the variable ret.

alt text http://img717.imageshack.us/img717/8273/assemblycodecopy.png

My question is, why are they different? (of course in the assumption that what I’ve done are all correct). Else, what have I done wrong? Is my understanding of the program’s runtime stack wrong? Please, help me understand this. My project is due nextweek and I’ve barely touched it yet. I’m sorry if I’m being demanding, I badly need your help.

ultrajohn
  • 2,527
  • 4
  • 31
  • 56
  • 8
    Please include the text of your actual code (not just screen shots) in your posting. – R Samuel Klatchko Jun 18 '10 at 06:22
  • i'm sorry, but there's all there is. – ultrajohn Jun 18 '10 at 06:25
  • You stack looks like this: http://1.bp.blogspot.com/_t9BeJ81cm7k/ScDGXubMsbI/AAAAAAAABuA/6ySZOeEm6Xc/s1600-h/Call_stack.png So return address on stack it's 8 bytes higher than the address of your first local variable. I guess that declaring an int and adding 8 to its address will retrieve the exact return address. – Daniel Băluţă Jun 18 '10 at 06:43
  • I've already solved the problem. It turned out that a lousy formatting of my outputs (printf) mwas actually the cause of the confusion on my part. – ultrajohn Sep 16 '13 at 02:57

3 Answers3

1

First off, notice that the address of buffer is an odd number 0xbffffd51 and then you add 8 to it to get 0xbffffd59. I would be quite surprised if the return address on the stack was not aligned to a four byte address.

Depending on the compiler, exactly how the stack frame is layed out could vary (for example, even though buffer is first in the source code, the compiler could put ret higher in the stack), so you may need to experiment with your values. I would do a couple of things:

  1. Change buffer to be 4 bytes.
  2. Experiment with different offsets. I have a feeling that you may need to look 12 bytes or even 16 bytes up to find your return address.
R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • yeah, from what i've understand the layout of stack should like this when func gets called, from higher mem address to lower mem address, |nums value| ret | sfp (ebp) | buffer | , so the distance between buffer and ret in the stack, should be like 8, – ultrajohn Jun 18 '10 at 06:43
  • @ultrajohn - and yet it is not 8 so your understanding is incorrect. Did you try the changes I recommended? – R Samuel Klatchko Jun 18 '10 at 07:12
  • yeah, i've tried using different offsets, and i was not able to get the correct value of the address, in one case, the retrieved value is correct for its first 7 digits from the left, except the last example: if the correct value is 0808425d, i'ce encountered a value in one particular offset that looks like this, 808425d1, and i don't why? – ultrajohn Jun 18 '10 at 07:25
1

For the following program

int main(int argc, char **argv) {
   int v[2];

   return 0;
}

The stack layout is basically the following:

 
       -------------   
           arg n 
       ------------- 
         .........
       -------------   
0x1010     arg 0 
       ------------- 
0x100C  ret address
       =============
0x1008     old fp 
       -------------
0x1004     v[1]
       -------------
0x1000     v[0]
       -------------

You can find out main's return address using v + 3.

Assuming the addresses placed on the left side of the stack, v has address 0x1000 , return adress has the address (v + 3 => 0x1000 + 4 * 3 = 0x100C)

Daniel Băluţă
  • 1,255
  • 11
  • 13
0

Of course, you can't modify the original num unless you pass the pointer to it; so in the main, num first is 0, then it is 1, and it is never really modified by the func. Address of a (&a) in func is the address of the local copy (by value) of the argument, likely an address on the stack in most cases. And what would ret point to? You have a 3 char buffer, and you get the address beyond it; you must consider it now a pointer to garbage, even though likely your pointing to something "interesting", according to how local variables are "organized" in memory. So you can't be 100% sure it points to the return address indeed. You're assuming the following:

0  4 bytes (for char, assuming 4bytes alignment)
4  4 bytes (for whatever, maybe argument)
8  4 bytes (return address)

And it depends. It depends on the architecture; it depends on how the compiler "translate" the code of the function. Let us imagine x86. The following is a reasonable way of doing func

func:
  push ebp  ; save some regs...
  push eax  ; or with pusha?
  mov ebp, esp
  push 0   ; for char a[3]
  mov eax, ebp
  add eax, 4  ; -4 + 8
  push eax ; for int *ret
  ; -4(ebp) gives a
  ; -8(ebp) gives int *ret
  ; so ebp-4 is the pointer to a, we
  ; add 8, to obtain ebp+4, which points
  ; to saved ebp... missing the ret ptr
  ; (other code...)
  mov esp, ebp
  pop eax ; or with popa?
  pop ebp
  ret

and what if the saved regs are more? what if the order of char a[4] and int *ret is swapped? How do you can know? You can't assume anything, unless, you write the code yourself directly in asm, in this case you can controll exactly what's happening. Otherwise, a working C code to do what you want would work by chance...

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39
  • I wrote a[n], or char *a ... instead of char buffer... mixed up a little bit with a (int arg)/buffer, and int *ret, basically forgot the argument... no matter: the same reasoning still works: i.e. you can't assume the layout of the on-stack stuffs will be exactly that on different compilers (and of course, on different cpus, but this case likely is not of your interest); even though using a frame pointer is a good idea on x86, no one assures you it is used, and not in the same way, by every compilers. – ShinTakezou Jun 18 '10 at 09:37