堆栈地址不对应(试图理解缓冲区溢出)

时间:2014-10-14 18:24:52

标签: c gcc assembly stack-overflow

我一直在http://insecure.org/stf/smashstack.html学习本教程,但是在example3.c我的函数返回地址与他所暗示的逻辑并不对应。我可以理解如何在函数中更改返回地址,但在我的计算机上执行此操作只是不起作用。我已经使用-fno-stack-protector和gdb与info寄存器和反汇编main并且还反汇编函数但无济于事。我对大会有点新意。 我的电脑正在运行xubuntu 14 32bits。 我的gcc指令是:gcc -Wall -ansi -g -fno-stack-protector example3.c

example3.c:
------------------------------------------------------------------------------
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);
}
------------------------------------------------------------------------------

gdb在main上用函数调用上的断点进行反汇编

(gdb) disassemble main
Dump of assembler code for function main:
   0x0804843b <+0>: push   %ebp
   0x0804843c <+1>: mov    %esp,%ebp
   0x0804843e <+3>: and    $0xfffffff0,%esp
   0x08048441 <+6>: sub    $0x20,%esp
   0x08048444 <+9>: movl   $0x0,0x1c(%esp)
=> 0x0804844c <+17>:    movl   $0x3,0x8(%esp)
   0x08048454 <+25>:    movl   $0x2,0x4(%esp)
   0x0804845c <+33>:    movl   $0x1,(%esp)
   0x08048463 <+40>:    call   0x804841d <function>
   0x08048468 <+45>:    movl   $0x1,0x1c(%esp)
   0x08048470 <+53>:    mov    0x1c(%esp),%eax
   0x08048474 <+57>:    mov    %eax,0x4(%esp)
   0x08048478 <+61>:    movl   $0x8048520,(%esp)
   0x0804847f <+68>:    call   0x80482f0 <printf@plt>
   0x08048484 <+73>:    leave  
   0x08048485 <+74>:    ret    
End of assembler dump.


(gdb) disassemble function 
Dump of assembler code for function function:
   0x0804841d <+0>: push   %ebp
   0x0804841e <+1>: mov    %esp,%ebp
   0x08048420 <+3>: sub    $0x20,%esp
=> 0x08048423 <+6>: lea    -0x9(%ebp),%eax
   0x08048426 <+9>: add    $0xc,%eax
   0x08048429 <+12>:    mov    %eax,-0x4(%ebp)
   0x0804842c <+15>:    mov    -0x4(%ebp),%eax
   0x0804842f <+18>:    mov    (%eax),%eax
   0x08048431 <+20>:    lea    0x8(%eax),%edx
   0x08048434 <+23>:    mov    -0x4(%ebp),%eax
   0x08048437 <+26>:    mov    %edx,(%eax)
   0x08048439 <+28>:    leave  
   0x0804843a <+29>:    ret    
End of assembler dump.

在功能的第9行,* ret指向一个完全不同的地址

9     (*ret) += 8;
(gdb) p/x *ret
$1 = 0x48468c7 (already with the + 8)

所以要澄清一下,这个程序是打印0,因为返回被改为跳过x = 1指令。

我的问题是,为什么不能指向一个与主要相应地址有点接近的地址?

对不起我的英语。

祝你好运, Vcoder

1 个答案:

答案 0 :(得分:1)

您的教程是关于一些非常古老的编译器。

让我们处理实验(比如gcc 4.8.1,64位Win32),结果相同:

步骤1.确定功能真正开始的位置:

(gdb) disassemble function
Dump of assembler code for function function:
=> 0x00000000004014f0 <+0>:     push   %rbp

步骤2.存储其地址并在此处中断

(gdb) b *0x00000000004014f0
Breakpoint 1 at 0x4014f0: file test3.c, line 1.
(gdb) r
Breakpoint 1, function (a=1, b=4200201, c=4) at test3.c:1
1       void function(int a, int b, int c) {

第3步。好的,我们来了。让我们探讨存储返回地址的位置:

(gdb) p $rsp
$1 = (void *) 0x22fe18
(gdb) x 0x22fe18
0x22fe18:       0x0040154c

哇。让我们检查一下main:

0x0000000000401547 <+36>:    callq  0x4014f0 <function>
0x000000000040154c <+41>:    movl   $0x1,-0x4(%rbp)

步骤4.看起来我们找到了它。存储$ rsp = 0x22fe18的某处值,现在让我们看看什么是缓冲区启动:

7          (*ret) += 8;
(gdb) p &buffer1[0] 
$2 = 0x22fe00 "`\035L"

所以缓冲区[0]地址是0x22fe18 - 0x22fe00 = 0x18来自我们的目标。不是0xc,如你的例子,呃 - 哦。

P.S。在您的编译器和操作系统以及优化选项上,它可能不是0x18,而是其他值。尝试。实验。黑客是关于试验的,而不是关于运行某些人的脚本。

祝你好运。