堆栈粉碎尝试产生段错误

发布于 2024-07-13 01:59:25 字数 723 浏览 11 评论 0原文

我正在尝试用 C 语言做一个 Smashing the Stack for Fun and Profit 的示例,但是我有点卡在某个点上 以下是代码(我有一台运行 Ubuntu 64 位的 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],仍然相同的代码应该可以正常工作,但是这并没有发生,并且它开始给出段错误。

问候, 努曼

I am trying to do an example from the Smashing the Stack for Fun and Profit in C, but am kind of stuck at a point,
following is the code (I have a 64-bit machine with Ubuntu 64-bit):

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;
}

The above code works fine and on returning the x=1 line is not executed, but I can't understand the logic behind ret = buffer + 17;, shouldn't it be ret = buffer + 16; i.e, 8bytes for buffer and 8 for the saved base pointer on stack.

Secondly, my understanding is that char buffer[1] is taking 8 bytes (owing to 64-bit arch)
and if I increase this buffer to say buffer[2], still the same code should work fine, BUT this is not happening and it starts giving seg fault.

Regards,
Numan

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

尐偏执 2024-07-20 01:59:25

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

将本地变量放入堆栈的顺序可以是特定于实现的。 我的猜测是,您的编译器将“int *ret”放在“char buffer1"。 因此,要到达返回地址,我们必须经过“char buffer1" (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

'char' on every architecture I've used is 8 bits wide irrespective of whether it's an 8 bit micro, a 16 bit micro, a 32 bit PC, or a 64 bit new PC. Int, on the other hand, tends to be the word size.

The order which the locals are put on the stack can be implementation specific. My guess is that your compiler is putting "int *ret" on the stack before "char buffer1". So, to get to the return address, we have to go through "char buffer1" (1 byte), "int *ret" (8 bytes), and the saved base pointer (8 bytes) for a total of 17 bytes.

Here's a description of the stack frame on x86 64-bit:
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/projects/x86-64

め七分饶幸 2024-07-20 01:59:25

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

下面是如何逐步进行反汇编:

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

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

Step through the disassembly in gdb (disassemble, stepi, nexti) and look at the registers at each step (info registers).

Here how you can step through disassembly:

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

You should also know (you probably already do given that you got part of it working) that on many distros, the stack protector is enabled by default in gcc. You can manually disable it with -fno-stack-protector.

裂开嘴轻声笑有多痛 2024-07-20 01:59:25

对于很多堆栈粉碎的东西,你最好的朋友是 gdb。 由于您已经出现了段错误,因此您已经在写入内存,而您不应该这样做(一个好兆头)。 更有效的方法是将返回地址更改为其他有效地址(例如,func 的地址或您拥有的某些 shellcode)。 我推荐的一个很好的资源是 Shellcoder 手册,但既然你在 64 位架构上,许多示例需要做一些工作才能开始。

With a lot of this stack smashing stuff, your best friend is gdb. Since you're segfaulting already you're already writing memory you're not supposed to be (a good sign). A more effective way to do it right is to change the return address to somewhere else that's a valid address (e.g. to func's address or to some shellcode you've got). A great resource I'd recommend is the Shellcoder's Handbook, but since you're on a 64-bit architecture a lot of the examples need a bit of work to get going.

安人多梦 2024-07-20 01:59:25

除了(或者更好的是,除了)运行调试器之外,您还可以使用 printf "%p" 构造来打印变量的地址,例如:

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

打印各种事物的地址可以让您深入了解编译器如何/implementation 正在后台安排事情。 您也可以直接从 C 代码完成!

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!

懵少女 2024-07-20 01:59:25

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

Consider taking a look at stealth's borrowed code chunk technique, if you're interested in x64 buffer overflow exploitation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文