当前位置:   article > 正文

程序的链接与ELF目标文件实验(1)_elf文件与程序链接实验

elf文件与程序链接实验

对于刚完成的lab2,程序的链接与ELF目标文件实验(linklab),本人认为难度较大,故作为总结复习用。

实验知识准备 

readelf指令:

readelf命令用于查看ELF文件的格式信息,包括linux上的可重定位目标文件(.o)与可执行目标文件

语法:readelf (选项)  <文件名>

常用选项: 

-h : 显示ELF头,包含文件结构说明信息

  1. ELF Header:
  2. Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  3. Class: ELF32
  4. Data: 2's complement, little endian
  5. Version: 1 (current)
  6. OS/ABI: UNIX - System V
  7. ABI Version: 0
  8. Type: REL (Relocatable file)
  9. Machine: Intel 80386
  10. Version: 0x1
  11. Entry point address: 0x0
  12. Start of program headers: 0 (bytes into file)
  13. Start of section headers: 912 (bytes into file)
  14. Flags: 0x0
  15. Size of this header: 52 (bytes)
  16. Size of program headers: 0 (bytes)
  17. Number of program headers: 0
  18. Size of section headers: 40 (bytes)
  19. Number of section headers: 14
  20. Section header string table index: 13

-S (大写):显示节头表

  1. There are 14 section headers, starting at offset 0x390:
  2. Section Headers:
  3. [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
  4. [ 0] NULL 00000000 000000 000000 00 0 0 0
  5. [ 1] .text PROGBITS 00000000 000034 000014 00 AX 0 0 1
  6. [ 2] .rel.text REL 00000000 000304 000010 08 I 11 1 4
  7. [ 3] .data PROGBITS 00000000 000060 000104 00 WA 0 0 32
  8. [ 4] .rel.data REL 00000000 000314 000010 08 I 11 3 4
  9. [ 5] .bss NOBITS 00000000 000164 000000 00 WA 0 0 1
  10. [ 6] .rodata PROGBITS 00000000 000164 000002 00 A 0 0 1
  11. [ 7] .comment PROGBITS 00000000 000166 00002e 01 MS 0 0 1
  12. [ 8] .note.GNU-stack PROGBITS 00000000 000194 000000 00 0 0 1
  13. [ 9] .eh_frame PROGBITS 00000000 000194 000038 00 A 0 0 4
  14. [10] .rel.eh_frame REL 00000000 000324 000008 08 I 11 9 4
  15. [11] .symtab SYMTAB 00000000 0001cc 000100 10 12 12 4
  16. [12] .strtab STRTAB 00000000 0002cc 000038 00 0 0 1
  17. [13] .shstrtab STRTAB 00000000 00032c 000063 00 0 0 1
  18. Key to Flags:
  19. W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  20. L (link order), O (extra OS processing required), G (group), T (TLS),
  21. C (compressed), x (unknown), o (OS specific), E (exclude),
  22. D (mbind), p (processor specific)

-s :显示字符串表

  1. Symbol table '.symtab' contains 16 entries:
  2. Num: Value Size Type Bind Vis Ndx Name
  3. 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
  4. 1: 00000000 0 FILE LOCAL DEFAULT ABS phase1.c
  5. 2: 00000000 0 SECTION LOCAL DEFAULT 1 .text
  6. 3: 00000000 0 SECTION LOCAL DEFAULT 3 .data
  7. 4: 00000000 0 SECTION LOCAL DEFAULT 5 .bss
  8. 5: 00000000 88 OBJECT LOCAL DEFAULT 3 dBJcwY
  9. 6: 00000000 0 SECTION LOCAL DEFAULT 6 .rodata
  10. 7: 00000060 157 OBJECT LOCAL DEFAULT 3 nwufMjQw
  11. 8: 000000fd 1 OBJECT LOCAL DEFAULT 3 TFddUO
  12. 9: 00000000 0 SECTION LOCAL DEFAULT 8 .note.GNU-stack
  13. 10: 00000000 0 SECTION LOCAL DEFAULT 9 .eh_frame
  14. 11: 00000000 0 SECTION LOCAL DEFAULT 7 .comment
  15. 12: 00000058 4 OBJECT GLOBAL DEFAULT 3 phase_id
  16. 13: 00000000 20 FUNC GLOBAL DEFAULT 1 do_phase
  17. 14: 00000000 0 NOTYPE GLOBAL DEFAULT UND puts
  18. 15: 00000100 4 OBJECT GLOBAL DEFAULT 3 phase

-r :显示可重定位节的信息

  1. Relocation section '.rel.text' at offset 0x304 contains 2 entries:
  2. Offset Info Type Sym.Value Sym. Name
  3. 00000009 00000301 R_386_32 00000000 .data
  4. 0000000e 00000e02 R_386_PC32 00000000 puts
  5. Relocation section '.rel.data' at offset 0x314 contains 2 entries:
  6. Offset Info Type Sym.Value Sym. Name
  7. 00000058 00000601 R_386_32 00000000 .rodata
  8. 00000100 00000d01 R_386_32 00000000 do_phase
  9. Relocation section '.rel.eh_frame' at offset 0x324 contains 1 entry:
  10. Offset Info Type Sym.Value Sym. Name
  11. 00000020 00000202 R_386_PC32 00000000 .text

-x .data(等其他节) :以16进制方式查看该节信息

  1. readelf -x .data phase1.o
  2. Hex dump of section '.data':
  3. NOTE: This section has relocations against it, but these have NOT been applied to this dump.
  4. 0x00000000 7daa6ec2 8c0412f3 19f1b745 87c7fc5c }.n........E...\
  5. 0x00000010 760e589d ed8f8520 40f2c570 5eb5a1c2 v.X.... @..p^...
  6. 0x00000020 9d2e7833 d43fffea 3237a8f6 bda80093 ..x3.?..27......
  7. 0x00000030 142cc2ee bf8ce45d 8f33df2c 4c940387 .,.....].3.,L...
  8. 0x00000040 6c227757 85c30922 8eea43d5 e3a4f700 l"wW..."..C.....
  9. 0x00000050 490b369d c0660c03 00000000 00000000 I.6..f..........
  10. 0x00000060 6b736d56 32724d46 4c707733 5a614167 ksmV2rMFLpw3ZaAg
  11. 0x00000070 6e4c5109 737a6f38 71450933 6b56304e nLQ.szo8qE.3kV0N
  12. 0x00000080 41343747 676e794e 69627a5a 796f4330 A47GgnyNibzZyoC0
  13. 0x00000090 504b4137 566b4857 6839774b 62413232 PKA7VkHWh9wKbA22
  14. 0x000000a0 31323230 31353000 50456d71 567a624d 1220150.PEmqVzbM
  15. 0x000000b0 304f5859 6776566e 66646169 636e6a78 0OXYgvVnfdaicnjx
  16. 0x000000c0 5647544b 6e69436f 4633746f 7833556d VGTKniCoF3tox3Um
  17. 0x000000d0 09706157 205a3151 6266674f 37346863 .paW Z1QbfgO74hc
  18. 0x000000e0 68374b65 69626f66 42513931 39477130 h7KeibofBQ919Gq0
  19. 0x000000f0 73704d55 5320556e 6e4f4b63 00580000 spMUS UnnOKc.X..
  20. 0x00000100 00000000 ....

hexedit工具:

hexedit是用来修改ELF文件的工具

使用: hexedit <elf文件名>

保存:ctrl+x

phase1. 静态数据对象与 ELF 数据节

实验要求:修改二进制可重定位目标文件“phase1.o”的.data 节的内容(注意不允许修改其它节的 内容),使其如下与 main.o 模块链接后运行时输出(且仅输出)学号:

让我们先尝试链接一下查看输出结果:gcc -no-pie -o ph1 main.o phase1.o  然后./ph1

  1. :~/lab2/mycopy$ gcc -m32 -no-pie -o ph1 main.o phase1.o
  2. :~/lab2/mycopy$ ./ph1
  3. 66CsMEpFtPEmqVzbM0OXYgvVnfdaicnjxVGTKniCoF3tox3Um paW Z1QbfgO74hch7KeibofBQ919Gq0spMUS UnnOKc

我们发现输出了一堆乱码,先把这段输出放在一边,让我们分析一下这个文件。

首先先反汇编查看该文件的内容,找到与输出有关的部分。

objdump -d phase1.o > phase1.s 

查看.s汇编语言源文件,内容非常简单

  1. phase1.o: file format elf32-i386
  2. Disassembly of section .text:
  3. 00000000 <do_phase>:
  4. 0: 55 push %ebp
  5. 1: 89 e5 mov %esp,%ebp
  6. 3: 83 ec 18 sub $0x18,%esp
  7. 6: c7 04 24 9e 00 00 00 movl $0x9e,(%esp)
  8. d: e8 fc ff ff ff call e <do_phase+0xe>
  9. 12: c9 leave
  10. 13: c3 ret

看到call指令的立即数为-4,即下一条指令地址,显然,这里要通过重定位节定位call的函数,让我们查看一下重定位信息:readelf -r phase1.o

  1. Relocation section '.rel.text' at offset 0x304 contains 2 entries:
  2. Offset Info Type Sym.Value Sym. Name
  3. 00000009 00000301 R_386_32 00000000 .data
  4. 0000000e 00000e02 R_386_PC32 00000000 puts

在.text节的0xe的位置为puts函数,采用R_386_PC32重定位方式。我们发现输出的内容全部来自该puts函数,让我们看看该函数的参数。

在0x6的mov指令为call指令进行了参数准备,在.rel.text节中可以发现从。.text节开始的0x9的位置,引用的了.data节偏移量为0x9e的位置。那么让我们查看一下.data节的内容。

  1. Hex dump of section '.data':
  2. NOTE: This section has relocations against it, but these have NOT been applied to this dump.
  3. 0x00000000 7daa6ec2 8c0412f3 19f1b745 87c7fc5c }.n........E...\
  4. 0x00000010 760e589d ed8f8520 40f2c570 5eb5a1c2 v.X.... @..p^...
  5. 0x00000020 9d2e7833 d43fffea 3237a8f6 bda80093 ..x3.?..27......
  6. 0x00000030 142cc2ee bf8ce45d 8f33df2c 4c940387 .,.....].3.,L...
  7. 0x00000040 6c227757 85c30922 8eea43d5 e3a4f700 l"wW..."..C.....
  8. 0x00000050 490b369d c0660c03 00000000 00000000 I.6..f..........
  9. 0x00000060 6b736d56 32724d46 4c707733 5a614167 ksmV2rMFLpw3ZaAg
  10. 0x00000070 6e4c5109 737a6f38 71450933 6b56304e nLQ.szo8qE.3kV0N
  11. 0x00000080 41343747 676e794e 69627a5a 796f4330 A47GgnyNibzZyoC0
  12. 0x00000090 504b4137 566b4857 6839774b 62412036 PKA7VkHWh9wKbA 6
  13. 0x000000a0 3643734d 45704674 50456d71 567a624d 6CsMEpFtPEmqVzbM
  14. 0x000000b0 304f5859 6776566e 66646169 636e6a78 0OXYgvVnfdaicnjx
  15. 0x000000c0 5647544b 6e69436f 4633746f 7833556d VGTKniCoF3tox3Um
  16. 0x000000d0 09706157 205a3151 6266674f 37346863 .paW Z1QbfgO74hc
  17. 0x000000e0 68374b65 69626f66 42513931 39477130 h7KeibofBQ919Gq0
  18. 0x000000f0 73704d55 5320556e 6e4f4b63 00580000 spMUS UnnOKc.X..
  19. 0x00000100 00000000 ....

直接定位到.data节偏移量0x9e的位置,我们可以发现对应右边的字符串正好和我们输出的字符串相符合(66CsME……),所以我们已经确定了puts函数参数引用的位置,让我们修改它。

在此之前,我们不仅需要知道字符串在.data节的偏移量,还需要知道.data节在整个可重定位目标文件的偏移量,故查看节头表:

  1. :~/lab2/mycopy$ readelf -S phase1.o
  2. There are 14 section headers, starting at offset 0x390:
  3. Section Headers:
  4. [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
  5. [ 0] NULL 00000000 000000 000000 00 0 0 0
  6. [ 1] .text PROGBITS 00000000 000034 000014 00 AX 0 0 1
  7. [ 2] .rel.text REL 00000000 000304 000010 08 I 11 1 4
  8. [ 3] .data PROGBITS 00000000 000060 000104 00 WA 0 0 32
  9. [ 4] .rel.data REL 00000000 000314 000010 08 I 11 3 4
  10. [ 5] .bss NOBITS 00000000 000164 000000 00 WA 0 0 1
  11. [ 6] .rodata PROGBITS 00000000 000164 000002 00 A 0 0 1
  12. [ 7] .comment PROGBITS 00000000 000166 00002e 01 MS 0 0 1
  13. [ 8] .note.GNU-stack PROGBITS 00000000 000194 000000 00 0 0 1
  14. [ 9] .eh_frame PROGBITS 00000000 000194 000038 00 A 0 0 4
  15. [10] .rel.eh_frame REL 00000000 000324 000008 08 I 11 9 4
  16. [11] .symtab SYMTAB 00000000 0001cc 000100 10 12 12 4
  17. [12] .strtab STRTAB 00000000 0002cc 000038 00 0 0 1
  18. [13] .shstrtab STRTAB 00000000 00032c 000063 00 0 0 1
  19. Key to Flags:
  20. W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  21. L (link order), O (extra OS processing required), G (group), T (TLS),
  22. C (compressed), x (unknown), o (OS specific), E (exclude),
  23. D (mbind), p (processor specific)

.data节在elf文件中的offset为0x60,故我们修改的字符串在elf文件总偏移量为0x60+0x9e=0xfe,使用hexedit查看该文件

确实如此,成功找到了该字符串位置,接下来直接将该位置编辑成32 32 x x x x x x x 00(学号+00)即可

phase2. 指令与 ELF 代码节

实验要求:修改二进制可重定位目标文件“phase2.o”的.text 节的内容(注意不允许修改其它节的内 容),使其如下与 main.o 模块链接后运行时输出(且仅输出)学号:

查看phase2.o的反汇编结果,可以发现有一个很多nop指令的函数,这就是我们要修改的函数了

  1. 0000008c <do_phase>:
  2. 8c: 55 push %ebp
  3. 8d: 89 e5 mov %esp,%ebp
  4. 8f: 90 nop
  5. 90: 90 nop
  6. ......
  7. ce: 90 nop
  8. cf: 5d pop %ebp
  9. d0: c3 ret

先将这里搁置一下,查看一下链接后的反汇编代码

这是链接后的main函数

  1. 08049196 <main>:
  2. 8049196: 55 push %ebp
  3. 8049197: 89 e5 mov %esp,%ebp
  4. 8049199: 83 e4 f0 and $0xfffffff0,%esp
  5. 804919c: 83 ec 10 sub $0x10,%esp
  6. 804919f: a1 28 c0 04 08 mov 0x804c028,%eax
  7. 80491a4: 85 c0 test %eax,%eax
  8. 80491a6: 74 09 je 80491b1 <main+0x1b>
  9. 80491a8: a1 28 c0 04 08 mov 0x804c028,%eax
  10. 80491ad: ff d0 call *%eax
  11. 80491af: eb 0c jmp 80491bd <main+0x27>
  12. 80491b1: c7 04 24 c0 a0 04 08 movl $0x804a0c0,(%esp)
  13. 80491b8: e8 a3 fe ff ff call 8049060 <puts@plt>
  14. 80491bd: b8 00 00 00 00 mov $0x0,%eax
  15. 80491c2: c9 leave
  16. 80491c3: c3 ret

通过gdb调试,我们可以发现main函数调用了do_phase函数,然后直接跳转到80491b8结束程序,而直接运行的话由于do_phase中都为nop,故什么都不会打印。

看到这里,对jmp跳过的第二个call puts产生好奇,让我们使用gdb看看如果执行到这里,puts的是什么,即0x804a0c0下是什么内容:

  1. (gdb) si
  2. 0x08049250 in do_phase ()
  3. (gdb) x/s 0x804a0c0
  4. 0x804a0c0: "Welcome to this small lab of linking. To begin lab, please link the relevant object module(s) with the main module."

是个与我们的目标完全无关的内容,虽然可以通过缓冲区溢出的方式将上一个调用do_phase地方的栈帧破坏,被迫执行下面的puts函数并将学号留在栈中,但是此方法对我个人的分析能力比较考验,也与本次实验的考察内容不符,涉及lab3(?)的内容。所以我们就要从phase2.s  .text节的另外两个函数入手,查看这两个函数的作用。

这两个函数都各有两次的重定位记录,我们需要找到与puts有直接关系的函数,直接查看重定位节内容:

  1. Relocation section '.rel.text' at offset 0x314 contains 4 entries:
  2. Offset Info Type Sym.Value Sym. Name
  3. 00000037 00000c02 R_386_PC32 00000000 strlen
  4. 0000006a 00000501 R_386_32 00000000 .rodata
  5. 00000075 00000d02 R_386_PC32 00000000 strcmp
  6. 00000086 00000e02 R_386_PC32 00000000 puts

在offset=0x86处重定位了函数puts,让我们查看该位置,位于<KUksJIfx>函数中:

  1. 00000060 <KUksJIfx>:
  2. 60: 55 push %ebp
  3. 61: 89 e5 mov %esp,%ebp
  4. 63: 83 ec 18 sub $0x18,%esp
  5. 66: c7 44 24 04 02 00 00 movl $0x2,0x4(%esp)
  6. 6d: 00
  7. 6e: 8b 45 08 mov 0x8(%ebp),%eax
  8. 71: 89 04 24 mov %eax,(%esp)
  9. 74: e8 fc ff ff ff call 75 <KUksJIfx+0x15>
  10. 79: 85 c0 test %eax,%eax
  11. 7b: 74 02 je 7f <KUksJIfx+0x1f>
  12. 7d: eb 0b jmp 8a <KUksJIfx+0x2a>
  13. 7f: 8b 45 0c mov 0xc(%ebp),%eax
  14. 82: 89 04 24 mov %eax,(%esp)
  15. 85: e8 fc ff ff ff call 86 <KUksJIfx+0x26>
  16. 8a: c9 leave
  17. 8b: c3 ret

通过分析与重定位,这个函数接受两个参数,第一个参数传入在调用strcmp函数,若比对相同,才会执行puts,puts打印第二个参数。

strcmp的第一个参数是什么?实际上是0x6a处重定位的结果,即.rodata节偏移量为0x2的位置。

(寻找该字符串过程如上题,略过)

所以我们在do_phase中调用这个函数,参数准备时参数1为.rodata节中的字符串,参数2为学号,先新建一个.s文件写入如下汇编代码

  1. sub $0x28,%esp
  2. movl $0x735a7464,-0x10(%ebp)
  3. movl $0x544646,-0xc(%ebp)
  4. movl $0x32313232,-0x1a(%ebp)
  5. movl $0x35313032,-0x16(%ebp)
  6. movw $0x30,-0x12(%ebp)
  7. sub $0x8,%esp
  8. lea -0x1a(%ebp),%eax
  9. movl %eax,0x4(%esp)
  10. lea -0x10(%ebp),%eax
  11. movl %eax,(%esp)
  12. call 0x00
  13. mov %ebp,%esp

汇编成可重定位目标文件后反汇编

  1. Disassembly of section .text:
  2. 0000000000000000 <.text>:
  3. 0: 83 ec 28 sub $0x28,%esp
  4. 3: c7 45 f0 64 74 5a movl $0x735a7464,-0x10(%ebp)
  5. a: 73
  6. b: c7 45 f4 46 46 54 movl $0x544646,-0xc(%ebp)
  7. 12: 00
  8. 13: c7 45 e6 32 32 31 movl $0x32313232,-0x1a(%ebp)
  9. 1a: 32
  10. 1b: c7 45 ea 32 30 31 movl $0x35313032,-0x16(%ebp)
  11. 22: 35
  12. 23: c7 45 ee 30 00 movw $0x30,-0x12(%ebp)
  13. 2a: 83 ec 08 sub $0x8,%esp
  14. 2d: 8d 45 e6 lea -0x1a(%ebp),%eax
  15. 31: 89 44 24 04 mov %eax,0x4(%esp)
  16. 36: 8d 45 f0 lea -0x10(%ebp),%eax
  17. 3a: 89 04 24 mov %eax,(%esp)
  18. 3e: e8 00 00 00 00 call 0x43
  19. 43: 89 ec mov %ebp,%esp

(这里用错成64位汇编,删除了一些长度编码,故偏移量与实际不符)

照着填入phase2.o的相应函数位置即可。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/849260
推荐阅读
相关标签
  

闽ICP备14008679号