栈溢出简介
栈的概念
🖥栈
是汇编语言中的一种数据结构,遵循LIFO(Last in Fist Out)原则,即后进先出
。
🚍栈的主要操作:压栈(Push)
、出栈(Pop)
。
📌注意:栈从高地址向低地址
存储。
栈溢出原理
🎈栈溢出是缓冲区溢出的一种。
🈳栈溢出指向某个变量写入的数据超过其申请的内存空间大小
,从而覆盖相邻栈
的数据。
🔐我们可以通过这种覆盖相邻栈操作去覆盖函数返回地址
从而劫持程序到我们想执行的地方。
函数调用原理图
📚想要学会Pwn和最简单的栈溢出,必须熟练掌握函数调用
在汇编中的实现过程。
🔗我们目前使用的C语言编写的漏洞程序一般使用栈传递参数
。
即调用函数前先将参数从右到左的顺序压入栈中。
具体存储结构图如下:
🔔High Address(高地址):栈底,最先入栈,最后出栈。
🔔Low Address(低地址):栈顶,最后入栈,最先出栈。
1.栈底是调用者保存的寄存器数据
。调用函数前,我们需要将原来存放在EAX、ECX、EDX等寄存器中的值保存起来,以便被调用函数使用寄存器的同时不会造成原来的数据丢失,被调函数返回后只需从栈中取回数据即可。2.紧接着是参数
,我们按从右到左
的顺序将参数压入栈中,方便被调函数访问。3.再往后是返回地址
。执行call调用函数时,ip会指向call的下一条指令
,然后执行call指令。接着,会将被调函数的下一条指令偏移地址(即ip中的值)压入栈中,以便被调函数结束后继续执行原来程序中的下一条指令。4.下一个是EBP
的值。5.最后是被调函数创建的局部变量
。📌EBP:EBP寄存器是函数调用中很重要的一个寄存器。它保存了栈的基址
。这个基址一般位于函数的开头部分。我们想要访问栈中的数据,必须有一个可以当作参考地址的对象,然后基于它用偏移地址访问我们需要的空间。
例如,大多数被调函数的开头:
push ebp
mov ebp,esp
sub esp,N
🔴首先将EBP寄存器里的值压入栈中
保存,这个ebp即主函数中栈的基址(用于在主函数中作为参考地址访问别的内存空间)。
🔵然后把esp(当前栈顶的偏移地址)传递给ebp
,此时ebp中的数据变成了当前函数的栈的基址。
🔴最后的用于为局部变量申请空间
(一般情况下,大多数编译器把C语言局部变量也保存在栈中)。
❓为什么需要EBP?
🔵我们访问栈中的数据明明可以用SS:SP
进行访问,为什么还需要