[pwn基础]静态链接原理

[pwn基础]静态链接原理

概念

静态链接就是把多个目标文件.o合并链接成一个可执行程序。

按序叠加

比如如下图:(将每个目标文件的数据都挨个复制到可执行程序)

详细点来说就是A.o的.text .data .bss B.o的.text .data .bss C.o的.text .data .bss拼成一个程序。

相似段合并

上面的做法虽然简单方便,但是非常的浪费程序空间,而且会出现成千上百个的零散段,而且每个段如果不足4096都会对其,非常的浪费空间。所以就有了新的策略即:相似段合并

将相同性质的段合并到一起,比如将所有输入文件的".text"合并到输出文件的".text",接着是".data"、".bss"等,如下图:

image-20220615132135655

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用来占位置。
image-20220615132159117
这时候再让我没来看看可执行程序中的汇编executable的,可以看到通过静态链接后,虚拟地址都确定了,这时候把0的位置都进行覆盖了。

image-20220615132222467

指令修正方式

不同的处理器指令对于地址的格式和方式都不一样。比如对于32位Intel x86处理器来说,转移跳转指令(jmp)、(call)、(mov)寻址方式千差万别,在2006年为止。jmp指令就有11种寻址方式、call有10种、move多达34种。

基本可以分为几种。

  • 近址寻址或远址寻址。
  • 绝对寻址或相对寻址
  • 寻址长度位8、12、32、64位。

不过就x86平台的ELF文件重定位入口修正指令寻址就两种

  1. 绝对近址32寻址
  2. 相对近址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

image-20220615132256429
shared和swap两个符号需要被修复,其中shared是相对寻址方式,而swap函数是绝对寻址方式。

修正shared变量

我们可以先通过readelf -s先查看executable可执行程序的符号表,来得到虚拟地址。

readelf -s executable

image-20220615132314388
得到虚拟地址后,我没查看shared符号被修复的方式是R_X86_64_PC32(相对寻址),他的公式是:S+A-P。
那么代入公式:**0x404000 + 0 - (0x401000+ 0x1A) = 0x2fe6 **,然后因为地址还占了4字节所以-4 = 2fe2
(可以看到和我们用objdump -M intel -dw executable,打印出来的值是一样的。)
image-20220615132333278

修正swap函数

既然我们已经回了shared变量的指令修正,那么swap函数大家可以先自动动手试试。
公式:(绝对寻址)S+A = 0x0401032 + 0 = 0x401032
image-20220615132348683

posted @ 2022-06-15 13:25  VxerLee昵称已被使用  阅读(332)  评论(0编辑  收藏  举报