Fig 1. 函数调用发生和结束时调用栈的变化shell
Fig 2. 将被调用函数的参数压入栈内函数
Fig 3. 将被调用函数的返回地址压入栈内布局
Fig 4. 将调用函数的基地址(ebp)压入栈内,并将当前栈顶地址传到 ebp 寄存器内spa
首先咱们来看看如下程序调用栈的过程:code
int sum(int a,int b) { int temp = 0; temp = a+b; return temp; } int main() { int a = 10; int b = 20; int ret = 0; ret = sum(a,b); cout<<ret<<endl; return 0; }
以下调用过程:blog
每一个函数在调用前都会作一件事情。 教程
(1)把调用方的ebp入到本身的栈里去内存
(2)用esp指向新的栈顶位置,把esp的值赋给ebp,产生新的ebp get
(3)开辟空间,初始0XCCCCCCCC。 ebp入栈,实参入栈,形参入栈,调用call指令。call有两步,把下一行指令的地址入栈,跳转到调用的函数执行。形参内存主调方开辟,主调方释放。class
main函数栈帧
开辟sum函数栈帧
sum函数内存布局
栈溢出的shellcode中常常会出现:
payload : padding1 + address of shellcode + padding2 + shellcode
payload: padding1 + address of system() + padding2 + address of “/bin/sh”
这几种payload,不少教程对于padding2这个没有解释的很清楚,ctf wiki上是这样说的 :“若是是正常调用 system 函数,咱们调用的时候会有一个对应的返回地址”