介绍:这是一个“拆弹”游戏,玩家要在反汇编中找到每一关的拆弹密码,一共有6个phases。 该Lab的下载地址:http://csapp.cs.cmu.edu/3e/labs.html

警告:本文含有剧透内容,想要玩Lab2的慎看!

先看phase_1

0000000000400ee0 <phase_1>:
  400ee0:	sub    $0x8,%rsp
  400ee4:   mov    $0x402400,%esi
  400ee9:	callq  401338 <strings_not_equal>
  400eee:	test   %eax,%eax
  400ef0:	je     400ef7 <phase_1+0x17>
  400ef2:	callq  40143a <explode_bomb>
  400ef7:	add    $0x8,%rsp
  400efb:	retq   

很短很简单,第2行和第8行是分配和释放栈空间,用来存放局部变量。 第3行将地址放到esi,并在第4行调用了函数strings_not_equal。根据寄存器表 reg.jpg 可以看出这里的调用是strings_not_equal(input, *0x402400) 然后第5,6行进行了比较,如果字符串相同才不炸。 剩下的就简单了,用gdb查一下那个地址存着什么就可以了:

(gdb) x/s 0x402400
0x402400:       "Border relations with Canada have never been better."

输入该字符串过关。

接下来是phase2

0000000000400efc <phase_2>:
  400efc:	push   %rbp
  400efd:	push   %rbx
  400efe:	sub    $0x28,%rsp
  400f02:   mov    %rsp,%rsi    ;rsi=rsp
  400f05    callq  40145c <read_six_numbers> ;read 6 numbers into rsp,+4,+8,+12,+16,+20
  400f0a:   cmpl   $0x1,(%rsp)
  400f0e:	je     400f30 <phase_2+0x34> ;N1==1
  400f10:	callq  40143a <explode_bomb>
  400f15:	jmp    400f30 <phase_2+0x34>
  400f17:	mov    -0x4(%rbx),%eax       ;eax=*(rbx-4)
  400f1a:	add    %eax,%eax             ;eax*=2
  400f1c:	cmp    %eax,(%rbx)
  400f1e:	je     400f25 <phase_2+0x29> ;if *rbx==eax
  400f20:	callq  40143a <explode_bomb> ;         |
  400f25:   add    $0x4,%rbx             ; rbx+=4
  400f29:   cmp    %rbp,%rbx
  400f2c:   jne    400f17 <phase_2+0x1b> ;if rbx!=rbp ->400f17
  400f2e:   jmp    400f3c <phase_2+0x40> ;else ->400f3c
  400f30:   lea    0x4(%rsp),%rbx        ;rbx=rsp+4
  400f35:   lea    0x18(%rsp),%rbp       ;rbp=rsp+24
  400f3a:   jmp    400f17 <phase_2+0x1b> ;->400f17
  400f3c:   add    $0x28,%rsp
  400f40:	pop    %rbx
  400f41:	pop    %rbp
  400f42:	retq   

汇编的含义已经注释在代码里了,一开始用函数read_six_numbers读入了6个数到栈上(那个函数我读了半天(╯‵□′)╯︵┻━┻),然后观察可以看出来中间的部分其实是一个for循环,17-19行是判断语句,20-22行是初始化语句,11-16行则是循环体。转换成伪c代码大约是这样的:

for(rbx=rsp+4,rbp=rsp+24;rbx!=rbp;rbx+=4){
    if((*(rbx-4))*2!=*rbx) explode_bomb();
}

结合第8行N1需要等于1的要求,很明显这段代码是要求6个由1开头每次*2的等比数列,即1 2 4 8 16 32。