栈
栈是计算机中一种先进后出的数据结构,先进入的数据进入(push)栈底,最后的数据在栈顶。当需要读取数据的时候从栈顶开始弹出(pop)数据。
进栈 Push
退栈 Pop
栈帧开辟详情
根据c语言常用调用协议 _cdecl协议。
函数从右向左传参。
32位程序用栈传参
64位是优先寄存器传参//6个以内RDI/RSI/RDX/RCX/R8/R9,六个使用完使用栈传参
#include<stdio.h>
void func(int n,int m)
{
int c=0;
printf("%d%d",n,m);
}
int main()
{
int a,b;
a=2;
b=1;
func(a,b);
printf("hello world!");
return 0;
}
例如这个func()函数,有两个参数a和b。
则先push b,再push a。
传完参数,然后调用函数。在汇编语言中的指令是:call func
call func内部
1.先push ret(call func的下一条指令,知道怎么回来)
2.jmp函数执行
函数执行内部:
push rbp //保存栈[上一个栈帧的rbp],好恢复
mov rbp,rsp//抬高栈底
sub rsp,xxh//抬高栈顶给局部变量预留栈空间
执行完函数,要进行退栈,最后两行汇编代码
leave
ret
leave= mov esp,ebp pop ebp
ret =pop eip
栈的结构
栈溢出
栈溢出原理:程序向栈中某个变量中写入的字节数超过了这个变量所申请的字节数,导致与其相邻的栈中的变量的值被改变。
1.程序必须向栈上写入数据
2.写入的数据的大小没有被良好的控制
看下buuctf的warmup_csaw_2016
checksec 文件发现什么也没开
拖进ida分析看看,按tab/f5看反汇编代码。
发现有个漏洞函数gets()
看左边的函数表,几个没具体名字的函数点进去发现有个后门函数
确定思路,利用gets()函数覆盖返回地址为getshell的地址。
getshell的地址可以在函数表滑向右侧时的start列看见。
则payload=(0x40+0x8)*‘a’+p64(0x40060D)
payload=覆盖v5+覆盖rbp+目的地址
成功获取flag
假设题目没有给我们getshell()这种后门地址。
在程序可写可执行的时候–NX没开
可以在变量中写入shellcode,让rip指向变量的位置[ret的位置写入已经写入shellcode的变量的地址]。
详情看后文
rbp—64位程序
ebp—32位程序
p32()打包成32位
p64()打包成64位