chain()
: 返回当前的字节序列 , 即payloaddump()
: 直观地展示出当前的rop chainraw()
: 在rop chain
中加上一个整数或字符串search(move=0, regs=None, order=’size’)
: 按特定条件搜索gadget
unresolve(value)
: 给出一个地址 , 反解析出符号- GOT(Global Offset Table)全局偏移表 。存储导入变量的地址
- PLT(Procedure Linkage Table)程序链接表 。它有两个功能 , 要么在
.got.plt
节中拿到地址 , 并跳转 。要么当.got.plt
没有所需地址的时 , 触发「链接器」去找到所需地址 , 与常见导入的函数有关 , 如 read 等函数 。 - .got.plt , 这个是 GOT 专门为 PLT 专门准备的节 。说白了 , .got.plt 中的值是 GOT 的一部分 。它包含上述 PLT 表所需地址(已经找到的和需要去触发的) , 存储导入函数的地址
- .plt.got , 与动态链接有关系 。
puts
这样的函数都是定义在glibc
动态库里的 , 只有当程序运行起来时才可以确定地址 , 而运行时重定位是无法修改.text
段的地址的 , 只能将puts
重定位到data
段 , 那么got
表怎么知道puts()
函数的真实地址呢 , 链接器会额外生成一小段代码 , 如下所示.text...// 调用printf的call指令call printf_stub...printf_stub:mov rax, [printf函数的储存地址] // 获取printf重定位之后的地址jmp rax // 跳过去执行printf函数.data...printf函数的储存地址,这里储存printf函数重定位后的地址
总体来说 , 动态链接每个函数需要两个东西:- 用来存放外部函数地址的数据段
- 用来获取数据段记录的外部函数地址的代码
文章插图
可执行文件里面保存的是 PLT 表的地址 , 对应 PLT 地址指向的是 GOT 的地址 , GOT 表指向的就是 glibc 中的地址 , 那我们可以发现 , 在这里面想要通过 plt 表获取函数的地址 , 首先要保证 got 表已经获取了正确的地址 , 但是在一开始就进行所有函数的重定位是比较麻烦的 , 为此 , linux 引入了延迟绑定机制
延迟绑定只有动态库函数在被调用时 , 才会地址解析和重定位工作 , 为此可以使用类似这样的代码来实现
//一开始没有重定位的时候将 printf@got 填成 lookup_printf 的地址void printf@plt(){address_good:jmp *printf@gotlookup_printf:调用重定位函数查找 printf 地址 , 并写到 printf@got goto address_good;//再返回去执行address_good}
说明一下这段代码工作流程 , 一开始 , printf@got 是 lookup_printf 函数的地址 , 这个函数用来寻找 printf() 的地址 , 然后写入 printf@got , lookup_printf 执行完成后会返回到 address_good , 这样再 jmp 的话就可以直接跳到printf 来执行了也就是说这样的机制的话如果不知道 printf 的地址 , 就去找一下 , 知道的话就直接去 jmp 执行 printf 了
经验总结扩展阅读
- 四十一 增删查改分页 Java开发学习----MyBatisPlus标准数据层开发
- 中 学习ASP.NET Core Blazor编程系列十——路由
- CC1,3,6回顾
- 图学习【参考资料2】-知识补充与node2vec代码注解
- 二十四 设计模式学习:Spring 中使用到的设计模式
- Java安全之CC3
- TensorFlow深度学习!构建神经网络预测股票价格!?
- JUC学习笔记——共享模型之管程
- Seata Server 1.5.2 源码学习
- 2022极端高温!机器学习如何预测森林火灾?? 万物AI