我写了一个小C代码,在GDB中打开它,在exploit = (long long *)&exploit+2;
行放置一个断点并运行程序。
#include<stdio.h>
char Shellcode[] = "\x48\xc7\xc0\x01\x00\x00\x00"
"\x48\xc7\xc3\x1a\x00\x00\x00"
"\xcd\x80";
int main()
{
long long *exploit;
exploit = (long long *)&exploit+2;
*exploit = (long long)Shellcode;
return 0;
}
由于断点在行exploit = (long long *)&exploit+2;
上设置,GDB在执行该行之前停止执行程序,这意味着只有行long long *exploit;
存在exploit
已被执行。
此时我期待exploit
驻留在堆栈顶部,因为它是唯一的局部变量,并且在调用函数后局部变量保持在堆栈顶部(如果我错了,请纠正我)。事实证明并非如此。
(gdb) print /x &exploit
$2 = 0x7fffffffdfe8
(gdb) x/6xg $rsp
0x7fffffffdff0: 0x0000555555554690 0x00007ffff7a5a2b1
0x7fffffffe000: 0x0000000000040000 0x00007fffffffe0d8
0x7fffffffe010: 0x00000001f7b9b288 0x0000555555554660
正如我们所看到的那样,元素的顶部是0x7fffffffdff0
,而漏洞利用的地址是0x7fffffffdfe8
上的堆栈指针(在上面?它怎么可能?)之上的8个字节。有人可以向我解释一下吗?
修改
反汇编主函数给出:
0x555555554660 <main> push %rbp │
│0x555555554661 <main+1> mov %rsp,%rbp │
B+>│0x555555554664 <main+4> lea -0x8(%rbp),%rax │
│0x555555554668 <main+8> add $0x10,%rax │
│0x55555555466c <main+12> mov %rax,-0x8(%rbp) │
│0x555555554670 <main+16> mov -0x8(%rbp),%rax │
│0x555555554674 <main+20> lea 0x2009b5(%rip),%rdx # 0x555555755030 <Shellcode> │
│0x55555555467b <main+27> mov %rdx,(%rax) │
│0x55555555467e <main+30> mov $0x0,%eax │
│0x555555554683 <main+35> pop %rbp │
│0x555555554684 <main+36> retq
编辑-2:此代码的作用是什么?
如果变量exploit
位于堆栈顶部(正如我预测的那样),则exploit
下面的下一个8字节将是RBP,后跟__libc_start_main中指令的返回地址( )function(为执行程序设置环境的函数,调用main(),然后在执行后清理乱码)。
exploit = (long long *)&exploit+2;
会转移并使漏洞指向我提到的返回地址,*exploit = (long long)Shellcode;
将覆盖地址为Shellcode
的返回地址。由于Shellcode
是预检指令的操作码并且可由处理器读取,因此一旦程序完成执行就会执行它,并尝试使用返回地址返回__libc_start_main(),前提是DEP是关掉了。
答案 0 :(得分:3)
SYS V ABI引入了许多优化,包括(Jester pointed out)Red zone - 1 下方128字节区域的堆栈指针被任何异步处理程序触及。
在叶函数的情况下,编译器可以使用Red区域来存储局部变量而不移动rsp
。
1 请注意,您似乎使用反义词来表示&#34;以上&#34;和&#34;以下&#34;堆栈指针。