堆栈崩溃代码无法在Linux内核2.6.38.7上运行。。。请帮忙

堆栈崩溃代码无法在Linux内核2.6.38.7上运行。。。请帮忙,linux,gcc,stack,stack-overflow,Linux,Gcc,Stack,Stack Overflow,我一直在阅读“Shellcoders手册”,并参考了有关堆栈溢出实践的链接。但是Linux内核开发人员似乎使内核非常安全。这是我的问题 1) 此代码 void function(int a, int b, int c) { char buffer1[8]; char buffer2[10]; int* ret; ret = buffer1 + 6; *ret+=8; } void main() { int x; x = 0; function(1,

我一直在阅读“Shellcoders手册”,并参考了有关堆栈溢出实践的链接。但是Linux内核开发人员似乎使内核非常安全。这是我的问题

1) 此代码

void function(int a, int b, int c) {
   char buffer1[8];
   char buffer2[10];
   int* ret;

   ret = buffer1 + 6;
   *ret+=8;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}
给出输出

$ cc smash.c
smash.c: In function ‘function’:
smash.c:7:8: warning: assignment from incompatible pointer type
$ ./a.out
1
但是将行
*ret+=8
替换为
*ret=8
会产生以下输出

*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x50)[0xa86df0]
/lib/i386-linux-gnu/libc.so.6(+0xe5d9a)[0xa86d9a]
./a.out[0x8048448]
./a.out[0x8048477]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x9b7e37]
./a.out[0x8048381]
======= Memory map: ========
003df000-003e0000 r-xp 00000000 00:00 0          [vdso]
009a1000-00afb000 r-xp 00000000 08:01 3277633    /lib/i386-linux-gnu/libc-2.13.so
00afb000-00afc000 ---p 0015a000 08:01 3277633    /lib/i386-linux-gnu/libc-2.13.so
00afc000-00afe000 r--p 0015a000 08:01 3277633    /lib/i386-linux-gnu/libc-2.13.so
...
...
如果我将
ret=buffer1+6
替换为
ret=buffer1+7
,结果与上面相同。 如果我将
ret=buffer1+
6替换为
ret=buffer1+8
(或任何更大的值),则上述两种情况都会出现堆栈崩溃(即,我是将值
*ret
增加8还是将其更改为8)

请告诉我这是怎么发生的。也将感谢有用的链接。 最重要的是,我如何禁用Linux内核的这个安全特性,以便我可以使用这本书

平台:i386
内核:2.6.38

要禁用堆栈破坏检测,请在编译时使用。在阅读“Shellcoders手册”时,您可能还希望使用-ggdb和-mprefered stack boundary=4来启用GDB符号并标准化堆栈

编辑: 当我编译您提供的代码时(
gcc-fno stack protector-ggdb-mprefered stack boundary=4-o sc in.c
),编译器重新排列了
函数中局部变量的顺序。我通过使用GDB发现了这一点:

willi@ubuntu:~/testing$ gdb sc
(gdb) set disassembly-flavor intel
(gdb) disassemble function
Dump of assembler code for function function:
   0x080483c4 <+0>: push   ebp
   0x080483c5 <+1>: mov    ebp,esp
   0x080483c7 <+3>: sub    esp,0x20
   0x080483ca <+6>: lea    eax,[ebp-0xc]
   0x080483cd <+9>: add    eax,0x6
   0x080483d0 <+12>:    mov    DWORD PTR [ebp-0x4],eax
   0x080483d3 <+15>:    mov    eax,DWORD PTR [ebp-0x4]
   0x080483d6 <+18>:    mov    eax,DWORD PTR [eax]
   0x080483d8 <+20>:    lea    edx,[eax+0x8]
   0x080483db <+23>:    mov    eax,DWORD PTR [ebp-0x4]
   0x080483de <+26>:    mov    DWORD PTR [eax],edx
   0x080483e0 <+28>:    leave  
   0x080483e1 <+29>:    ret    
End of assembler dump.
在不修改返回指针的情况下,对0x0804840a处的
函数的调用将返回0x0804840f。但是我们想跳过这个,返回到下一条指令。下一条指令从0x08048417开始,即进一步的0x8字节。因此,我们对返回指针的修改必须将其值增加0x8

考虑到这些因素,我使用以下代码打印“0”而不是“1”:


可以按如下方式禁用堆栈粉碎保护:

$ gcc -ggdb -m32 -o buffer1 -fno-stack-protector -mpreferred-stack-boundary=4 buffer1.c

提供了有关Linux安全特性的更多信息

回答得不错,但我不明白一件事。为什么要从
函数中获取返回地址`您添加了
0x2
0x2
0xc
(关于
0xc
我理解,但不是
0x2
)?
ebp
存储保存的堆栈指针,返回地址直接存储在该指针下。因此,我们需要将
sizeof(void*)
添加到保存的堆栈指针的地址中,以获取返回地址的地址。我已经更新了帖子,使用
0x4
而不是
0x2
,以反映
sizeof(void*)
(不确定为什么使用
0x2
)。
void function(int a, int b, int c) {
   char buffer1[8];
   char buffer2[10];
   int* ret;

   ret = buffer1 + 0x10;
   *ret+=8;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}
$ gcc -ggdb -m32 -o buffer1 -fno-stack-protector -mpreferred-stack-boundary=4 buffer1.c