该 Lab 的附加材料会在文后提供下载。
Linklab 的主要作用就是帮助我们理解 ELF 文件格式的链接等操作,顺便复习一下之前学习的汇编知识。此次实验给我们提供了一个 main.o 以及五个phasex.o 文件。我们在每一阶段需要做的就是把 main.o 以及 phasex.o 文件链接起来,然后完成要求的输出。
Phase 1
本阶段要求我们通过修改 phase1.o 中的 .rodata 字段,来实现修改输出为学号的目标。难度极小,为热身活动。
首先我们直接进行链接操作,查看结果:
name1e5s@ubuntu:~/ll$ ./1
fZGFY ZYzVwwqe1HLlPI0uiWm24xVn1pFMpwVVOa5BIeIQW6ih7xbEeJ kCz2qNa7XQo4 2DA3yYVeA3hfqF6AtTRvWK64r9KRROgH9Qmt7bNgrO
然后在 .data 字段查找这段乱码:
00000080: 5a66 5a47 4659 205a 597a 5677 7771 6531 ZfZGFY ZYzVwwqe1
00000090: 484c 6c50 4930 7569 576d 3234 7856 6e31 HLlPI0uiWm24xVn1
000000a0: 7046 4d70 7756 564f 6135 4249 6549 5157 pFMpwVVOa5BIeIQW
000000b0: 3669 6837 7862 4565 4a09 6b43 7a32 714e 6ih7xbEeJ.kCz2qN
000000c0: 6137 5851 6f34 0932 4441 3379 5956 6541 a7XQo4.2DA3yYVeA
000000d0: 3368 6671 4636 4174 5452 7657 4b36 3472 3hfqF6AtTRvWK64r
000000e0: 394b 5252 4f67 4839 516d 7437 624e 6772 9KRROgH9Qmt7bNgr
000000f0: 4f00 0000 0000 0000 0047 4343 3a20 2855 O........GCC: (U
显然这段就是我们需要修改的部分,我们只需要将此修改为我们的学号即可。修改如下(假设笔者的学号为0000000000):
00000080: 3030 3030 3030 3030 3030 3030 0071 6531 0000000000.Vwwqe1
00000090: 484c 6c50 4930 7569 576d 3234 7856 6e31 HLlPI0uiWm24xVn1
之后链接运行,即可得到结果:
name1e5s@ubuntu:~/ll$ ./1
0000000000
Phase 2
本阶段,我们的目标仍是输出我们的学号,与上次不同的是,此次我们的学号已经预先存储在phase2.o 的 .rodata 字段,我们需要做的是补全 do_phase 函数,并修改相关内容,是指能够输出我们的学号。
首先进行反汇编:
name1e5s@ubuntu:~/ll$ objdump -d phase2.o
phase2.o: file format elf32-i386
Disassembly of section .text:
00000000 <ThbYPvDz>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 08 sub $0x8,%esp
6: 83 ec 08 sub $0x8,%esp
9: 68 00 00 00 00 push $0x0
e: ff 75 08 pushl 0x8(%ebp)
11: e8 fc ff ff ff call 12 <ThbYPvDz+0x12>
16: 83 c4 10 add $0x10,%esp
19: 85 c0 test %eax,%eax
1b: 75 10 jne 2d <ThbYPvDz+0x2d>
1d: 83 ec 0c sub $0xc,%esp
20: ff 75 08 pushl 0x8(%ebp)
23: e8 fc ff ff ff call 24 <ThbYPvDz+0x24>
28: 83 c4 10 add $0x10,%esp
2b: eb 01 jmp 2e <ThbYPvDz+0x2e>
2d: 90 nop
2e: c9 leave
2f: c3 ret
00000030 <do_phase>:
30: 55 push %ebp
31: 89 e5 mov %esp,%ebp
33: 90 nop
34: 90 nop
35: 90 nop
36: 90 nop
37: 90 nop
38: 90 nop
39: 90 nop
3a: 90 nop
3b: 90 nop
3c: 90 nop
3d: 90 nop
3e: 90 nop
3f: 90 nop
40: 90 nop
41: 90 nop
42: 90 nop
43: 90 nop
44: 90 nop
45: 90 nop
46: 90 nop
47: 90 nop
48: 90 nop
49: 90 nop
4a: 90 nop
4b: 90 nop
4c: 90 nop
4d: 90 nop
4e: 90 nop
4f: 90 nop
50: 90 nop
51: 90 nop
52: 90 nop
53: 90 nop
54: 5d pop %ebp
55: c3 ret
我们要做的就是修改这些 nop 指令为我们自己的指令。上面那个乱码函数给了我们很好的示范,因此我们只需修改为如下即可:
$ objdump -d phase2.o
phase2.o: file format elf32-i386
Disassembly of section .text:
00000000 <ThbYPvDz>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 08 sub $0x8,%esp
6: 83 ec 08 sub $0x8,%esp
9: 68 00 00 00 00 push $0x0
e: ff 75 08 pushl 0x8(%ebp)
11: e8 fc ff ff ff call 12 <ThbYPvDz+0x12>
16: 83 c4 10 add $0x10,%esp
19: 85 c0 test %eax,%eax
1b: 75 10 jne 2d <ThbYPvDz+0x2d>
1d: 83 ec 0c sub $0xc,%esp
20: ff 75 08 pushl 0x8(%ebp)
23: e8 fc ff ff ff call 24 <ThbYPvDz+0x24>
28: 83 c4 10 add $0x10,%esp
2b: eb 01 jmp 2e <ThbYPvDz+0x2e>
2d: 90 nop
2e: c9 leave
2f: c3 ret
00000030 <do_phase>:
30: 55 push %ebp
31: 89 e5 mov %esp,%ebp
33: 83 ec 10 sub $0x10,%esp
36: 68 00 00 00 00 push $0x0
3b: e8 fc ff ff ff call 3c <do_phase+0xc>
40: 83 c4 10 add $0x10,%esp
43: 90 nop
44: 90 nop
45: 90 nop
46: 90 nop
47: 90 nop
48: 90 nop
49: 90 nop
4a: 90 nop
4b: 90 nop
4c: 90 nop
4d: 90 nop
4e: 90 nop
4f: 90 nop
50: 90 nop
51: 90 nop
52: 90 nop
53: 90 nop
54: c9 leave
55: c3 ret
之后修改重定位规则,使得链接器重定位的是我们的代码,而非上面的乱码函数的代码。定位.rel.text字段以及其内容:
name1e5s@ubuntu:~/ll$ readelf -r phase2.o
Relocation section '.rel.text' at offset 0x22c contains 3 entries:
Offset Info Type Sym.Value Sym. Name
0000000a 00000501 R_386_32 00000000 .rodata
00000012 00000a02 R_386_PC32 00000000 strcmp
00000024 00000b02 R_386_PC32 00000000 puts
Relocation section '.rel.data' at offset 0x244 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
00000000 00000c01 R_386_32 00000030 do_phase
Relocation section '.rel.eh_frame' at offset 0x24c contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000020 00000202 R_386_PC32 00000000 .text
00000040 00000202 R_386_PC32 00000000 .text
name1e5s@ubuntu:~/ll$ readelf -S phase2.o
There are 14 section headers, starting at offset 0x2c0:
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 000056 00 AX 0 0 1
[ 2] .rel.text REL 00000000 00022c 000018 08 I 12 1 4
[ 3] .data PROGBITS 00000000 00008c 000004 00 WA 0 0 4
[ 4] .rel.data REL 00000000 000244 000008 08 I 12 3 4
[ 5] .bss NOBITS 00000000 000090 000000 00 WA 0 0 1
[ 6] .rodata PROGBITS 00000000 000090 00000b 00 A 0 0 1
[ 7] .comment PROGBITS 00000000 00009b 00002e 01 MS 0 0 1
[ 8] .note.GNU-stack PROGBITS 00000000 0000c9 000000 00 0 0 1
[ 9] .eh_frame PROGBITS 00000000 0000cc 000058 00 A 0 0 4
[10] .rel.eh_frame REL 00000000 00024c 000010 08 I 12 9 4
[11] .shstrtab STRTAB 00000000 00025c 000063 00 0 0 1
[12] .symtab SYMTAB 00000000 000124 0000e0 10 13 10 4
[13] .strtab STRTAB 00000000 000204 000028 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),
p (processor specific)
找到目标后进行修改,因为我们只是用到了 puts 函数以及 .rodata 的位置,因此我们直接修改这两处的位置即可,修改后结果如下:
name1e5s@ubuntu:~/linklab$ readelf -r phase2.o
Relocation section '.rel.text' at offset 0x22c contains 3 entries:
Offset Info Type Sym.Value Sym. Name
00000037 00000501 R_386_32 00000000 .rodata
00000012 00000a02 R_386_PC32 00000000 strcmp
0000003c 00000b02 R_386_PC32 00000000 puts
Relocation section '.rel.data' at offset 0x244 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
00000000 00000c01 R_386_32 00000030 do_phase
Relocation section '.rel.eh_frame' at offset 0x24c contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000020 00000202 R_386_PC32 00000000 .text
00000040 00000202 R_386_PC32 00000000 .text
name1e5s@ubuntu:~/linklab$ ./2
0000000000
可以看到,我们的代码已经被正确地重定位,并完美的执行。
Phase_3
这个实验,我们还是得输出自己的学号,不过这次是利用 ELF 文件链接时候的强弱规则进行输出。我们先说些什么是强弱规则。
针对强弱符号的概念,链接器就会按如下规则处理与选择被多次定义的全局符号:
· 规则1:不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号);如果有多个强符号定义,则链接器报符号重复定义错误。
· 规则2:如果一个符号在某个目标文件中是强符号,在其他文件中都是弱符号,那么选择强符号。
· 规则3:如果一个符号在所有目标文件中都是弱符号,那么选择其中占用空间最大的一个。比如目标文件A定义全局变量global为int型,占4个字节;目标文件B定义global为double型,占8个字节,那么目标文件A和B链接后,符号global占8个字节(尽量不要使用多个不同类型的弱符号,否则容易导致很难发现的程序错误)。
说完规则我们来看这个实验。利用 nm 指令,我们可以看到文件中的符号定义:
name1e5s@ubuntu:~/linklab$ nm phase3.o
00000000 T do_phase
00000100 C lOXXBDHjiI
00000000 D phase
U putchar
U __stack_chk_fail
在结合 readelf 的输出结果不难发现该文件中有一命名为 lOXXBDHjiI 的长度为256的字符串没有定义为强符号。既然如此,我们就先写如下 C 文件与之链接:
char lOXXBDHjiI[256] = "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
结果如下:
name1e5s@ubuntu:~/linklab$ ./3
6666666666
嗯,可以!非常6!
再使用 GDB 在 do_phase() 下断点;
name1e5s@ubuntu:~/linklab$ gdb 3
GNU gdb (Ubuntu 8.0.1-0ubuntu1) 8.0.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from 3...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/name1e5s/linklab/3
[Inferior 1 (process 1833) exited normally]
(gdb) disas do_phase
Dump of assembler code for function do_phase:
0x565555ed <+0>: push %ebp
0x565555ee <+1>: mov %esp,%ebp
0x565555f0 <+3>: sub $0x28,%esp
0x565555f3 <+6>: mov %gs:0x14,%eax
0x565555f9 <+12>: mov %eax,-0xc(%ebp)
0x565555fc <+15>: xor %eax,%eax
0x565555fe <+17>: movl $0x69716f67,-0x17(%ebp)
0x56555605 <+24>: movl $0x776a6876,-0x13(%ebp)
0x5655560c <+31>: movw $0x6378,-0xf(%ebp)
0x56555612 <+37>: movb $0x0,-0xd(%ebp)
0x56555616 <+41>: movl $0x0,-0x1c(%ebp)
0x5655561d <+48>: jmp 0x56555647 <do_phase+90>
0x5655561f <+50>: lea -0x17(%ebp),%edx
0x56555622 <+53>: mov -0x1c(%ebp),%eax
0x56555625 <+56>: add %edx,%eax
0x56555627 <+58>: movzbl (%eax),%eax
0x5655562a <+61>: movzbl %al,%eax
0x5655562d <+64>: movzbl 0x2020(%eax),%eax
0x56555634 <+71>: movsbl %al,%eax
0x56555637 <+74>: sub $0xc,%esp
0x5655563a <+77>: push %eax
0x5655563b <+78>: call 0x5655563c <do_phase+79>
0x56555640 <+83>: add $0x10,%esp
0x56555643 <+86>: addl $0x1,-0x1c(%ebp)
0x56555647 <+90>: mov -0x1c(%ebp),%eax
0x5655564a <+93>: cmp $0x9,%eax
0x5655564d <+96>: jbe 0x5655561f <do_phase+50>
0x5655564f <+98>: sub $0xc,%esp
0x56555652 <+101>: push $0xa
0x56555654 <+103>: call 0x56555655 <do_phase+104>
0x56555659 <+108>: add $0x10,%esp
0x5655565c <+111>: nop
0x5655565d <+112>: mov -0xc(%ebp),%eax
0x56555660 <+115>: xor %gs:0x14,%eax
0x56555667 <+122>: je 0x5655566e <do_phase+129>
0x56555669 <+124>: call 0x5655566a <do_phase+125>
0x5655566e <+129>: leave
0x5655566f <+130>: ret
End of assembler dump.
(gdb) b 0x56555634
Function "0x56555634" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b *0x56555634
Breakpoint 1 at 0x56555634
(gdb) r
Starting program: /home/name1e5s/linklab/3
Breakpoint 1, 0x56555634 in do_phase ()
(gdb) i r
eax 0x0 0
ecx 0xffffd2b0 -11600
edx 0xffffd271 -11663
ebx 0x0 0
esp 0xffffd260 0xffffd260
ebp 0xffffd288 0xffffd288
esi 0x1 1
edi 0xf7fb5000 -134524928
eip 0x56555634 0x56555634 <do_phase+71>
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) disas
Dump of assembler code for function do_phase:
0x565555ed <+0>: push %ebp
0x565555ee <+1>: mov %esp,%ebp
0x565555f0 <+3>: sub $0x28,%esp
0x565555f3 <+6>: mov %gs:0x14,%eax
0x565555f9 <+12>: mov %eax,-0xc(%ebp)
0x565555fc <+15>: xor %eax,%eax
0x565555fe <+17>: movl $0x69716f67,-0x17(%ebp)
0x56555605 <+24>: movl $0x776a6876,-0x13(%ebp)
0x5655560c <+31>: movw $0x6378,-0xf(%ebp)
0x56555612 <+37>: movb $0x0,-0xd(%ebp)
0x56555616 <+41>: movl $0x0,-0x1c(%ebp)
0x5655561d <+48>: jmp 0x56555647 <do_phase+90>
0x5655561f <+50>: lea -0x17(%ebp),%edx
0x56555622 <+53>: mov -0x1c(%ebp),%eax
0x56555625 <+56>: add %edx,%eax
0x56555627 <+58>: movzbl (%eax),%eax
0x5655562a <+61>: movzbl %al,%eax
0x5655562d <+64>: movzbl 0x56557020(%eax),%eax
=> 0x56555634 <+71>: movsbl %al,%eax
0x56555637 <+74>: sub $0xc,%esp
0x5655563a <+77>: push %eax
0x5655563b <+78>: call 0xf7e4ed50 <putchar>
0x56555640 <+83>: add $0x10,%esp
0x56555643 <+86>: addl $0x1,-0x1c(%ebp)
0x56555647 <+90>: mov -0x1c(%ebp),%eax
0x5655564a <+93>: cmp $0x9,%eax
0x5655564d <+96>: jbe 0x5655561f <do_phase+50>
0x5655564f <+98>: sub $0xc,%esp
0x56555652 <+101>: push $0xa
0x56555654 <+103>: call 0xf7e4ed50 <putchar>
0x56555659 <+108>: add $0x10,%esp
0x5655565c <+111>: nop
0x5655565d <+112>: mov -0xc(%ebp),%eax
0x56555660 <+115>: xor %gs:0x14,%eax
0x56555667 <+122>: je 0x5655566e <do_phase+129>
0x56555669 <+124>: call 0xf7eeb860 <__stack_chk_fail>
0x5655566e <+129>: leave
0x5655566f <+130>: ret
End of assembler dump.
(gdb) x /s $eax
0x0: <error: Cannot access memory at address 0x0>
(gdb) x /s $ebp-17
0xffffd277: "jwxc"
(gdb) x /s $ebp - 0x17
0xffffd271: "goqivhjwxc"
(gdb) x /s $ebp - 0x18
0xffffd270: ""
(gdb) x /s $ebp - 0x17
0xffffd271: "goqivhjwxc"
(gdb) q
不难发现,这段代码其实等价于如下 C 代码:
void do_phase(void)
{
char s[9] = "goqivhjwxc";
for(int i = 0; i < 10 ; i++)
printf("%c",s[i]);
putchar('\n');
return;
}
这就好办多了,我们只需要保证对应的字符为我们的学号就可以啦~
因此构造如下 C 文件:
char lOXXBDHjiI[256] = "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666066600006666060666600066666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
与之链接,即可拿到结果:
name1e5s@ubuntu:~/linklab$ ./3
0000000000
Phase 4
这一关,考察的是对于switch 的掌握。但是,显然我们不需要理解 switch 的运行原理也可以解决问题。
我们先查看其反汇编码:
name1e5s@ubuntu:~/ll$ objdump -d phase4.o
phase4.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 28 sub $0x28,%esp
6: 65 a1 14 00 00 00 mov %gs:0x14,%eax
c: 89 45 f4 mov %eax,-0xc(%ebp)
f: 31 c0 xor %eax,%eax
11: c7 45 e9 4f 58 59 44 movl $0x4459584f,-0x17(%ebp)
18: c7 45 ed 4b 50 56 47 movl $0x4756504b,-0x13(%ebp)
1f: 66 c7 45 f1 46 5a movw $0x5a46,-0xf(%ebp)
25: c6 45 f3 00 movb $0x0,-0xd(%ebp)
29: c7 45 e4 00 00 00 00 movl $0x0,-0x1c(%ebp)
30: e9 e2 00 00 00 jmp 117 <do_phase+0x117>
35: 8d 55 e9 lea -0x17(%ebp),%edx
38: 8b 45 e4 mov -0x1c(%ebp),%eax
3b: 01 d0 add %edx,%eax
3d: 0f b6 00 movzbl (%eax),%eax
40: 88 45 e3 mov %al,-0x1d(%ebp)
43: 0f be 45 e3 movsbl -0x1d(%ebp),%eax
47: 83 e8 41 sub $0x41,%eax
4a: 83 f8 19 cmp $0x19,%eax
4d: 0f 87 b0 00 00 00 ja 103 <do_phase+0x103>
53: 8b 04 85 00 00 00 00 mov 0x0(,%eax,4),%eax
5a: ff e0 jmp *%eax
5c: c6 45 e3 33 movb $0x33,-0x1d(%ebp)
60: e9 9e 00 00 00 jmp 103 <do_phase+0x103>
65: c6 45 e3 34 movb $0x34,-0x1d(%ebp)
69: e9 95 00 00 00 jmp 103 <do_phase+0x103>
6e: c6 45 e3 74 movb $0x74,-0x1d(%ebp)
72: e9 8c 00 00 00 jmp 103 <do_phase+0x103>
77: c6 45 e3 36 movb $0x36,-0x1d(%ebp)
7b: e9 83 00 00 00 jmp 103 <do_phase+0x103>
80: c6 45 e3 6d movb $0x6d,-0x1d(%ebp)
84: eb 7d jmp 103 <do_phase+0x103>
86: c6 45 e3 38 movb $0x38,-0x1d(%ebp)
8a: eb 77 jmp 103 <do_phase+0x103>
8c: c6 45 e3 62 movb $0x62,-0x1d(%ebp)
90: eb 71 jmp 103 <do_phase+0x103>
92: c6 45 e3 30 movb $0x30,-0x1d(%ebp)
96: eb 6b jmp 103 <do_phase+0x103>
98: c6 45 e3 79 movb $0x79,-0x1d(%ebp)
9c: eb 65 jmp 103 <do_phase+0x103>
9e: c6 45 e3 3b movb $0x3b,-0x1d(%ebp)
a2: eb 5f jmp 103 <do_phase+0x103>
a4: c6 45 e3 37 movb $0x37,-0x1d(%ebp)
a8: eb 59 jmp 103 <do_phase+0x103>
aa: c6 45 e3 47 movb $0x47,-0x1d(%ebp)
ae: eb 53 jmp 103 <do_phase+0x103>
b0: c6 45 e3 4d movb $0x4d,-0x1d(%ebp)
b4: eb 4d jmp 103 <do_phase+0x103>
b6: c6 45 e3 5a movb $0x5a,-0x1d(%ebp)
ba: eb 47 jmp 103 <do_phase+0x103>
bc: c6 45 e3 3f movb $0x3f,-0x1d(%ebp)
c0: eb 41 jmp 103 <do_phase+0x103>
c2: c6 45 e3 39 movb $0x39,-0x1d(%ebp)
c6: eb 3b jmp 103 <do_phase+0x103>
c8: c6 45 e3 40 movb $0x40,-0x1d(%ebp)
cc: eb 35 jmp 103 <do_phase+0x103>
ce: c6 45 e3 6b movb $0x6b,-0x1d(%ebp)
d2: eb 2f jmp 103 <do_phase+0x103>
d4: c6 45 e3 70 movb $0x70,-0x1d(%ebp)
d8: eb 29 jmp 103 <do_phase+0x103>
da: c6 45 e3 32 movb $0x32,-0x1d(%ebp)
de: eb 23 jmp 103 <do_phase+0x103>
e0: c6 45 e3 31 movb $0x31,-0x1d(%ebp)
e4: eb 1d jmp 103 <do_phase+0x103>
e6: c6 45 e3 7c movb $0x7c,-0x1d(%ebp)
ea: eb 17 jmp 103 <do_phase+0x103>
ec: c6 45 e3 40 movb $0x40,-0x1d(%ebp)
f0: eb 11 jmp 103 <do_phase+0x103>
f2: c6 45 e3 6e movb $0x6e,-0x1d(%ebp)
f6: eb 0b jmp 103 <do_phase+0x103>
f8: c6 45 e3 35 movb $0x35,-0x1d(%ebp)
fc: eb 05 jmp 103 <do_phase+0x103>
fe: c6 45 e3 5e movb $0x5e,-0x1d(%ebp)
102: 90 nop
103: 0f be 45 e3 movsbl -0x1d(%ebp),%eax
107: 83 ec 0c sub $0xc,%esp
10a: 50 push %eax
10b: e8 fc ff ff ff call 10c <do_phase+0x10c>
110: 83 c4 10 add $0x10,%esp
113: 83 45 e4 01 addl $0x1,-0x1c(%ebp)
117: 8b 45 e4 mov -0x1c(%ebp),%eax
11a: 83 f8 09 cmp $0x9,%eax
11d: 0f 86 12 ff ff ff jbe 35 <do_phase+0x35>
123: 83 ec 0c sub $0xc,%esp
126: 6a 0a push $0xa
128: e8 fc ff ff ff call 129 <do_phase+0x129>
12d: 83 c4 10 add $0x10,%esp
130: 90 nop
131: 8b 45 f4 mov -0xc(%ebp),%eax
134: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
13b: 74 05 je 142 <do_phase+0x142>
13d: e8 fc ff ff ff call 13e <do_phase+0x13e>
142: c9 leave
143: c3 ret
不难看出中间那一堆 jmp 等语句就是所谓的 switch 结构,以及 movb 后面的第一个操作数就是某些字符的 ANSCII 码,现在链接并运行程序:
name1e5s@ubuntu:~/ll$ gcc -o 4 phase4.o main.o -m32
name1e5s@ubuntu:~/ll$ ./4
?n5679|b8^
并查看程序的二进制码:
vim -b phase4.o
我们能在 phase4.o 里面看到一些被
进行测试:
name1e5s@ubuntu:~/ll$ gcc -o 4 phase4.o main.o -m32
name1e5s@ubuntu:~/ll$ ./4
0000000000
Phase 5
终于来到最后,也是最难办的一关。在进行实验前,我们先看下程序框架:
const int TRAN_ARRAY[] = {… …};
const char FDICT[] = FDICTDAT;
char BUF[] = MYID;
char CODE = PHASE5_COOKIE;
int transform_code( int code, int mode ) {
switch( TRAN_ARRAY [mode] & 0x00000007 ) {
case 0:
code = code & (~ TRAN_ARRAY[mode]);
break;
case 1:
code = code ^ TRAN_ARRAY[mode];
break;
… …
}
return code;
}
void generate_code( int cookie ) {
int i;
CODE = cookie;
for( i=0; i<sizeof(TRAN_ARRAY)/sizeof(int); i++ )
CODE = transform_code( CODE, i );
}
int encode( char* str ) {
int i, n = strlen(str);
for( i=0; i<n; i++) {
str[i] = (FDICT[str[i]] ^ CODE)& 0x7F;
if( str[i]<0x20 || str[i]>0x7E ) str[i] = ' ';
}
return n;
}
void do_phase() {
generate_code(PHASE5_COOKIE);
encode(BUF);
printf("%s\n", BUF);
}
这里的部分符号的重定位表被置为0了,我们需要做的就是将之修复,使得程序能够正常运行。操作很简单,在此按下不表。
实验材料下载地址:
https://pan.baidu.com/s/1dG64Pnr
密码:c1or
(学号已经置为 0000000000,不要妄图从中找到笔者的学号~)