动态延迟绑定


执行过程:
-
call库函数首先会跳转到plt条目的第一条指令处
-
跳转got表:
-
- 如果是非第一次调用该函数,则got表中存储的是函数的实际地址,然后直接去执行函数了,就无下面的操作
- 如果是第一次调用,则存储的是函数的plt条目的第二条指令地址,然后就会执行以下步骤
-
将got表中偏移压入栈中,并跳转到解析地址的代码片段
-
解析完成后跳转去执行库函数并把实际地址写入got表
IDA 分析过程

plt表结构如上,
以puts函数为例,在ida中该函数指向的是plt表第一个值
jmp cs:off_601018
plt表第二个表项push 0
代表获取got表中偏移量为0的库函数,也就是第一个函数

plt表第三个表项为jmp sub_4003F0跳转过去可以发现执行了两个指令

第一条push cs:qword_601008将got表中ink_map结构的地址压入栈中
ink_map中记载了动态链接库加载的一些信息
然后执行jmp cs:qword_601010跳转到got表的第三个表项数据动态连接器地址
跳转过去的时候已经给了动态连接器两个参数:
- puts函数偏移
- ink_map地址
然后动态连接器会进行解析获取puts函数在内存中的地址,解析完成后跳转去执行库函数并把实际地址写入got表
原理:

函数在动态链接库中偏移量是固定的,但是动态链接库的基址不是固定的,函数地址=动态链接库基址+偏移
在内存中多个进程间共享动态链接库。
好处:用不上的函数是不会做解析的,提高效率,缩减程序运行时间
使用gdb调试
gdb test1
b main
r
got
此时指向plt+6也就是push 0的地址
n
n
got
当我们执行过一次call指令后

此时解析成了puts函数在整个内存中的实际地址
看一下puts函数地址
disass puts
此时地址是能够对应上的

通过plt调用和call调用栈结构的不同
直接覆盖函数返回地址为system函数的plt表的话,栈结构如下

相比较与call指令来说,我们可以更容易控制system执行完后的程序流,当执行到run函数的ret指令后,整个栈结构为

call指令自动将下面一个单元地址
call system等于push $eip+1;jmp system@plt
文章详细阐述了动态延迟绑定的过程,包括通过plt表和got表的交互,首次调用时的函数解析步骤。在IDA中分析puts函数的plt条目,展示了如何使用gdb设置断点来观察got表的变化。同时,对比了通过plt调用与call指令的栈结构差异,讨论了动态绑定对于程序效率和安全性的影响。

1698

被折叠的 条评论
为什么被折叠?



