5

I have been trying to skip an instruction by changing the return address through stack smashing. The following code skips a++ in main and prints an output of "1 3". I have executed this code on a 32-bit intel machine.

#include<stdio.h>
void fun(int a,int b) {
    // buffer
    char buf[8];
    char *p;
    p = (char *)buf+24;
    *p=*p+5;
    return;
}

int main() {
    int a=1,b=2;
    fun(a,b);
    a++;
    b++;
    printf("%d %d",a,b);
 }

I am unable to understand why return address is stored at a displacement of 24 bytes from starting address of buf. I have tried executing the same code on a different 32-bit intel machine and I had to use a displacement of 20 bytes instead of 24 bytes. I have put my understanding in the following figure. I am not sure about what fills the gap represented by "?" in the figure. Does gcc put any canary value there or am I missing something ?

Link to figure: http://www.cse.iitb.ac.in/~shashankr/stack.png

Smashing the stack example3.c confusion asked the same question but could not explain the reason for displacement in general.

The following figure gives a view of the stack obtained by placing a breakpoint in function.

stack content
(source: shashankr at www.cse.iitb.ac.in)

The following is the assembly code for main and fun:

 Dump of assembler (fun):
 0x08048434 <+0>:   push   %ebp
 0x08048435 <+1>:   mov    %esp,%ebp
 0x08048437 <+3>:   sub    $0x18,%esp
 0x0804843a <+6>:   mov    %gs:0x14,%eax
 0x08048440 <+12>:  mov    %eax,-0xc(%ebp)
 0x08048443 <+15>:  xor    %eax,%eax
 0x08048445 <+17>:  lea    -0x14(%ebp),%eax
 0x08048448 <+20>:  add    $0x18,%eax
 0x0804844b <+23>:  mov    %eax,-0x18(%ebp)
 0x0804844e <+26>:  mov    -0x18(%ebp),%eax
 0x08048451 <+29>:  movzbl (%eax),%eax
 0x08048454 <+32>:  add    $0x5,%eax
 0x08048457 <+35>:  mov    %eax,%edx
 0x08048459 <+37>:  mov    -0x18(%ebp),%eax
 0x0804845c <+40>:  mov    %dl,(%eax)
 0x0804845e <+42>:  mov    -0xc(%ebp),%eax
 0x08048461 <+45>:  xor    %gs:0x14,%eax
 0x08048468 <+52>:  je     0x804846f <fun+59>
 0x0804846a <+54>:  call   0x8048350 <__stack_chk_fail@plt>
 0x0804846f <+59>:  leave  
 0x08048470 <+60>:  ret    


 Dump of assembler (main)
 0x08048471 <+0>:   push   %ebp
 0x08048472 <+1>:   mov    %esp,%ebp
 0x08048474 <+3>:   and    $0xfffffff0,%esp
 0x08048477 <+6>:   sub    $0x20,%esp
 0x0804847a <+9>:   movl   $0x1,0x18(%esp)
 0x08048482 <+17>:  movl   $0x2,0x1c(%esp)
 0x0804848a <+25>:  mov    0x1c(%esp),%eax
 0x0804848e <+29>:  mov    %eax,0x4(%esp)
 0x08048492 <+33>:  mov    0x18(%esp),%eax
 0x08048496 <+37>:  mov    %eax,(%esp)
 0x08048499 <+40>:  call   0x8048434 <fun>
 0x0804849e <+45>:  addl   $0x1,0x18(%esp)
 0x080484a3 <+50>:  addl   $0x1,0x1c(%esp)
 0x080484a8 <+55>:  mov    $0x80485a0,%eax
 0x080484ad <+60>:  mov    0x1c(%esp),%edx
 0x080484b1 <+64>:  mov    %edx,0x8(%esp)
 0x080484b5 <+68>:  mov    0x18(%esp),%edx
 0x080484b9 <+72>:  mov    %edx,0x4(%esp)
 0x080484bd <+76>:  mov    %eax,(%esp)
 0x080484c0 <+79>:  call   0x8048340 <printf@plt>
 0x080484c5 <+84>:  leave  
 0x080484c6 <+85>:  ret    
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
shashank
  • 53
  • 4
  • Please note that I have figured out the value 24 by trial and error. Also, the value 5 through gdb disassembly of main function. – shashank Nov 11 '12 at 09:59
  • The variable `p` should also be on the stack, so you can add 4 bytes there, I believe. I'm not sure where the remainder is coming from. – Chris Hayes Nov 11 '12 at 10:08
  • In retrospect it's also likely that the arguments `a` and `b` are never removed from the stack for efficiency reasons, therefore accounting for the remainder of the memory. – Chris Hayes Nov 11 '12 at 10:14
  • Have you tried to decompile it, and place a hardware breakpoint in the function ? That way you could actually dump the stack, and see what happens with these ! I recommend using OllyDbg for this task ! – Anthony Teisseire Nov 11 '12 at 10:21
  • One "?" is definitely `p`. What does the compiled code look like? Is the ?-marked part of the stack referenced in any way? The other ? may be the register values of the registers used by `fun`. – Klas Lindbäck Nov 11 '12 at 10:27
  • Thanks for the inputs. I have added a figure with stack contents along with disassembled code. Variable p is part of the stack. I do not see a and b being part of the function's stack frame. ( If I refer them inside function, then I see them on the stack frame ). Also, I think gcc puts a canary value on the stack frame. This is because the assembly code pushes a value from gs segment onto stack. (http://stackoverflow.com/questions/9249315/what-is-gs-in-assembly) talks about gs segment. – shashank Nov 11 '12 at 16:10
  • You may have more luck/consistency using `__builtin_frame_address` instead of trying random offsets from a local variable... – Chris Dodd Aug 26 '19 at 21:22
  • see [Getting the Return or Frame address of a Function](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Return-Address.html#Return-Address) – Chris Dodd Aug 26 '19 at 21:34

1 Answers1

2

I believe the answer is nothing. Are you having different gcc versions? Anyway a compiler is allowed to allocate a bit more stack than necessary. Perhaps it's the initial "guess" based on the number of variables, but which isn't reduced by optimization stages, which are allowed to move any variable to a register. Or it's some reservoir to save ecx,ebp or other registers in case the subroutine needs to.

There's anyway one fixed address variable to overcome the problem: a. Return address = &a[-1].

Aki Suihkonen
  • 19,144
  • 1
  • 36
  • 57
  • Yes, the machines have different gcc versions. You may be right about gcc allocating some extra space on stack. When I executed the same code on the second machine, I noticed that the size of stack frame came down. It can also be because gcc on first machine used canary value. When I did a strcpy to overflow the buffer, I got a stack smash error on first machine. This did not happen on second machine as the gcc is of older version and perhaps did not use canary value. Also, thanks for suggesting a workaround to find location of return address through a's address. – shashank Nov 11 '12 at 17:23