理解elf文件的got和plt
2021-01-12 18:58:00 Author: mp.weixin.qq.com(查看原文) 阅读量:163 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:Heavenml


在Linux平台下,elf文件中的got节和plt节在动态链接过程中起着非常重要的作用,学习got节和plt节是在学习elf文件格式过程中必不可少的一部分。所以在此笔记中,记录一下got节和plt节的原理。
got(全局偏移表)

got表是Linux平台用来解决对全局数据,外部函数引用的表,当在程序中引用外部的数据,函数时,通过got表来实现对相关数据符号的解析。

plt(过程链接表)

在动态链接过程中, 函数在加载共享库之后,会对got节中的函数地址进行填充,所以,调用的时候利用plt跳转到got表中项指定的地址即可。


我们通过如下的两段代码,来学习got/plt的实现机制。
//foo.c//使用如下的编译命令编译生成foo.so//gcc -shared -fPIC foo.c foo.so extern int foo();extern int test;int foo(){    return test;} //main.c//使用如下的命令,链接foo.so//gcc -g -nostdlib  -o a.out main.c lib.soint test;_start(){    foo(test);    return 0;}

使用objdump查看生成的lib.so共享库的的foo函数的反汇编代码。
00000000000005aa <foo>: 5aa:    55                       push   rbp 5ab:    48 89 e5                 mov    rbp,rsp 5ae:    48 8b 05 33 0a 20 00     mov    rax,QWORD PTR [rip+0x200a33]        # 200fe8 <test> 5b5:    8b 00                    mov    eax,DWORD PTR [rax] 5b7:    5d                       pop    rbp 5b8:    c3                       ret     readelf -S lib.so[16] .got              PROGBITS         0000000000200fd8  00000fd8       0000000000000028  0000000000000008  WA       0     0     8

 
可以看到foo函数对test变量的查找是通过当前的rip+0x200a33(需要配合重定位表实现)来获取的,也就是0x200fe8,使用readelf查看lib.so的节信息,0x200fe8位于got表中,以上是全局变量在got表中的解析过程。
可以看到_start函数在调用foo函数时,call的地址为0x3a0,在foo@plt(0x3a0)处呢,jmp到当前rip偏移0x0x200c52出指向的地址,也就是0x360处的地址,紧接着执行push 0,jmp390,也就是plt表中,最后在plt表中跳转到rip+0x200c54=0x200ff0(存储foo函数的实际地址) 的指向地址,查看elf信息,也可以看到0x200ff0的地址位于got表中。以上是函数在got表在函数调用过程中的解析过程。
这里需要注意两个问题
1. 地址0x3a0处的的指令jmp QWORD PTR [rip+0x200c52],跳转到200ff8 (got中的条目)地址指向的地址,当前指向的数据是0x3a0下一条指令指向的地址,也就是push 0 ,然后跳转到plt中。
2. 在plt中,执行了push QWORD PTR [rip+0x200c52] # 200fe8 <_GLOBAL_OFFSET_TABLE_+0x8>,也就是将got表的第二个条目数据压栈,然后jmp QWORD PTR [rip+0x200c54] # 200ff0 <_GLOBAL_OFFSET_TABLE_+0x10>,也就是跳转到got表的第三个条目指向的地址。在got中,前三个数据保存如下的数据
为什么要这样做?

动态链接器默认采用延迟链接方式时,动态链接器不会在程序加载时解析每一个函数,而是在调用时通过plt和got来对函数进行解析,然后会将解析获得函数地址存放在got中,下一次调用时会直接使用got中的函数地址对函数进行调用。
在ELF将GOT拆分成两个表“.got”和".got.plt",前者用来保存全局变量引用的地址,后者用来保存函数引用的地址。也就是说,所有对于外部函数的引用被分离出来放到了“.got.plt”中。
调试:

- End -

看雪ID:Heavenml

https://bbs.pediy.com/user-home-771815.htm

  *本文由看雪论坛 Heavenml 原创,转载请注明来自看雪社区。

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458379473&idx=1&sn=62b9ce2d4a8b5d6471c194135b914c4d&chksm=b180d45b86f75d4d3649980f998bc0acdd62d27f49889c70a52907749b52366f794a5485ba6c#rd
如有侵权请联系:admin#unsafe.sh