https://zhuanlan.zhihu.com/p/25816426#
程序运行时,内存一段连续的区域,用来保存函数运行时的状态信息,包括函数参数和局部变量
调用栈 从高地址向低地址生长 压栈时 地址变小 出栈时 地址变大
esp 栈顶指针 ebp 栈基指针 eip 下一条指令的地址
函数调用时: 参数按照逆序压栈
通用寄存器
一般寄存器(eax、ebx、ecx、edx)
eax 被称为累加寄存器
ebx 被称为基址寄存器
ecx 被称为记数寄存器
edx 被称为数据寄存器
索引寄存器(esi、edi)
esi 指向要处理的数据地址
edi 指向存放处理结果的数据地址
以及堆栈指针寄存器(esp、ebp)
特殊寄存器(被特定的汇编指令使用,不能用来任意存储数据)
段地址寄存器(ss、cs、ds、es、fs、gs)
存储内存分段地址
ss 存储函数调用栈
cs 存储代码段
ds 存储数据段
es、fs、gs 是附加的存储数据段地址
标志位寄存器(EFLAGS)
OF 数值溢出
IF 中断
ZF 运算结果为
CF 运算产生进位
以及指令指针寄存器(eip)
寄存器名称和数值前无符号
指令名称 目标操作数 DST,源操作数 SRC
寄存器名称前加“%”,数值前加“$”:
“指令名称 源操作数 SRC,目标操作数 DST”
MOV:数据传输指令,将 SRC 传至 DST,格式为
MOV DST, SRC;
PUSH:压入堆栈指令,将 SRC 压入栈内,格式为
PUSH SRC;
POP:弹出堆栈指令,将栈顶的数据弹出并存至 DST,格式为
POP DST;
LEA:取地址指令,将 MEM 的地址存至 REG ,格式为
LEA REG, MEM;
ADD/SUB:加/减法指令,将运算结果存至 DST,格式为
ADD/SUB DST, SRC;
AND/OR/XOR:按位与/或/异或,将运算结果存至 DST ,格式为
AND/OR/XOR DST,SRC;
CALL:调用指令,将当前的 eip 压入栈顶,并将 PTR 存入 eip,格式为
CALL PTR;
RET:返回指令,操作为将栈顶数据弹出至 eip,格式为
RET;
攻击的时机:发生函数调用或者结束函数调用
攻击的方式:修改 控制程序执行指令的关键寄存器eip 的值
攻击的目标:让eip载入攻击指令的地址
让溢出数据用攻击指令来覆盖返回地址
攻击指令可以存在于溢出数据中,也可以是内存中的其它位置
返回地址 指向溢出数据中的一段指令(shellcode)
返回地址 指向内存中已经有的函数 (return2libc)
返回地址 执行内存中已经有的一段指令(rop)
修改返回地址,让其指向另外一个函数(hijack GOT)
技术生效的前提:
1. 关闭地址随机化
2. shellcode有权限
在溢出数据内包含一段攻击指令 攻击指令一般是为了打开shell从而获得当前程序的控制权限
payload : padding1 + address of shellcode + padding2 + shellcode
修改返回地址 让其指向内存中已有的某个函数
要完成的任务:在内存中确定要调用的函数地址,覆盖要攻击的函数地址 通常使用lic动态连接库中的系统级的函数获取当前进程的控制权限
payload: padding1 + address of system() + padding2 + address of “/bin/sh”
覆盖返回地址来执行内存内已有的代码片段
payload : padding + address of gadget
payload : padding + address of gadget + address of gadget + ......
+ address of gadget n
payload : padding + address of gadget + param for gadget + address of gadget + param for gadget + ...... + address of gadget n + shellcode
gadget 执行完毕可以将控制权交给下一个 gadget
gadget 的最后一步应该是 RET 指令
将某个函数的地址替换成另一个函数的地址
对外部函数的调用需要在生成可执行文件时将外部函数链接到程序
静态链接
可执行文件包含外部函数的全部代码
动态链接
可执行文件并不包含外部函数的代码
运行时将动态链接库(若干外部函数的集合)加载到内存的某个位置
发生调用时去链接库定位所需的函数
GOT 全称是全局偏移量表(Global Offset Table)
存储外部函数在内存的确切地址
GOT 存储在数据段(Data Segment)内
可以在程序运行中被修改
PLT 全称是程序链接表
存储外部函数的入口点(entry)
PLT 存储在代码段(Code Segment)内
运行之前就已经确定并且不会被修改
当程序需要调用某个外部函数时,首先到 PLT 表内寻找对应的入口点,跳转到 GOT 表中
确定函数 A 在 GOT 表中的条目位置
函数调用的汇编指令中找到 PLT 表中该函数的入口点位置,从而定位到该函数在 GOT 中的条目
如何确定函数 B 在内存中的地址
假如我们知道了函数 A 的运行时地址(读取 GOT 表内容),也知道函数 A 和函数 B 在动态链接库内的相对位置,就可以推算出函数 B 的运行时地址