PLT & GOT 表动态链接详解及 pwn 应用

  动态链接,是提高程序空间效率的重要方法。通过动态链接, 我们可以调用外部共享库中的函数,而不需要将其编译在可执行文件中。在运行时动态链接的过程中,PLT表和GOT表起到了至关重要的作用。本文,我们就从运行过程的角度探究程序依靠这两个表进行动态链接的原理。
  ps: 转眼加入CSDN也已经一年了,从一年前的徒有热情却无目的,孤身在计算机的世界中摸索,到现在拥有了组织的归属,获得了许多前辈们的宝贵经验,也逐渐确定了自己在CTF中的方向:二进制安全。希望在接下来的一年中,能朝着既定的方向迈进。接下来我也会尽量更新一些pwn方向的学习笔记,争取在日益嘈杂的环境中坚持做技术的本心。知识与大家共享,CSDN见证我的成长,未来,一起努力!

Conception

PLT与GOT表均为动态链接过程中的重要部分

  • GOT: Global Offset Table, 全局偏移表,包含所有需要动态链接的外部函数的地址(在第一次执行后)
  • PLT: Procedure Link Table, 过程链接表,包含调用外部函数的跳转指令(跳转到GOT表中),以及初始化外部调用指令(用于链接器动态绑定dl_runtime_resolve)

Linux虚拟内存分段映射中,一般会分出三个相关的段:

  • .plt: 即上文提到的过程链接表,包含全部的外部函数跳转指令信息
    • Attributes: Read / Execute
  • .got.plt: 即下文将要表达的GOT表,与PLT表搭配使用,包含全部外部函数地址(第一次调用前为伪地址,具体见下)
    • Attributes: Read / Write
  • .got : 存放其他全局符号信息,注意与.got.plt不同,与下文函数动态链接过程关系不大(所以了解不深请见谅,有兴趣的读者也欢迎分享)
    • Attributes: Read / Write

简单来说,PLT表存放跳转相关指令,GOT表存放外部函数(符号)地址


接下来,所有GOT表指代.got.plt

Content

PLT

  • 结构可见下图 Procedure

  • 第一个表项PLT[0]为(通用调用解析表项)没有存储任何外部函数的跳转信息,保存调用dynamic linker resolve函数_dl_runtime_resolve的参数(link_map)和地址

  • 之后的每个表项,分为两部分(三句):

    ;part 1
    jmp *fun@got
    ;part 2
    push offset
    jmp plt[0]
    
  • 实际上,每个PLT都可理解为一个程序 (thunk)

PLT

GOT

  • 每一项为单个地址

  • 第一项指向dynamic段

  • 第二项指向link_map

  • 第三项指向_dl_runtime_resolve函数

  • 之后每项一一对应PLT表中每个表项(序号不同)

GOT

Procedure

第一次调用

First
(此图片转自prettyX 博客,原来源B站视频)

  • 每次调用外部函数,形式均为call func@plt,PC指向每个PLT表项的第一部分:跳转到GOT表对应项指向位置(为表项的值,非表项本身地址

  • 第一次调用前,GOT表中对应项存储的不是外部函数的真实地址,而重新指回PLT表,指向PLT表对应表项(相同函数)的第二部分,使其初始化dynamic linker进行运行时解析(_dl_runtime_resolve)

  • 回到PLT表第二部分,向栈中压入表项序号

    • x86为offset,如图所示

x86

  • x86-64为序号,如图所示

x86-64

  • 接下来,jmp PLT[0],进行链接器调用

  • PLT[0]将link_map压入栈,即跳转到_dl_runtime_resolve

  • _dl_runtime_resolve

    • 将解析到的真实外部函数地址改写入对应GOT表项
    • 执行对应外部函数

第二次调用

Second
(此图片转自prettyX 博客,原来源B站视频)

  • 依然调用PLT对应表项
  • PLT表项第一部分执行,跳转到GOT对应项所指向位置
  • 外部函数直接执行,不需要重新解析(类似于缓存机制)

Application

  • 利用ROP调用外部函数,直接将对应PLT地址覆盖返回地址

    • PLT对应项为一个命令,在跳转后可以得到直接执行
    • 若填充GOT,但该位置为函数外部地址,一个地址不能被解析为命令,通常报Segmentation Fault

注意:使用PLT地址跳转,跳转目标函数的下一层应该放该函数的返回地址(因为jmpcall的差异,产生一层栈偏移),参数放在其下

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值