[原创](pwn零基础入门到进阶)第一章 二进制文件 & 4 动态链接
2022-12-9 20:17:0 Author: bbs.pediy.com(查看原文) 阅读量:8 收藏

把系统库和自己编写的代码分割成两个独立的模块,等程序真正运行时再把两个模块进行链接,这种在运行或加载时,在内存中完成链接的过程叫动态链接。节省了内存空间,并且内存中一个系统库可以被多个程序共同使用,也节省了内存空间。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

    1078:    48 8d 3d ca 00 00 00     lea    rdi,[rip+0xca]       

    107f:    ff 15 53 2f 00 00        call   QWORD PTR [rip+0x2f53]       

    1085:    f4                       hlt   

    1086:    66 2e 0f 1f 84 00 00     cs nop WORD PTR [rax+rax*1+0x0]

    108d:    00 00 00

0000000000001090 <deregister_tm_clones>:

    1090:    48 8d 3d 79 2f 00 00     lea    rdi,[rip+0x2f79]       

    1097:    48 8d 05 72 2f 00 00     lea    rax,[rip+0x2f72]       

    109e:    48 39 f8                 cmp    rax,rdi

    10a1:    74 15                    je     10b8 <deregister_tm_clones+0x28>

    10a3:    48 8b 05 36 2f 00 00     mov    rax,QWORD PTR [rip+0x2f36]       

    10aa:    48 85 c0                 test   rax,rax

    10ad:    74 09                    je     10b8 <deregister_tm_clones+0x28>

    10af:    ff e0                    jmp    rax

    10b1:    0f 1f 80 00 00 00 00     nop    DWORD PTR [rax+0x0]

--

0000000000001149 <main>:

    1149:    f3 0f 1e fa              endbr64

    114d:    55                       push   rbp

    114e:    48 89 e5                 mov    rbp,rsp

    1151:    48 83 ec 10              sub    rsp,0x10

    1155:    c7 45 fc 64 00 00 00     mov    DWORD PTR [rbp-0x4],0x64

    115c:    48 8d 45 fc              lea    rax,[rbp-0x4]

    1160:    48 8d 15 a9 2e 00 00     lea    rdx,[rip+0x2ea9]       

    1167:    48 89 d6                 mov    rsi,rdx

    116a:    48 89 c7                 mov    rdi,rax

    1172:    b8 00 00 00 00           mov    eax,0x0

    1177:    c9                       leave 

    1178:    c3                       ret

可以加载而且无需重定位的代码被称为位置无关代码(PIC),它是共享库必有属性。gcc的-fpic参数可生成PIC。通过pic共享库代码可以被无限多个进程共享,从而节约内从资源。

一个程序的数据段和代码段的相对距离总是保持不变的,因此,指令和变量之间的距离是一个运行时常量,与绝对内存地址无关,因此便有了全局偏移量表。它位于数据段的开头,用于保存全局变量和库函数的引用,每个条目占8个字节,在加载时会进行重定位并填入符号的绝对地址。

为了引入RELRO保护机制,GOT被拆分为.got节和.got.plt节。前者不需延迟绑定,用于保存全局变量引用,加载到内存后被标记为只读;后者需要延迟绑定,用于保存函数引用,具有读写权限。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

func.so:     文件格式 elf64-x86-64

节:

Idx Name          Size      VMA               LMA               File off  Algn

  0 .note.gnu.property 00000020  00000000000002a8  00000000000002a8  000002a8  2**3

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  1 .note.gnu.build-id 00000024  00000000000002c8  00000000000002c8  000002c8  2**2

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  2 .gnu.hash     00000030  00000000000002f0  00000000000002f0  000002f0  2**3

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  3 .dynsym       000000c0  0000000000000320  0000000000000320  00000320  2**3

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  4 .dynstr       00000065  00000000000003e0  00000000000003e0  000003e0  2**0

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  5 .rela.dyn     000000c0  0000000000000448  0000000000000448  00000448  2**3

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  6 .init         0000001b  0000000000001000  0000000000001000  00001000  2**2

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  7 .plt          00000010  0000000000001020  0000000000001020  00001020  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  8 .plt.got      00000010  0000000000001030  0000000000001030  00001030  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  9 .text         000000f6  0000000000001040  0000000000001040  00001040  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

 10 .fini         0000000d  0000000000001138  0000000000001138  00001138  2**2

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

 11 .eh_frame_hdr 00000024  0000000000002000  0000000000002000  00002000  2**2

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

 12 .eh_frame     0000007c  0000000000002028  0000000000002028  00002028  2**3

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

 13 .init_array   00000008  0000000000003e78  0000000000003e78  00002e78  2**3

                  CONTENTS, ALLOC, LOAD, DATA

 14 .fini_array   00000008  0000000000003e80  0000000000003e80  00002e80  2**3

                  CONTENTS, ALLOC, LOAD, DATA

 15 .dynamic      00000150  0000000000003e88  0000000000003e88  00002e88  2**3

                  CONTENTS, ALLOC, LOAD, DATA

 16 .got          00000028  0000000000003fd8  0000000000003fd8  00002fd8  2**3

                  CONTENTS, ALLOC, LOAD, DATA

 17 .got.plt      00000018  0000000000004000  0000000000004000  00003000  2**3

                  CONTENTS, ALLOC, LOAD, DATA

 18 .data         0000000c  0000000000004018  0000000000004018  00003018  2**3

                  CONTENTS, ALLOC, LOAD, DATA

 19 .bss          0000000c  0000000000004024  0000000000004024  00003024  2**2

                  ALLOC

 20 .comment      0000002b  0000000000000000  0000000000000000  00003024  2**0

                  CONTENTS, READONLY

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

00000000000010f9 <func>:

    10f9:    f3 0f 1e fa              endbr64

    10fd:    55                       push   rbp

    10fe:    48 89 e5                 mov    rbp,rsp

    1101:    48 89 7d f8              mov    QWORD PTR [rbp-0x8],rdi

    1105:    48 89 75 f0              mov    QWORD PTR [rbp-0x10],rsi

    1109:    48 8b 45 f8              mov    rax,QWORD PTR [rbp-0x8]

    110d:    8b 10                    mov    edx,DWORD PTR [rax]

    110f:    48 8b 05 c2 2e 00 00     mov    rax,QWORD PTR [rip+0x2ec2]       

    1116:    89 10                    mov    DWORD PTR [rax],edx

    1118:    48 8b 45 f0              mov    rax,QWORD PTR [rbp-0x10]

    111c:    8b 10                    mov    edx,DWORD PTR [rax]

    111e:    48 8b 45 f8              mov    rax,QWORD PTR [rbp-0x8]

    1122:    89 10                    mov    DWORD PTR [rax],edx

    1124:    48 8b 05 ad 2e 00 00     mov    rax,QWORD PTR [rip+0x2ead]       

    112b:    8b 10                    mov    edx,DWORD PTR [rax]

    112d:    48 8b 45 f0              mov    rax,QWORD PTR [rbp-0x10]

    1131:    89 10                    mov    DWORD PTR [rax],edx

    1133:    90                       nop

    1134:    5d                       pop    rbp

    1135:    c3                       ret

可以看到全局变量tmp位于GOT上,R_X86_64_GLOB_DAT表示需要动态链接器找到tmp值并填充到0x3fd8。在func()函数取出tmp时计算符号相对PC的偏移rip+0x2ec2,也就是0x1116+0x2ec2=0x3fd8,同理,0x112b+0x2ead=0x3fd8.

延迟绑定的基本思想是当函数第一次被调用时,动态链接器才进行符号查找,重定位等操作,如果未被调用则不进行绑定。它是为了解决需重定位符号过多影响性能的问题。
ELF文件通过过程链接表(PLT)和GOT配合来实现延迟绑定,每个被调用的库函数都有一组对应的PLT和GOT。位于代码段.plt节的PLT是一个数组,为个条目占16个字节。PLT[0]用于跳转到动态链接器,PLT[1]用于调用系统启动函数_libc_start_main(),我们熟悉的main()函数就是在这里面调用的,从PLT[2]开始就是被调用的各个函数条目。位于数据段的.got.plt节的GOT也是一个数组,每个条目占8字节。其中GOT[0]和GOT[1]包含动态链接器在解析函数地址时所需要的两个地址(.dynamic和relor条目)。GOT[2]是动态链接器(ld-linux.so)的入口点,从GOT[3]开始就是被调用的各个函数条目,这些条目默认指向PLT条目的第二条指令,完成绑定后才会被修改为函数的实际地址。


文章来源: https://bbs.pediy.com/thread-275478.htm
如有侵权请联系:admin#unsafe.sh