【问题标题】:how to know location of return address on stack c/c++如何知道堆栈c / c ++上的返回地址的位置
【发布时间】:2011-02-09 14:42:23
【问题描述】:

我一直在阅读一个可以覆盖其返回地址的函数。

void foo(const char* input)
{
    char buf[10];

    //What? No extra arguments supplied to printf?
    //It's a cheap trick to view the stack 8-)
    //We'll see this trick again when we look at format strings.
    printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); //%p ie expect pointers

    //Pass the user input straight to secure code public enemy #1.
    strcpy(buf, input);
    printf("%s\n", buf);

    printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
}  

有人建议这就是堆栈的样子

foo的地址=00401000

我的堆栈如下所示:
00000000
00000000
7FFDF000
0012FF80
0040108A
00410EDE

问题:
-。为什么作者随意选择倒数第二个值作为 foo() 的返回地址?

-。值是从底部还是从顶部添加到堆栈中?

  • 除了函数返回地址,我显然在堆栈上看到的其他值是什么?即为什么不填零

谢谢。

【问题讨论】:

  • 这取决于您使用的 CPU(系列),也取决于 ABI。您可能应该适当地标记您的问题,以便清楚您在这里谈论的是什么(我猜是 Linux 或 Windows 上的 x86 ?)。
  • 这也取决于编译器。较新版本的 Visual Studio 和 GCC 对堆栈重新排序以使此类攻击更加困难。如果buf 位于返回地址之后,则需要一个缓冲区underflow 来覆盖返回地址。而且下溢的情况要少得多。

标签: c++ c winapi x86 stack


【解决方案1】:

它上面的那个是之前的 EBP (0012FF80)。 prev-EBP 上面的值始终是返回地址。

(这显然假设非 FPO 二进制和 32 位 Windows)1.

如果你还记得,序幕是这样的:

push ebp      ; back up the previous ebp on the stack
mov ebp, esp  ; set up the new frame pointer

当一个函数被调用时,例如

call 0x00401000

当前EIP被压入栈中(作为返回地址),所以序言后面的栈是这样的:

[ebp+0xc]  ; contains parameter 1, etc
[ebp+0x8]  ; contains parameter 0
[ebp+0x4]  ; contains return address
[ebp]      ; contains prev-EBP

所以对于每个%p,printf 使用从[ebp+0xc] 开始的接下来的4 个字节(第一个%p 参数)。最终,您点击了存储在堆栈中的上一个 EBP 值,即 (0012FF80),然后下一个是返回地址。

请注意,这些地址必须“有意义”,他们在这里清楚地做到了(尽管可能并非所有人都“清楚”)。

关于 Q2) 堆栈向下增长。所以当你push eax时,esp减去4,然后eax的值就移动到[esp],相当于代码中:

push eax
;  <=>
sub esp, 4
mov [esp], eax

  1. 这本书是编写安全代码,是吗?

【讨论】:

    猜你喜欢
    • 2020-09-23
    • 2010-12-14
    • 2015-01-28
    • 1970-01-01
    • 2021-05-20
    • 2012-06-26
    • 1970-01-01
    • 2014-04-21
    • 2011-04-01
    相关资源
    最近更新 更多