C 我的溢出代码不工作
下面的代码来自著名的文章 我想我必须解释一下我的目标代码。 下面是堆栈模型。字下面的数字是堆栈中变量的字节数。因此,如果我想重写RET来跳过我想要的语句,我计算从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
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