Bomb Lab 在这里插入代码片
0000000000001254 :
1254: 48 83 ec 08 sub $0x8,%rsp
1258: 48 8d 35 31 18 00 00 lea 0x1831(%rip),%rsi # 2a90 <_IO_stdin_used+0x150>
125f: e8 ed 04 00 00 callq 1751
1264: 85 c0 test %eax,%eax
1266: 75 05 jne 126d
1268: 48 83 c4 08 add $0x8,%rsp
126c: c3 retq
126d: e8 e3 07 00 00 callq 1a55
1272: eb f4 jmp 1268
结合1258和125f 我们可以猜测0x1831(%rip)处存放了本phase的答案
利用gdb工具查看%rsi处存的地址,再使用gdb打印
\000是字符串数组的终止符,故该字符串为 There are rumors on the internets.
因此本phase答案为该字符串
0000000000001274 :
1274: 55 push %rbp
1275: 53 push %rbx
1276: 48 83 ec 28 sub $0x28,%rsp
127a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1281: 00 00
1283: 48 89 44 24 18 mov %rax,0x18(%rsp)
1288: 31 c0 xor %eax,%eax
128a: 48 89 e6 mov %rsp,%rsi
128d: e8 ff 07 00 00 callq 1a91
1292: 83 3c 24 01 cmpl $0x1,(%rsp) #第一个数字和1相比,%rsp处存的是第一个数字的地址
1296: 75 09 jne 12a1
1298: 48 89 e3 mov %rsp,%rbx #用%rbx存第一个数字的地址
129b: 48 8d 6b 14 lea 0x14(%rbx),%rbp #%rbp存最后一个数字的地址
129f: eb 10 jmp 12b1
12a1: e8 af 07 00 00 callq 1a55
12a6: eb f0 jmp 1298
12a8: 48 83 c3 04 add $0x4,%rbx #更新%rbx为第二个数字的地址
12ac: 48 39 eb cmp %rbp,%rbx #
12af: 74 10 je 12c1
12b1: 8b 03 mov (%rbx),%eax #%eax存第一个数字 #%eax存第二个数字
12b3: 01 c0 add %eax,%eax #%eax等于所存数字的2倍 #%eax等于所存数字的2倍
12b5: 39 43 04 cmp %eax,0x4(%rbx) #第二个数字与第一个的2倍相比 #第三个与第二个相比
12b8: 74 ee je 12a8
12ba: e8 96 07 00 00 callq 1a55
12bf: eb e7 jmp 12a8
12c1: 48 8b 44 24 18 mov 0x18(%rsp),%rax
12c6: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
12cd: 00 00
12cf: 75 07 jne 12d8
12d1: 48 83 c4 28 add $0x28,%rsp
12d5: 5b pop %rbx
12d6: 5d pop %rbp
12d7: c3 retq
12d8: e8 b3 fb ff ff callq e90 <__stack_chk_fail@plt>
通过128d行
进入循环
即以上循环在判断输入的数字是否为一个公比为2,首项为1的等比数列
故密码为 1 2 4 8 16 32
00000000000012dd :
12dd: 48 83 ec 18 sub $0x18,%rsp
12e1: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
12e8: 00 00
12ea: 48 89 44 24 08 mov %rax,0x8(%rsp)
12ef: 31 c0 xor %eax,%eax
12f1: 48 8d 4c 24 04 lea 0x4(%rsp),%rcx
12f6: 48 89 e2 mov %rsp,%rdx
12f9: 48 8d 35 8d 1a 00 00 lea 0x1a8d(%rip),%rsi # 2d8d
1300: e8 2b fc ff ff callq f30 <__isoc99_sscanf@plt>
1305: 83 f8 01 cmp $0x1,%eax
1308: 7e 1d jle 1327 # <=1 直接爆炸
130a: 83 3c 24 07 cmpl $0x7,(%rsp)
130e: 0f 87 99 00 00 00 ja 13ad # > 7 直接爆炸
1314: 8b 04 24 mov (%rsp),%eax # 将第一个数字存到%eax
1317: 48 8d 15 c2 17 00 00 lea 0x17c2(%rip),%rdx # 2ae0 <_IO_stdin_used+0x1a0>
131e: 48 63 04 82 movslq (%rdx,%rax,4),%rax
1322: 48 01 d0 add %rdx,%rax
1325: ff e0 jmpq *%rax
1327: e8 29 07 00 00 callq 1a55
132c: eb dc jmp 130a
132e: b8 0d 03 00 00 mov $0x30d,%eax
1333: eb 05 jmp 133a
1335: b8 00 00 00 00 mov $0x0,%eax
133a: 2d 62 03 00 00 sub $0x362,%eax
133f: 05 c5 02 00 00 add $0x2c5,%eax
1344: 2d fa 00 00 00 sub $0xfa,%eax
1349: 05 fa 00 00 00 add $0xfa,%eax
134e: 2d fa 00 00 00 sub $0xfa,%eax
1353: 05 fa 00 00 00 add $0xfa,%eax
1358: 2d fa 00 00 00 sub $0xfa,%eax
135d: 83 3c 24 05 cmpl $0x5,(%rsp)
1361: 7f 06 jg 1369 # >5 bomb!
1363: 39 44 24 04 cmp %eax,0x4(%rsp)
1367: 74 05 je 136e
1369: e8 e7 06 00 00 callq 1a55
136e: 48 8b 44 24 08 mov 0x8(%rsp),%rax
1373: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
137a: 00 00
137c: 75 3b jne 13b9
137e: 48 83 c4 18 add $0x18,%rsp
1382: c3 retq
1383: b8 00 00 00 00 mov $0x0,%eax
1388: eb b5 jmp 133f #case 2
138a: b8 00 00 00 00 mov $0x0,%eax
138f: eb b3 jmp 1344
1391: b8 00 00 00 00 mov $0x0,%eax
1396: eb b1 jmp 1349
1398: b8 00 00 00 00 mov $0x0,%eax
139d: eb af jmp 134e
139f: b8 00 00 00 00 mov $0x0,%eax
13a4: eb ad jmp 1353
13a6: b8 00 00 00 00 mov $0x0,%eax
13ab: eb ab jmp 1358
13ad: e8 a3 06 00 00 callq 1a55
13b2: b8 00 00 00 00 mov $0x0,%eax
13b7: eb a4 jmp 135d
13b9: e8 d2 fa ff ff callq e90 <__stack_chk_fail@plt>
判断输入类型
函数主体
故 2 459为此switch的一组解答
00000000000013be :
13be: b8 00 00 00 00 mov $0x0,%eax
13c3: 85 ff test %edi,%edi
13c5: 7e 07 jle 13ce # %edi <= 0 return
13c7: 89 f0 mov %esi,%eax # %eax = 第2个数字
13c9: 83 ff 01 cmp $0x1,%edi # %edi初始值 = 7
13cc: 75 02 jne 13d0
13ce: f3 c3 repz retq
13d0: 41 54 push %r12
13d2: 55 push %rbp
13d3: 53 push %rbx
13d4: 41 89 f4 mov %esi,%r12d # %r12d = 第2个参数
13d7: 89 fb mov %edi,%ebx # %ebx = %edi
13d9: 8d 7f ff lea -0x1(%rdi),%edi # %edi --
13dc: e8 dd ff ff ff callq 13be
13e1: 42 8d 2c 20 lea (%rax,%r12,1),%ebp
13e5: 8d 7b fe lea -0x2(%rbx),%edi
13e8: 44 89 e6 mov %r12d,%esi
13eb: e8 ce ff ff ff callq 13be
13f0: 01 e8 add %ebp,%eax
13f2: 5b pop %rbx
13f3: 5d pop %rbp
13f4: 41 5c pop %r12
13f6: c3 retq
00000000000013f7 :
13f7: 48 83 ec 18 sub $0x18,%rsp
13fb: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1402: 00 00
1404: 48 89 44 24 08 mov %rax,0x8(%rsp)
1409: 31 c0 xor %eax,%eax
140b: 48 89 e1 mov %rsp,%rcx
140e: 48 8d 54 24 04 lea 0x4(%rsp),%rdx
1413: 48 8d 35 73 19 00 00 lea 0x1973(%rip),%rsi # 2d8d
141a: e8 11 fb ff ff callq f30 <__isoc99_sscanf@plt>
141f: 83 f8 02 cmp $0x2,%eax
1422: 75 0b jne 142f
1424: 8b 04 24 mov (%rsp),%eax
1427: 83 e8 02 sub $0x2,%eax
142a: 83 f8 02 cmp $0x2,%eax
142d: 76 05 jbe 1434 # <=
142f: e8 21 06 00 00 callq 1a55 # (第2个数字)>4 bomb!
1434: 8b 34 24 mov (%rsp),%esi # %esi=第2个数字
1437: bf 07 00 00 00 mov $0x7,%edi
143c: e8 7d ff ff ff callq 13be
1441: 39 44 24 04 cmp %eax,0x4(%rsp) # 返回值和第1个参数相等
1445: 74 05 je 144c
1447: e8 09 06 00 00 callq 1a55
144c: 48 8b 44 24 08 mov 0x8(%rsp),%rax
1451: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
1458: 00 00
145a: 75 05 jne 1461
145c: 48 83 c4 18 add $0x18,%rsp
1460: c3 retq
1461: e8 2a fa ff ff callq e90 <__stack_chk_fail@plt>
输入数据类型
函数主体
func4
通过13dc、13eb两行反复调用func4本身可以看出func4是个递归函数
从13be到13ce可以看出该函数的递归边界为
int func4(int edi,int esi){
if(edi == 0)return 0;
if(edi == 1)return esi;
return func4(edi-1,esi)+func4(edi-2,esi);
}
经过测试在第二个参数为3的情况下,用gdb打印出执行func4后的结果为99
故一组解答为 99 3
0000000000001466 :
1466: 48 83 ec 18 sub $0x18,%rsp
146a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1471: 00 00
1473: 48 89 44 24 08 mov %rax,0x8(%rsp)
1478: 31 c0 xor %eax,%eax
147a: 48 8d 4c 24 04 lea 0x4(%rsp),%rcx
147f: 48 89 e2 mov %rsp,%rdx
1482: 48 8d 35 04 19 00 00 lea 0x1904(%rip),%rsi # 2d8d
1489: e8 a2 fa ff ff callq f30 <__isoc99_sscanf@plt>
148e: 83 f8 01 cmp $0x1,%eax # 参数数量<=1 explode
1491: 7e 5a jle 14ed
1493: 8b 04 24 mov (%rsp),%eax
1496: 83 e0 0f and $0xf,%eax #取低四位的a1
1499: 89 04 24 mov %eax,(%rsp)
149c: 83 f8 0f cmp $0xf,%eax #低四位为0xf就bomb
149f: 74 32 je 14d3
14a1: b9 00 00 00 00 mov $0x0,%ecx
14a6: ba 00 00 00 00 mov $0x0,%edx
14ab: 48 8d 35 4e 16 00 00 lea 0x164e(%rip),%rsi # 2b00
14b2: 83 c2 01 add $0x1,%edx #olution.
14b5: 48 98 cltq
14b7: 8b 04 86 mov (%rsi,%rax,4),%eax #4个字节所以要乘4
14ba: 01 c1 add %eax,%ecx
14bc: 83 f8 0f cmp $0xf,%eax #15次以内不能取到0xf
14bf: 75 f1 jne 14b2
14c1: c7 04 24 0f 00 00 00 movl $0xf,(%rsp)
14c8: 83 fa 0f cmp $0xf,%edx
14cb: 75 06 jne 14d3 #edx == 0xf 循环15次
14cd: 39 4c 24 04 cmp %ecx,0x4(%rsp) #ecx == a2
14d1: 74 05 je 14d8
14d3: e8 7d 05 00 00 callq 1a55
14d8: 48 8b 44 24 08 mov 0x8(%rsp),%rax
14dd: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
14e4: 00 00
14e6: 75 0c jne 14f4
14e8: 48 83 c4 18 add $0x18,%rsp
14ec: c3 retq
14ed: e8 63 05 00 00 callq 1a55
14f2: eb 9f jmp 1493
14f4: e8 97 f9 ff ff callq e90 <__stack_chk_fail@plt>
首先通过1489行推断需要的输入类型
接下来进入循环
1593行开始 进入前先进行判断:取第一个参数的最后4位如果是0xf则bomb
进入循环,14b2表面%edx是循环变量i
循环过程中(14b7)跟新%eax的值(进入时为第一个参数)
根据14ab行提示,发现2b00处存了一个大小为16的int数组
14b7中每次将%eax的值跟新为数组中对应位置所存储的数值
14ba处用%ecx计算每一次%eax的累加值
14bc处验证在%eax是否为0xf
满足第十五次循环取得oxf的情况下再去看%ecx的值与第二个参数是否相等
接下来推理输入数据
由于第十五次需要取得f,根据数组逆向寻找第一次的数据,发现结果为5
接下来寻找十五次结果的累加值,先随便输入第二个参数,通过gdb工具查看十五次循环以后%ecx的值,发现是115
即答案为 5 115
00000000000014f9 :
14f9: 41 55 push %r13
14fb: 41 54 push %r12
14fd: 55 push %rbp
14fe: 53 push %rbx
14ff: 48 83 ec 68 sub $0x68,%rsp
1503: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
150a: 00 00
150c: 48 89 44 24 58 mov %rax,0x58(%rsp)
1511: 31 c0 xor %eax,%eax
1513: 49 89 e4 mov %rsp,%r12
1516: 4c 89 e6 mov %r12,%rsi
1519: e8 73 05 00 00 callq 1a91
151e: 41 bd 00 00 00 00 mov $0x0,%r13d
1524: eb 25 jmp 154b
1526: e8 2a 05 00 00 callq 1a55
152b: eb 2d jmp 155a
152d: 83 c3 01 add $0x1,%ebx
1530: 83 fb 05 cmp $0x5,%ebx
1533: 7f 12 jg 1547
1535: 48 63 c3 movslq %ebx,%rax
1538: 8b 04 84 mov (%rsp,%rax,4),%eax
153b: 39 45 00 cmp %eax,0x0(%rbp)
153e: 75 ed jne 152d
1540: e8 10 05 00 00 callq 1a55
1545: eb e6 jmp 152d
1547: 49 83 c4 04 add $0x4,%r12
154b: 4c 89 e5 mov %r12,%rbp
154e: 41 8b 04 24 mov (%r12),%eax
1552: 83 e8 01 sub $0x1,%eax
1555: 83 f8 05 cmp $0x5,%eax
1558: 77 cc ja 1526
155a: 41 83 c5 01 add $0x1,%r13d
155e: 41 83 fd 06 cmp $0x6,%r13d
1562: 74 35 je 1599
1564: 44 89 eb mov %r13d,%ebx
1567: eb cc jmp 1535
1569: 48 8b 52 08 mov 0x8(%rdx),%rdx
156d: 83 c0 01 add $0x1,%eax
1570: 39 c8 cmp %ecx,%eax
1572: 75 f5 jne 1569
1574: 48 89 54 f4 20 mov %rdx,0x20(%rsp,%rsi,8)
1579: 48 83 c6 01 add $0x1,%rsi
157d: 48 83 fe 06 cmp $0x6,%rsi
1581: 74 1d je 15a0
1583: 8b 0c b4 mov (%rsp,%rsi,4),%ecx
1586: b8 01 00 00 00 mov $0x1,%eax
158b: 48 8d 15 9e 2c 20 00 lea 0x202c9e(%rip),%rdx # 204230
1592: 83 f9 01 cmp $0x1,%ecx
1595: 7f d2 jg 1569
1597: eb db jmp 1574
1599: be 00 00 00 00 mov $0x0,%esi
159e: eb e3 jmp 1583
15a0: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
15a5: 48 8b 44 24 28 mov 0x28(%rsp),%rax
15aa: 48 89 43 08 mov %rax,0x8(%rbx)
15ae: 48 8b 54 24 30 mov 0x30(%rsp),%rdx
15b3: 48 89 50 08 mov %rdx,0x8(%rax)
15b7: 48 8b 44 24 38 mov 0x38(%rsp),%rax
15bc: 48 89 42 08 mov %rax,0x8(%rdx)
15c0: 48 8b 54 24 40 mov 0x40(%rsp),%rdx
15c5: 48 89 50 08 mov %rdx,0x8(%rax)
15c9: 48 8b 44 24 48 mov 0x48(%rsp),%rax
15ce: 48 89 42 08 mov %rax,0x8(%rdx)
15d2: 48 c7 40 08 00 00 00 movq $0x0,0x8(%rax)
15d9: 00
15da: bd 05 00 00 00 mov $0x5,%ebp
15df: eb 09 jmp 15ea
15e1: 48 8b 5b 08 mov 0x8(%rbx),%rbx
15e5: 83 ed 01 sub $0x1,%ebp
15e8: 74 11 je 15fb
15ea: 48 8b 43 08 mov 0x8(%rbx),%rax
15ee: 8b 00 mov (%rax),%eax
15f0: 39 03 cmp %eax,(%rbx)
15f2: 7d ed jge 15e1
15f4: e8 5c 04 00 00 callq 1a55
15f9: eb e6 jmp 15e1
15fb: 48 8b 44 24 58 mov 0x58(%rsp),%rax
1600: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
1607: 00 00
1609: 75 0b jne 1616
160b: 48 83 c4 68 add $0x68,%rsp
160f: 5b pop %rbx
1610: 5d pop %rbp
1611: 41 5c pop %r12
1613: 41 5d pop %r13
1615: c3 retq
1616: e8 75 f8 ff ff callq e90 <__stack_chk_fail@plt>
读入数据
验证数据
154b到1555保证了每个数字都小于等于6
1535到153e保证了六个数字互不相同
整个过程写成c语言为
for(i= 0; i <= 5; i++){
if(a[i] >6) explode_bomb();
for(j=i+1; j<=5; j++){
if(a[i] == a[j])
explode_bomb();
}
15a0到15da根据输入到六个数字将链表重新排序
for(i=0; i<=5; i++){
p = list;
for(j=1; j<a[i]; j++)
p = p->next;
list_array[i]=p;
}
15e1到15f2的循环用来判读新的链表是否按照元素的降序排列
p = list_array;
for(i=0; i<=4; i++){
if(*p <*p->next) explode_bomb();
p = p->next;
}
得到正确序列
158b: 48 8d 15 9e 2c 20 00 lea 0x202c9e(%rip),%rdx # 204230
从而得到 node1 的地址为0x555555758230
用gdb将它打印出来
该数据结构分为 int value int index node*next
故得到node1以后可以得到所有node
根据value值对index排序得到1 5 6 4 3 2
所以最后一题答案为1 5 6 4 3 2