csapp bombLab


Bomb Lab 在这里插入代码片


phase_1

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答案为该字符串

phase_2

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行 可以推断出,本关的密码为六个数字

  • 由于参数入栈的顺序是从右向左,所以(%rsp)到0x14(%rsp)所存的是从第一个参数到第六个参数
  • 1292和1296行结合来看,如果第一个数字不是1就爆炸,故第一个数字为1
  • 1298行用%rbx来存第一个数字的地址
  • 129b行用%rbp来存最后一个数字的地址

进入循环

  • 判断%eax中存的数字的两倍是否与输入中的下一个数字相等
    • 不等于就爆炸
    • 相等进入下一次循环
      • 更新%rbx为下一个数字的地址

即以上循环在判断输入的数字是否为一个公比为2,首项为1的等比数列

故密码为 1 2 4 8 16 32

phase_3

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>


判断输入类型

  • 结合12f9和1300可以推测%rsi中存了scanf的参数
  • 通过gdb打印(%rsi)得到%d %d,故scanf的参数为两个int
  • 1305 1308中scanf返回结果如果<=1直接爆炸,验证了我们的参数为2个

函数主体

  • 130a和130e能够确定第一个参数值不能大于7
  • 从1317到1325可以推测此后进入了switch语句,第一个参数是switch的参数
  • 通过试探,发现输入第一个参数为2时进入1383行,即1383行对应case2
    • 1388 jmp到133f
    • 从133f到1358的计算 %eax = 0x362 - 0xfa = 459
    • 1363和1367比较了第二个参数和%eax,相同则返回

故 2 459为此switch的一组解答

phase_4

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>


输入数据类型

  • 通过1413和141a发现和上题一样用了scanf,且注释中 2d8d 都一样,故可知此题也需要2个int作为输入
  • 141f和1422判断scanf 的返回值是否为2 验证了需要两个数字输入

函数主体

  • 1424到142f判断第二个参数是否大于4,如果大于4就explode
  • 调用func4函数,将7作为第一个参数,将输入的第二个数值作为第一个参数
  • 接着比较输入的第一个数字和func4的返回结果是否相等,不等就bomb
  • 故输入的第一个数字应该为func4(7,第二个参数)的返回结果

func4

  • 通过13dc、13eb两行反复调用func4本身可以看出func4是个递归函数

  • 从13be到13ce可以看出该函数的递归边界为

    • 若%edi <= 0 ,返回值%eax = 0
    • 若%edi = 1,返回值%eax = %esi
    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

phase_5

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行推断需要的输入类型

  • 看到1482行中注释是2d8d,意识到输入和前两个phase一样,都是“%d %d”
  • 148e行sscanf返回的参数如果小于等于1则explode验证了需要输入两个参数

接下来进入循环

  • 1593行开始 进入前先进行判断:取第一个参数的最后4位如果是0xf则bomb

  • 进入循环,14b2表面%edx是循环变量i

  • 循环过程中(14b7)跟新%eax的值(进入时为第一个参数)

  • 根据14ab行提示,发现2b00处存了一个大小为16的int数组

    • 用gdb查看,发现数组为{a 2 e 7 8 c f b 0 4 1 d 3 9 6 5}
  • 14b7中每次将%eax的值跟新为数组中对应位置所存储的数值

  • 14ba处用%ecx计算每一次%eax的累加值

  • 14bc处验证在%eax是否为0xf

    • 如果等于,再去验证%edx是否为0xf,即判断是否是在循环第十五次取得oxf的数值
  • 满足第十五次循环取得oxf的情况下再去看%ecx的值与第二个参数是否相等


接下来推理输入数据

由于第十五次需要取得f,根据数组逆向寻找第一次的数据,发现结果为5

接下来寻找十五次结果的累加值,先随便输入第二个参数,通过gdb工具查看十五次循环以后%ecx的值,发现是115

即答案为 5 115

phase_6

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>


读入数据

  • 从1519可知要读入6个数字

验证数据

  • 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;
    }
    

得到正确序列

  • 利用gdb工具 当程序执行到这一行一行 查看%rdx存储的地址
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

你可能感兴趣的:(其他)