[toc]
[pwn基础]静态链接原理
概念
静态链接就是把多个目标文件.o合并链接成一个可执行程序。
按序叠加
比如如下图:(将每个目标文件的数据都挨个复制到可执行程序)
详细点来说就是A.o的
.text .data .bssB.o的
.text .data .bssC.o的
.text .data .bss拼成一个程序。
相似段合并
上面的做法虽然简单方便,但是非常的浪费程序空间,而且会出现成千上百个的零散段,而且每个段如果不足4096都会对其,非常的浪费空间。所以就有了新的策略即:
相似段合并。
将相同性质的段合并到一起,比如将所有输入文件的".text"合并到输出文件的".text",接着是".data"、".bss"等,如下图:
ld a.o b.o c.o -e main -o excutable #利用ld将所有目标文件链接成一个可执行程序。
空间地址分配
一般Linux下的ELF默认装载地址是0x08040000,至于分配的过程可以详细的参考可执行文件的装载与进程笔记。
符号解析,重定位
在完成空间地址的分配后,接着链接器就开始进行符号解析和重定位的步骤了,也是静态链接的核心内容。
extern int shared; //外部符号,跨模块 int main() { int a = 100; swap(&a,&shared);//外部符号,调用外部模块的swap函数 }
int shared = 1; void swap(int *a,int *b) { *a ^= *b ^= *a ^= *b; }
#编译汇编成.o目标文件(一定要关stack-protector) gcc -c a.c -fno-stack-protector #同上 gcc -c b.c -fno-stack-protector #将这两个目标文件汇编成一个可执行程序 ld a.o b.o -e main -o executabl
标记处分别代表的是int shared和调用swap()函数,我们可以看到他的opcode部分分别是**48 8d 35 00 00 00 00,e8 00 00 00 00 **其中这里面的488d35和e8分别代表的就是lea和call指令,但是奇怪的是他后面的值都是0,这是因为shared变量定义在b.o模块中,所以编译器暂时是不知道shared变量的实际值的,所以他就暂时填0用来占位置。
这时候再让我没来看看可执行程序中的汇编executable的,可以看到通过静态链接后,虚拟地址都确定了,这时候把0的位置都进行覆盖了。
指令修正方式
不同的处理器指令对于地址的格式和方式都不一样。比如对于32位Intel x86处理器来说,转移跳转指令(jmp)、(call)、(mov)寻址方式千差万别,在2006年为止。jmp指令就有11种寻址方式、call有10种、move多达34种。
基本可以分为几种。
- 近址寻址或远址寻址。
- 绝对寻址或相对寻址
- 寻址长度位8、12、32、64位。
不过就x86平台的ELF文件重定位入口修正指令寻址就两种
- 绝对近址32寻址
- 相对近址32寻址
宏定义 | 方式 | 重定位修正方法 |
---|---|---|
R_X86_64_PC32 | 相对寻址 | 相对寻址修正S+A-P |
R_X86_64_PLT32 | 绝对寻址 | 绝对寻址修正S+A |
A = 保存在被修正位置的址 P = 被修正的位置(相对于段开始的偏移量或者虚拟地址),注意,该值可通过r_offset计算得到 S = 符号的实际地址,即由r_info的高24位指定的符号的实际地址
接下来,我们手动来还原链接器对a.o指令修复的过程。 首先,我们通过重定位表来进行查看,目标文件里面那些符号需要被重定位和指令修复的。
objdump -r a.o
shared和swap两个符号需要被修复,其中shared是相对寻址方式,而swap函数是绝对寻址方式。
修正shared变量
我们可以先通过readelf -s先查看executable可执行程序的符号表,来得到虚拟地址。
readelf -s executable
得到虚拟地址后,我没查看shared符号被修复的方式是R_X86_64_PC32(相对寻址),他的公式是:S+A-P。
那么代入公式:**0x404000 + 0 - (0x401000+ 0x1A) = 0x2fe6 **,然后因为地址还占了4字节所以-4 = 2fe2
(可以看到和我们用objdump -M intel -dw executable,打印出来的值是一样的。)
修正swap函数
既然我们已经回了shared变量的指令修正,那么swap函数大家可以先自动动手试试。
公式:(绝对寻址)S+A = 0x0401032 + 0 = 0x401032
- 深度学习基础模型算法原理及编程实现--03.全链接
- Java基础加强重温_02:接口(成分:抽象方法、常量、默认方法、静态方法、私有方法,实现、继承)、final关键字(修饰类、方法)、单例设计模式(懒汉、饿汉)、枚举(底层原理、编译与反编译)
- 深入计算机组成原理(八)ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?
- 几个移动机器人lab资料 相关链接,实验室、原理、基础知识
- 静态路由基础-路由交换原理10-【HCNA笔记】
- python的一些基础操作和c文件的链接编译原理
- PHP基础-生成静态html页面原理
- hbase基础知识及原理
- C#超基础:静态数组与动态数组的区别
- 静态时序分析(Static Timing Analysis)基础与应用(上) 2 [zz]
- 算法基础:堆排序原理及其实现
- 分布式系统理论之基础原理
- 静态链接之符号解析(待完善)
- DNS基础原理
- C++语言基础 例程 静态成员
- C++基础7【难】 多态:实现原理 vptr指针 证明vptr存在 类的步长 纯虚函数:抽象类 案例 【面试题】
- PHP基础知识系列:静态
- JSP基础知识-学习笔记(一) 基础语法、三大指令、静态包含与动态包含的区别
- 基础集合论 第五章 5 良序化原理
- RNN、LSTM基础内容学习链接