堆栈上缺少返回地址

时间:2014-04-20 12:54:55

标签: gdb stack arm buffer-overflow raspbian

我想使用Raspberry PI和Raspbian OS为ARMv6指令集架构编写一个简单的缓冲区溢出示例。我首先看一下堆栈框架的布局。很遗憾,我无法找到回邮地址。请考虑以下示例:

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

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

我用它编译了它:

gcc exploit_me.c -g -O0 -o exploit_me

使用gdb调试代码可以获得以下信息:

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

根据保存返回地址的链接寄存器设置为地址0x83d8

lr             0x83d8   33752

这确实是main中下一条指令的正确地址:

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

然而,堆栈(请参阅gdb输出的结尾)不包含阻止缓冲区溢出攻击的返回地址。

根据设计,返回地址是仅保存在链接寄存器中而不是被推入堆栈还是我遗漏了什么?

1 个答案:

答案 0 :(得分:5)

我对手臂架构并不熟悉,但Power PC也是如此。当你调用一个函数时,你的返回地址存储在lr中。如果再调用一个级别,则将前一个lr推入堆栈。基本上,lr始终包含您所在功能的返回地址。如果您需要在呼叫历史记录中更高一些,则需要查看堆栈。

因此...

void myFunc2( void)
{
  myFunc3();
}

void myFunc1( void )
{
   myFunc2();
}

如果您在myFunc3中,则lr将包含myFunc2的返回地址。从myFunc2到myFunc1的返回地址位于堆栈的某处。我认为你可以做你正在尝试破坏myFunc1的返回地址,而不是你想要的myFunc2。

对于power pc,您可以通过阅读本文来了解寄存器和堆栈的工作原理 Power PC EABI