linux - 堆栈粉碎代码在 Linux 内核 2.6.38.7 上不起作用...请帮忙

标签 linux gcc stack stack-overflow

我一直在阅读“The Shellcoders Handbook”并引用了 this堆栈溢出练习链接。但似乎 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

最佳答案

要禁用堆栈粉碎检测,请使用 -fno-stack-protector编译时。在阅读“The Shellcoders Handbook”时,您可能还想使用 -ggdb 和 -mpreferred-stack-boundary=4 以启用 GDB 符号并标准化堆栈。

编辑: 当我编译您提供的代码时(gcc -fno-stack-protector -ggdb -mpreferred-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.

0x080483ca 告诉我 ebp - 0xC 是 buffer1,0x080483d0 告诉我 ebp - 0x4 是 ret。因此,变量不存在于堆栈中,因为它们存在于我们的 C 代码中。鉴于 ret 是我们最顶层的局部变量,我们可以直接使用它。不过,让我们使用您的代码。

要修改返回指针,我们需要更改存储在保存的 ebp 正下方的地址,因此 ebp + 0x4。因此,要从变量 buffer1 获取返回指针,我们必须添加 0xC(获取 ebp),然后添加 0x4(返回指针在 ebp 下为 0x4 ).现在我们可以进行修改了。

我从您的 C 代码中得知您想跳过 x = 1 的赋值并直接返回到 printf。我反汇编了 main 以找到对返回指针的适当修改:

(gdb) disassemble main
Dump of assembler code for function main:
   0x080483e2 <+0>: push   ebp
   0x080483e3 <+1>: mov    ebp,esp
   0x080483e5 <+3>: and    esp,0xfffffff0
   0x080483e8 <+6>: sub    esp,0x20
   0x080483eb <+9>: mov    DWORD PTR [esp+0x1c],0x0
   0x080483f3 <+17>:    mov    DWORD PTR [esp+0x8],0x3
   0x080483fb <+25>:    mov    DWORD PTR [esp+0x4],0x2
   0x08048403 <+33>:    mov    DWORD PTR [esp],0x1
   0x0804840a <+40>:    call   0x80483c4 <function>
   0x0804840f <+45>:    mov    DWORD PTR [esp+0x1c],0x1
   0x08048417 <+53>:    mov    eax,DWORD PTR [esp+0x1c]
   0x0804841b <+57>:    mov    DWORD PTR [esp+0x4],eax
   0x0804841f <+61>:    mov    DWORD PTR [esp],0x80484f0
   0x08048426 <+68>:    call   0x80482f4 <printf@plt>
   0x0804842b <+73>:    leave  
   0x0804842c <+74>:    ret    
End of assembler dump.

在不修改返回指针的情况下,对 0x0804840a 处的函数 的调用返回到 0x0804840f。但是我们想跳过这个并返回到下一条指令。下一条指令从 0x08048417 开始,也就是 0x8 字节。所以我们对返回指针的修改必须将其值增加0x8。

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

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

关于linux - 堆栈粉碎代码在 Linux 内核 2.6.38.7 上不起作用...请帮忙,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7133176/

相关文章:

linux - 重新链接匿名(未链接但打开)文件

linux - 删除损坏的链接 Unix

linux - g++ 错误 : expected ; before "it"

java - 条件条款未按预期发挥作用

data-structures - 堆栈的动态数组实现的复杂性

c - 检查文件或文件夹是否存在阻塞或非阻塞?

linux - 使用具有模式映射的外部文件替换模式后的行

c - 字符串初始化的 gcc 诊断不一致

c - 嵌套循环、内循环并行化、重用线程

c++ - 如何查找lua堆栈中有多少项(值)