堆栈上局部变量的地址
我写了一个小小的C代码,在GDB中打开它,在线exploit = (long long *)&exploit+2;
上放置一个断点exploit = (long long *)&exploit+2;
并运行该程序。
#include<stdio.h>
char Shellcode[] = "x48xc7xc0x01x00x00x00"
"x48xc7xc3x1ax00x00x00"
"xcdx80";
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
而exploit的地址是堆栈指针上方的8个字节(上图?它怎么可能?)在0x7fffffffdfe8
。 有人可以向我解释吗?
编辑:
拆卸主要功能给出:
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()函数中的指令的返回地址(设置执行环境的函数的程序,调用main(),然后清理执行后的混乱)。
exploit = (long long *)&exploit+2;
将转移并使利用指向我提到的返回地址和*exploit = (long long)Shellcode;
会用Shellcode
的地址覆盖返回地址。 由于Shellcode
是预先检查的指令的操作码,并且可以被处理器读取,所以一旦程序完成执行并且尝试使用返回地址返回__libc_start_main(),只要DEP被关闭,它就会被执行。
SYS V ABI引入了一些优化,包括(如Jester指出的)红色区域 - 堆栈指针下面的128字节区域,不受任何异步处理程序触摸。
在叶函数的情况下,编译器可以使用Red区域来存储局部变量而不移动rsp
。
1请注意,您似乎对栈指针的“之上”和“之下”使用了相反的术语。
链接地址: http://www.djcxy.com/p/80367.html