26

我正在尝试从Smashing the Stack for Fun and Profit in C 中举一个例子,但我有点卡住了,下面是代码(我有一个 64 位机器和 Ubuntu 64 位):

int main()
{
    int x;

    x = 0;
    func(1,2,3);
    x = 1;
    printf("x is : %d\n", x);
}

void func(int a, int b, int c)
{
    char buffer[1];
    int *ret;

    ret = buffer + 17;
    (*ret) += 7;
}

上面的代码工作正常,返回x=1行时没有执行,但我无法理解背后的逻辑ret = buffer + 17;,不应该是ret = buffer + 16;8 字节用于缓冲区,8 字节用于堆栈上保存的基指针。

其次,我的理解是char buffer[1]占用 8 个字节(由于 64 位拱),如果我增加这个缓冲区说buffer[2],同样的代码应该可以正常工作,但是这没有发生,它开始给出 seg 错误。

问候,努曼

4

5 回答 5

13

无论是 8 位 micro、16 位 micro、32 位 PC 还是 64 位新 PC,我使用的每个架构上的“char”都是 8 位宽。另一方面,Int 往往是字长。

将局部变量放入堆栈的顺序可以是特定于实现的。我的猜测是您的编译器将“int *ret”放在“char buffer 1 ”之前的堆栈中。因此,要获得返回地址,我们必须经过“char buffer 1 ”(1 个字节)、“int *ret”(8 个字节)和保存的基指针(8 个字节),总共 17 个字节。

以下是 x86 64 位堆栈帧的描述:http: //ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/projects /x86-64

于 2009-01-29T08:36:54.960 回答
9

逐步完成 gdb 中的反汇编(disassemble、stepi、nexti)并查看每一步的寄存器(信息寄存器)。

在这里,您可以如何逐步进行反汇编:

gdb ./myprogram
break main
run
display/4i $eip
stepi
stepi
...
info registers
...

您还应该知道(您可能已经知道了,因为您已经完成了部分工作)在许多发行版中,堆栈保护器在 gcc 中默认启用。您可以使用 手动禁用它-fno-stack-protector

于 2009-01-29T08:25:25.123 回答
3

有很多这种堆栈粉碎的东西,你最好的朋友是gdb。由于您已经在进行分段错误,因此您已经在编写您不应该的内存(一个好兆头)。一个更有效的方法是将返回地址更改为其他有效地址(例如,更改为func's 地址或您拥有的某些 shellcode)。我推荐的一个很好的资源是Shellcoder's Handbook,但是由于您使用的是 64 位架构,因此很多示例需要一些工作才能开始。

于 2009-01-29T08:22:34.737 回答
0

Aside from (or better yet, in addition to) running a debugger, you can also use the printf "%p" construct to print the addresses of your variables, e.g.:

printf("buf: %p\n", buffer); //&buffer[0] works too; &buffer works for an array
printf("ret: %p\n", &ret):
printf("a:   %p\n", &a);

Printing the addresses of various things can give great insight into how your compiler/implementation is arranging things in the background. And you can do it directly from C code, too!

于 2009-01-29T11:48:42.743 回答
0

如果您对 x64 缓冲区溢出利用感兴趣,请考虑查看Stealth 的借用代码块技术。

于 2010-02-04T02:17:12.453 回答