关于PLT.got 表的理解

发布于 2021-01-27  541 次阅读


0x01----准备工作:

安装有peda 或者 pwndbg

大概了解 .plt | .got | 还有 .plt.got 和 .got.plt 这两个节

  • .got

GOT(Global Offset Table)全局偏移表。这是「链接器」为「外部符号」填充的实际偏移表。

  • .plt

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

  • .got.plt

这个是 GOT 专门为 PLT 专门准备的节。说白了,.got.plt 中的值是 GOT 的一部分。它包含上述 PLT 表所需地址(已经找到的和需要去触发的)

  • .plt.got

不知道

摘自madao756

这里提供一个代码 通过调试这个代码 来理解plt表的动态装载过成 和 .plt .got表

#include<stdio.h>

int main(void){
    printf("1st");
    printf("2nd");
    return 0;
}

编译方式:

gcc ./test.c -o test -no-pie #-no-pie 就是关闭 ASLR 的指令

0x02 开始调试:

进入gdb dump 一下主函数

disassemble main
image-20210127142059123
  • 给 两个print 下断 通过观察两次print的过程了解.plt .got
image-20210127142529978
使用 si (step into) 命令查看跳转到 printf@plt (这其实就是位于 plt 表中)的过程。
可见,此时 printf 处共有三行汇编语句。
第一行是跳转到了[rip+0x200c12]=jmp 0x601018
image-20210127142712936
  • 我们看看 这个0x601018是什么
    image-20210127142925834

0x400406 为< printf@plt >的下一句 意思是这个jump 0x601018 又直接跳回来的没起到作用

printf@plt 的第一步是去 .got.plt 找地址,但是没找到所以又跳回来了,因为我们之前没有调用过 puts@plt 函数,.got.plt里面没有对应的值

  • 多按几个si看看
image-20210127144419350

这里有个dl_runtime_resolve这个是动态链接器 这里是应为没有找到plt 存的地址

printf.plt:
jmp print.got
push printf.rel offset
jmp xxxxx ;plt[0]的地址这里存储的是调用动态链接器的过程指令

中间这些dl 都是动态链接的过程 这里继续用 ni指令向下跳

  • 直到跳到这里 记住这个地址 0x7ffff7a62810
image-20210127145142655
  • 使用 c (continue) 命令接着运行到下一次调用 printf。
  • 同样,还是使用 si 命令步入到 printf@plt 中
image-20210127145737958
image-20210127145512686
  • 现在来看刚刚 第一次在 0x400400< printf@plt >jump [rip+0x200c12]=jmp 0x601018 位置上储存了个地址
  • 这个地址为 0x7ffff7a62810 和我们刚刚要记住那个地址是一样的
  • 这个 0x7ffff7a62810 实际上就是printf的真正地址 这里说明通过 动态加载将 printf的真正地址填入了 .plt.got中
先概况一下上面调试中的发生的情况:
1.第一次调用 printf 时,“顺序”执行了 printf@plt 中的三条语句(实际上是跳出去又跳回来);
因为还没调用过 找不到.plt.got 表中的真正地址
所以进行了动态加载
2.第二次调用 printf 时,直接跳转到了 0x00007ffff7e46db0 处,也就是执行了 printf 函数
此时printf的真正地址已经被填入 所以printf@plt 第一行跳转的地址 此时指向了printf的真实地址

0x03 总结

  1. 调用库函数时,先查 plt 表(如 print@plt),plt 表中第一条语句索引了 got 表中的值。
  2. 若从未调用过该库函数,则此时 got 表中的字段是指回 plt 表中的第二条汇编指令的(如 printf@got.plt 中最开始的值为 0x0x401036),此时顺序执行,而后续指令就是在装载相应的库,然后对 got 表进行覆写
  3. 后续的调用中,got 表均保存着库函数的真实地址,因此无需再去装载一遍动态链接库等,直接跳转到对应的库函数的真实地址处,执行即可 可以和另一篇这个文章里有动态图 对比起来看 来理解

计算机原理系列之八 ——– 可执行文件的PLT和GOT

参考文章:

1.一篇文章,搞懂 GOT表 & PLT表

2.彻底搞清楚 GOT 和 PLT

3聊聊动态链接


山鸟和鱼不同路,从此山水不相逢