csapp-linklab之第3阶段“输出学号”实验报告(强弱符号)
题目
新建一个phase3_patch.o,使其与main.o和phase3.o链接后,运行输出自己的学号:
$ gcc -o linkbomb main.o phase3.o phase3_patch.o
$ ./linkbomb
$学号
提示
利用符号解析中的强弱符号规则。(COOKIE字符串未初始化,可以利用强弱符号,在phase3_patch.c中定义一个初始化的COOKIE字符串。)
解决
先链接main.o 与phase3.o(linux> gcc main.o phase3.o linux> objdump -d a.out )以便看do_phase里做了什么。这时就需要使用在bomb lab中的“逆向工程”技能,猜这个函数在干嘛。
080484dd <do_phase>:
80484dd: 55 push %ebp
80484de: 89 e5 mov %esp,%ebp
80484e0: 83 ec 28 sub $0x28,%esp
80484e3: 65 a1 14 00 00 00 mov %gs:0x14,%eax
80484e9: 89 45 f4 mov %eax,-0xc(%ebp)
80484ec: 31 c0 xor %eax,%eax
80484ee: c7 45 e9 67 6f 71 69 movl $0x69716f67,-0x17(%ebp)
80484f5: c7 45 ed 76 68 6a 77 movl $0x776a6876,-0x13(%ebp)
80484fc: 66 c7 45 f1 78 63 movw $0x6378,-0xf(%ebp)
8048502: c6 45 f3 00 movb $0x0,-0xd(%ebp)
8048506: c7 45 e4 00 00 00 00 movl $0x0,-0x1c(%ebp)
804850d: eb 28 jmp 8048537 <do_phase+0x5a>
804850f: 8d 55 e9 lea -0x17(%ebp),%edx
8048512: 8b 45 e4 mov -0x1c(%ebp),%eax
8048515: 01 d0 add %edx,%eax
8048517: 0f b6 00 movzbl (%eax),%eax
804851a: 0f b6 c0 movzbl %al,%eax
804851d: 0f b6 80 60 a0 04 08 movzbl 0x804a060(%eax),%eax
8048524: 0f be c0 movsbl %al,%eax
8048527: 83 ec 0c sub $0xc,%esp
804852a: 50 push %eax
804852b: e8 60 fe ff ff call 8048390 <putchar@plt>
8048530: 83 c4 10 add $0x10,%esp
8048533: 83 45 e4 01 addl $0x1,-0x1c(%ebp)
8048537: 8b 45 e4 mov -0x1c(%ebp),%eax
804853a: 83 f8 09 cmp $0x9,%eax
804853d: 76 d0 jbe 804850f <do_phase+0x32>
804853f: 83 ec 0c sub $0xc,%esp
8048542: 6a 0a push $0xa
8048544: e8 47 fe ff ff call 8048390 <putchar@plt>
8048549: 83 c4 10 add $0x10,%esp
804854c: 90 nop
804854d: 8b 45 f4 mov -0xc(%ebp),%eax
8048550: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
8048557: 74 05 je 804855e <do_phase+0x81>
8048559: e8 f2 fd ff ff call 8048350 <__stack_chk_fail@plt>
804855e: c9 leave
804855f: c3 ret
以下是逐句解释:
080484dd <do_phase>:
80484dd: 55 push %ebp
80484de: 89 e5 mov %esp,%ebp
前两行,函数调用的惯常操作,基址寄存器存sp
80484e0: 83 ec 28 sub $0x28,%esp
栈扩展0x28字节
80484e3: 65 a1 14 00 00 00 mov %gs:0x14,%eax
80484e9: 89 45 f4 mov %eax,-0xc(%ebp)
金丝雀
80484ec: 31 c0 xor %eax,%eax
ax清零
80484ee: c7 45 e9 67 6f 71 69 movl $0x69716f67,-0x17(%ebp)
80484f5: c7 45 ed 76 68 6a 77 movl $0x776a6876,-0x13(%ebp)
80484fc: 66 c7 45 f1 78 63 movw $0x6378,-0xf(%ebp)
8048502: c6 45 f3 00 movb $0x0,-0xd(%ebp)
往栈里放一个字符串(局部变量)
————————————————————————————————
地址:bp-17 bp-13 bp-f bp-d
内容:goqi vhjw xc \0
————————————————————————————————
8048506: c7 45 e4 00 00 00 00 movl $0x0,-0x1c(%ebp)
-0x1c(%ebp)处赋为0(局部变量)
804850d: eb 28 jmp 8048537 <do_phase+0x5a>
804850f: 8d 55 e9 lea -0x17(%ebp),%edx
8048512: 8b 45 e4 mov -0x1c(%ebp),%eax
ax = i
8048515: 01 d0 add %edx,%eax
ax = bp-0x17+i(取上面那个字符串的第i个字符的地址)
8048517: 0f b6 00 movzbl (%eax),%eax
取第i个字符
804851a: 0f b6 c0 movzbl %al,%eax
不知道
804851d: 0f b6 80 60 a0 04 08 movzbl 0x804a060(%eax),%eax
取绝对地址为(0x804a060+ax)处的东西存到ax里
8048524: 0f be c0 movsbl %al,%eax
不知道
8048527: 83 ec 0c sub $0xc,%esp
栈变大12字节
804852a: 50 push %eax
栈变大4字节
804852b: e8 60 fe ff ff call 8048390 <putchar@plt>
打出ax里的东西,以ascii码对应字符的方式
8048530: 83 c4 10 add $0x10,%esp
栈变小16字节
8048533: 83 45 e4 01 addl $0x1,-0x1c(%ebp)
8048537: 8b 45 e4 mov -0x1c(%ebp),%eax
看出-0x1c(%ebp)处的局部变量存的是循环变量,每次自增1
804853a: 83 f8 09 cmp $0x9,%eax
循环10次
804853d: 76 d0 jbe 804850f <do_phase+0x32>
804853f: 83 ec 0c sub $0xc,%esp
栈变大12字节
8048542: 6a 0a push $0xa
8048544: e8 47 fe ff ff call 8048390 <putchar@plt>
此时ax为十进制10,打印10刚好是一个换行符(\n),完美
8048549: 83 c4 10 add $0x10,%esp
804854c: 90 nop
以下是金丝雀的检查
804854d: 8b 45 f4 mov -0xc(%ebp),%eax
8048550: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
8048557: 74 05 je 804855e <do_phase+0x81>
8048559: e8 f2 fd ff ff call 8048350 <__stack_chk_fail@plt>
804855e: c9 leave
804855f: c3 ret
所以绝对地址0x804a060处有用,readelf -s a.out 打印符号表
看来这个lOXXBDHjiI就是COOKIE字符串(我一开始还以为COOKIE字符串的变量名就叫COOKIE =_=)
————————————————————————————————
地址:bp-17 bp-13 bp-f bp-d
内容:goqi vhjw xc \0
————————————————————————————————
位置分别是103 111 113 105 118 104 106 119 120 99
假设学号是0123456789,在phase3_patch.c文件中,写入
char lOXXBDHjiI [256] = "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666966605366666162666647866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
成功
后记
本例看出如果学号全是一样的数字(比如0000000000)你只需要把lOXXBDHjiI字符串赋为256个0即可,根本不用考虑究竟是哪个位置被打印(幸运号的福利)