我的溢出代码不起作用

时间:2011-12-06 12:36:05

标签: c linux stack-overflow

以下代码来自着名文章Smashing The Stack For Fun And Profit

void function(int a, int b, int c) {
  char buffer1[5];
  char buffer2[10];
  int *ret;
  ret = buffer1 + 12;
  (*ret)+=8;
}

void main() {
  int x;
  x=0;
  function(1,2,3);
  x=1;
  printf("%d\n",x);
}

我想我必须解释这个代码的目标。 堆栈模型如下。单词下面的数字是堆栈中变量的字节数。所以,如果我想重写RET以跳过我想要的语句,我计算从buffer1到RET的偏移量是8 + 4 = 12。由于该架构是x86 Linux。

buffer2 buffer1 BSP RET   a    b    c
(12)    (8)     (4) (4)   (4)  (4)  (4)

我想跳过语句x=1;并让printf()在屏幕上输出0

我用以下代码编译代码:

gcc  stack2.c  -g

并在gdb中运行:

gdb ./a.out

gdb给我这样的结果:

Program received signal SIGSEGV, Segmentation fault.
main () at stack2.c:17
17  x = 1;

我认为Linux使用一些机制来防止堆栈溢出。也许Linux将RET地址存储在另一个地方,并在函数返回之前比较堆栈中的RET地址。

这个机制的细节是什么?我应该如何重写代码以使程序输出0

好的,反汇编代码在下面。它来自gdb的输出,因为我认为更容易为你阅读。任何人都可以告诉我如何粘贴一个长代码序列?一个一个地复制粘贴让我太累了......

Dump of assembler code for function main:
0x08048402 <+0>:    push   %ebp
0x08048403 <+1>:    mov    %esp,%ebp
0x08048405 <+3>:    sub    $0x10,%esp
0x08048408 <+6>:    movl   $0x0,-0x4(%ebp)
0x0804840f <+13>:   movl   $0x3,0x8(%esp)
0x08048417 <+21>:   movl   $0x2,0x4(%esp)
0x0804841f <+29>:   movl   $0x1,(%esp)
0x08048426 <+36>:   call   0x80483e4 <function>
0x0804842b <+41>:   movl   $0x1,-0x4(%ebp)
0x08048432 <+48>:   mov    $0x8048520,%eax
0x08048437 <+53>:   mov    -0x4(%ebp),%edx
0x0804843a <+56>:   mov    %edx,0x4(%esp)
0x0804843e <+60>:   mov    %eax,(%esp)
0x08048441 <+63>:   call   0x804831c <printf@plt>
0x08048446 <+68>:   mov    $0x0,%eax
0x0804844b <+73>:   leave
0x0804844c <+74>:   ret


Dump of assembler code for function function:
0x080483e4 <+0>:    push   %ebp
0x080483e5 <+1>:    mov    %esp,%ebp
0x080483e7 <+3>:    sub    $0x14,%esp
0x080483ea <+6>:    lea    -0x9(%ebp),%eax
0x080483ed <+9>:    add    $0x3,%eax
0x080483f0 <+12>:   mov    %eax,-0x4(%ebp)
0x080483f3 <+15>:   mov    -0x4(%ebp),%eax
0x080483f6 <+18>:   mov    (%eax),%eax
0x080483f8 <+20>:   lea    0x8(%eax),%edx
0x080483fb <+23>:   mov    -0x4(%ebp),%eax
0x080483fe <+26>:   mov    %edx,(%eax)
0x08048400 <+28>:   leave
0x08048401 <+29>:   ret

我检查汇编代码并发现我的程序有些错误,并且我已将(*ret)+=8重写为(*ret)+=7,因为0x08048432 <+48>减去0x0804842b <+41>为7。

3 个答案:

答案 0 :(得分:2)

因为那篇文章是从1996年开始的,所以假设是不正确的。

请参阅“为了娱乐和利润粉碎现代堆栈”

http://www.ethicalhacker.net/content/view/122/24/

从以上链接:

  

然而,自1998年以来,GNU C编译器(gcc)已经发展,因此,许多人不知道为什么他们不能让这些例子为他们工作,或者如果他们确实让代码工作,为什么他们必须做出他们所做的改变。

答案 1 :(得分:0)

函数function会覆盖堆栈的某个位置,这就是main的堆栈。覆盖的东西我不知道,但它会导致您看到的分段错误。它可能是操作系统使用的一些保护,但是当错误的值在堆栈上的那个位置时,生成的代码也可能只是做错了。

这是在您分配的内存之外写入时可能发生的事情的一个很好的例子。它可能会直接崩溃,它可能会在完全不同的地方崩溃,或者根本不会崩溃,而只是做一些错误的计算。

答案 2 :(得分:0)

尝试ret = buffer1 + 3;

说明:ret是一个整数指针;将它递增1会将4个字节添加到32位机器上的地址。