原理分析
本篇介绍ret2text的一种特殊情况
先前我们学习过的是没有pie的情况下 这时候我们backdoor函数的地址清清楚楚
我们可以直接栈溢出覆盖 控制程序执行流 但是如果开了pie呢?
这样的话后门函数的地址就随机化了 我们通过ida只能得知其与基址的偏移
如上图所示 这样的情况下 我们又该如何得知backdoor函数的真实返回地址呢?
不知道你还记不记得我们曾经讲过虚拟内存分页机制
其导致了基址的后三位一定为000 所以函数的地址后三位保持不变 不会因为pie的开启而变化
所以:
我们假设程序的基址是0xfffffffffffff000
那么函数的偏移是0x0000 其除了后四位 其他位和基址是一样的(不排除进一的情况)
而程序正常结束后的ret 其地址也是基址+偏移得到的
所以,我们在已经直到后三位的情况下 要想得知后门函数的真实地址 只需要爆破倒数第四位 就可以试出来了
真题解析
int __cdecl main(int argc, const char **argv, const char **envp) |
__int64 vuln() |
int backdoor() |
最简单的栈溢出到后门函数 唯一不同的是开启了pie需要爆破倒数第四位的地址
直接上exp吧
from pwn import* |
这里你会发现后三位的地址有点不一样 后门函数的后三位是1DD 但是exp上写的是1e2
这里是栈对齐的问题 因为开启了pie 又没办法泄露基址 所以我们无法获得ret的汇编地址
这里看一下汇编代码 就比较好理解了
我们相当于是跳过了push rbp这一指令 因为此时的rbp已经被我们填入的垃圾数据覆盖了 如果这时候将rbp入栈
就会破坏原有的栈结构 至于为什么在没有开启pie的ret2text的题目中不用注意这一点 只能解释说这是pie特有的需要注意的情况