Question

I wanna write a simple buffer overflow example for the ARMv6 instruction set architecture using a Raspberry PI and Raspbian OS. First thing i took a look on was the layout of the stack frame. Unfortunately I am not able to find the return address. Consider the following example:

void foo
(int b)
{
    int c = 3;
}

int main
(int argc, char **argv)
{
    int a = 1;
    foo(2);
    a = 4;
}

I have compiled it with:

gcc exploit_me.c -g -O0 -o exploit_me

Debugging the code with gdb gives me the following information:

gdb exploit_me 
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/pi/_development/buffer_overflow/exploit_me...done.
(gdb) b 4
Breakpoint 1 at 0x83a0: file exploit_me.c, line 4.
(gdb) run
Starting program: /home/pi/_development/buffer_overflow/exploit_me 

Breakpoint 1, foo (b=2) at exploit_me.c:4
4       int c = 3;
(gdb) disas foo
Dump of assembler code for function foo:
   0x00008390 <+0>: push    {r11}       ; (str r11, [sp, #-4]!)
   0x00008394 <+4>: add r11, sp, #0
   0x00008398 <+8>: sub sp, sp, #20
   0x0000839c <+12>:    str r0, [r11, #-16]
=> 0x000083a0 <+16>:    mov r3, #3
   0x000083a4 <+20>:    str r3, [r11, #-8]
   0x000083a8 <+24>:    add sp, r11, #0
   0x000083ac <+28>:    pop {r11}
   0x000083b0 <+32>:    bx  lr
End of assembler dump.
(gdb) info r
r0             0x2  2
r1             0xbefff804   3204446212
r2             0xbefff80c   3204446220
r3             0x1  1
r4             0x0  0
r5             0x0  0
r6             0x82e4   33508
r7             0x0  0
r8             0x0  0
r9             0x0  0
r10            0xb6fff000   3070226432
r11            0xbefff69c   3204445852
r12            0xb6fc0000   3069968384
sp             0xbefff688   0xbefff688
lr             0x83d8   33752
pc             0x83a0   0x83a0 <foo+16>
cpsr           0x60000010   1610612752
(gdb) disas main
Dump of assembler code for function main:
   0x000083b4 <+0>: push    {r11, lr}
   0x000083b8 <+4>: add r11, sp, #4
   0x000083bc <+8>: sub sp, sp, #16
   0x000083c0 <+12>:    str r0, [r11, #-16]
   0x000083c4 <+16>:    str r1, [r11, #-20]
   0x000083c8 <+20>:    mov r3, #1
   0x000083cc <+24>:    str r3, [r11, #-8]
   0x000083d0 <+28>:    mov r0, #2
   0x000083d4 <+32>:    bl  0x8390 <foo>
   0x000083d8 <+36>:    mov r3, #4
   0x000083dc <+40>:    str r3, [r11, #-8]
   0x000083e0 <+44>:    mov r0, r3
   0x000083e4 <+48>:    sub sp, r11, #4
   0x000083e8 <+52>:    pop {r11, pc}
End of assembler dump.
(gdb) x/12xw $sp
0xbefff688: 0x00000000  0x00000002  0x00008360  0x00008438
0xbefff698: 0xb6fc1b80  0xbefff6b4  0xbefff804  0x00000001
0xbefff6a8: 0x00000000  0x00000001  0x00000000  0xb6eac81c

According to that the link register which holds the return address is set to the address 0x83d8

lr             0x83d8   33752

which is indeed the correct address for the next instruction in main:

0x000083d8 <+36>:    mov r3, #4

However the stack (see end of gdb output) does not contain the return address preventing an buffer overflow attack.

Is it by design that the return address is only held in the link register and not being pushed to the stack or am I missing something?

Was it helpful?

Solution

I am not familiar with the arm architecture but this is true for Power PC. When you call one function down your return address is stored in the lr. If you call one more level down the previous lr is pushed onto the stack. Basically the lr always contains the return address for the function you are in. If you need to go higher back in the call history you need to look on the stack.

So...

void myFunc2( void)
{
  myFunc3();
}

void myFunc1( void )
{
   myFunc2();
}

If you are in myFunc3 the lr will contain the return address to myFunc2. The return address from myFunc2 to myFunc1 is on the stack somewhere. I think you can do what you are trying my corrupting the return address to myFunc1 not myFunc2 like you were trying to.

For power pc you can check out how the registers and the stack works by reading this Power PC EABI

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top