如何知道堆栈c/c ++上的返回地址的位置

Dr *_*Deo 5 c c++ x86 winapi stack

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

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");
}  
Run Code Online (Sandbox Code Playgroud)

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

地址foo = 00401000

我的堆栈看起来像:
00000000
00000000
7FFDF000
0012FF80
0040108A < - 我们要覆盖foo的返回地址.
00410EDE

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

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

  • 除了函数返回地址,我在堆栈中看到的其他值是什么?也就是为什么它不是用零填充

谢谢.

Ale*_*ski 4

上面的是前一个 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
Run Code Online (Sandbox Code Playgroud)

当调用函数时,例如

call 0x00401000
Run Code Online (Sandbox Code Playgroud)

当前的EIP被压入堆栈(用作返回地址),因此序言之后的堆栈如下所示:

[ebp+0xc]  ; contains parameter 1, etc
[ebp+0x8]  ; contains parameter 0
[ebp+0x4]  ; contains return address
[ebp]      ; contains prev-EBP
Run Code Online (Sandbox Code Playgroud)

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

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

关于 Q2)堆栈向下增长。因此push eax,当您从 中减去 4 时esp,eax 的值将移动到 [esp],相当于代码中的:

push eax
;  <=>
sub esp, 4
mov [esp], eax
Run Code Online (Sandbox Code Playgroud)
  1. 这本书是《编写安全代码》,是吗?