链接
链接
因为平常我们所使用的开发环境都是集合的开发环境,把编译和链接合在一起,所以我们对于链接等细节很少了解。写这篇文章就是简单记一下动态链接省略了很多细节。对于其中的细节我也是一知半解,所以不会过多的去解读,所以本文仅适于小白。
在linux环境下我们只用两个命令就可以完成对一个程序的开发
gcc main.c
./main
这两个命令执行了4个工作
1、预处理:除去注释。展开宏,对#开头的指令进行处理
2、编译:个人理解就是有关算法,语法的处理
3、汇编:将汇编代码转换为机械码
4、链接:将很多目标文件合在一起输出成一个可执行文件
ld xxx.o xxx.o ....
链接的过程
-
地址和空间的分配(主要是对虚拟地址的分析)
-
确定符号引用关系(符号解析)
-
合并相关 .o 文件(重定位)
-
确定每个符号的地址(重定位)
-
在指令中填入新的地址(重定位)
符号解析:将每个符号的引用都与一个确定的符号定义建立关联
静态链接(模块拼接)
关于静态链接不会很细致的讲解,因为我们实际的开发环境中都是动态链接,这里主要是讲一下一些基础知识
引入,当一个程序非常大时,我们需要把这个程序分成很多很小的模块进行分析和开发,
在静态链接中,链接就是处理好模块之间的引用,使之能够正确的衔接。
两步链接
1、地址和空间的分配
获得各个目标文件中的各个段的长度,属性建立一个符号表,并计算相似段合并后的长度和位置,建立映射关系
(1)什么是符号?符号首先是一种象征物,用来指称和代表其他事物。其次符号是一种载体,(官方表达)
在链接中,我们将函数和变量统称为符号(Symbol),函数名或变量名就是符号名(Symbol Name)
每一个目标文件都会有一个相应的符号表(Symbol Table),这个表里记录了目标文件中所用到的所有符号。
每个定义的符号有一个对应的值叫做符号值(Symbol Value),对于变量和函数来说,符号值就是它们的地址。
(2)什么时符号表? 符号表就是用于记录函数名、文件名、行号的映射关系的结构体
2、符号解析和重定位(核心)
这一步就是在上一步的基础上,进行细节上的填充,因为此时我们还不知道符号值,所以这一步就是进行符号解析和重定位
符号解析就是确定符号的唯一引用关系
重定位就是查找引用未知函数,变量地址的一个过程(就简单的讲一下这两个概念)
在没有重定位之前对于一些未知的函数和变量地址先赋值为0,每个重要的段都会有一个重定位表,用于记录指令,数据相对于段起始的偏移。
0k,对于静态链接的讲述就到此为止,主要还是动态链接
动态链接
为什么要动态链接?(或者动态链接相对于静态链接的好处)
因为静态链接在装载是需要把所有的函数都加载在程序中也就是内存中,内存的大小是有限的且是十分珍贵。为了解决这个问题动态链接就出现了
首先简单讲一下什么是动态链接
动态链接也是分成许多模块独立的编译,动态链接和静态链接的区别就是在链接的时候。静态链接是装载前就链接,而动态链接就是在装载是进行链接,简单的将就是不对那些组成程序的目标文件进行链接,等到程序运行时才进行链接。
打个比喻就是把一个程序编译链接当作一道菜的制作过程,厨房相当于内存,食材相当于各个函数,虚拟空间就是个其他的空间。静态链接的做法就是把所有的食材都放进厨房内,这样做的后果就是厨房显得十分的拥挤。而动态链接就是把先把各个食材放进其他房间,当需要这个食材是就会去其他房间去拿并记录地址,这样下次去拿时就会很快。(这也是动态链接中延迟绑定的原理)
全局偏移表.got .got.plt
实质上就是一个指针数组,got表存放的是全局变量.got.plt存放的是函数引用的地址(指向的可以是变量,函数),当指令要访问变量b时,程序会先找到got表,链接器在装载模块时会找到每个变量对应的地址放到对应的项中
.got.plt表的前三项
1、.dynameic段的地址
2、本模块的ID
3、_ld_runtime_resolve()的地址
延迟绑定
动态链接虽然比静态链接要节省内存空间,更加灵活,但也牺牲了一部分性能,这是因为动态链接是在运行时才去加载模块,这就导致动态链接比静态链接慢一点。而延迟绑定就是为加快运行速度而设计的(也叫做plt)
在动态链接中假设我们第一次调用libc.so中一个函数show(),这就需要调用链接器中的一个函数去找到这个函数的地址,假设叫lookup函数,那么这个函数需要那些信息才可以完成查找地址地工作,很明显是实在那个模块,是哪个函数(关于这个函数其实是一个攻击方法,这里就不再讲解,有兴趣的可以在浏览器上查找)
plt为了实现延迟绑定,又增加一个跳转,调用函数是并不是直接通过got表去寻址,而是通过plt表去跳转,如果是第一次调用这个函数plt表第一行是jmp got会跳转到got.plt表调用_ld_runtime_resolve()获得这个函数的真是地址,并把plt表的第一行改为这函数的真实地址,这样下次调用这个该函数时就会直接跳转到函数的真实地址。
关于动态链接的攻击
1、ret2libc 原理就是libc库是很大的几乎有你所有想用的gadget
2、修改got.plt表 :因为plt的跳转的时got
3、ret2_dl_resolve
ret2_dl_resolve zikh师傅写的很好