漏洞挖掘-第二章-栈溢出原理与实践

2.1.1 内存的不同用途
内存大致分为:代码区、数据区、堆区、栈区
代码区:存储二进制机器代码,函数在内存区相互散乱无关
数据区:存储全局变量
堆区:为进程动态分配内存
栈区:动态存储函数之间的调用关系
PE文件被装载运行后,就成了所谓的进程

2.1.2 栈与系统栈
本质:栈是一种数据结构,是一种先进后出的数据表
操作:
PUSH(压栈):在栈顶添加一个元素
POP(弹栈):从栈顶移除一个元素
属性:
TOP(栈顶):标识栈顶位置,动态变化。POP一次,自减1;PUSH一次,自增1
BASE(栈底):标识栈底位置,防止栈空后继续POP
内存的栈区=系统栈,由系统自动维护

漏洞挖掘-第二章-栈溢出原理与实践
2.1.4 寄存器与函数栈帧
每一个函数独占自己的栈帧空间
正在运行的的函数栈帧总是在栈顶
Win32系统提供两个特殊寄存器用于标识系统栈顶端的栈帧
ESP(extended stack pointer,栈指针寄存器),其内存放着一个指向系统栈的最上面一个栈帧的栈顶的指针
EBP(extended base pointer,基址指针寄存器),其内存放着一个指向系统栈最上面一个栈帧的底部的指针
函数栈帧:ESP和EBP之间的内存空间为当前栈帧,EBP标识了当前栈帧的底部,ESP标识了当前栈帧的顶部。一般包含以下三种信息:
局部变量
栈帧状态值
函数返回地址
EIP(指令寄存器,extended instruction pointer),其内存放着一个指向下一条等待执行的指令地址。控制了EIP,就控制了CPU。

2.1.5 函数调用约定与相关指令
函数调用约定描述了函数传递方式和栈协同工作的技术细节

如果要明确使用某一种调用约定,只需要在函数前加上调用约定的声明即可,否则默认情况下,VC会使用_stdcall的
调用方式
参数传递方面的差异:每个C++类成员函数都有一个this指针,在Windows平台中,这个指针一般是用ECX寄存器来传递的,但如果用GCC编译器编译,这个指针会作为最后一个参数压入栈中
函数调用大致包括以下几个步骤
参数入栈:将参数从右至左压入系统栈中
返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行
代码区跳转:处理器从当前代码区跳转到调用函数的入口处
栈帧调整:
保存当前栈帧状态值,以备后面恢复本栈帧时使用(EBP入栈)
将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部)
给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶)

函数返回的步骤如下
保存返回值:通常保存在寄存器EAX中
弹出当前栈帧,恢复上一个栈帧