深入理解计算机系统 / CSAPP Data Lab2
深入理解计算机系统 / CSAPP Data Lab2 "扫雷"
前
拿着锅碗瓢盆造火箭(我更新了!)
反汇编
objdump -d bomb >test.txt
答案
1、Border relations with Canada have never been better.
2、1 2 4 8 16 32
3、0 207 ;1 311 ;2 707 ;3 256 ;4 389 ;5 206 ;6 682 ;7 327(任意一组)
4、0 0 ;1 0 ;3 0 ;7 0(任意一组)
5、ioNu6W(省略其余38880种答案)
6、4 3 2 1 6 5
隐藏关卡见最后
phase_1:字符串
0000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 sub $0x8,%rsp
#压栈
400ee4: be 00 24 40 00 mov $0x402400,%esi
#将内存 0x402400 中的值移动到%esi
400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal>
#调用函数string_not_equal #猜测是判断函数,见 401338
400eee: 85 c0 test %eax,%eax
#测试(%eax)(由string_not_equal返回)是否为 0
400ef0: 74 05 je 400ef7 <phase_1+0x17>
# 相等(%eax==0)时跳转到 400ef7(出栈)
400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>
#不相等时调用 explode_bomb(爆炸)
400ef7: 48 83 c4 08 add $0x8,%rsp
#出栈
400efb: c3 retq retq
查看内存 0x402400的内容
(gdb) x/ls 0x402400
0x402400: "Border relations with Canada have never been better."
第一个炸弹的答案 Border relations with Canada have never been better.
phase_2:循环
0000000000400efc <phase_2>:
400efc: 55 push %rbp
#压栈
400efd: 53 push %rbx
#压栈
400efe: 48 83 ec 28 sub $0x28,%rsp
#压栈 0x28 = 40
400f02: 48 89 e6 mov %rsp,%rsi
400f05: e8 52 05 00 00 callq 40145c <read_six_numbers>
#调用函数 read_six_numbers #猜测输入六个数的函数
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)
#比较 1 和 (%rsp)
400f0e: 74 20 je 400f30 <phase_2+0x34>
# 相等 跳转到 400f30
400f10: e8 25 05 00 00 callq 40143a <explode_bomb>
#不相等 调用explode_bomb (爆炸)
400f15: eb 19 jmp 400f30 <phase_2+0x34>
400f17: 8b 43 fc mov -0x4(%rbx),%eax
# %eax = -4 + (%rbx) (%rbx 为内存地址,-4 则为前一个数)
400f1a: 01 c0 add %eax,%eax
# %eax = 2 * %eax
400f1c: 39 03 cmp %eax,(%rbx)
#比较%eax和(%rbx) (比较一个数和是否和前一个数的二倍相等)
400f1e: 74 05 je 400f25 <phase_2+0x29>
# 相等则跳转到 400f25
400f20: e8 15 05 00 00 callq 40143a <explode_bomb>
#不相等则调用explode_bomb (爆炸)
400f25: 48 83 c3 04 add $0x4,%rbx
# %rbx = %rbx + 4
400f29: 48 39 eb cmp %rbp,%rbx
# %rbp == %rbx
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
#不相等则跳转到 400f17 (循环出现,这里应该是判断)
400f2e: eb 0c jmp 400f3c <phase_2+0x40>
#循环结束 则跳转到 400f3c (出栈)
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
# %rbx = 4 + (%rsp) (第二个数的值)
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
# %rbp = 24 + (%rsp) (第六+1个数的值,应该结束后的空间,地址偏移24空间反正是无效的)
400f3a: eb db jmp 400f17 <phase_2+0x1b>
#跳转到 400f17
400f3c: 48 83 c4 28 add $0x28,%rsp
#出栈
400f40: 5b pop %rbx
#出栈
400f41: 5d pop %rbp
#出栈
400f42: c3 retq
一个数必须为 1
存在一个循环, 循环结构为 [400f17,400f3a] ,大概整理伪代码,假设六个数为数列(同名变量名表示寄存器)a[5]:
if a[0]!=1
explode_bomb();
int *rbx = a+1;
int *rbp = a+6;
do
{
int *eax =rbx-1;
if((*eax) * 2 != rbx)
explode_bomb()
rbx + 1
}
while(rbx!=rbp)
不满足条件则不触发
即为长度6,(多也无所谓,read_six_numbers()将多余的数字过滤)为首项为1,公比为2的等比数列为第二题的解1 2 4 8 16 32
phase_3:分支
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub $0x18,%rsp
#压栈 0x18 = 24
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
# %rcx = (%rsp) + 12
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
# %rdx = (%rsp) + 8
400f51: be cf 25 40 00 mov $0x4025cf,%esi
# 0x4025cf:%d %d 暗示输入为两个操作数
400f56: b8 00 00 00 00 mov $0x0,%eax #
400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt>
# scanf
400f60: 83 f8 01 cmp $0x1,%eax
# 1 == %eax
400f63: 7f 05 jg 400f6a <phase_3+0x27>
#如果 %eax > 1 则跳转到 400f6a
400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>
# 调用 explode_bomb(爆炸)
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
# 7== (%rsp) +8
400f6f: 77 3c ja 400fad <phase_3+0x6a>
#如果(%rsp) + 8 > 7 即,第一个是大于 7 则跳转到 400fad (爆炸)
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
# %eax = (%rsp) + 8 第一个数
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
#跳转到 0x402470 + 8 * (%rax)
#这里似乎使用的是switch的判断条件,但是不知道%rax的值
#可以通过 x/s *(int *)(0X402470 + i * 8)寻址,但是不知道的具体方式
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
# %eax = 0xcf = 207
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
# %eax = 0x2c3 = 707
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400f8a: b8 00 01 00 00 mov $0x100,%eax
# %eax = 0x100 = 256
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400f91: b8 85 01 00 00 mov $0x185,%eax
# %eax = 0x185 = 344
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400f98: b8 ce 00 00 00 mov $0xce,%eax
# %eax = 0xce 206
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
# %eax = 0x2aa = 682
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400fa6: b8 47 01 00 00 mov $0x147,%eax
# %eax = 0x147 = 327
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
# 调用 explode_bomb(爆炸)
400fb2: b8 00 00 00 00 mov $0x0,%eax
# %eax = 0x0 = 0
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
#直接跳转到 400fbe
400fb9: b8 37 01 00 00 mov $0x137,%eax
# %eax = 0x137 = 311
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
# %rsp + 12 /(%rcx 即输入的第二个值) == %eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
#如果相等则跳转到 400fc9(出栈)
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>
#调用 explode_bomb(爆炸)
400fc9: 48 83 c4 18 add $0x18,%rsp
#出栈
输入两个数 , 第一个数的范围是需要小于 7
存在一个switch语句,判断代码在 400f75 没看到跳转机制,然后查找资料得可以使用命令查看跳转位置:
(gdb) x/s *(int *) (0x402470)
0x400f7c <phase_3+57>: "\270", <incomplete sequence \317>
(gdb) x/s *(int *) (0x402470 + 8)
0x400fb9 <phase_3+118>: "\270\067\001"
(gdb) x/s *(int *) (0x402470 + 16)
0x400f83 <phase_3+64>: "\270\303\002"
(gdb) x/s *(int *) (0x402470 + 24)
0x400f8a <phase_3+71>: "\270"
(gdb) x/s *(int *) (0x402470 + 32)
0x400f91 <phase_3+78>: "\270\205\001"
(gdb) x/s *(int *) (0x402470 + 40)
0x400f98 <phase_3+85>: "\270", <incomplete sequence \316>
(gdb) x/s *(int *) (0x402470 + 48)
0x400f9f <phase_3+92>: "\270\252\002"
(gdb) x/s *(int *) (0x402470 + 56)
0x400fa6 <phase_3+99>: "\270G\001"
程序大概为(同名变量名表示寄存器):
long rdx;
int rcx;
int eax;
scanf("%d,%d",&rdx,&rcx);
if(rdx < 7)
explode_bomb();
switch(rdx)
{
case 0:
eax = 207;
break;
case 1:
eax = 311;
break;
case 2:
eax = 707;
break;
case 3:
eax = 256;
break;
case 4:
eax = 389;
break;
case 5:
eax = 206;
break;
case 6:
eax = 682;
break;
case 7:
eax = 327;
break;
default:
explode_bomb();
}
}
if(eax != rcx)
explode_bomb()
即,满足条件的四组分别为 0 207
;1 311
;2 707
;3 256
;4 389
;5 206
;6 682
;7 327
phase_4:递归
0000000000400fce <func4>:
# %edi等于传入的第二个数, %esi = 0,%edx = 14;
400fce: 48 83 ec 08 sub $0x8,%rsp
#压栈
400fd2: 89 d0 mov %edx,%eax
# %eax = %edx
400fd4: 29 f0 sub %esi,%eax
# %eax= %eax - %esi
400fd6: 89 c1 mov %eax,%ecx
# %ecx = %eax
400fd8: c1 e9 1f shr $0x1f,%ecx
#右移 %ecx = %ecx >> 0x1f
400fdb: 01 c8 add %ecx,%eax
# %eax = %eax + %ecx
400fdd: d1 f8 sar %eax
#右移一位 %eax = %eax >> 1
# 上面6行的效果是 %eax = ((%edx - %esi) >>31 + %edx - %esi ) >> 1
400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx
# %ecx = %rax + %rsi (%rax = %eax,%rsi = %esi)|?
# %ecx = (((%edx - %esi >>31) + %edx - %esi ) >> 1) + %esi
400fe2: 39 f9 cmp %edi,%ecx
# %ecx == %edi
400fe4: 7e 0c jle 400ff2 <func4+0x24>
#如果 %ecx小于等于%edi 则跳转到 400ff2
400fe6: 8d 51 ff lea -0x1(%rcx),%edx
# %edx = (%ecx) - 1
400fe9: e8 e0 ff ff ff callq 400fce <func4>
#递归
400fee: 01 c0 add %eax,%eax
# %eax = %eax + %eax
400ff0: eb 15 jmp 401007 <func4+0x39>
#跳转到 401007 (出栈,递归结束)
400ff2: b8 00 00 00 00 mov $0x0,%eax
# %eax = 0
400ff7: 39 f9 cmp %edi,%ecx
# %edi == %ecx
400ff9: 7d 0c jge 401007 <func4+0x39>
#如果 %ecx >= %edi 则跳转到 401007 (出栈,递归结束)
400ffb: 8d 71 01 lea 0x1(%rcx),%esi
# %esi = (%ecx) + 1
400ffe: e8 cb ff ff ff callq 400fce <func4>
#出现递归,自己调用自己
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
# %eax = %rax + %rax +1
401007: 48 83 c4 08 add $0x8,%rsp
#出栈
40100b: c3
0000000000400fce <func4>:
# %edi等于传入的第二个数, %esi = 0,%edx = 14;
400fce: 48 83 ec 08 sub $0x8,%rsp
#压栈
400fd2: 89 d0 mov %edx,%eax
# %eax = %edx
400fd4: 29 f0 sub %esi,%eax
# %eax= %eax - %esi
400fd6: 89 c1 mov %eax,%ecx
# %ecx = %eax
400fd8: c1 e9 1f shr $0x1f,%ecx
#右移 %ecx = %ecx >> 0x1f
400fdb: 01 c8 add %ecx,%eax
# %eax = %eax + %ecx
400fdd: d1 f8 sar %eax
#右移一位 %eax = %eax >> 1
# 上面6行的效果是 %eax = ((%edx - %esi) >>31 + %edx - %esi ) >> 1
400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx
# %ecx = %rax + %rsi (%rax = %eax,%rsi = %esi)|?
# %ecx = (((%edx - %esi >>31) + %edx - %esi ) >> 1) + %esi
400fe2: 39 f9 cmp %edi,%ecx
# %ecx == %edi
400fe4: 7e 0c jle 400ff2 <func4+0x24>
#如果 %ecx小于等于%edi 则跳转到 400ff2
400fe6: 8d 51 ff lea -0x1(%rcx),%edx
# %edx = (%ecx) - 1
400fe9: e8 e0 ff ff ff callq 400fce <func4>
#递归
400fee: 01 c0 add %eax,%eax
# %eax = %eax + %eax
400ff0: eb 15 jmp 401007 <func4+0x39>
#跳转到 401007 (出栈,递归结束)
400ff2: b8 00 00 00 00 mov $0x0,%eax
# %eax = 0
400ff7: 39 f9 cmp %edi,%ecx
# %edi == %ecx
400ff9: 7d 0c jge 401007 <func4+0x39>
#如果 %ecx >= %edi 则跳转到 401007 (出栈,递归结束)
400ffb: 8d 71 01 lea 0x1(%rcx),%esi
# %esi = (%ecx) + 1
400ffe: e8 cb ff ff ff callq 400fce <func4>
#出现递归,自己调用自己
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
# %eax = %rax + %rax +1
401007: 48 83 c4 08 add $0x8,%rsp
#出栈
第一个数的范围小于15 值有func4决定,%eax 为函数func4 的返回值, 第二个数的值为 0
func4 是一个递归函数,见 400fce
我们通过一个程序来测试出符合条件的取值。
include <stdio.h>
int main()
{
int i;
int result;
for(i = 0;i < 15;i++)
{
result = func4(i,0,14);
if (result==0)
printf("%d\n",i);
}
return 0;
}
int func4(int edi,int esi,int edx)
{
int ecx = (((edx - esi >>31) + edx - esi ) >> 1) + esi;
if (ecx <= edi)
{
if(ecx >= edi)
return 0;
else
return func4(edi,ecx+1,edx) * 2 +1;
}
else
return func4(edi,esi,ecx-1) * 2;
}
输出为 0 1 3 7
即,满足条件的四组分别为 0 0
;1 0
;3 0
;7 0
phase_5:字符串Plus
00000000004010f4 <phase_6>:
4010f4: 41 56 push %r14
#压栈
4010f6: 41 55 push %r13
#压栈
4010f8: 41 54 push %r12
#压栈
4010fa: 55 push %rbp
#压栈
4010fb: 53 push %rbx
#压栈
4010fc: 48 83 ec 50 sub $0x50,%rsp
#压栈 0x50 = 80
401100: 49 89 e5 mov %rsp,%r13
# %r13 = %rsp
401103: 48 89 e6 mov %rsp,%rsi
# %rsi = %rsp
401106: e8 51 03 00 00 callq 40145c <read_six_numbers>
#调用函数 read_six_numbers 输入六个数(和phase_2相同)
40110b: 49 89 e6 mov %rsp,%r14
# %r14 = %rsp
40110e: 41 bc 00 00 00 00 mov $0x0,%r12d
# %r12d = 0
401114: 4c 89 ed mov %r13,%rbp
# %rbp = %r13
401117: 41 8b 45 00 mov 0x0(%r13),%eax
# %eax = %r13
40111b: 83 e8 01 sub $0x1,%eax
# %eax -= 1
40111e: 83 f8 05 cmp $0x5,%eax
# %eax == 5
401121: 76 05 jbe 401128 <phase_6+0x34>
#如果小于等于这跳转到 401128
401123: e8 12 03 00 00 callq 40143a <explode_bomb>
#如果大于则 调用 40143a (爆炸)
401128: 41 83 c4 01 add $0x1,%r12d
# %r12d += 1
40112c: 41 83 fc 06 cmp $0x6,%r12d
# %12d == 6
401130: 74 21 je 401153 <phase_6+0x5f>
# 相等则跳转到 401153
401132: 44 89 e3 mov %r12d,%ebx
#不相等则 %r12 = %ebx
401135: 48 63 c3 movslq %ebx,%rax
# %rax = %ebx
401138: 8b 04 84 mov (%rsp,%rax,4),%eax
# %eax = (%rsp + %rax * 4) # %rsp + 4 即到下一个数
40113b: 39 45 00 cmp %eax,0x0(%rbp)
# %eax == (%rbp)
40113e: 75 05 jne 401145 <phase_6+0x51>
#不相等则跳转到 401145
401140: e8 f5 02 00 00 callq 40143a <explode_bomb>
# 相等则调用 40143a (爆炸)
401145: 83 c3 01 add $0x1,%ebx
# %ebx += 1
401148: 83 fb 05 cmp $0x5,%ebx
# %ebx == 5
40114b: 7e e8 jle 401135 <phase_6+0x41>
#小于等于则 跳转到 401135
40114d: 49 83 c5 04 add $0x4,%r13
# %r13 += 4 # %rsp + 4 即到下一个数
401151: eb c1 jmp 401114 <phase_6+0x20>
# 跳转到 401114 (循环???)
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi
# %rsi = (%rsp) + 24
401158: 4c 89 f0 mov %r14,%rax
# %rax = %r14
40115b: b9 07 00 00 00 mov $0x7,%ecx
# %ecx = 7
401160: 89 ca mov %ecx,%edx
# %edx = %ecx
401162: 2b 10 sub (%rax),%edx
# %edx -= %rax
401164: 89 10 mov %edx,(%rax)
# (%rax) = %edx
401166: 48 83 c0 04 add $0x4,%rax
# %rax +=4 #这里应该是 (%rax) + 4 更加准确
40116a: 48 39 f0 cmp %rsi,%rax
# %rsi == %rax
40116d: 75 f1 jne 401160 <phase_6+0x6c>
#不相等则跳转到 401160 (循环出现)
40116f: be 00 00 00 00 mov $0x0,%esi
# 相等则 %esi = 0
401174: eb 21 jmp 401197 <phase_6+0xa3>
#直接跳转到 401197
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx
# %rdx = (%rdx) + 8
40117a: 83 c0 01 add $0x1,%eax
# %eax += 1 #%eax = %rsp
40117d: 39 c8 cmp %ecx,%eax
# %eax ==%ecx
40117f: 75 f5 jne 401176 <phase_6+0x82>
#不相等则跳转到 401176 (也是一个循环)
401181: eb 05 jmp 401188 <phase_6+0x94>
# 相等则跳转到 401188
401183: ba d0 32 60 00 mov $0x6032d0,%edx
# %edx = $0x6032d0
401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)
# (%rsp + %rsi * 2) + 32 =%rdx
40118d: 48 83 c6 04 add $0x4,%rsi
# %rsi += 4
401191: 48 83 fe 18 cmp $0x18,%rsi
# %rsi == 24
401195: 74 14 je 4011ab <phase_6+0xb7>
# 相等则跳转到 4011ab
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
# %ecx = (%rsp + %rsi)
40119a: 83 f9 01 cmp $0x1,%ecx
# %ecx == 1
40119d: 7e e4 jle 401183 <phase_6+0x8f>
#小于等于调用 401183
40119f: b8 01 00 00 00 mov $0x1,%eax
#%eax = 1
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx
#%edx = $0x6032d0
4011a9: eb cb jmp 401176 <phase_6+0x82>
#跳转到 401176 (还有一个循环)
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
# %rbx = (%rsp) + 32
4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax
# %rax = (%rsp) + 40
4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi
# %rsi = (%rsp) + 80
4011ba: 48 89 d9 mov %rbx,%rcx
# %rcx = %rbx
4011bd: 48 8b 10 mov (%rax),%rdx
# %rdx = (%rax)
4011c0: 48 89 51 08 mov %rdx,0x8(%rcx)
# (%rcx) + 8 =%rdx #指向下一个
4011c4: 48 83 c0 08 add $0x8,%rax
# %rax += 8
4011c8: 48 39 f0 cmp %rsi,%rax
# %rax == %rsi
4011cb: 74 05 je 4011d2 <phase_6+0xde>
# 相等则跳转到 4011d2
4011cd: 48 89 d1 mov %rdx,%rcx
#不相等 %rcx = %rdx
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
#跳转到 4011bd (又是一个循环?)
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
# (%rdx) +8 = 0 #尾节点 ->NULL
4011d9: 00
4011da: bd 05 00 00 00 mov $0x5,%ebp
# %ebp = 5
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax
# %rax = (%rbx) + 8
4011e3: 8b 00 mov (%rax),%eax
# %eax = (%rax)
4011e5: 39 03 cmp %eax,(%rbx)
# (%rbx) == (%eax)
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
#大于等于则 跳转到 4011ee
4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb>
#否则 调用40143a(爆炸)
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
# %rbx = (%rbx) + 8
4011f2: 83 ed 01 sub $0x1,%ebp
# %ebp -= 1
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
#不相等则跳转到 4011df
4011f7: 48 83 c4 50 add $0x50,%rsp
# 下面为出栈和返回
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 retq
确定输入一个长度为 6 的字符串
经过查看的 %rbx为输入的字符串的值
在 401099 将一个值一个数移动到 %eax, 使用gdb 查看
(gdb) x/s 0x4024b0
0x4024b0 <array.3449>: "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
在 4010b3 又将一个值一个数移动到 %eax, 使用gdb 查看
在 4010b3 又将一个值一个数移动到 %eax, 使用gdb 查看
(gdb) x/ls 0x40245e
0x40245e: "flyers"
这个题的具体操作就是将输入的字符串安装他的规则映射后与 "flyers"对比
基本步骤超级伪代码为:
这个题的具体操作就是将输入的字符串安装他的规则映射后与 "flyers"对比
基本步骤超级伪代码为:
字符串2[] = "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
字符串1[] = 输入()
if len(字符串[]) != 6
explode_bomb()
i = 0
do
{
新字符串[i]=字符串2[字符串1[i].ascii尾位]
i++
}
while i<6
新字符串[6] = "\0"
if 新字符串 == "flyers"
return 0;
else
explode_bomb()
flyers在字符串2中的索引分别为 9 f e 5 6 7
我们这次用Python将所有答案打印出来(只包括标准ASCII课显示字符),大约 38881 种答案
num1=[]
for i in range(32,127):
if hex(i)[-1]=="9":
num1.append(chr(i))
print(num1)
num2=[]
for i in range(32,127):
if hex(i)[-1]=="f":
num2.append(chr(i))
print(num2)
num3=[]
for i in range(32,127):
if hex(i)[-1]=="e":
num3.append(chr(i))
print(num3)
num4=[]
for i in range(32,127):
if hex(i)[-1]=="5":
num4.append(chr(i))
print(num4)
num5=[]
for i in range(32,127):
if hex(i)[-1]=="6":
num5.append(chr(i))
print(num5)
num6=[]
for i in range(32,127):
if hex(i)[-1]=="7":
num6.append(chr(i))
print(num6)
for i in num1:
for j in num2:
print()
for k in num3:
for l in num4:
print()
for m in num5:
for n in num6:
print(i+j+k+l+m+n,end="\t")
随便输一组答案 ioNu6W
就过关了
phase_6:链表
00000000004010f4 <phase_6>:
4010f4: 41 56 push %r14
#压栈
4010f6: 41 55 push %r13
#压栈
4010f8: 41 54 push %r12
#压栈
4010fa: 55 push %rbp
#压栈
4010fb: 53 push %rbx
#压栈
4010fc: 48 83 ec 50 sub $0x50,%rsp
#压栈 0x50 = 80
401100: 49 89 e5 mov %rsp,%r13
# %r13 = %rsp
401103: 48 89 e6 mov %rsp,%rsi
# %rsi = %rsp
401106: e8 51 03 00 00 callq 40145c <read_six_numbers>
#调用函数 read_six_numbers 输入六个数(和phase_2相同)
40110b: 49 89 e6 mov %rsp,%r14
# %r14 = %rsp
40110e: 41 bc 00 00 00 00 mov $0x0,%r12d
# %r12d = 0
401114: 4c 89 ed mov %r13,%rbp
# %rbp = %r13
401117: 41 8b 45 00 mov 0x0(%r13),%eax
# %eax = %r13
40111b: 83 e8 01 sub $0x1,%eax
# %eax -= 1
40111e: 83 f8 05 cmp $0x5,%eax
# %eax == 5
401121: 76 05 jbe 401128 <phase_6+0x34>
#如果小于等于这跳转到 401128
401123: e8 12 03 00 00 callq 40143a <explode_bomb>
#如果大于则 调用 40143a (爆炸)
401128: 41 83 c4 01 add $0x1,%r12d
# %r12d += 1
40112c: 41 83 fc 06 cmp $0x6,%r12d
# %12d == 6
401130: 74 21 je 401153 <phase_6+0x5f>
# 相等则跳转到 401153
401132: 44 89 e3 mov %r12d,%ebx
#不相等则 %r12 = %ebx
401135: 48 63 c3 movslq %ebx,%rax
# %rax = %ebx
401138: 8b 04 84 mov (%rsp,%rax,4),%eax
# %eax = (%rsp + %rax * 4) # %rsp + 4 即到下一个数
40113b: 39 45 00 cmp %eax,0x0(%rbp)
# %eax == (%rbp)
40113e: 75 05 jne 401145 <phase_6+0x51>
#不相等则跳转到 401145
401140: e8 f5 02 00 00 callq 40143a <explode_bomb>
# 相等则调用 40143a (爆炸)
401145: 83 c3 01 add $0x1,%ebx
# %ebx += 1
401148: 83 fb 05 cmp $0x5,%ebx
# %ebx == 5
40114b: 7e e8 jle 401135 <phase_6+0x41>
#小于等于则 跳转到 401135
40114d: 49 83 c5 04 add $0x4,%r13
# %r13 += 4 # %rsp + 4 即到下一个数
401151: eb c1 jmp 401114 <phase_6+0x20>
# 跳转到 401114 (循环???)
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi
# %rsi = (%rsp) + 24
401158: 4c 89 f0 mov %r14,%rax
# %rax = %r14
40115b: b9 07 00 00 00 mov $0x7,%ecx
# %ecx = 7
401160: 89 ca mov %ecx,%edx
# %edx = %ecx
401162: 2b 10 sub (%rax),%edx
# %edx -= %rax
401164: 89 10 mov %edx,(%rax)
# (%rax) = %edx
401166: 48 83 c0 04 add $0x4,%rax
# %rax +=4 #这里应该是 (%rax) + 4 更加准确
40116a: 48 39 f0 cmp %rsi,%rax
# %rsi == %rax
40116d: 75 f1 jne 401160 <phase_6+0x6c>
#不相等则跳转到 401160 (循环出现)
40116f: be 00 00 00 00 mov $0x0,%esi
# 相等则 %esi = 0
401174: eb 21 jmp 401197 <phase_6+0xa3>
#直接跳转到 401197
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx
# %rdx = (%rdx) + 8
40117a: 83 c0 01 add $0x1,%eax
# %eax += 1 #%eax = %rsp
40117d: 39 c8 cmp %ecx,%eax
# %eax ==%ecx
40117f: 75 f5 jne 401176 <phase_6+0x82>
#不相等则跳转到 401176 (也是一个循环)
401181: eb 05 jmp 401188 <phase_6+0x94>
# 相等则跳转到 401188
401183: ba d0 32 60 00 mov $0x6032d0,%edx
# %edx = $0x6032d0
401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)
# (%rsp + %rsi * 2) + 32 =%rdx
40118d: 48 83 c6 04 add $0x4,%rsi
# %rsi += 4
401191: 48 83 fe 18 cmp $0x18,%rsi
# %rsi == 24
401195: 74 14 je 4011ab <phase_6+0xb7>
# 相等则跳转到 4011ab
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
# %ecx = (%rsp + %rsi)
40119a: 83 f9 01 cmp $0x1,%ecx
# %ecx == 1
40119d: 7e e4 jle 401183 <phase_6+0x8f>
#小于等于调用 401183
40119f: b8 01 00 00 00 mov $0x1,%eax
#%eax = 1
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx
#%edx = $0x6032d0
4011a9: eb cb jmp 401176 <phase_6+0x82>
#跳转到 401176 (还有一个循环)
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
# %rbx = (%rsp) + 32
4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax
# %rax = (%rsp) + 40
4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi
# %rsi = (%rsp) + 80
4011ba: 48 89 d9 mov %rbx,%rcx
# %rcx = %rbx
4011bd: 48 8b 10 mov (%rax),%rdx
# %rdx = (%rax)
4011c0: 48 89 51 08 mov %rdx,0x8(%rcx)
# (%rcx) + 8 =%rdx #指向下一个
4011c4: 48 83 c0 08 add $0x8,%rax
# %rax += 8
4011c8: 48 39 f0 cmp %rsi,%rax
# %rax == %rsi
4011cb: 74 05 je 4011d2 <phase_6+0xde>
# 相等则跳转到 4011d2
4011cd: 48 89 d1 mov %rdx,%rcx
#不相等 %rcx = %rdx
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
#跳转到 4011bd (又是一个循环?)
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
# (%rdx) +8 = 0 #尾节点 ->NULL
4011d9: 00
4011da: bd 05 00 00 00 mov $0x5,%ebp
# %ebp = 5
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax
# %rax = (%rbx) + 8
4011e3: 8b 00 mov (%rax),%eax
# %eax = (%rax)
4011e5: 39 03 cmp %eax,(%rbx)
# (%rbx) == (%eax)
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
#大于等于则 跳转到 4011ee
4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb>
#否则 调用40143a(爆炸)
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
# %rbx = (%rbx) + 8
4011f2: 83 ed 01 sub $0x1,%ebp
# %ebp -= 1
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
#不相等则跳转到 4011df
4011f7: 48 83 c4 50 add $0x50,%rsp
# 下面为出栈和返回
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 retq
代码特别长,逻辑特别复杂,循环特别多
六个数,第n个数为:%rsp+((n-1) * 4)
第一部分:[401114,401151],这是一个双层循环(内循环[401160,40114b])。目的是、判断输入的值不大于 6,且六个互不相等
假设是数组一个 a[5]伪代码:
for(i = 0; i++ ;i < 5)
{
if(a[i] -1 >= 5)
for(j = i + 1; j++ ;j <5)
{
if(a[i]==a[j])
explode_bomb();
}
else
explode_bomb();
}
第二部分: [401160,40116d]将每个数和 7 作差,如,输入1 2 3 4 5 6 得到的值为 6 5 4 3 2 1
假设是数组一个 a[5]伪代码,变量使用寄存器名:
*rsi = a[6];
*rax = a[0];
do
{
*rax = 7 - *rax
rax+1;
}
while(rsi != rax)
第三部分:[401176,4011a9],其中存在两个循环[401176,40117f],[401188,40119d],作用将 0x6032d0 后面的内容排序。使用gdb查看
(gdb) x/s 0x6032d0
0x6032d0 <node1>: "L\001"
(gdb) x/s 0x6032e0
0x6032e0 <node2>: "\250"
(gdb) x/s 0x6032f0
0x6032f0 <node3>: "\234\003"
可以确定结构由三个元素组成,两个整形数据,一个结构类型的指针,大小刚好16字节,名称分别为node1,node2,node3...
结构包括三个部分分别为:value、id、下一元素地址
typedef struct node{
int value;
int id;
struct node *next;
}node;
(gdb) p/s *0x6032d0@18
$16 = {332, 1, 6304480, 0, 168, 2, 6304496, 0, 924, 3, 6304512, 0,691, 4, 6304528, 0, 477, 5, 6304544, 0, 443, 6, 0, 0}
得到了原始链表的值 332
168
924
691
477
443
第四部分:[4011ab,4011d0],存在循环[4011bd,4011d0],循环的作用node之间建立链表连接指针
第五部分[4011df,4011f5] 检查链表是否以节点的 num1 值为依据从大到小排列
将链表排序的后的顺序为 924(3) 691(4) 477(5) 443(6) 332(1) 168(2)
由于存在7减的操作,则这个题的正确答案为 4 3 2 1 6 5
secret_phase:二叉树
0000000000401204 <fun7>:
401204: 48 83 ec 08 sub $0x8,%rsp
401208: 48 85 ff test %rdi,%rdi
40120b: 74 2b je 401238 <fun7+0x34>
40120d: 8b 17 mov (%rdi),%edx
40120f: 39 f2 cmp %esi,%edx
401211: 7e 0d jle 401220 <fun7+0x1c>
401213: 48 8b 7f 08 mov 0x8(%rdi),%rdi
401217: e8 e8 ff ff ff callq 401204 <fun7>
40121c: 01 c0 add %eax,%eax
40121e: eb 1d jmp 40123d <fun7+0x39>
401220: b8 00 00 00 00 mov $0x0,%eax
401225: 39 f2 cmp %esi,%edx
401227: 74 14 je 40123d <fun7+0x39>
401229: 48 8b 7f 10 mov 0x10(%rdi),%rdi
40122d: e8 d2 ff ff ff callq 401204 <fun7>
401232: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401236: eb 05 jmp 40123d <fun7+0x39>
401238: b8 ff ff ff ff mov $0xffffffff,%eax
40123d: 48 83 c4 08 add $0x8,%rsp
401241: c3 retq
0000000000401242 <secret_phase>:
401242: 53 push %rbx
401243: e8 56 02 00 00 callq 40149e <read_line>
401248: ba 0a 00 00 00 mov $0xa,%edx
40124d: be 00 00 00 00 mov $0x0,%esi
401252: 48 89 c7 mov %rax,%rdi
401255: e8 76 f9 ff ff callq 400bd0 <strtol@plt>
40125a: 48 89 c3 mov %rax,%rbx
40125d: 8d 40 ff lea -0x1(%rax),%eax
401260: 3d e8 03 00 00 cmp $0x3e8,%eax
401265: 76 05 jbe 40126c <secret_phase+0x2a>
401267: e8 ce 01 00 00 callq 40143a <explode_bomb>
40126c: 89 de mov %ebx,%esi
40126e: bf f0 30 60 00 mov $0x6030f0,%edi
401273: e8 8c ff ff ff callq 401204 <fun7>
401278: 83 f8 02 cmp $0x2,%eax
40127b: 74 05 je 401282 <secret_phase+0x40>
40127d: e8 b8 01 00 00 callq 40143a <explode_bomb>
401282: bf 38 24 40 00 mov $0x402438,%edi
401287: e8 84 f8 ff ff callq 400b10 <puts@plt>
40128c: e8 33 03 00 00 callq 4015c4 <phase_defused>
401291: 5b pop %rbx
401292: c3 retq
401293: 90 nop
401294: 90 nop
401295: 90 nop
401296: 90 nop
401297: 90 nop
401298: 90 nop
401299: 90 nop
40129a: 90 nop
40129b: 90 nop
40129c: 90 nop
40129d: 90 nop
40129e: 90 nop
隐藏炸弹就不分析了 ,分析不下去了。直接百度一个答案:
触发secret_phase
: 在phase_4
输入时添加 DrEvil
答案:22
后
实在对汇编不熟悉,做这个太勉强,花了我不少时间,也参考了不少资料,得去写Python了。