-2

I'm creating an exercise that demonstrates different concepts in buffer overflow. I've encountered the following strange problem - I can't get the argument address. I have the following simple function:

void vuln(char *str) {
    char buf[64];
    strcpy(buf, str);
    dump_stack((void **) buf, 32, (void **) &str);
}

The dump_stack is defined as: void dump_stack(void **stack, size_t n, void **arg0)

When I compile and run the code for x86 using gcc or clang I see the same issue: the compiler creates a stack variable for str, copies the argument to it and &str points to this local stack variable instead of the argument!

The disassembly of the call to vuln looks like:

mov     eax, [ebp+argv]
add     eax, 4
mov     eax, [eax]
mov     [esp], eax
call    vuln

The disassembly of the vuln function looks as follows:

public vuln
vuln proc near

src= dword ptr -5Ch
dest= byte ptr -4Ch
var_C= dword ptr -0Ch
arg_0= dword ptr  8

push    ebp
mov     ebp, esp
sub     esp, 78h
mov     eax, [ebp+arg_0]
mov     [ebp+src], eax
mov     eax, large gs:14h
mov     [ebp+var_C], eax
xor     eax, eax
mov     eax, [ebp+src]
mov     [esp+4], eax    ; src
lea     eax, [ebp+dest]
mov     [esp], eax      ; dest
call    _strcpy

As one can see the function takes the first argument and stores it in a local variable. So there is no way in my C code to get the address of the argument on the stack.

I tried different optimization settings, but can't get this to compile to what I expect it to!!! What I need is just a way to get the stack address where the first argument is sitting

Moshe Kravchik
  • 2,341
  • 2
  • 16
  • 18
  • Probably the ABI (i86_64 does that, e.g) of your platform passes the first parameters in registers, so they don't have a stack location. The called function itself is then responsible to place it on the stack if it needs it to. – Jens Gustedt Nov 05 '14 at 20:19
  • This was a great idea, but it is not the reason. I compile it for x86. I will reflect it in the question – Moshe Kravchik Nov 06 '14 at 06:01
  • what is your expectation then ? – tristan Nov 06 '14 at 08:05
  • My expectation is to see the good old behavior where the arguments sit on the stack where the caller pushed them and &str returns it. – Moshe Kravchik Nov 06 '14 at 11:19

3 Answers3

1

Well, I've found that this neat feature is part of GCC stack protection, which is ON by default. If I turn it off using the advice from here How to turn off gcc compiler optimization to enable buffer overflow - my problem is resolved.

Community
  • 1
  • 1
Moshe Kravchik
  • 2,341
  • 2
  • 16
  • 18
0

Your call to dump_stack should get the adresses of the variables not the variables, i.e.

dump_stack(&buf,32,&str);

&buf and &str are the adresses of the variables buf and str on the stack.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0
this code:

// get something (i think from within the stack frame of the caller
mov     eax, [ebp+argv]

add     eax, 4      // step forward 4 bytes
mov     eax, [eax]  // load what is at the calculated location in memory
                    // I.E the address of str in the callers' area

mov     [esp], eax  // save the address of str parameter on the stack

// save the PC register on the stack and jump execution to the vuln function
call    vuln        

1) this has nothing to do with the call to dump_stack()
2) this has nothing to do with the local variables within the function vuln
3) the first 3 instructions are getting the address of str, 
   found in the callers' area
3.5) the next to last instruction is pushing the passed variable
   in reverse order, onto the stack
4) the last instruction is the actual jump 
   (with the PC/return register pushed onto stack 
   by the hardware of the call instruction)
   to the vuln function. 
5) the vuln function will be (possibly) setting a new stack frame,
   then pushing the local variables (in reverse order)
   onto the stack however that code is not shown
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Yes, this is what it does. I added it to the question after people asked that maybe the argument is passed in the register. The problem I try to resolve is in the vuln function and I added its disassembly as well to make it more clear. – Moshe Kravchik Nov 06 '14 at 11:20