Pwn学习随笔( 四 )


  • chain() : 返回当前的字节序列 , 即payload
  • dump(): 直观地展示出当前的rop chain
  • raw() : 在rop chain中加上一个整数或字符串
  • search(move=0, regs=None, order=’size’) : 按特定条件搜索gadget
  • unresolve(value) : 给出一个地址 , 反解析出符号
  • PLT和GOT
    • 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函数重定位后的地址总体来说 , 动态链接每个函数需要两个东西:
    • 用来存放外部函数地址的数据段
    • 用来获取数据段记录的外部函数地址的代码
    对应有两个表 , 一个用来存放外部的函数地址的数据表称为全局偏移表(GOT, Global Offset Table) , 那个存放额外代码的表称为程序链接表(PLT , Procedure Link Table) , plt 表不是查询表 , 而是一块代码 。这一块内容是与代码相关的
    Pwn学习随笔

    文章插图
    可执行文件里面保存的是 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 了

    经验总结扩展阅读