pfl*_*flz 2 linux stack-overflow stack gcc
我一直在阅读"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);
}
Run Code Online (Sandbox Code Playgroud)
给出输出
$ cc smash.c
smash.c: In function ‘function’:
smash.c:7:8: warning: assignment from incompatible pointer type
$ ./a.out
1
Run Code Online (Sandbox Code Playgroud)
用的线*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
...
...
Run Code Online (Sandbox Code Playgroud)
如果我更换 ret = buffer1 + 6用 ret = buffer1 + 7,结果同上.如果我ret = buffer1 +用ret=buffer1+8(或任何更大的值)替换 6 ,那么上面描述的情况(即,我是将值*ret 增加8还是将其更改为8)都会有碎片堆栈 .
请告诉我这是怎么回事.有用的链接也将不胜感激.最重要的是,如何禁用Linux内核的这种安全功能,以便我可以使用本书?
平台:i386内核:2.6.38
Wil*_*hin 11
要禁用堆栈粉碎检测,请在编译时使用-fno-stack-protector.在处理"Shellcoders Handbook"时,您可能还希望使用-ggdb和-mpreferred-stack-boundary = 4来启用GDB符号并标准化堆栈.
编辑:当我编译你提供的代码(gcc -fno-stack-protector -ggdb -mpreferred-stack-boundary=4 -o sc in.c)时,编译器重新排列了局部变量的顺序function.我通过使用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.
Run Code Online (Sandbox Code Playgroud)
0x080483ca告诉我那ebp - 0xC是buffer1,而0x080483d0告诉我ebp - 0x4是ret.因此,堆栈中不存在变量,因为它们存在于我们的C代码中.鉴于这ret是我们最顶级的局部变量,我们可以直接使用它.但是,让我们使用您的代码.
要修改返回指针,我们需要更改存储在保存的ebp下面的地址,这样ebp + 0x4.因此,要从我们的变量buffer1获取返回指针,我们必须添加0xC(以获取ebp),然后添加0x4(返回指针为0x4 ebp).现在我们可以进行修改.
我从您的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.
Run Code Online (Sandbox Code Playgroud)
在不修改返回指针的情况下,对function0x0804840a 的调用返回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);
}
Run Code Online (Sandbox Code Playgroud)