3

我之前的堆栈帧中有一个返回值,它指向我后续堆栈帧中的缓冲区。如何获取放置在缓冲区中的机器指令来执行?

这甚至可能吗?根据我对堆栈的了解,这是荒谬的。因为,当然,堆栈是后进先出结构。换句话说,一旦 PC 到达返回地址,缓冲区就已经被弹出。

有任何想法吗?

函数(下<test>)调用<getbuf>函数(也在下):

08048c53 <test>:
 8048c53:   55                      push   %ebp
 8048c54:   89 e5                   mov    %esp,%ebp
 8048c56:   83 ec 28                sub    $0x28,%esp
 8048c59:   e8 63 04 00 00          call   80490c1 <uniqueval>
 8048c5e:   89 45 f0                mov    %eax,-0x10(%ebp)
 8048c61:   e8 5f 00 00 00          call   8048cc5 <getbuf>
 8048c66:   89 45 f4                mov    %eax,-0xc(%ebp)
 8048c69:   e8 53 04 00 00          call   80490c1 <uniqueval>
 8048c6e:   8b 55 f0                mov    -0x10(%ebp),%edx
 8048c71:   39 d0                   cmp    %edx,%eax
 8048c73:   74 0e                   je     8048c83 <test+0x30>
 8048c75:   c7 04 24 f0 a3 04 08    movl   $0x804a3f0,(%esp)
 8048c7c:   e8 9f fc ff ff          call   8048920 <puts@plt>
 8048c81:   eb 40                   jmp    8048cc3 <test+0x70>
 8048c83:   8b 55 f4                mov    -0xc(%ebp),%edx
 8048c86:   a1 20 e1 04 08          mov    0x804e120,%eax
 8048c8b:   39 c2                   cmp    %eax,%edx
 8048c8d:   75 21                   jne    8048cb0 <test+0x5d>
 8048c8f:   8b 45 f4                mov    -0xc(%ebp),%eax
 8048c92:   89 44 24 04             mov    %eax,0x4(%esp)
 8048c96:   c7 04 24 19 a4 04 08    movl   $0x804a419,(%esp)
 8048c9d:   e8 ae fb ff ff          call   8048850 <printf@plt>
 8048ca2:   c7 04 24 03 00 00 00    movl   $0x3,(%esp)
 8048ca9:   e8 a0 07 00 00          call   804944e <validate>
 8048cae:   eb 13                   jmp    8048cc3 <test+0x70>
 8048cb0:   8b 45 f4                mov    -0xc(%ebp),%eax
 8048cb3:   89 44 24 04             mov    %eax,0x4(%esp)
 8048cb7:   c7 04 24 36 a4 04 08    movl   $0x804a436,(%esp)
 8048cbe:   e8 8d fb ff ff          call   8048850 <printf@plt>
 8048cc3:   c9                      leave
 8048cc4:   c3                      ret

08048cc5 <getbuf>:
 8048cc5:   55                      push   %ebp
 8048cc6:   89 e5                   mov    %esp,%ebp
 8048cc8:   83 ec 38                sub    $0x38,%esp
 8048ccb:   8d 45 d8                lea    -0x28(%ebp),%eax
 8048cce:   89 04 24                mov    %eax,(%esp)
 8048cd1:   e8 32 01 00 00          call   8048e08 <Gets>
 8048cd6:   b8 01 00 00 00          mov    $0x1,%eax
 8048cdb:   c9                      leave
 8048cdc:   c3                      ret
4

2 回答 2

3

这甚至可能吗?

如果数据执行保护正在运行,则不会。

缓冲区已经被弹出

POP/RET不会改变堆栈上的任何数据。它只会更改堆栈指针SP,而数据会保持在原来的位置,直到被 a PUSHor替换CALL

这就是为什么虫子喜欢

int* foo() {
  int i = 123;
  return &i;
}

在错误显示之前似乎可以工作一段时间。在堆栈上的位置实际被覆盖之前,数据仍然存在不确定的时间。

于 2015-10-20T13:24:20.143 回答
1

是的,它是可能的预数据执行保护。

一段代码会在缓冲区中填充超出预期的内容,这会漂移到堆栈上。此时,您有两种可用的机制。

1)维基百科:返回到libc

2)维基百科:堆栈缓冲区溢出

返回到 libc

在这里,您使用一组函数调用覆盖堆栈(通常在程序中预先存在)。这允许您构建进一步的代码,并执行您所追求的。

堆栈缓冲区溢出

这个覆盖修改了保存的帧指针,或者堆栈上的返回地址。这些将更改为堆栈上函数的预期位置。这有点偶然,因此通常会添加一个缓冲区(nop-slide)以提高可靠性。

wikipedia :地址空间布局随机化使得从程序外部更难做到这一点,因为您无法预测重要功能和数据的位置。

数据执行和地址空间布局随机化有助于缓解这些问题,因为它们通常是不需要的。我强烈建议避免这种形式的动态编程,因为它很容易被一些恶意实体利用。

于 2015-10-20T13:39:52.160 回答