Lab 采用的是 coursera 上华盛顿大学的The Hardware/Software Interface. 与CSAPP书上的不同,这里的lab采用的是64位机器。
Lab2 要求拆除6个炸弹加一个secret bomb。
phase_1
0000000000400e70 <phase_1>: 400e70: 48 83 ec 08 sub $0x8,%rsp 400e74: be f8 1a 40 00 mov $0x401af8,%esi 400e79: e8 bf 03 00 00 callq 40123d <strings_not_equal> 400e7e: 85 c0 test %eax,%eax 400e80: 74 05 je 400e87 <phase_1+0x17> 400e82: e8 b6 07 00 00 callq 40163d <explode_bomb> 400e87: 48 83 c4 08 add $0x8,%rsp 400e8b: c3 retq
000000000040123d <strings_not_equal>: 40123d: 48 89 5c 24 e8 mov %rbx,-0x18(%rsp) 401242: 48 89 6c 24 f0 mov %rbp,-0x10(%rsp) 401247: 4c 89 64 24 f8 mov %r12,-0x8(%rsp) 40124c: 48 83 ec 18 sub $0x18,%rsp 401250: 48 89 fb mov %rdi,%rbx 401253: 48 89 f5 mov %rsi,%rbp 401256: e8 c6 ff ff ff callq 401221 <string_length> 40125b: 41 89 c4 mov %eax,%r12d 40125e: 48 89 ef mov %rbp,%rdi 401261: e8 bb ff ff ff callq 401221 <string_length> 401266: ba 01 00 00 00 mov $0x1,%edx 40126b: 41 39 c4 cmp %eax,%r12d 40126e: 75 36 jne 4012a6 <strings_not_equal+0x69>
0000000000401221 <string_length>: 401221: b8 00 00 00 00 mov $0x0,%eax 401226: 80 3f 00 cmpb $0x0,(%rdi) 401229: 74 10 je 40123b <string_length+0x1a> 40122b: 48 89 fa mov %rdi,%rdx 40122e: 48 83 c2 01 add $0x1,%rdx 401232: 89 d0 mov %edx,%eax 401234: 29 f8 sub %edi,%eax 401236: 80 3a 00 cmpb $0x0,(%rdx) 401239: 75 f3 jne 40122e <string_length+0xd> 40123b: f3 c3 repz retq
string_length 中的代码比较好懂,是以%rdi中的内容为地址,然后与0比较(0即是字符串的终结符号)。所以字符串起始地址应该藏在%rdi中!再看 strings_not_equal,分别有两次 string_length 调用,再结合函数名 strings_not_equal,可以想见是我们输入的字符串与藏在程序中的字符串进行比较!所以只要在 401256,401261两处设置断点,打印出以%rdi中内容为起始地址的字符串。其中一个是我们输入的字符串,而另一个就是我们寻找的字符串。
phase_2
0000000000400e8c <phase_2>: 400e8c: 48 89 5c 24 e0 mov %rbx,-0x20(%rsp) 400e91: 48 89 6c 24 e8 mov %rbp,-0x18(%rsp) 400e96: 4c 89 64 24 f0 mov %r12,-0x10(%rsp) 400e9b: 4c 89 6c 24 f8 mov %r13,-0x8(%rsp) 400ea0: 48 83 ec 48 sub $0x48,%rsp 400ea4: 48 89 e6 mov %rsp,%rsi 400ea7: e8 97 08 00 00 callq 401743 <read_six_numbers> 400eac: 48 89 e5 mov %rsp,%rbp 400eaf: 4c 8d 6c 24 0c lea 0xc(%rsp),%r13 400eb4: 41 bc 00 00 00 00 mov $0x0,%r12d 400eba: 48 89 eb mov %rbp,%rbx 400ebd: 8b 45 0c mov 0xc(%rbp),%eax 400ec0: 39 45 00 cmp %eax,0x0(%rbp) 400ec3: 74 05 je 400eca <phase_2+0x3e> 400ec5: e8 73 07 00 00 callq 40163d <explode_bomb> 400eca: 44 03 23 add (%rbx),%r12d 400ecd: 48 83 c5 04 add $0x4,%rbp 400ed1: 4c 39 ed cmp %r13,%rbp 400ed4: 75 e4 jne 400eba <phase_2+0x2e> 400ed6: 45 85 e4 test %r12d,%r12d 400ed9: 75 05 jne 400ee0 <phase_2+0x54> 400edb: e8 5d 07 00 00 callq 40163d <explode_bomb> 400ee0: 48 8b 5c 24 28 mov 0x28(%rsp),%rbx 400ee5: 48 8b 6c 24 30 mov 0x30(%rsp),%rbp 400eea: 4c 8b 64 24 38 mov 0x38(%rsp),%r12 400eef: 4c 8b 6c 24 40 mov 0x40(%rsp),%r13 400ef4: 48 83 c4 48 add $0x48,%rsp 400ef8: c3 retq
phase_2 会调用 read_six_numbers,所以我们要输入的应该是6个数字。
这段汇编代码比较好懂,是让我们比较 0x0(%rbp) 与 0xc(%rbp) ,0x4(%rbp) 与 0x10(%rbp),0x8(%rbp) 与 0x14(%rbp)的内容,一旦有一个不符就引爆炸弹,同时还会检测 0x0(%rbp) + 0x4(%rbp) + 0x8(%rbp) 的和是否为0,为0则引爆炸弹。
那么上面这些与我们输入的数字又有什么关系呢?只要在gdb中打印出来看看就行了。
啊哈,表示的就是我们输入进去的数字嘛。所以我们只要保证后三位与前三位相同同时前三位之和不为0就ok了。 比如 1 2 3 1 2 3
phase_3
0000000000400ef9 <phase_3>: 400ef9: 48 83 ec 18 sub $0x18,%rsp 400efd: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx 400f02: 48 8d 54 24 0c lea 0xc(%rsp),%rdx 400f07: be be 1e 40 00 mov $0x401ebe,%esi 400f0c: b8 00 00 00 00 mov $0x0,%eax 400f11: e8 9a fb ff ff callq 400ab0 <__isoc99_sscanf@plt> 400f16: 83 f8 01 cmp $0x1,%eax 400f19: 7f 05 jg 400f20 <phase_3+0x27> 400f1b: e8 1d 07 00 00 callq 40163d <explode_bomb> 400f20: 83 7c 24 0c 07 cmpl $0x7,0xc(%rsp) 400f25: 77 3c ja 400f63 <phase_3+0x6a> 400f27: 8b 44 24 0c mov 0xc(%rsp),%eax 400f2b: ff 24 c5 60 1b 40 00 jmpq *0x401b60(,%rax,8) 400f32: b8 17 02 00 00 mov $0x217,%eax 400f37: eb 3b jmp 400f74 <phase_3+0x7b> 400f39: b8 d6 00 00 00 mov $0xd6,%eax 400f3e: eb 34 jmp 400f74 <phase_3+0x7b> 400f40: b8 53 01 00 00 mov $0x153,%eax 400f45: eb 2d jmp 400f74 <phase_3+0x7b> 400f47: b8 77 00 00 00 mov $0x77,%eax 400f4c: eb 26 jmp 400f74 <phase_3+0x7b> 400f4e: b8 60 01 00 00 mov $0x160,%eax 400f53: eb 1f jmp 400f74 <phase_3+0x7b> 400f55: b8 97 03 00 00 mov $0x397,%eax 400f5a: eb 18 jmp 400f74 <phase_3+0x7b> 400f5c: b8 9c 01 00 00 mov $0x19c,%eax 400f61: eb 11 jmp 400f74 <phase_3+0x7b> 400f63: e8 d5 06 00 00 callq 40163d <explode_bomb> 400f68: b8 00 00 00 00 mov $0x0,%eax 400f6d: eb 05 jmp 400f74 <phase_3+0x7b> 400f6f: b8 9e 03 00 00 mov $0x39e,%eax 400f74: 3b 44 24 08 cmp 0x8(%rsp),%eax 400f78: 74 05 je 400f7f <phase_3+0x86> 400f7a: e8 be 06 00 00 callq 40163d <explode_bomb> 400f7f: 48 83 c4 18 add $0x18,%rsp 400f83: c3 retq
400ab0 <__isoc99_sscanf@plt> 指明了 sscanf 是标准库函数,经查文档,得到该函数的 signature 为 int sscanf(const char *buffer,const char *format,[argument ]...);
与gets函数一样都要有buffer,结合前面将 0x8(%rsp),0xc(%rsp) 的地址压入寄存器,以及后面会取出0x8(%rsp),0xc(%rsp)进行其他操作,所以猜测应该是输入的内容放入栈中这两个位置(作为buffer)。而且该函数的返回值(返回值为参数数目)要求大于1才不会爆炸,所以结合buffer的大小为2输入的应该是两个字符。%esi 对应的是参数 const char *forma,经打印为
更加确定输入的是两个字符,而且是两个数字。
后面部分就很简单,要求输入的第一个数字小于等于7,且跳转到 *(0x401b60 + 8 * args[1] ) 处。
这是一个switch结构,分别对eax赋值,然后与我们输入的第二个数字比较,相等才过关。
所以相应的这里的答案也有8组。其中一组为 0 535 。
phase_4
0000000000400fc1 <phase_4>: 400fc1: 48 83 ec 18 sub $0x18,%rsp 400fc5: 48 8d 54 24 0c lea 0xc(%rsp),%rdx 400fca: be c1 1e 40 00 mov $0x401ec1,%esi 400fcf: b8 00 00 00 00 mov $0x0,%eax 400fd4: e8 d7 fa ff ff callq 400ab0 <__isoc99_sscanf@plt> 400fd9: 83 f8 01 cmp $0x1,%eax 400fdc: 75 07 jne 400fe5 <phase_4+0x24> 400fde: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp) 400fe3: 7f 05 jg 400fea <phase_4+0x29> 400fe5: e8 53 06 00 00 callq 40163d <explode_bomb> 400fea: 8b 7c 24 0c mov 0xc(%rsp),%edi 400fee: e8 91 ff ff ff callq 400f84 <func4> 400ff3: 83 f8 37 cmp $0x37,%eax 400ff6: 74 05 je 400ffd <phase_4+0x3c> 400ff8: e8 40 06 00 00 callq 40163d <explode_bomb> 400ffd: 48 83 c4 18 add $0x18,%rsp 401001: c3 retq
0000000000400f84 <func4>: 400f84: 48 89 5c 24 f0 mov %rbx,-0x10(%rsp) 400f89: 48 89 6c 24 f8 mov %rbp,-0x8(%rsp) 400f8e: 48 83 ec 18 sub $0x18,%rsp 400f92: 89 fb mov %edi,%ebx 400f94: b8 01 00 00 00 mov $0x1,%eax 400f99: 83 ff 01 cmp $0x1,%edi 400f9c: 7e 14 jle 400fb2 <func4+0x2e> 400f9e: 8d 7b ff lea -0x1(%rbx),%edi 400fa1: e8 de ff ff ff callq 400f84 <func4> 400fa6: 89 c5 mov %eax,%ebp 400fa8: 8d 7b fe lea -0x2(%rbx),%edi 400fab: e8 d4 ff ff ff callq 400f84 <func4> 400fb0: 01 e8 add %ebp,%eax 400fb2: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx 400fb7: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp 400fbc: 48 83 c4 18 add $0x18,%rsp 400fc0: c3
要求是输入一个数(只能有一个数),要求这个数比0大,而且将这个数作为 func4 的参数。然后要求func4函数的返回值为0x37.而func4这个函数是个递归函数,所以这题的关键是func4函数。我们只要写出该函数的 C 形式,然后不同的数去试就ok了。
原文:http://www.cnblogs.com/whuyt/p/4842368.html