bomb lab是一道学习汇编语言的题,一共有六个阶段,全部解开即可完成
phase_1
1 0x0000000000400e32 <+146>: callq 0x40149e2 0x0000000000400e37 <+151>: mov %rax,%rdi 3 0x0000000000400e3a <+154>: callq 0x400ee0
这三个指令就是phase_1了,第一条是一个调用read_line的命令,众所周知...%rax代表返回值,所以第二条命令则是指:将%rax的值赋给%rdi,记住这个rdi,待会儿有用,然后调用第三条指令phase_1
1 0x0000000000400ee0 <+0>: sub $0x8,%rsp 2 0x0000000000400ee4 <+4>: mov $0x402400,%esi 3 0x0000000000400ee9 <+9>: callq 0x4013384 0x0000000000400eee <+14>: test %eax,%eax 5 0x0000000000400ef0 <+16>: je 0x400ef7 23> 6 0x0000000000400ef2 <+18>: callq 0x40143a 7 0x0000000000400ef7 <+23>: add $0x8,%rsp 8 0x0000000000400efb <+27>: retq
第一条和第八条就不看了,从第二条开始,将0x402400赋给了%esi,记住这个数,然后调用了strings_not_equal,这个函数很好理解,判断两个字符串是否相等,这个函数是这样的(一部分)
1 0x000000000040133c <+4>: mov %rdi,%rbx 2 0x000000000040133f <+7>: mov %rsi,%rbp
从这两行可以看出,这个函数的参数是%rdi和%rsi,%rdi是read_line得到的值,%rsi是0x402400,回到phase_1,第四条指令test判断strings_not_euqal的返回值是否为0,若为零则跳转到0x400ef7,若不为零则会执行explode_bomb,这就是这个炸弹函数,我们不能执行它,所以,我们需要让%eax为零,也就是让%rdi和%rsi的字符串相等,我们使用命令x/s 0x402400查看内存,可以看到如下输出
1 0x402400: "Border relations with Canada have never been better."
这就是我们第一题的答案了
phase_2
接下来是phase_2,我们还是像第一阶段一样,先看看代码
1 0x0000000000400efc <+0>: push %rbp 2 0x0000000000400efd <+1>: push %rbx 3 0x0000000000400efe <+2>: sub $0x28,%rsp 4 0x0000000000400f02 <+6>: mov %rsp,%rsi 5 0x0000000000400f05 <+9>: callq 0x40145c6 0x0000000000400f0a <+14>: cmpl $0x1,(%rsp) 7 0x0000000000400f0e <+18>: je 0x400f30 52> 8 0x0000000000400f10 <+20>: callq 0x40143a 9 0x0000000000400f15 <+25>: jmp 0x400f30 52> 10 0x0000000000400f17 <+27>: mov -0x4(%rbx),%eax 11 0x0000000000400f1a <+30>: add %eax,%eax 12 0x0000000000400f1c <+32>: cmp %eax,(%rbx) 13 0x0000000000400f1e <+34>: je 0x400f25 41> 14 0x0000000000400f20 <+36>: callq 0x40143a 15 0x0000000000400f25 <+41>: add $0x4,%rbx 16 0x0000000000400f29 <+45>: cmp %rbp,%rbx 17 0x0000000000400f2c <+48>: jne 0x400f17 27> 18 0x0000000000400f2e <+50>: jmp 0x400f3c 64> 19 0x0000000000400f30 <+52>: lea 0x4(%rsp),%rbx 20 0x0000000000400f35 <+57>: lea 0x18(%rsp),%rbp 21 0x0000000000400f3a <+62>: jmp 0x400f17 27> 22 0x0000000000400f3c <+64>: add $0x28,%rsp 23 0x0000000000400f40 <+68>: pop %rbx 24 0x0000000000400f41 <+69>: pop %rbp 25 0x0000000000400f42 <+70>: retq
首先将rsp减28,将rsp赋值给rsi
这样,rsi和rsp都指向-28
然后调用read_six_numbers
1 0x000000000040145c <+0>: sub $0x18,%rsp 2 0x0000000000401460 <+4>: mov %rsi,%rdx 3 0x0000000000401463 <+7>: lea 0x4(%rsi),%rcx 4 0x0000000000401467 <+11>: lea 0x14(%rsi),%rax 5 0x000000000040146b <+15>: mov %rax,0x8(%rsp) 6 0x0000000000401470 <+20>: lea 0x10(%rsi),%rax 7 0x0000000000401474 <+24>: mov %rax,(%rsp) 8 0x0000000000401478 <+28>: lea 0xc(%rsi),%r9 9 0x000000000040147c <+32>: lea 0x8(%rsi),%r8 10 0x0000000000401480 <+36>: mov $0x4025c3,%esi 11 0x0000000000401485 <+41>: mov $0x0,%eax 12 0x000000000040148a <+46>: callq 0x400bf0 <__isoc99_sscanf@plt> 13 0x000000000040148f <+51>: cmp $0x5,%eax 14 0x0000000000401492 <+54>: jg 0x40149961> 15 0x0000000000401494 <+56>: callq 0x40143a 16 0x0000000000401499 <+61>: add $0x18,%rsp 17 0x000000000040149d <+65>: retq
这个的话主要作用是调用sscanf函数,这是一个c语言函数
大概是这样的
1 int sscanf(const char *str, const char *format, ...)
str就是我们要输入的字符串,而format是模板,这个模板存在0x4025c3所在的内存中,我们通过x指令看一下
1 0x4025c3: "%d %d %d %d %d %d"
6个数字,很清晰
而sscanf还可以接受任意个参数,用来解析模板中的数字,这6个参数分别是:rdx/rcx/r8/r9/栈顶/栈顶-1
为了不触发炸弹,我们从汇编代码中推测出rsp指向的内存为1,而整个循环则是判断高位的数是否是低位的2倍,那么就可以得知,从rsp开始的6个数为1,2,4,8,16,32了
答案便是"1 2 4 8 16 32"
phase_3
1 0x0000000000400f43 <+0>: sub $0x18,%rsp 2 0x0000000000400f47 <+4>: lea 0xc(%rsp),%rcx 3 0x0000000000400f4c <+9>: lea 0x8(%rsp),%rdx 4 0x0000000000400f51 <+14>: mov $0x4025cf,%esi 5 0x0000000000400f56 <+19>: mov $0x0,%eax 6 0x0000000000400f5b <+24>: callq 0x400bf0 <__isoc99_sscanf@plt> 7 0x0000000000400f60 <+29>: cmp $0x1,%eax 8 0x0000000000400f63 <+32>: jg 0x400f6a39> 9 0x0000000000400f65 <+34>: callq 0x40143a 10 0x0000000000400f6a <+39>: cmpl $0x7,0x8(%rsp) 11 0x0000000000400f6f <+44>: ja 0x400fad 106> 12 0x0000000000400f71 <+46>: mov 0x8(%rsp),%eax 13 0x0000000000400f75 <+50>: jmpq *0x402470(,%rax,8) 14 0x0000000000400f7c <+57>: mov $0xcf,%eax 15 0x0000000000400f81 <+62>: jmp 0x400fbe 123> 16 0x0000000000400f83 <+64>: mov $0x2c3,%eax 17 0x0000000000400f88 <+69>: jmp 0x400fbe 123> 18 0x0000000000400f8a <+71>: mov $0x100,%eax 19 0x0000000000400f8f <+76>: jmp 0x400fbe 123> 20 0x0000000000400f91 <+78>: mov $0x185,%eax 21 0x0000000000400f96 <+83>: jmp 0x400fbe 123> 22 0x0000000000400f98 <+85>: mov $0xce,%eax 23 0x0000000000400f9d <+90>: jmp 0x400fbe 123> 24 0x0000000000400f9f <+92>: mov $0x2aa,%eax 25 0x0000000000400fa4 <+97>: jmp 0x400fbe 123> 26 0x0000000000400fa6 <+99>: mov $0x147,%eax 27 0x0000000000400fab <+104>: jmp 0x400fbe 123> 28 0x0000000000400fad <+106>: callq 0x40143a 29 0x0000000000400fb2 <+111>: mov $0x0,%eax 30 0x0000000000400fb7 <+116>: jmp 0x400fbe 123> 31 ---Type to continue, or q to quit--- 32 0x0000000000400fb9 <+118>: mov $0x137,%eax 33 0x0000000000400fbe <+123>: cmp 0xc(%rsp),%eax 34 0x0000000000400fc2 <+127>: je 0x400fc9134> 35 0x0000000000400fc4 <+129>: callq 0x40143a 36 0x0000000000400fc9 <+134>: add $0x18,%rsp 37 0x0000000000400fcd <+138>: retq
还是sscanf,首先确定rdx和rcx的位置分别是+8和+c,这就是你要输的两个数字,然后关注+39行,将rdx和7比较,大于则bomb,然后根据rdx的值去访问(0x402470+rdx*8)代表的内存,然后以这个值作为地址,进行跳转
从0x402470开始的8个跳转地址分别是:
1 0x402470: 0x400f7c57> 0x400fb9 118> 2 0x402480: 0x400f83 64> 0x400f8a 71> 3 0x402490: 0x400f91 78> 0x400f98 85> 4 0x4024a0: 0x400f9f 92> 0x400fa6 99>
尖括号内则是跳转的地址,我们可以知道,如果rdx是7,跳到99,让rcx与0x147比较,相等则成功,这里有8个地址
根据rdx的不同,rcx的值也不同,从7到0分别是:0x147,0x2aa,0xce,0x185,0x100,0x203,0x137,0xcf,那么答案就显而易见了
顺便,那个模板的样式是这样的
1 0x4025cf: "%d %d"