avatar

Catalog
初探GOT与PLT

前言

之前看了个讲GOT和PLT的视频。看明白了,但没完全明白。所以,就把看明白的那部分,先整理成笔记写下来。以后全看明白了,再补充。

基础知识

  • .got(位于数据段)

    GOT(Global Offset Table)全局偏移表。这是「链接器」为「外部符号」填充的实际偏移表。这里的外部符号当然也包含全局变量。同时也存放不需要延迟绑定的函数的地址。

    GOT 表中前 3 个为特殊项,分别用于保存 .dynamic段地址、本镜像的 link_map 数据结构地址和 _dl_runtime_resolve 函数地址

  • .plt(位于代码段)

    PLT(Procedure Linkage Table)程序链接表。它有两个功能,要么在.got.plt节中拿到地址,并跳转。要么当.got.plt没有所需地址的时,触发「链接器」_dl_runtime_resolve 去找到所需地址。

    PLT表中的第一项为公共表项,剩下的是每个动态库函数为一项,每项 PLT 都从对应的 GOT 表项中读取目标函数地址

  • .got.plt(位于数据段)

    这个是 GOT 专门为 PLT 准备的节。说白了,.got.plt 是 GOT 的一部分。它包含上述 PLT 表所需地址(已经找到的和需要去触发的)。功能类似 PE 的 IAT 表,存放的是需要延迟绑定的函数的地址

  • .plt.got(位于代码段)

    用于存放 __cxa_finalize 函数对应的 PLT 条目

演示

小程序

c
1
2
3
4
5
6
7
int main()
{
printf("Hello World\n");
printf("This is LiveOverflow\n");
exit(0);
return 1;
}

gdb调试

具体步骤参考下图,第一次调用printf(对应库函数puts),调用时在.got.plt中没找到函数地址,于是又回到了.plt,然后就调用了函数_dl_runtime_resolve,该函数位于ld.so,用于将共享库(例如libc.so)中的函数写入程序的.got.plt表中。

第二次调用printf时,可以看到.got.plt表里有函数地址,所以直接就跳转过去调用puts了。

关于利用

在进行栈溢出的练习时,往往会通过 pwntools 拿到某个函数的 got 或 plt 地址,之后再将其写入 rop 中进行利用链的构筑。实际上,应该往 rop 写入 got 地址还是 plt 地址需要根据实际情况判断:

  • 如果是通过 ret 的方式调用,那么使用 elf.plt['xxx']
  • 如果是通过 call 的方式调用,那么使用 elf.got['xxx'],前提是 xxx 已经被调用过

参考链接

  1. 简书:彻底搞清楚 GOT 和 PLT
  2. LiveOverflow:GOT and PLT
  3. 看雪:Android Hook技术学习——常见的Hook技术方案总结
Author: cataLoc
Link: http://cata1oc.github.io/2021/10/31/%E5%88%9D%E6%8E%A2GOT%E4%B8%8EPLT/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶