【问题标题】:How to execute machine instructions placed on the stack如何执行放置在堆栈上的机器指令
【发布时间】:2015-10-20 13:19:23
【问题描述】:

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

这甚至可能吗?根据我对堆栈的了解,这是荒谬的。因为,当然,堆栈是后进先出结构。换句话说,一旦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

【问题讨论】:

  • “前一个”和“后一个”堆栈帧是什么意思?你能告诉我们一些你的 C 源代码吗?

标签: c assembly buffer buffer-overflow machine-instruction


【解决方案1】:

这可能吗?

如果Data Execution Prevention 正在运行,则不会。

缓冲区已经被弹出

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

这就是为什么像这样的错误

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

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

【讨论】:

  • 说它没有起作用。缓冲区是否仍会从堆栈中弹出?
  • @KendallWeihe - 没有区别。更改堆栈指针时,旧堆栈帧不会发生任何事情,直到您再次推送或调用。执行数据曾经很容易受到病毒的攻击,因此在现代系统上执行此操作变得越来越难。
【解决方案2】:

是的,在数据​​执行保护之前是可能的。

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

1) wikipedia: return into libc

2) wikipedia: stack buffer overflow

返回libc

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

堆栈缓冲区溢出

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

wikipedia : address space layout randomization 从程序外部使这变得更加困难,因为您无法预测重要的函数和数据在哪里。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 2012-06-30
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多