25 Oct 2019

动态链接

动态链接

GOT和PLT

.got

Global Offset Table,全局偏移表。这是链接器在执行链接时实际上要填充的部分, 保存了所有外部符号的地址信息

.plt

Procedure Linkage Table,进程链接表

调用动态链接器来解析某个外部函数的地址,并填充到.got.plt中,然后跳转到该函数

如果已经填充过,直接在.got.plt中查找并跳转到对应外部函数

.got.plt

.got.plt是got的一部分,相当于.plt的GOT全局偏移表,其内容有两种情况,如果在之前查找过该符号,内容为外部函数的具体地址;如果没查找过,则内容为跳转回.plt的代码,,并调用动态链接器

4

动态链接

在生成可执行程序的时候,只是引用的未定义的符号作了标识,到加载到内存中的时候才进行符号重定位

动态链接器

ld.so

动态库

命名规则lib(.*).so

动态库生成

#include <stdio.h>
int	main(int argc, char const *argv[])
{
	puts("hello world");
	return 0;
}
gcc -fPIC -shared hello.c -o libhello.so

重定位

链接时重定位

链接阶段是将一个或多个中间文件(.o文件)通过链接器将它们链接成一个可执行文件

如果是在中间文件中已经定义的函数,链接阶段可以直接重定位到函数地址

如果是在动态库中定义的函数,链接阶段无法直接重定位到函数地址,只能生成额外的小片段代码(PLT表),然后重定位到该代码片段

运行时重定位

运行后加载动态库,把动态库中的相应函数地址填入GOT表

延迟重定位

只有动态库函数在被调用时,才会进行地址解析和重定位工作,这时候动态库函数的地址才会被写入到GOT表项中

样例

#include <stdio.h>
int main(int argc, char const *argv[])
{
	puts("hello world");
	puts("A1_D4i");
	return 0;
}
//gcc 1.c -o 1 -no-pie 

objdump -h看一波

root@A1_D4i:/mnt/c/Users/wdbbw/Desktop/test# objdump -h 1

1:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     0000001c  0000000000400298  0000000000400298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000060  00000000004002b8  00000000004002b8  000002b8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000003d  0000000000400318  0000000000400318  00000318  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  00000008  0000000000400356  0000000000400356  00000356  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  0000000000400360  0000000000400360  00000360  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00000030  0000000000400380  0000000000400380  00000380  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000018  00000000004003b0  00000000004003b0  000003b0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000017  00000000004003c8  00000000004003c8  000003c8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000020  00000000004003e0  00000000004003e0  000003e0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         00000192  0000000000400400  0000000000400400  00000400  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000009  0000000000400594  0000000000400594  00000594  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00000017  00000000004005a0  00000000004005a0  000005a0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 0000003c  00000000004005b8  00000000004005b8  000005b8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00000100  00000000004005f8  00000000004005f8  000005f8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000008  0000000000600e10  0000000000600e10  00000e10  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000008  0000000000600e18  0000000000600e18  00000e18  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .dynamic      000001d0  0000000000600e20  0000000000600e20  00000e20  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .got          00000010  0000000000600ff0  0000000000600ff0  00000ff0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got.plt      00000020  0000000000601000  0000000000601000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .data         00000010  0000000000601020  0000000000601020  00001020  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .bss          00000008  0000000000601030  0000000000601030  00001030  2**0
                  ALLOC
 24 .comment      0000002b  0000000000000000  0000000000000000  00001030  2**0
                  CONTENTS, READONLY
>>> hex(elf.plt['puts'])
'0x4003ec'#0x4003f0
>>> hex(elf.got['puts'])
'0x601018'
pwndbg> x/10gi 0x4003ec
   0x4003ec:    nop    DWORD PTR [rax+0x0]
=> 0x4003f0 <puts@plt>: jmp    QWORD PTR [rip+0x200c22]        # 0x601018
   0x4003f6 <puts@plt+6>:       push   0x0
   0x4003fb <puts@plt+11>:      jmp    0x4003e0
   0x400400 <_start>:   xor    ebp,ebp
   0x400402 <_start+2>: mov    r9,rdx
   0x400405 <_start+5>: pop    rsi
   0x400406 <_start+6>: mov    rdx,rsp
   0x400409 <_start+9>: and    rsp,0xfffffffffffffff0
   0x40040d <_start+13>:        push   rax

在0x4003f0断

1

跳0x601018

此时

pwndbg> x/10gx 0x601018
0x601018:       0x00000000004003f6      0x0000000000000000
0x601028:       0x0000000000000000      0x0000000000000000
0x601038:       0x0000000000000000      0x0000000000000000
0x601048:       0x0000000000000000      0x0000000000000000
0x601058:       0x0000000000000000      0x0000000000000000

执行jmp qword ptr [rip + 0x200c22] <0x601018> ,跳转到0x4003f6

2

继续执行,跳转到0x4003e0,然后跳_dl_runtime_resolve_xsavec@got,执行_dl_runtime_resolve_xsavec

puts地址写入.got.plt,然后跳转

3

pwndbg> x/10gx 0x601018
0x601018:       0x00007fffff0809c0      0x0000000000000000
0x601028:       0x0000000000000000      0x0000000000000000
0x601038:       0x0000000000000000      0x0000000000000000
0x601048:       0x0000000000000000      0x0000000000000000
0x601058:       0x0000000000000000      0x0000000000000000

之后再调用puts时,直接跳转到puts

4

RELRO

relocations read-only

gcc -o test test.c // 默认情况下,是Partial RELRO
gcc -z norelro -o test test.c // 关闭,即No RELRO
gcc -z lazy -o test test.c // 部分开启,即Partial RELRO
gcc -z now -o test test.c // 全部开启,即Full RELRO

No RELRO

  • 白给

Partial RELRO

  • 一些节区初始化后只读
  • non-PLT got只读,.got.plt可写
  • 重新排列节以减少全局变量溢出到控制结构中的可能性

Full RELRO

  • 延迟重定位不存在,所有符号都在程序启动时解析并绑定
  • 整个.got只读

Tags:
0 comments



本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议CC BY-NC-ND 4.0)进行许可。

This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).