赞
踩
对于刚完成的lab2,程序的链接与ELF目标文件实验(linklab),本人认为难度较大,故作为总结复习用。
readelf命令用于查看ELF文件的格式信息,包括linux上的可重定位目标文件(.o)与可执行目标文件
语法:readelf (选项) <文件名>
常用选项:
-h : 显示ELF头,包含文件结构说明信息
- ELF Header:
- Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
- Class: ELF32
- Data: 2's complement, little endian
- Version: 1 (current)
- OS/ABI: UNIX - System V
- ABI Version: 0
- Type: REL (Relocatable file)
- Machine: Intel 80386
- Version: 0x1
- Entry point address: 0x0
- Start of program headers: 0 (bytes into file)
- Start of section headers: 912 (bytes into file)
- Flags: 0x0
- Size of this header: 52 (bytes)
- Size of program headers: 0 (bytes)
- Number of program headers: 0
- Size of section headers: 40 (bytes)
- Number of section headers: 14
- Section header string table index: 13
-S (大写):显示节头表
- There are 14 section headers, starting at offset 0x390:
-
- Section Headers:
- [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
- [ 0] NULL 00000000 000000 000000 00 0 0 0
- [ 1] .text PROGBITS 00000000 000034 000014 00 AX 0 0 1
- [ 2] .rel.text REL 00000000 000304 000010 08 I 11 1 4
- [ 3] .data PROGBITS 00000000 000060 000104 00 WA 0 0 32
- [ 4] .rel.data REL 00000000 000314 000010 08 I 11 3 4
- [ 5] .bss NOBITS 00000000 000164 000000 00 WA 0 0 1
- [ 6] .rodata PROGBITS 00000000 000164 000002 00 A 0 0 1
- [ 7] .comment PROGBITS 00000000 000166 00002e 01 MS 0 0 1
- [ 8] .note.GNU-stack PROGBITS 00000000 000194 000000 00 0 0 1
- [ 9] .eh_frame PROGBITS 00000000 000194 000038 00 A 0 0 4
- [10] .rel.eh_frame REL 00000000 000324 000008 08 I 11 9 4
- [11] .symtab SYMTAB 00000000 0001cc 000100 10 12 12 4
- [12] .strtab STRTAB 00000000 0002cc 000038 00 0 0 1
- [13] .shstrtab STRTAB 00000000 00032c 000063 00 0 0 1
- Key to Flags:
- W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
- L (link order), O (extra OS processing required), G (group), T (TLS),
- C (compressed), x (unknown), o (OS specific), E (exclude),
- D (mbind), p (processor specific)
-s :显示字符串表
- Symbol table '.symtab' contains 16 entries:
- Num: Value Size Type Bind Vis Ndx Name
- 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
- 1: 00000000 0 FILE LOCAL DEFAULT ABS phase1.c
- 2: 00000000 0 SECTION LOCAL DEFAULT 1 .text
- 3: 00000000 0 SECTION LOCAL DEFAULT 3 .data
- 4: 00000000 0 SECTION LOCAL DEFAULT 5 .bss
- 5: 00000000 88 OBJECT LOCAL DEFAULT 3 dBJcwY
- 6: 00000000 0 SECTION LOCAL DEFAULT 6 .rodata
- 7: 00000060 157 OBJECT LOCAL DEFAULT 3 nwufMjQw
- 8: 000000fd 1 OBJECT LOCAL DEFAULT 3 TFddUO
- 9: 00000000 0 SECTION LOCAL DEFAULT 8 .note.GNU-stack
- 10: 00000000 0 SECTION LOCAL DEFAULT 9 .eh_frame
- 11: 00000000 0 SECTION LOCAL DEFAULT 7 .comment
- 12: 00000058 4 OBJECT GLOBAL DEFAULT 3 phase_id
- 13: 00000000 20 FUNC GLOBAL DEFAULT 1 do_phase
- 14: 00000000 0 NOTYPE GLOBAL DEFAULT UND puts
- 15: 00000100 4 OBJECT GLOBAL DEFAULT 3 phase
-r :显示可重定位节的信息
- Relocation section '.rel.text' at offset 0x304 contains 2 entries:
- Offset Info Type Sym.Value Sym. Name
- 00000009 00000301 R_386_32 00000000 .data
- 0000000e 00000e02 R_386_PC32 00000000 puts
-
- Relocation section '.rel.data' at offset 0x314 contains 2 entries:
- Offset Info Type Sym.Value Sym. Name
- 00000058 00000601 R_386_32 00000000 .rodata
- 00000100 00000d01 R_386_32 00000000 do_phase
-
- Relocation section '.rel.eh_frame' at offset 0x324 contains 1 entry:
- Offset Info Type Sym.Value Sym. Name
- 00000020 00000202 R_386_PC32 00000000 .text
-x .data(等其他节) :以16进制方式查看该节信息
- readelf -x .data phase1.o
-
- Hex dump of section '.data':
- NOTE: This section has relocations against it, but these have NOT been applied to this dump.
- 0x00000000 7daa6ec2 8c0412f3 19f1b745 87c7fc5c }.n........E...\
- 0x00000010 760e589d ed8f8520 40f2c570 5eb5a1c2 v.X.... @..p^...
- 0x00000020 9d2e7833 d43fffea 3237a8f6 bda80093 ..x3.?..27......
- 0x00000030 142cc2ee bf8ce45d 8f33df2c 4c940387 .,.....].3.,L...
- 0x00000040 6c227757 85c30922 8eea43d5 e3a4f700 l"wW..."..C.....
- 0x00000050 490b369d c0660c03 00000000 00000000 I.6..f..........
- 0x00000060 6b736d56 32724d46 4c707733 5a614167 ksmV2rMFLpw3ZaAg
- 0x00000070 6e4c5109 737a6f38 71450933 6b56304e nLQ.szo8qE.3kV0N
- 0x00000080 41343747 676e794e 69627a5a 796f4330 A47GgnyNibzZyoC0
- 0x00000090 504b4137 566b4857 6839774b 62413232 PKA7VkHWh9wKbA22
- 0x000000a0 31323230 31353000 50456d71 567a624d 1220150.PEmqVzbM
- 0x000000b0 304f5859 6776566e 66646169 636e6a78 0OXYgvVnfdaicnjx
- 0x000000c0 5647544b 6e69436f 4633746f 7833556d VGTKniCoF3tox3Um
- 0x000000d0 09706157 205a3151 6266674f 37346863 .paW Z1QbfgO74hc
- 0x000000e0 68374b65 69626f66 42513931 39477130 h7KeibofBQ919Gq0
- 0x000000f0 73704d55 5320556e 6e4f4b63 00580000 spMUS UnnOKc.X..
- 0x00000100 00000000 ....
hexedit是用来修改ELF文件的工具
使用: hexedit <elf文件名>
保存:ctrl+x
实验要求:修改二进制可重定位目标文件“phase1.o”的.data 节的内容(注意不允许修改其它节的 内容),使其如下与 main.o 模块链接后运行时输出(且仅输出)学号:
让我们先尝试链接一下查看输出结果:gcc -no-pie -o ph1 main.o phase1.o 然后./ph1
- :~/lab2/mycopy$ gcc -m32 -no-pie -o ph1 main.o phase1.o
- :~/lab2/mycopy$ ./ph1
- 66CsMEpFtPEmqVzbM0OXYgvVnfdaicnjxVGTKniCoF3tox3Um paW Z1QbfgO74hch7KeibofBQ919Gq0spMUS UnnOKc
我们发现输出了一堆乱码,先把这段输出放在一边,让我们分析一下这个文件。
首先先反汇编查看该文件的内容,找到与输出有关的部分。
objdump -d phase1.o > phase1.s
查看.s汇编语言源文件,内容非常简单
- phase1.o: file format elf32-i386
-
- Disassembly of section .text:
-
- 00000000 <do_phase>:
- 0: 55 push %ebp
- 1: 89 e5 mov %esp,%ebp
- 3: 83 ec 18 sub $0x18,%esp
- 6: c7 04 24 9e 00 00 00 movl $0x9e,(%esp)
- d: e8 fc ff ff ff call e <do_phase+0xe>
- 12: c9 leave
- 13: c3 ret
看到call指令的立即数为-4,即下一条指令地址,显然,这里要通过重定位节定位call的函数,让我们查看一下重定位信息:readelf -r phase1.o
- Relocation section '.rel.text' at offset 0x304 contains 2 entries:
- Offset Info Type Sym.Value Sym. Name
- 00000009 00000301 R_386_32 00000000 .data
- 0000000e 00000e02 R_386_PC32 00000000 puts
在.text节的0xe的位置为puts函数,采用R_386_PC32重定位方式。我们发现输出的内容全部来自该puts函数,让我们看看该函数的参数。
在0x6的mov指令为call指令进行了参数准备,在.rel.text节中可以发现从。.text节开始的0x9的位置,引用的了.data节偏移量为0x9e的位置。那么让我们查看一下.data节的内容。
- Hex dump of section '.data':
- NOTE: This section has relocations against it, but these have NOT been applied to this dump.
- 0x00000000 7daa6ec2 8c0412f3 19f1b745 87c7fc5c }.n........E...\
- 0x00000010 760e589d ed8f8520 40f2c570 5eb5a1c2 v.X.... @..p^...
- 0x00000020 9d2e7833 d43fffea 3237a8f6 bda80093 ..x3.?..27......
- 0x00000030 142cc2ee bf8ce45d 8f33df2c 4c940387 .,.....].3.,L...
- 0x00000040 6c227757 85c30922 8eea43d5 e3a4f700 l"wW..."..C.....
- 0x00000050 490b369d c0660c03 00000000 00000000 I.6..f..........
- 0x00000060 6b736d56 32724d46 4c707733 5a614167 ksmV2rMFLpw3ZaAg
- 0x00000070 6e4c5109 737a6f38 71450933 6b56304e nLQ.szo8qE.3kV0N
- 0x00000080 41343747 676e794e 69627a5a 796f4330 A47GgnyNibzZyoC0
- 0x00000090 504b4137 566b4857 6839774b 62412036 PKA7VkHWh9wKbA 6
- 0x000000a0 3643734d 45704674 50456d71 567a624d 6CsMEpFtPEmqVzbM
- 0x000000b0 304f5859 6776566e 66646169 636e6a78 0OXYgvVnfdaicnjx
- 0x000000c0 5647544b 6e69436f 4633746f 7833556d VGTKniCoF3tox3Um
- 0x000000d0 09706157 205a3151 6266674f 37346863 .paW Z1QbfgO74hc
- 0x000000e0 68374b65 69626f66 42513931 39477130 h7KeibofBQ919Gq0
- 0x000000f0 73704d55 5320556e 6e4f4b63 00580000 spMUS UnnOKc.X..
- 0x00000100 00000000 ....
直接定位到.data节偏移量0x9e的位置,我们可以发现对应右边的字符串正好和我们输出的字符串相符合(66CsME……),所以我们已经确定了puts函数参数引用的位置,让我们修改它。
在此之前,我们不仅需要知道字符串在.data节的偏移量,还需要知道.data节在整个可重定位目标文件的偏移量,故查看节头表:
- :~/lab2/mycopy$ readelf -S phase1.o
- There are 14 section headers, starting at offset 0x390:
-
- Section Headers:
- [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
- [ 0] NULL 00000000 000000 000000 00 0 0 0
- [ 1] .text PROGBITS 00000000 000034 000014 00 AX 0 0 1
- [ 2] .rel.text REL 00000000 000304 000010 08 I 11 1 4
- [ 3] .data PROGBITS 00000000 000060 000104 00 WA 0 0 32
- [ 4] .rel.data REL 00000000 000314 000010 08 I 11 3 4
- [ 5] .bss NOBITS 00000000 000164 000000 00 WA 0 0 1
- [ 6] .rodata PROGBITS 00000000 000164 000002 00 A 0 0 1
- [ 7] .comment PROGBITS 00000000 000166 00002e 01 MS 0 0 1
- [ 8] .note.GNU-stack PROGBITS 00000000 000194 000000 00 0 0 1
- [ 9] .eh_frame PROGBITS 00000000 000194 000038 00 A 0 0 4
- [10] .rel.eh_frame REL 00000000 000324 000008 08 I 11 9 4
- [11] .symtab SYMTAB 00000000 0001cc 000100 10 12 12 4
- [12] .strtab STRTAB 00000000 0002cc 000038 00 0 0 1
- [13] .shstrtab STRTAB 00000000 00032c 000063 00 0 0 1
- Key to Flags:
- W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
- L (link order), O (extra OS processing required), G (group), T (TLS),
- C (compressed), x (unknown), o (OS specific), E (exclude),
- 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.o”的.text 节的内容(注意不允许修改其它节的内 容),使其如下与 main.o 模块链接后运行时输出(且仅输出)学号:
查看phase2.o的反汇编结果,可以发现有一个很多nop指令的函数,这就是我们要修改的函数了
- 0000008c <do_phase>:
- 8c: 55 push %ebp
- 8d: 89 e5 mov %esp,%ebp
- 8f: 90 nop
- 90: 90 nop
- ......
- ce: 90 nop
- cf: 5d pop %ebp
- d0: c3 ret
先将这里搁置一下,查看一下链接后的反汇编代码
这是链接后的main函数
- 08049196 <main>:
- 8049196: 55 push %ebp
- 8049197: 89 e5 mov %esp,%ebp
- 8049199: 83 e4 f0 and $0xfffffff0,%esp
- 804919c: 83 ec 10 sub $0x10,%esp
- 804919f: a1 28 c0 04 08 mov 0x804c028,%eax
- 80491a4: 85 c0 test %eax,%eax
- 80491a6: 74 09 je 80491b1 <main+0x1b>
- 80491a8: a1 28 c0 04 08 mov 0x804c028,%eax
- 80491ad: ff d0 call *%eax
- 80491af: eb 0c jmp 80491bd <main+0x27>
- 80491b1: c7 04 24 c0 a0 04 08 movl $0x804a0c0,(%esp)
- 80491b8: e8 a3 fe ff ff call 8049060 <puts@plt>
- 80491bd: b8 00 00 00 00 mov $0x0,%eax
- 80491c2: c9 leave
- 80491c3: c3 ret
通过gdb调试,我们可以发现main函数调用了do_phase函数,然后直接跳转到80491b8结束程序,而直接运行的话由于do_phase中都为nop,故什么都不会打印。
看到这里,对jmp跳过的第二个call puts产生好奇,让我们使用gdb看看如果执行到这里,puts的是什么,即0x804a0c0下是什么内容:
- (gdb) si
- 0x08049250 in do_phase ()
- (gdb) x/s 0x804a0c0
- 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有直接关系的函数,直接查看重定位节内容:
- Relocation section '.rel.text' at offset 0x314 contains 4 entries:
- Offset Info Type Sym.Value Sym. Name
- 00000037 00000c02 R_386_PC32 00000000 strlen
- 0000006a 00000501 R_386_32 00000000 .rodata
- 00000075 00000d02 R_386_PC32 00000000 strcmp
- 00000086 00000e02 R_386_PC32 00000000 puts
在offset=0x86处重定位了函数puts,让我们查看该位置,位于<KUksJIfx>函数中:
- 00000060 <KUksJIfx>:
- 60: 55 push %ebp
- 61: 89 e5 mov %esp,%ebp
- 63: 83 ec 18 sub $0x18,%esp
- 66: c7 44 24 04 02 00 00 movl $0x2,0x4(%esp)
- 6d: 00
- 6e: 8b 45 08 mov 0x8(%ebp),%eax
- 71: 89 04 24 mov %eax,(%esp)
- 74: e8 fc ff ff ff call 75 <KUksJIfx+0x15>
- 79: 85 c0 test %eax,%eax
- 7b: 74 02 je 7f <KUksJIfx+0x1f>
- 7d: eb 0b jmp 8a <KUksJIfx+0x2a>
- 7f: 8b 45 0c mov 0xc(%ebp),%eax
- 82: 89 04 24 mov %eax,(%esp)
- 85: e8 fc ff ff ff call 86 <KUksJIfx+0x26>
- 8a: c9 leave
- 8b: c3 ret
通过分析与重定位,这个函数接受两个参数,第一个参数传入在调用strcmp函数,若比对相同,才会执行puts,puts打印第二个参数。
strcmp的第一个参数是什么?实际上是0x6a处重定位的结果,即.rodata节偏移量为0x2的位置。
(寻找该字符串过程如上题,略过)
所以我们在do_phase中调用这个函数,参数准备时参数1为.rodata节中的字符串,参数2为学号,先新建一个.s文件写入如下汇编代码
- sub $0x28,%esp
- movl $0x735a7464,-0x10(%ebp)
- movl $0x544646,-0xc(%ebp)
- movl $0x32313232,-0x1a(%ebp)
- movl $0x35313032,-0x16(%ebp)
- movw $0x30,-0x12(%ebp)
- sub $0x8,%esp
- lea -0x1a(%ebp),%eax
- movl %eax,0x4(%esp)
- lea -0x10(%ebp),%eax
- movl %eax,(%esp)
- call 0x00
- mov %ebp,%esp
汇编成可重定位目标文件后反汇编
- Disassembly of section .text:
-
- 0000000000000000 <.text>:
- 0: 83 ec 28 sub $0x28,%esp
- 3: c7 45 f0 64 74 5a movl $0x735a7464,-0x10(%ebp)
- a: 73
- b: c7 45 f4 46 46 54 movl $0x544646,-0xc(%ebp)
- 12: 00
- 13: c7 45 e6 32 32 31 movl $0x32313232,-0x1a(%ebp)
- 1a: 32
- 1b: c7 45 ea 32 30 31 movl $0x35313032,-0x16(%ebp)
- 22: 35
- 23: c7 45 ee 30 00 movw $0x30,-0x12(%ebp)
- 2a: 83 ec 08 sub $0x8,%esp
- 2d: 8d 45 e6 lea -0x1a(%ebp),%eax
- 31: 89 44 24 04 mov %eax,0x4(%esp)
- 36: 8d 45 f0 lea -0x10(%ebp),%eax
- 3a: 89 04 24 mov %eax,(%esp)
- 3e: e8 00 00 00 00 call 0x43
- 43: 89 ec mov %ebp,%esp
(这里用错成64位汇编,删除了一些长度编码,故偏移量与实际不符)
照着填入phase2.o的相应函数位置即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。