当前位置: 首页 > news >正文

【学习记录】Week1:彻底搞懂动态链接原理——PLT/GOT 懒绑定机制

写在前面:在之前的checksec学习中,我们提到了RELRO保护机制会保护 GOT 表。但很多新手会疑惑:GOT 表到底是什么?为什么黑客总是想方设法去篡改它?
要弄懂这个问题,我们必须深入理解 Linux 下动态链接的核心机制——PLT 与 GOT 的懒绑定。这是 PWN 学习路上绕不开的一座大山,也是后续学习ret2libc的前置基础。本文将用最通俗的语言,带你扒开动态链接的底裤。

📑 目录

  1. 为什么需要动态链接?
  2. 核心概念:PLT 与 GOT 是什么?
  3. 懒绑定:按需加载的智慧
  4. 图解第一次调用(慢路径)
  5. 图解第二次调用(快路径)
  6. 实战观察:用 GDB 看 PLT/GOT 的变化
  7. PWN 视角:为什么 GOT 表是兵家必争之地?

1. 为什么需要动态链接?

如果每个 C 语言程序都把printfsystem等函数的代码静态编译进自己的可执行文件里,会导致:

  1. 文件体积巨大。
  2. 大量内存浪费(每个进程都有一份相同的printf代码)。

动态链接解决了这个问题:系统把公用的函数打包成动态链接库(如libc.so)。程序运行时才去把 libc 加载到内存中,然后去寻找对应的函数地址。

但这里有个矛盾:

  • libc 的加载地址每次运行都不一样(ASLR),程序在编译时根本不知道printf的真实内存地址在哪。
  • 程序在执行call printf时,必须知道确切的跳转地址。

为了解决这个矛盾,ELF 文件引入了PLTGOT两张表。

2. 核心概念:PLT 与 GOT 是什么?

你可以把它们理解为两个配合默契的“特工”:

  • GOT (Global Offset Table,全局偏移表)
    这是一个数据表,位于内存的数据段。它的本质是一个指针数组。里面存放着外部函数(如printf)的真实内存地址。因为地址会变,所以 GOT 表是可写的。

  • PLT (Procedure Linkage Table,过程链接表)
    这是一个代码表,位于内存的代码段。它是一小段一小段的跳板代码。程序调用外部函数时,实际上是先call PLT表中的代码,然后由 PLT 去跳转到 GOT 表中记录的真实地址。

打个比方
你(程序)要寄快递给张三(调用函数),但你不知道张三的地址。
你先把包裹交给快递驿站(PLT表),驿站查一下自己的账本(GOT表)。如果账本上有张三的地址,直接寄过去;如果没有,驿站就去总台查地址,查到后写在账本上,下次再寄就直接看账本了。

3. 懒绑定:按需加载的智慧

Linux 默认采用懒绑定策略。

什么是懒?就是不到万不得已不去找地址
如果一个程序引用了 100 个 libc 函数,但本次运行只用到了 2 个,如果一启动就去找齐 100 个函数的地址,会极大拖慢启动速度。

懒绑定的逻辑是:

  1. 程序启动时,GOT 表里不写真实地址,而是写指向 PLT 表中下一条指令的地址。
  2. 当函数第一次被调用时,触发 PLT 的兜底逻辑,去调用动态链接器找到真实地址。
  3. 找到后,把真实地址写进 GOT 表里。
  4. 以后再次调用时,直接从 GOT 表里拿真实地址跳转。

4. 图解第一次调用(慢路径)

假设程序第一次调用puts函数。

1. 程序执行 call puts@plt | v 2. 来到 PLT 表的 puts 项 (代码段): puts@plt: jmp [GOT表对应puts的地址] <-- 此时 GOT 表里存的不是真实地址,而是下面这条指令的地址! push 0 <-- 告诉动态链接器:我要找的是第 0 号函数 jmp PLT[0] <-- 跳转到 PLT 表的初始项 | v 3. 来到 PLT[0] (代码段): PLT[0]: push [GOT[1]] <-- 压入链接器需要的信息 jmp [GOT[2]] <-- 跳转到动态链接器的核心函数 _dl_runtime_resolve | v 4. 动态链接器 执行: 根据 push 0 的编号,去 libc.so 里找到 puts 的真实内存地址。 将真实地址写入 GOT 表中对应 puts 的位置。 最后,跳转到 puts 的真实地址去执行。

5. 图解第二次调用(快路径)

当程序第二次调用puts时,因为第一次已经填好了 GOT 表:

1. 程序执行 call puts@plt | v 2. 来到 PLT 表的 puts 项 (代码段): puts@plt: jmp [GOT表对应puts的地址] <-- 此时 GOT 表里已经是 puts 的真实地址了! | v 3. 直接跳转到 libc 中 puts 的真实地址执行。一气呵成,无需再找!

6. 实战观察:用 GDB 看 PLT/GOT 的变化

纸上得来终觉浅,我们在 GDB 中实际观察一下这个过程。

  1. gdb ./vuln
  2. gets函数下断点(gets也会用到动态链接)。
  3. 运行程序:r
  4. 查看反汇编,你会看到程序调用了gets@plt
  5. 使用 pwndbg 的神奇命令pltgot
pwndbg> got

你会看到类似这样的输出:

GOT protection: Partial RELRO ... 0x404000 | gets@GLIBC_2.2.5 <- [0x401046] <-- 注意这里!存的不是 libc 地址,而是 PLT 里的地址

此时gets还没被真正解析。

  1. 输入字符串让程序继续执行完gets后,再次查看got
pwndbg> got 0x404000 | gets@GLIBC_2.2.5 <- 0x7ffff7e5e... <-- 变了!变成了 libc 中的真实地址

这就是懒绑定的全过程!

7. PWN 视角:为什么 GOT 表是兵家必争之地?

理解了上述原理,你就会明白 PWN 攻击中最经典的一种手法:GOT 表覆写

攻击思路
假设程序开启了 NX(不能执行 shellcode),也没有后门函数。我们只能利用 libc 里的system函数。

  1. 程序里有puts函数,且puts的 GOT 表项已经被解析了(存了 libc 真实地址)。
  2. 我们通过漏洞(比如格式化字符串漏洞,或任意地址写),把 GOT 表中puts的真实地址,篡改成system的真实地址
  3. 当程序下一次调用puts("hello")时,实际上执行的却是system("hello")

这就是为什么在checksec中,Partial RELRO(GOT 可写)是非常危险的,因为它给攻击者留下了篡改执行流的捷径。

Full RELRO的原理就是:程序一启动就立即解析所有函数地址填入 GOT,然后把 GOT 所在的内存页设为只读。这样黑客就无法篡改 GOT 表了。

8. Week1 终极收官感言

历经多天的学习,Week1 的任务终于圆满完成!
从最初的环境搭建,到二进制工具分析;从吃透五大保护机制,到摸清汇编级调用约定;从手动计算偏移量编写 Python Exploit,再到今天深入操作系统底层剖析动态链接。

我感觉自己仿佛把一个程序的“前世今生”都看透了。虽然目前还只是停留在静态分析和理论阶段,但这座地基已经打得无比坚实。


如果本篇硬核原理解析对你有帮助,请点赞收藏支持一下,感谢阅读,我们 Week2 见!🙏

http://www.jsqmd.com/news/1090394/

相关文章:

  • 9 系列 SUV 车型推荐:2026 旗舰新能源 SUV 全维度对比 智己 LS9 深度盘点
  • 如何快速完整地下载任何网站:Python网站离线下载器终极指南
  • 5个步骤掌握B站资源本地化管理:BiliTools终极指南
  • 终极Windows 11优化指南:4步让你的系统性能飙升70%的免费方案
  • COM3D2 MaidFiddler终极指南:如何5分钟掌握实时游戏编辑器
  • MobaXterm 高效运维实战:从基础配置到进阶调优
  • Swagger API安全测试:三种全局Token注入方案对比与实践
  • 3个实战场景教会你:Kafka-UI可视化集群管理全攻略
  • 5分钟掌握OOTDiffusion:基于扩散模型的AI虚拟试穿终极指南
  • 掌握ProperTree跨平台Plist编辑器的实战技巧:提升macOS配置管理效率
  • MSP430BT5190嵌入式开发实战:文档、封装与ESD防护全解析
  • 嵌入式硬件数学加速器MATHACL:从定点数原理到电机控制实战
  • 硬件调试工具终极指南:免费开源AMD处理器性能调校完全教程
  • Java计算机毕设之基于 SpringBoot 的急诊病患信息登记与随访管理系统 医院急诊分诊诊疗一体化管理系统设计与开发(完整前后端代码+说明文档+LW,调试定制等)
  • 5步终极指南:用Win11Debloat轻松优化Windows 11系统性能与隐私
  • OpCore-Simplify:三分钟快速配置黑苹果OpenCore EFI的终极自动化工具
  • Java生产环境密码安全:从MD5到BCrypt的完整实践指南
  • 【Netty源码解读和权威指南】第82篇:ChannelOutboundBuffer源码深度解析——Netty写缓冲区的秘密
  • 免费畅玩Switch游戏:Ryujinx模拟器完整指南
  • Windows 11系统优化终极指南:告别卡顿提升性能的完整解决方案
  • 终极Windows优化指南:3分钟让你的系统重获新生
  • 鼠标性能测试神器:MouseTester如何帮你解锁精准输入体验
  • 从VSCode到Source Insight:打造高效代码审阅环境的字体、语法与配色迁移指南
  • 5个技巧让ProperTree成为你的跨平台plist编辑利器
  • Mini Shai-Hulud 供应链蠕虫攻击实战复盘:从 npm 到 AI 助手的完整防御配置手册
  • 3分钟掌握哔咔漫画下载器:打造你的个人永久漫画图书馆
  • Icarus Verilog深度解析:开源硬件验证工具的技术架构与实战指南
  • TI TCAN4550-Q1 CAN FD控制器与TLIN2029-Q1 LIN收发器BoosterPack开发板硬件设计与固件开发实战
  • 网易云音乐自动打卡神器:3步实现每天300首听歌,轻松冲级LV10终极指南
  • BiliTools跨平台哔哩哔哩工具箱:如何高效下载管理B站资源