C 我的溢出代码不工作

C 我的溢出代码不工作,c,linux,stack-overflow,C,Linux,Stack Overflow,下面的代码来自著名的文章 我想我必须解释一下我的目标代码。 下面是堆栈模型。字下面的数字是堆栈中变量的字节数。因此,如果我想重写RET来跳过我想要的语句,我计算从buffer1到RET的偏移量是8+4=12。因为体系结构是x86 Linux buffer2 buffer1 BSP RET a b c (12) (8) (4) (4) (4) (4) (4) 我想跳过语句x=1并让printf()在屏幕上输出0 我用以下代码编译代码: gcc stack2

下面的代码来自著名的文章

我想我必须解释一下我的目标代码。 下面是堆栈模型。字下面的数字是堆栈中变量的字节数。因此,如果我想重写RET来跳过我想要的语句,我计算从
buffer1
到RET的偏移量是8+4=12。因为体系结构是x86 Linux

buffer2 buffer1 BSP RET   a    b    c
(12)    (8)     (4) (4)   (4)  (4)  (4)
我想跳过语句
x=1
并让
printf()
在屏幕上输出
0

我用以下代码编译代码:

gcc  stack2.c  -g
并在gdb中运行它:

gdb ./a.out
gdb给我的结果如下:

Program received signal SIGSEGV, Segmentation fault.
main () at stack2.c:17
17  x = 1;
我认为Linux使用某种机制来防止堆栈溢出。也许Linux将RET地址存储在另一个地方,并在函数返回之前比较堆栈中的RET地址

机制的细节是什么?如何重写代码以使程序输出
0

好的,反汇编代码如下。它来自gdb的输出,因为我认为对你来说更容易阅读。任何人都可以告诉我如何粘贴一个长的代码序列?一个接一个的复制粘贴让我太累了

Dump of assembler code for function main:
0x08048402 <+0>:    push   %ebp
0x08048403 <+1>:    mov    %esp,%ebp
0x08048405 <+3>:    sub    $0x10,%esp
0x08048408 <+6>:    movl   $0x0,-0x4(%ebp)
0x0804840f <+13>:   movl   $0x3,0x8(%esp)
0x08048417 <+21>:   movl   $0x2,0x4(%esp)
0x0804841f <+29>:   movl   $0x1,(%esp)
0x08048426 <+36>:   call   0x80483e4 <function>
0x0804842b <+41>:   movl   $0x1,-0x4(%ebp)
0x08048432 <+48>:   mov    $0x8048520,%eax
0x08048437 <+53>:   mov    -0x4(%ebp),%edx
0x0804843a <+56>:   mov    %edx,0x4(%esp)
0x0804843e <+60>:   mov    %eax,(%esp)
0x08048441 <+63>:   call   0x804831c <printf@plt>
0x08048446 <+68>:   mov    $0x0,%eax
0x0804844b <+73>:   leave
0x0804844c <+74>:   ret


Dump of assembler code for function function:
0x080483e4 <+0>:    push   %ebp
0x080483e5 <+1>:    mov    %esp,%ebp
0x080483e7 <+3>:    sub    $0x14,%esp
0x080483ea <+6>:    lea    -0x9(%ebp),%eax
0x080483ed <+9>:    add    $0x3,%eax
0x080483f0 <+12>:   mov    %eax,-0x4(%ebp)
0x080483f3 <+15>:   mov    -0x4(%ebp),%eax
0x080483f6 <+18>:   mov    (%eax),%eax
0x080483f8 <+20>:   lea    0x8(%eax),%edx
0x080483fb <+23>:   mov    -0x4(%ebp),%eax
0x080483fe <+26>:   mov    %edx,(%eax)
0x08048400 <+28>:   leave
0x08048401 <+29>:   ret
主函数的汇编程序代码转储: 0x08048402:推送%ebp 0x08048403:mov%esp,%ebp 0x08048405:子$0x10,%esp 0x08048408:movl$0x0,-0x4(%ebp) 0x0804840f:movl$0x3,0x8(%esp) 0x08048417:movl$0x2,0x4(%esp) 0x0804841f:movl$0x1,(%esp) 0x08048426:调用0x80483e4 0x0804842b:movl$0x1,-0x4(%ebp) 0x08048432:mov$0x8048520,%eax 0x08048437:mov-0x4(%ebp),%edx 0x0804843a:mov%edx,0x4(%esp) 0x0804843e:mov%eax,(%esp) 0x08048441:调用0x804831c 0x08048446:mov$0x0,%eax 0x0804844b:离开 0x0804844c:ret 函数的汇编程序代码转储: 0x080483e4:推送%ebp 0x080483e5:mov%esp,%ebp 0x080483e7:子$0x14,%esp 0x080483ea:lea-0x9(%ebp),%eax 0x080483ed:添加$0x3,%eax 0x080483f0:mov%eax,-0x4(%ebp) 0x080483f3:mov-0x4(%ebp),%eax 0x080483f6:mov(%eax),%eax 0x080483f8:lea 0x8(%eax),%edx 0x080483fb:mov-0x4(%ebp),%eax 0x080483fe:mov%edx,(%eax) 0x08048400:离开 0x08048401:ret
我检查汇编代码,发现我的程序有一些错误,我已经将
(*ret)+=8
重写为
(*ret)+=7
,因为
0x08048432
减去
0x0804842b
是7。

函数
函数
函数
覆盖了堆栈自身之外的一些位置,这种情况下是
main
的堆栈。我不知道它覆盖了什么,但它会导致你看到的分割错误。这可能是操作系统使用的一些保护,但也可能是生成的代码在堆栈上的那个位置出现错误值时出错了


这是一个很好的例子,说明了在分配的内存之外进行写入时可能发生的情况。它可能会直接崩溃,也可能会在完全不同的地方崩溃,或者根本不会崩溃,只是做了一些错误的计算。

试试
ret=buffer1+3


说明:
ret
是一个整数指针;在32位机器上,如果将其增加1,地址将增加4个字节。

因为那篇文章来自1996年,假设是不正确的

请参阅“打破现代堆栈以获得乐趣和利润”

从以上链接:

然而,GNUC编译器(gcc)自1998年以来一直在发展,因此,许多人都想知道为什么他们不能让示例为他们工作,或者如果他们确实让代码工作了,为什么他们必须做出他们所做的更改


检查生成的程序集,可能您的函数已经内联。我保证函数没有内联,因为我已经检查了程序集代码。您假设“x=1”生成8字节的程序集代码,并且堆栈按照您所示的方式布置(可能还有其他内容)。添加程序集列表,答案将变得非常明显。使用
printf(“0x%x\n”,buffer1)
要查看buffer1的实际地址并计算要修改的返回地址的偏移量。@JACK M,我建议您阅读Jon Erickson的“优秀”一书。-1没有任何东西可以阻止您将任何其他函数的堆栈帧覆盖到堆栈的根。在这种情况下,他可能是在堆栈开始之外进行写入(取决于调用
main()
)的代码),分段错误是由进程在其内存之外写入引起的。由于这两个函数属于同一个进程,它们可以在不引发SIGSEGV的情况下涂鸦对方的内存(除非编译器或操作系统做了一些非常奇怪的事情来防止堆栈崩溃)。打印
x
a
buffer1
的地址。这会让你知道错误在哪一边。PS:“不工作”永远不会用作错误消息。请不要再使用这个句子了。:-)好的。我已经厌倦了重写“ret=buffer1+3”并运行程序。在我厌倦了代码之后,我发布了第一条注释。但是它不起作用。使用
buffer1
转储堆栈的内容:
for(int I=0;I
Dump of assembler code for function main:
0x08048402 <+0>:    push   %ebp
0x08048403 <+1>:    mov    %esp,%ebp
0x08048405 <+3>:    sub    $0x10,%esp
0x08048408 <+6>:    movl   $0x0,-0x4(%ebp)
0x0804840f <+13>:   movl   $0x3,0x8(%esp)
0x08048417 <+21>:   movl   $0x2,0x4(%esp)
0x0804841f <+29>:   movl   $0x1,(%esp)
0x08048426 <+36>:   call   0x80483e4 <function>
0x0804842b <+41>:   movl   $0x1,-0x4(%ebp)
0x08048432 <+48>:   mov    $0x8048520,%eax
0x08048437 <+53>:   mov    -0x4(%ebp),%edx
0x0804843a <+56>:   mov    %edx,0x4(%esp)
0x0804843e <+60>:   mov    %eax,(%esp)
0x08048441 <+63>:   call   0x804831c <printf@plt>
0x08048446 <+68>:   mov    $0x0,%eax
0x0804844b <+73>:   leave
0x0804844c <+74>:   ret


Dump of assembler code for function function:
0x080483e4 <+0>:    push   %ebp
0x080483e5 <+1>:    mov    %esp,%ebp
0x080483e7 <+3>:    sub    $0x14,%esp
0x080483ea <+6>:    lea    -0x9(%ebp),%eax
0x080483ed <+9>:    add    $0x3,%eax
0x080483f0 <+12>:   mov    %eax,-0x4(%ebp)
0x080483f3 <+15>:   mov    -0x4(%ebp),%eax
0x080483f6 <+18>:   mov    (%eax),%eax
0x080483f8 <+20>:   lea    0x8(%eax),%edx
0x080483fb <+23>:   mov    -0x4(%ebp),%eax
0x080483fe <+26>:   mov    %edx,(%eax)
0x08048400 <+28>:   leave
0x08048401 <+29>:   ret