Linklab 解題報告
該 Lab 的附加材料會在文後提供下載。
Linklab 的主要作用就是幫助我們理解 ELF 文件格式的鏈接等操作,順便複習一下之前學習的彙編知識。此次實驗給我們提供了一個 main.o 以及五個phase*.o 文件。我們在每一結算 需要做的就是把 main.o 以及 phase*.o 文件鏈接起來,然後完成要求的輸出。
Phase 1
本階段要求我們通過修改 phase1.o 中的 .rodata 欄位,來實現修改輸出為學號的目標。難度極小,為熱身活動。
首先我們直接進行鏈接操作,查看結果:
name1e5s@ubuntu:~/ll$ ./1nfZGFY ZYzVwwqe1HLlPI0uiWm24xVn1pFMpwVVOa5BIeIQW6ih7xbEeJtkCz2qNa7XQo4t2DA3yYVeA3hfqF6AtTRvWK64r9KRROgH9Qmt7bNgrOn
然後在 .data 欄位查找這段亂碼:
00000080: 5a66 5a47 4659 205a 597a 5677 7771 6531 ZfZGFY ZYzVwwqe1n 00000090: 484c 6c50 4930 7569 576d 3234 7856 6e31 HLlPI0uiWm24xVn1n 000000a0: 7046 4d70 7756 564f 6135 4249 6549 5157 pFMpwVVOa5BIeIQWn 000000b0: 3669 6837 7862 4565 4a09 6b43 7a32 714e 6ih7xbEeJ.kCz2qNn 000000c0: 6137 5851 6f34 0932 4441 3379 5956 6541 a7XQo4.2DA3yYVeAn 000000d0: 3368 6671 4636 4174 5452 7657 4b36 3472 3hfqF6AtTRvWK64rn 000000e0: 394b 5252 4f67 4839 516d 7437 624e 6772 9KRROgH9Qmt7bNgrn 000000f0: 4f00 0000 0000 0000 0047 4343 3a20 2855 O........GCC: (Un
顯然這段就是我們需要修改的部分,我們只需要將此修改為我們的學號即可。修改如下(假設筆者的學號為0000000000):
00000080: 3030 3030 3030 3030 3030 3030 0071 6531 0000000000.Vwwqe1n 00000090: 484c 6c50 4930 7569 576d 3234 7856 6e31 HLlPI0uiWm24xVn1n
之後鏈接運行,即可得到結果:
name1e5s@ubuntu:~/ll$ ./1n0000000000n
Phase 2
本階段,我們的目標仍是輸出我們的學號,與上次不同的是,此次我們的學號已經預先存儲在phase2.o 的 .rodata 欄位,我們需要做的是補全 do_phase 函數,並修改相關內容,是指能夠輸出我們的學號。
首先進行反彙編:
name1e5s@ubuntu:~/ll$ objdump -d phase2.o nnphase2.o: file format elf32-i386nnnDisassembly of section .text:nn00000000 <ThbYPvDz>:n 0:t55 tpush %ebpn 1:t89 e5 tmov %esp,%ebpn 3:t83 ec 08 tsub $0x8,%espn 6:t83 ec 08 tsub $0x8,%espn 9:t68 00 00 00 00 tpush $0x0n e:tff 75 08 tpushl 0x8(%ebp)n 11:te8 fc ff ff ff tcall 12 <ThbYPvDz+0x12>n 16:t83 c4 10 tadd $0x10,%espn 19:t85 c0 ttest %eax,%eaxn 1b:t75 10 tjne 2d <ThbYPvDz+0x2d>n 1d:t83 ec 0c tsub $0xc,%espn 20:tff 75 08 tpushl 0x8(%ebp)n 23:te8 fc ff ff ff tcall 24 <ThbYPvDz+0x24>n 28:t83 c4 10 tadd $0x10,%espn 2b:teb 01 tjmp 2e <ThbYPvDz+0x2e>n 2d:t90 tnopn 2e:tc9 tleave n 2f:tc3 tret nn00000030 <do_phase>:n 30:t55 tpush %ebpn 31:t89 e5 tmov %esp,%ebpn 33:t90 tnopn 34:t90 tnopn 35:t90 tnopn 36:t90 tnopn 37:t90 tnopn 38:t90 tnopn 39:t90 tnopn 3a:t90 tnopn 3b:t90 tnopn 3c:t90 tnopn 3d:t90 tnopn 3e:t90 tnopn 3f:t90 tnopn 40:t90 tnopn 41:t90 tnopn 42:t90 tnopn 43:t90 tnopn 44:t90 tnopn 45:t90 tnopn 46:t90 tnopn 47:t90 tnopn 48:t90 tnopn 49:t90 tnopn 4a:t90 tnopn 4b:t90 tnopn 4c:t90 tnopn 4d:t90 tnopn 4e:t90 tnopn 4f:t90 tnopn 50:t90 tnopn 51:t90 tnopn 52:t90 tnopn 53:t90 tnopn 54:t5d tpop %ebpn 55:tc3 tret n
我們要做的就是修改這些 nop 指令為我們自己的指令。上面那個亂碼函數給了我們很好的示範,因此我們只需修改為如下即可:
$ objdump -d phase2.o nnphase2.o: file format elf32-i386nnnDisassembly of section .text:nn00000000 <ThbYPvDz>:n 0:t55 tpush %ebpn 1:t89 e5 tmov %esp,%ebpn 3:t83 ec 08 tsub $0x8,%espn 6:t83 ec 08 tsub $0x8,%espn 9:t68 00 00 00 00 tpush $0x0n e:tff 75 08 tpushl 0x8(%ebp)n 11:te8 fc ff ff ff tcall 12 <ThbYPvDz+0x12>n 16:t83 c4 10 tadd $0x10,%espn 19:t85 c0 ttest %eax,%eaxn 1b:t75 10 tjne 2d <ThbYPvDz+0x2d>n 1d:t83 ec 0c tsub $0xc,%espn 20:tff 75 08 tpushl 0x8(%ebp)n 23:te8 fc ff ff ff tcall 24 <ThbYPvDz+0x24>n 28:t83 c4 10 tadd $0x10,%espn 2b:teb 01 tjmp 2e <ThbYPvDz+0x2e>n 2d:t90 tnopn 2e:tc9 tleave n 2f:tc3 tret nn00000030 <do_phase>:n 30:t55 tpush %ebpn 31:t89 e5 tmov %esp,%ebpn 33:t83 ec 10 tsub $0x10,%espn 36:t68 00 00 00 00 tpush $0x0n 3b:te8 fc ff ff ff tcall 3c <do_phase+0xc>n 40:t83 c4 10 tadd $0x10,%espn 43:t90 tnopn 44:t90 tnopn 45:t90 tnopn 46:t90 tnopn 47:t90 tnopn 48:t90 tnopn 49:t90 tnopn 4a:t90 tnopn 4b:t90 tnopn 4c:t90 tnopn 4d:t90 tnopn 4e:t90 tnopn 4f:t90 tnopn 50:t90 tnopn 51:t90 tnopn 52:t90 tnopn 53:t90 tnopn 54:tc9 tleave n 55:tc3 tret n
之後修改重定位規則,使得鏈接器重定位的是我們的代碼,而非上面的亂碼函數的代碼。定位.rel.text欄位以及其內容:
name1e5s@ubuntu:~/ll$ readelf -r phase2.onnRelocation section .rel.text at offset 0x22c contains 3 entries:n Offset Info Type Sym.Value Sym. Namen0000000a 00000501 R_386_32 00000000 .rodatan00000012 00000a02 R_386_PC32 00000000 strcmpn00000024 00000b02 R_386_PC32 00000000 putsnnRelocation section .rel.data at offset 0x244 contains 1 entries:n Offset Info Type Sym.Value Sym. Namen00000000 00000c01 R_386_32 00000030 do_phasennRelocation section .rel.eh_frame at offset 0x24c contains 2 entries:n Offset Info Type Sym.Value Sym. Namen00000020 00000202 R_386_PC32 00000000 .textn00000040 00000202 R_386_PC32 00000000 .textnname1e5s@ubuntu:~/ll$ readelf -S phase2.onThere are 14 section headers, starting at offset 0x2c0:nnSection Headers:n [Nr] Name Type Addr Off Size ES Flg Lk Inf Aln [ 0] NULL 00000000 000000 000000 00 0 0 0n [ 1] .text PROGBITS 00000000 000034 000056 00 AX 0 0 1n [ 2] .rel.text REL 00000000 00022c 000018 08 I 12 1 4n [ 3] .data PROGBITS 00000000 00008c 000004 00 WA 0 0 4n [ 4] .rel.data REL 00000000 000244 000008 08 I 12 3 4n [ 5] .bss NOBITS 00000000 000090 000000 00 WA 0 0 1n [ 6] .rodata PROGBITS 00000000 000090 00000b 00 A 0 0 1n [ 7] .comment PROGBITS 00000000 00009b 00002e 01 MS 0 0 1n [ 8] .note.GNU-stack PROGBITS 00000000 0000c9 000000 00 0 0 1n [ 9] .eh_frame PROGBITS 00000000 0000cc 000058 00 A 0 0 4n [10] .rel.eh_frame REL 00000000 00024c 000010 08 I 12 9 4n [11] .shstrtab STRTAB 00000000 00025c 000063 00 0 0 1n [12] .symtab SYMTAB 00000000 000124 0000e0 10 13 10 4n [13] .strtab STRTAB 00000000 000204 000028 00 0 0 1nKey to Flags:n W (write), A (alloc), X (execute), M (merge), S (strings), I (info),n L (link order), O (extra OS processing required), G (group), T (TLS),n C (compressed), x (unknown), o (OS specific), E (exclude),n p (processor specific)n
找到目標後進行修改,因為我們只是用到了 puts 函數以及 .rodata 的位置,因此我們直接修改這兩處的位置即可,修改後結果如下:
name1e5s@ubuntu:~/linklab$ readelf -r phase2.o nnRelocation section .rel.text at offset 0x22c contains 3 entries:n Offset Info Type Sym.Value Sym. Namen00000037 00000501 R_386_32 00000000 .rodatan00000012 00000a02 R_386_PC32 00000000 strcmpn0000003c 00000b02 R_386_PC32 00000000 putsnnRelocation section .rel.data at offset 0x244 contains 1 entries:n Offset Info Type Sym.Value Sym. Namen00000000 00000c01 R_386_32 00000030 do_phasennRelocation section .rel.eh_frame at offset 0x24c contains 2 entries:n Offset Info Type Sym.Value Sym. Namen00000020 00000202 R_386_PC32 00000000 .textn00000040 00000202 R_386_PC32 00000000 .textnname1e5s@ubuntu:~/linklab$ ./2n0000000000n
可以看到,我們的代碼已經被正確地重定位,並完美的執行。
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 n00000000 T do_phasen00000100 C lOXXBDHjiIn00000000 D phasen U putcharn U __stack_chk_failn
在結合 readelf 的輸出結果不難發現該文件中有一命名為 lOXXBDHjiI 的長度為256的字元串沒有定義為強符號。既然如此,我們就先寫如下 C 文件與之鏈接:
char lOXXBDHjiI[256] = "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";n
結果如下:
name1e5s@ubuntu:~/linklab$ ./3n6666666666n
嗯,可以!非常6!
再使用 GDB 在 do_phase() 下斷點;
name1e5s@ubuntu:~/linklab$ gdb 3nGNU gdb (Ubuntu 8.0.1-0ubuntu1) 8.0.1nCopyright (C) 2017 Free Software Foundation, Inc.nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>nThis is free software: you are free to change and redistribute it.nThere is NO WARRANTY, to the extent permitted by law. Type "show copying"nand "show warranty" for details.nThis GDB was configured as "x86_64-linux-gnu".nType "show configuration" for configuration details.nFor bug reporting instructions, please see:n<http://www.gnu.org/software/gdb/bugs/>.nFind the GDB manual and other documentation resources online at:n<http://www.gnu.org/software/gdb/documentation/>.nFor help, type "help".nType "apropos word" to search for commands related to "word"...nReading symbols from 3...(no debugging symbols found)...done.n(gdb) rnStarting program: /home/name1e5s/linklab/3 nn[Inferior 1 (process 1833) exited normally]n(gdb) disas do_phasenDump of assembler code for function do_phase:n 0x565555ed <+0>:tpush %ebpn 0x565555ee <+1>:tmov %esp,%ebpn 0x565555f0 <+3>:tsub $0x28,%espn 0x565555f3 <+6>:tmov %gs:0x14,%eaxn 0x565555f9 <+12>:tmov %eax,-0xc(%ebp)n 0x565555fc <+15>:txor %eax,%eaxn 0x565555fe <+17>:tmovl $0x69716f67,-0x17(%ebp)n 0x56555605 <+24>:tmovl $0x776a6876,-0x13(%ebp)n 0x5655560c <+31>:tmovw $0x6378,-0xf(%ebp)n 0x56555612 <+37>:tmovb $0x0,-0xd(%ebp)n 0x56555616 <+41>:tmovl $0x0,-0x1c(%ebp)n 0x5655561d <+48>:tjmp 0x56555647 <do_phase+90>n 0x5655561f <+50>:tlea -0x17(%ebp),%edxn 0x56555622 <+53>:tmov -0x1c(%ebp),%eaxn 0x56555625 <+56>:tadd %edx,%eaxn 0x56555627 <+58>:tmovzbl (%eax),%eaxn 0x5655562a <+61>:tmovzbl %al,%eaxn 0x5655562d <+64>:tmovzbl 0x2020(%eax),%eaxn 0x56555634 <+71>:tmovsbl %al,%eaxn 0x56555637 <+74>:tsub $0xc,%espn 0x5655563a <+77>:tpush %eaxn 0x5655563b <+78>:tcall 0x5655563c <do_phase+79>n 0x56555640 <+83>:tadd $0x10,%espn 0x56555643 <+86>:taddl $0x1,-0x1c(%ebp)n 0x56555647 <+90>:tmov -0x1c(%ebp),%eaxn 0x5655564a <+93>:tcmp $0x9,%eaxn 0x5655564d <+96>:tjbe 0x5655561f <do_phase+50>n 0x5655564f <+98>:tsub $0xc,%espn 0x56555652 <+101>:tpush $0xan 0x56555654 <+103>:tcall 0x56555655 <do_phase+104>n 0x56555659 <+108>:tadd $0x10,%espn 0x5655565c <+111>:tnopn 0x5655565d <+112>:tmov -0xc(%ebp),%eaxn 0x56555660 <+115>:txor %gs:0x14,%eaxn 0x56555667 <+122>:tje 0x5655566e <do_phase+129>n 0x56555669 <+124>:tcall 0x5655566a <do_phase+125>n 0x5655566e <+129>:tleave n 0x5655566f <+130>:tret nEnd of assembler dump.n(gdb) b 0x56555634nFunction "0x56555634" not defined.nMake breakpoint pending on future shared library load? (y or [n]) nn(gdb) b *0x56555634nBreakpoint 1 at 0x56555634n(gdb) rnStarting program: /home/name1e5s/linklab/3 nnBreakpoint 1, 0x56555634 in do_phase ()n(gdb) i rneax 0x0t0necx 0xffffd2b0t-11600nedx 0xffffd271t-11663nebx 0x0t0nesp 0xffffd260t0xffffd260nebp 0xffffd288t0xffffd288nesi 0x1t1nedi 0xf7fb5000t-134524928neip 0x56555634t0x56555634 <do_phase+71>neflags 0x286t[ PF SF IF ]ncs 0x23t35nss 0x2bt43nds 0x2bt43nes 0x2bt43nfs 0x0t0ngs 0x63t99n(gdb) disasnDump of assembler code for function do_phase:n 0x565555ed <+0>:tpush %ebpn 0x565555ee <+1>:tmov %esp,%ebpn 0x565555f0 <+3>:tsub $0x28,%espn 0x565555f3 <+6>:tmov %gs:0x14,%eaxn 0x565555f9 <+12>:tmov %eax,-0xc(%ebp)n 0x565555fc <+15>:txor %eax,%eaxn 0x565555fe <+17>:tmovl $0x69716f67,-0x17(%ebp)n 0x56555605 <+24>:tmovl $0x776a6876,-0x13(%ebp)n 0x5655560c <+31>:tmovw $0x6378,-0xf(%ebp)n 0x56555612 <+37>:tmovb $0x0,-0xd(%ebp)n 0x56555616 <+41>:tmovl $0x0,-0x1c(%ebp)n 0x5655561d <+48>:tjmp 0x56555647 <do_phase+90>n 0x5655561f <+50>:tlea -0x17(%ebp),%edxn 0x56555622 <+53>:tmov -0x1c(%ebp),%eaxn 0x56555625 <+56>:tadd %edx,%eaxn 0x56555627 <+58>:tmovzbl (%eax),%eaxn 0x5655562a <+61>:tmovzbl %al,%eaxn 0x5655562d <+64>:tmovzbl 0x56557020(%eax),%eaxn=> 0x56555634 <+71>:tmovsbl %al,%eaxn 0x56555637 <+74>:tsub $0xc,%espn 0x5655563a <+77>:tpush %eaxn 0x5655563b <+78>:tcall 0xf7e4ed50 <putchar>n 0x56555640 <+83>:tadd $0x10,%espn 0x56555643 <+86>:taddl $0x1,-0x1c(%ebp)n 0x56555647 <+90>:tmov -0x1c(%ebp),%eaxn 0x5655564a <+93>:tcmp $0x9,%eaxn 0x5655564d <+96>:tjbe 0x5655561f <do_phase+50>n 0x5655564f <+98>:tsub $0xc,%espn 0x56555652 <+101>:tpush $0xan 0x56555654 <+103>:tcall 0xf7e4ed50 <putchar>n 0x56555659 <+108>:tadd $0x10,%espn 0x5655565c <+111>:tnopn 0x5655565d <+112>:tmov -0xc(%ebp),%eaxn 0x56555660 <+115>:txor %gs:0x14,%eaxn 0x56555667 <+122>:tje 0x5655566e <do_phase+129>n 0x56555669 <+124>:tcall 0xf7eeb860 <__stack_chk_fail>n 0x5655566e <+129>:tleave n 0x5655566f <+130>:tret nEnd of assembler dump.n(gdb) x /s $eaxn0x0:t<error: Cannot access memory at address 0x0>n(gdb) x /s $ebp-17n0xffffd277:t"jwxc"n(gdb) x /s $ebp - 0x17n0xffffd271:t"goqivhjwxc"n(gdb) x /s $ebp - 0x18n0xffffd270:t""n(gdb) x /s $ebp - 0x17n0xffffd271:t"goqivhjwxc"n(gdb) qn
不難發現,這段代碼其實等價於如下 C 代碼:
void do_phase(void)n{n char s[9] = "goqivhjwxc";n for(int i = 0; i < 10 ; i++)n printf("%c",s[i]);n putchar(n);n return;n}n
這就好辦多了,我們只需要保證對應的字元為我們的學號就可以啦~
因此構造如下 C 文件:
char lOXXBDHjiI[256] = "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666066600006666060666600066666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";n
與之鏈接,即可拿到結果:
name1e5s@ubuntu:~/linklab$ ./3n0000000000n
Phase 4
這一關,考察的是對於switch 的掌握。但是,顯然我們不需要理解 switch 的運行原理也可以解決問題。
我們先查看其反彙編碼:
name1e5s@ubuntu:~/ll$ objdump -d phase4.o nnphase4.o: file format elf32-i386nnnDisassembly of section .text:nn00000000 <do_phase>:n 0:t55 tpush %ebpn 1:t89 e5 tmov %esp,%ebpn 3:t83 ec 28 tsub $0x28,%espn 6:t65 a1 14 00 00 00 tmov %gs:0x14,%eaxn c:t89 45 f4 tmov %eax,-0xc(%ebp)n f:t31 c0 txor %eax,%eaxn 11:tc7 45 e9 4f 58 59 44 tmovl $0x4459584f,-0x17(%ebp)n 18:tc7 45 ed 4b 50 56 47 tmovl $0x4756504b,-0x13(%ebp)n 1f:t66 c7 45 f1 46 5a tmovw $0x5a46,-0xf(%ebp)n 25:tc6 45 f3 00 tmovb $0x0,-0xd(%ebp)n 29:tc7 45 e4 00 00 00 00 tmovl $0x0,-0x1c(%ebp)n 30:te9 e2 00 00 00 tjmp 117 <do_phase+0x117>n 35:t8d 55 e9 tlea -0x17(%ebp),%edxn 38:t8b 45 e4 tmov -0x1c(%ebp),%eaxn 3b:t01 d0 tadd %edx,%eaxn 3d:t0f b6 00 tmovzbl (%eax),%eaxn 40:t88 45 e3 tmov %al,-0x1d(%ebp)n 43:t0f be 45 e3 tmovsbl -0x1d(%ebp),%eaxn 47:t83 e8 41 tsub $0x41,%eaxn 4a:t83 f8 19 tcmp $0x19,%eaxn 4d:t0f 87 b0 00 00 00 tja 103 <do_phase+0x103>n 53:t8b 04 85 00 00 00 00 tmov 0x0(,%eax,4),%eaxn 5a:tff e0 tjmp *%eaxn 5c:tc6 45 e3 33 tmovb $0x33,-0x1d(%ebp)n 60:te9 9e 00 00 00 tjmp 103 <do_phase+0x103>n 65:tc6 45 e3 34 tmovb $0x34,-0x1d(%ebp)n 69:te9 95 00 00 00 tjmp 103 <do_phase+0x103>n 6e:tc6 45 e3 74 tmovb $0x74,-0x1d(%ebp)n 72:te9 8c 00 00 00 tjmp 103 <do_phase+0x103>n 77:tc6 45 e3 36 tmovb $0x36,-0x1d(%ebp)n 7b:te9 83 00 00 00 tjmp 103 <do_phase+0x103>n 80:tc6 45 e3 6d tmovb $0x6d,-0x1d(%ebp)n 84:teb 7d tjmp 103 <do_phase+0x103>n 86:tc6 45 e3 38 tmovb $0x38,-0x1d(%ebp)n 8a:teb 77 tjmp 103 <do_phase+0x103>n 8c:tc6 45 e3 62 tmovb $0x62,-0x1d(%ebp)n 90:teb 71 tjmp 103 <do_phase+0x103>n 92:tc6 45 e3 30 tmovb $0x30,-0x1d(%ebp)n 96:teb 6b tjmp 103 <do_phase+0x103>n 98:tc6 45 e3 79 tmovb $0x79,-0x1d(%ebp)n 9c:teb 65 tjmp 103 <do_phase+0x103>n 9e:tc6 45 e3 3b tmovb $0x3b,-0x1d(%ebp)n a2:teb 5f tjmp 103 <do_phase+0x103>n a4:tc6 45 e3 37 tmovb $0x37,-0x1d(%ebp)n a8:teb 59 tjmp 103 <do_phase+0x103>n aa:tc6 45 e3 47 tmovb $0x47,-0x1d(%ebp)n ae:teb 53 tjmp 103 <do_phase+0x103>n b0:tc6 45 e3 4d tmovb $0x4d,-0x1d(%ebp)n b4:teb 4d tjmp 103 <do_phase+0x103>n b6:tc6 45 e3 5a tmovb $0x5a,-0x1d(%ebp)n ba:teb 47 tjmp 103 <do_phase+0x103>n bc:tc6 45 e3 3f tmovb $0x3f,-0x1d(%ebp)n c0:teb 41 tjmp 103 <do_phase+0x103>n c2:tc6 45 e3 39 tmovb $0x39,-0x1d(%ebp)n c6:teb 3b tjmp 103 <do_phase+0x103>n c8:tc6 45 e3 40 tmovb $0x40,-0x1d(%ebp)n cc:teb 35 tjmp 103 <do_phase+0x103>n ce:tc6 45 e3 6b tmovb $0x6b,-0x1d(%ebp)n d2:teb 2f tjmp 103 <do_phase+0x103>n d4:tc6 45 e3 70 tmovb $0x70,-0x1d(%ebp)n d8:teb 29 tjmp 103 <do_phase+0x103>n da:tc6 45 e3 32 tmovb $0x32,-0x1d(%ebp)n de:teb 23 tjmp 103 <do_phase+0x103>n e0:tc6 45 e3 31 tmovb $0x31,-0x1d(%ebp)n e4:teb 1d tjmp 103 <do_phase+0x103>n e6:tc6 45 e3 7c tmovb $0x7c,-0x1d(%ebp)n ea:teb 17 tjmp 103 <do_phase+0x103>n ec:tc6 45 e3 40 tmovb $0x40,-0x1d(%ebp)n f0:teb 11 tjmp 103 <do_phase+0x103>n f2:tc6 45 e3 6e tmovb $0x6e,-0x1d(%ebp)n f6:teb 0b tjmp 103 <do_phase+0x103>n f8:tc6 45 e3 35 tmovb $0x35,-0x1d(%ebp)n fc:teb 05 tjmp 103 <do_phase+0x103>n fe:tc6 45 e3 5e tmovb $0x5e,-0x1d(%ebp)n 102:t90 tnopn 103:t0f be 45 e3 tmovsbl -0x1d(%ebp),%eaxn 107:t83 ec 0c tsub $0xc,%espn 10a:t50 tpush %eaxn 10b:te8 fc ff ff ff tcall 10c <do_phase+0x10c>n 110:t83 c4 10 tadd $0x10,%espn 113:t83 45 e4 01 taddl $0x1,-0x1c(%ebp)n 117:t8b 45 e4 tmov -0x1c(%ebp),%eaxn 11a:t83 f8 09 tcmp $0x9,%eaxn 11d:t0f 86 12 ff ff ff tjbe 35 <do_phase+0x35>n 123:t83 ec 0c tsub $0xc,%espn 126:t6a 0a tpush $0xan 128:te8 fc ff ff ff tcall 129 <do_phase+0x129>n 12d:t83 c4 10 tadd $0x10,%espn 130:t90 tnopn 131:t8b 45 f4 tmov -0xc(%ebp),%eaxn 134:t65 33 05 14 00 00 00 txor %gs:0x14,%eaxn 13b:t74 05 tje 142 <do_phase+0x142>n 13d:te8 fc ff ff ff tcall 13e <do_phase+0x13e>n 142:tc9 tleave n 143:tc3 tret n
不難看出中間那一堆 jmp 等語句就是所謂的 switch 結構,以及 movb 後面的第一個操作數就是某些字元的 ANSCII 碼,現在鏈接並運行程序:
name1e5s@ubuntu:~/ll$ gcc -o 4 phase4.o main.o -m32nname1e5s@ubuntu:~/ll$ ./4n?n5679|b8^n
並查看程序的二進位碼:
vim -b phase4.on
我們能在 phase4.o 裡面看到一些被<e3><eb>包圍的字元,這裡就是之前看到的movb 後面的操作數的字元表示,我們只需把對應的字元改為我們的學號(對於筆者,就是把?n5679|b8^統統改為0)即可。
進行測試:
name1e5s@ubuntu:~/ll$ gcc -o 4 phase4.o main.o -m32nname1e5s@ubuntu:~/ll$ ./4n0000000000n
Phase 5
終於來到最後,也是最難辦的一關。在進行實驗前,我們先看下程序框架:
const int TRAN_ARRAY[] = {… …};nconst char FDICT[] = FDICTDAT;nchar BUF[] = MYID; nchar CODE = PHASE5_COOKIE;nnint transform_code( int code, int mode ) {n switch( TRAN_ARRAY [mode] & 0x00000007 ) {n case 0:n code = code & (~ TRAN_ARRAY[mode]);n break;n case 1:n code = code ^ TRAN_ARRAY[mode];n break;n … …n }n return code;n}nnvoid generate_code( int cookie ) {n int i;n CODE = cookie;n for( i=0; i<sizeof(TRAN_ARRAY)/sizeof(int); i++ )n CODE = transform_code( CODE, i );n}nnint encode( char* str ) {n int i, n = strlen(str);n for( i=0; i<n; i++) {n str[i] = (FDICT[str[i]] ^ CODE)& 0x7F;n if( str[i]<0x20 || str[i]>0x7E ) str[i] = ;n }n return n;n}nnvoid do_phase() {n generate_code(PHASE5_COOKIE);n encode(BUF);n printf("%sn", BUF);n}n
這裡的部分符號的重定位表被置為0了,我們需要做的就是將之修復,使得程序能夠正常運行。操作很簡單,在此按下不表。
實驗材料下載地址:
https://pan.baidu.com/s/1dG64Pnr密碼:c1or
(學號已經置為 0000000000,不要妄圖從中找到筆者的學號~)
推薦閱讀:
※CS:APP Lab 3 解題報告
※CS:APP配套實驗3:Attack Lab筆記
※如何評價北京大學2016-2017年計算機系統導論(ICS)期末考試?
※彙編過程調用是怎樣操作棧的?
※請問popl %esp這個語句有什麼用處?
TAG:CSAPP | 深入理解计算机系统书籍 |