Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Skipping an instruction using stack smashing

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    
like image 469
shashank Avatar asked Nov 04 '22 11:11

shashank


1 Answers

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].

like image 71
Aki Suihkonen Avatar answered Nov 12 '22 22:11

Aki Suihkonen