一、Bomb Lab

一、准备

Bomb Lab下载地址 :http://csapp.cs.cmu.edu/3e/bomb.tar
帮助文档 :http://csapp.cs.cmu.edu/3e/bomblab.pdf
深入理解计算系统配套实验:http://csapp.cs.cmu.edu/3e/labs.html
这篇文章其实是写了很久了, 上面链接资源可能不存在了,备份:https://gitee.com/beneil/csapplabc

二、概述

解压bomb.tar得到bomb.cbomb,通过objdump得到bomb的反汇编代码,gdb调试程序,观察得到正确的字符串,输入以拆除bomb.

objdump -d bomb > bomb.txt

常用寄存器

寄存器作用寄存器作用
%rax,%eax返回值%rsi,%esi第2个参数
%rbx,%ebx被调用者保存%rdi,%edi第1个参数
%rcx,%ecx第4个参数%rbp,%ebp被调用者保存
%rdx,%edx第3个参数%rsp,%esp栈指针

gdb常用操作

gdb bomb
(gdb) break xxx	其中xxx可以是函数名,行,*指令地址,简写:b *0x1234
(gdb) info b	断点信息
(gdb) del 1		删除第一个断点

(gdb) run		开始调试,简写:r
(gdb) continue	继续执行,简写:c
(gdb) nexti		汇编级别逐行执行,next是C语言级别,简写:ni
(gdb) stepi		同上,区别在于step会进入函数内,简写:si
(gdb) quit		终止调试,q

(gdb) layout regs	显示汇编和寄存器窗口,Ctrl+x,再按a 退出
(gdb) print xxx	打印指定变量的值,简写:p $rax
(gdb) x/<n/f/u> <addr>	n、f、u是可选的参数,<addr>表示一个内存地址,读取指定内存地址的内容
x/4wd 0x1234	从内存地址0x1234读取内容,w表示4个字节为一个单位,4表示4个单位,d表示按十进制显示
x/s 0x1234		s按字符串显示

三、步骤

首先看bomb.c,main方法,read_line读取一行,input作为参数传递进phase_1.总共要拆除phase_1-6个炸弹

...
     /* Hmm...  Six phases must be more secure than one phase! */
    input = read_line();             /* Get input                   */
    phase_1(input);                  /* Run the phase               */
    phase_defused();                 /* Drat!  They figured it out!
                          * Let me know how they did it. */
    printf("Phase 1 defused. How about the next one?\n");
...

phase_1

打开汇编文件bomb.txt,找到phase_1

0000000000400ee0 <phase_1>:
  400ee0:	48 83 ec 08          	sub    $0x8,%rsp
  400ee4:	be 00 24 40 00       	mov    $0x402400,%esi				;打印函数的第二个参数	x/s 0x402400
  400ee9:	e8 4a 04 00 00       	callq  401338 <strings_not_equal>	;调用函数,字符串比较, 
  400eee:	85 c0                	test   %eax,%eax					;返回值0,表示字符串相等
  400ef0:	74 05                	je     400ef7 <phase_1+0x17>
  400ef2:	e8 43 05 00 00       	callq  40143a <explode_bomb>
  400ef7:	48 83 c4 08          	add    $0x8,%rsp
  400efb:	c3                   	retq   

strings_not_equal比较两个字符串,第一个参数%rsi,第二个参数%rdi,两字符串相等explode_bomb才不执行.第一个参数为输入字符串,因此第二个参数就是答案.下面gdb验证.输入1234567890

在这里插入图片描述

得到第一关答案,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
  400f02:	48 89 e6             	mov    %rsp,%rsi
  400f05:	e8 52 05 00 00       	callq  40145c <read_six_numbers>	;读入6个数字
  400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)					;(%rsp)第一个输入值,跟1比较,猜测第一个数字=1
  400f0e:	74 20                	je     400f30 <phase_2+0x34>
  400f10:	e8 25 05 00 00       	callq  40143a <explode_bomb>
  400f15:	eb 19                	jmp    400f30 <phase_2+0x34>
  400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax				;读入第一个数字,(上一个数字)
  400f1a:	01 c0                	add    %eax,%eax					;*=2,计算得出目标值(1+1,2+2,4+4...)
  400f1c:	39 03                	cmp    %eax,(%rbx)					;目标值与输入值(rbx)比较
  400f1e:	74 05                	je     400f25 <phase_2+0x29>
  400f20:	e8 15 05 00 00       	callq  40143a <explode_bomb>
  400f25:	48 83 c3 04          	add    $0x4,%rbx					;rbx+4 移动到下一个输入值
  400f29:	48 39 eb             	cmp    %rbp,%rbx					;到末尾
  400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>
  400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>
  400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx				;比较第一个数字后,转跳 保存下一个数字的地址到rbx
  400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp				;0x18=24 输入的末尾(最后一个数字为rsp+20)
  400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>
  400f3c:	48 83 c4 28          	add    $0x28,%rsp
  400f40:	5b                   	pop    %rbx
  400f41:	5d                   	pop    %rbp
  400f42:	c3                   	retq   

第7行400f0a,猜测第一个数为1;第12行400f1a,每次将%rbx的上一个数字*2,得到目标值,然后与当前保存数字比较.
所以答案为1 2 4 8 16 32

phase_3

同样看汇编

  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi				;%d %d 输入两个值
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <__isoc99_sscanf@plt>	;输入参数

猜测要输入参数,gdb调试,得知输入2个数字

在这里插入图片描述

继续看汇编

  400f6a:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp)		;0x8(%rsp) 第一个数字<7,猜测第二数字=0xc(%rsp)
  400f6f:	77 3c                	ja     400fad <phase_3+0x6a>
  400f71:	8b 44 24 08          	mov    0x8(%rsp),%eax		;0x8(%rsp) 输入的第一个数字,保存到%eax
  400f75:	ff 24 c5 70 24 40 00 	jmpq   *0x402470(,%rax,8)	;转跳地址: *(0x402470+8*%rax)	
  																;gdb查看 x/x 0x402470 得到 0x00400f7c,
  400f7c:	b8 cf 00 00 00       	mov    $0xcf,%eax
  400f81:	eb 3b                	jmp    400fbe <phase_3+0x7b>
  ;...
  400fb9:	b8 37 01 00 00       	mov    $0x137,%eax	
  400fbe:	3b 44 24 0c          	cmp    0xc(%rsp),%eax		;第二个数字0x137=311 对应第一个数字1
  																;(如果第一个数字0,第二个数字0xcf=207)
  400fc2:	74 05                	je     400fc9 <phase_3+0x86>
  400fc4:	e8 71 04 00 00       	callq  40143a <explode_bomb>

第1行400f6a,猜测第一个数字=0x8+%rsp,第二个数字=0xc+%rsp; (gdb x/d $rsp+8)
第4行400f75说明,转跳地址=*(0x402470+8*%rax),通过x/x 0x402470+0/8.. 观察范围是从400f7c400fb9,所以rax取值可以是0,1
所以答案为1 311 或者 0 207

phase_4

phase_4汇编

000000000040100c <phase_4>:
  40100c:	48 83 ec 18          	sub    $0x18,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi			;%d %d 输入两个值
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax
  40102c:	75 07                	jne    401035 <phase_4+0x29>
  40102e:	83 7c 24 08 0e       	cmpl   $0xe,0x8(%rsp)			;第一个参数<=14 ja/jb unsigned比较
  401033:	76 05                	jbe    40103a <phase_4+0x2e>
  401035:	e8 00 04 00 00       	callq  40143a <explode_bomb>
  40103a:	ba 0e 00 00 00       	mov    $0xe,%edx
  40103f:	be 00 00 00 00       	mov    $0x0,%esi
  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi
  401048:	e8 81 ff ff ff       	callq  400fce <func4>			;调用func4必须返回0
  40104d:	85 c0                	test   %eax,%eax
  40104f:	75 07                	jne    401058 <phase_4+0x4c>
  401051:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp)			;第二个参数0
  401056:	74 05                	je     40105d <phase_4+0x51>
  401058:	e8 dd 03 00 00       	callq  40143a <explode_bomb>
  40105d:	48 83 c4 18          	add    $0x18,%rsp
  401061:	c3                   	retq   

由第10行和第19行知道,第一个参数<=14,第二个参数=0
第16行401048,调用func4

0000000000400fce <func4>:
  400fce:	48 83 ec 08          	sub    $0x8,%rsp
  400fd2:	89 d0                	mov    %edx,%eax		;eax=14
  400fd4:	29 f0                	sub    %esi,%eax		
  400fd6:	89 c1                	mov    %eax,%ecx		
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx		;右移31位 ecx=0
  400fdb:	01 c8                	add    %ecx,%eax		
  400fdd:	d1 f8                	sar    %eax				;sar $1 %eax =>eax=7
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx	;ecx=rax=eax=7的地址
  400fe2:	39 f9                	cmp    %edi,%ecx			
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>;比较 ecx<=edi(第一个参数 >=7,>=3,>=1,>=0,)
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>	
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax		;无论前面递归多少次,也就是说最后必须eax=0,连续执行到<=7
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>;ecx>=edi(第一个参数 <=7)
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi	;必不能走到这里,例如参数为8,(8>7,不满足再次调用)rcx=11
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>	
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax;不能走到这一步(eax必须返回0),表明(第一个参数必须<=7)
  401007:	48 83 c4 08          	add    $0x8,%rsp		
  40100b:	c3                   	retq   

递归调用,多用gdb调试体会,用layout regs显示汇编和寄存器窗口,观察寄存器变化
所以答案为:第一个参数可以是7,3,1,0,第二个参数是0

phase_5

phase_5汇编

0000000000401062 <phase_5>:
  401062:	53                   	push   %rbx
  401063:	48 83 ec 20          	sub    $0x20,%rsp
  401067:	48 89 fb             	mov    %rdi,%rbx				;rdi 输入的字符串,保存到rbx
  40106a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  401071:	00 00 
  401073:	48 89 44 24 18       	mov    %rax,0x18(%rsp)
  401078:	31 c0                	xor    %eax,%eax
  40107a:	e8 9c 02 00 00       	callq  40131b <string_length>	;计算字符串长度
  40107f:	83 f8 06             	cmp    $0x6,%eax				;长度=6
  401082:	74 4e                	je     4010d2 <phase_5+0x70>
  401084:	e8 b1 03 00 00       	callq  40143a <explode_bomb>
  401089:	eb 47                	jmp    4010d2 <phase_5+0x70>
  40108b:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx		;每次读入一个字符
  40108f:	88 0c 24             	mov    %cl,(%rsp)				;将读入字符保存到(rsp)
  401092:	48 8b 14 24          	mov    (%rsp),%rdx				;将读入字符保存到rdx
  401096:	83 e2 0f             	and    $0xf,%edx				;与15 就是mod16(将读入字符mod16)
  401099:	0f b6 92 b0 24 40 00 	movzbl 0x4024b0(%rdx),%edx		;将mod16后的值加上0x4024b0,保存到edx
  4010a0:	88 54 04 10          	mov    %dl,0x10(%rsp,%rax,1)
  4010a4:	48 83 c0 01          	add    $0x1,%rax
  4010a8:	48 83 f8 06          	cmp    $0x6,%rax				;遍历输入6个字符
  4010ac:	75 dd                	jne    40108b <phase_5+0x29>
  4010ae:	c6 44 24 16 00       	movb   $0x0,0x16(%rsp)
  4010b3:	be 5e 24 40 00       	mov    $0x40245e,%esi			;目的字符串在  0x40245e 得到flyers
  4010b8:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  4010bd:	e8 76 02 00 00       	callq  401338 <strings_not_equal>;字符串比较,目的字符串在 %rsi
  4010c2:	85 c0                	test   %eax,%eax
  4010c4:	74 13                	je     4010d9 <phase_5+0x77>
  4010c6:	e8 6f 03 00 00       	callq  40143a <explode_bomb>
  4010cb:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  4010d0:	eb 07                	jmp    4010d9 <phase_5+0x77>
  4010d2:	b8 00 00 00 00       	mov    $0x0,%eax				
  4010d7:	eb b2                	jmp    40108b <phase_5+0x29>
  4010d9:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  4010de:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4010e5:	00 00 
  4010e7:	74 05                	je     4010ee <phase_5+0x8c>
  4010e9:	e8 42 fa ff ff       	callq  400b30 <__stack_chk_fail@plt>
  4010ee:	48 83 c4 20          	add    $0x20,%rsp
  4010f2:	5b                   	pop    %rbx
  4010f3:	c3                   	retq   

第24行4010b3,说明目的字符串是flyers
第14行到第18行说明,输入的每个字符要mod16后的值加上0x4024b0,x/s 0x4024b0得到前16个字符为maduiersnfotvbyl
假设字符i,ascii等于105,105mod16=9,字符串第10个为f,也就是i转换成f
同理答案得ionefg(大小写任意)

phase_6

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					
  401100:	49 89 e5             	mov    %rsp,%r13					
  401103:	48 89 e6             	mov    %rsp,%rsi
  401106:	e8 51 03 00 00       	callq  40145c <read_six_numbers>	;读6个数字,返回后,rsp指向对应输入的数字
  40110b:	49 89 e6             	mov    %rsp,%r14					;r14=第一个数字
  40110e:	41 bc 00 00 00 00    	mov    $0x0,%r12d
  401114:	4c 89 ed             	mov    %r13,%rbp					
  401117:	41 8b 45 00          	mov    0x0(%r13),%eax				
  40111b:	83 e8 01             	sub    $0x1,%eax				;eax-1
  40111e:	83 f8 05             	cmp    $0x5,%eax				;eax<=5,(表示每个数字<=6)
  401121:	76 05                	jbe    401128 <phase_6+0x34>	;这里也表明数字不能<=0
  401123:	e8 12 03 00 00       	callq  40143a <explode_bomb>
  401128:	41 83 c4 01          	add    $0x1,%r12d					
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d				;循环6次
  401130:	74 21                	je     401153 <phase_6+0x5f>	;循环结束
  401132:	44 89 e3             	mov    %r12d,%ebx					
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax		;eax=rsp+循环次数*4(移动到下一个值)
  40113b:	39 45 00             	cmp    %eax,0x0(%rbp)			;比较eax(第二个数) rbp(第一个数)
  40113e:	75 05                	jne    401145 <phase_6+0x51>	;表示数字不能相等
  401140:	e8 f5 02 00 00       	callq  40143a <explode_bomb>
  401145:	83 c3 01             	add    $0x1,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>		
  40114d:	49 83 c5 04          	add    $0x4,%r13					
  401151:	eb c1                	jmp    401114 <phase_6+0x20>		
  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi				
  401158:	4c 89 f0             	mov    %r14,%rax					
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx
  401160:	89 ca                	mov    %ecx,%edx
  401162:	2b 10                	sub    (%rax),%edx				;edx=7-rax 7-输入数字
  401164:	89 10                	mov    %edx,(%rax)				;(rax)(输入数字变成7-i)
  401166:	48 83 c0 04          	add    $0x4,%rax				;移动到下一个值
  40116a:	48 39 f0             	cmp    %rsi,%rax
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>	;循环,把输入数字变成7-i
  40116f:	be 00 00 00 00       	mov    $0x0,%esi					
  401174:	eb 21                	jmp    401197 <phase_6+0xa3>	;替换7-i完毕,转跳
  401176:	48 8b 52 08          	mov    0x8(%rdx),%rdx			;rdx=下一个node节点
  40117a:	83 c0 01             	add    $0x1,%eax				;eax=+1
  40117d:	39 c8                	cmp    %ecx,%eax				;这几行表示:取出7-i(输入值),遍历找到对应的7-i node
  40117f:	75 f5                	jne    401176 <phase_6+0x82>
  401181:	eb 05                	jmp    401188 <phase_6+0x94>		
  401183:	ba d0 32 60 00       	mov    $0x6032d0,%edx				
  401188:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)	;存放7-i对应的链表节点地址 %rsp+0x20(32)
  40118d:	48 83 c6 04          	add    $0x4,%rsi				;rsi+=4
  401191:	48 83 fe 18          	cmp    $0x18,%rsi				;0x18=24 ;6次后 跳转
  401195:	74 14                	je     4011ab <phase_6+0xb7>	
  401197:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx		;ecx=第一个数(注意是:7-i) 取出下一个数
  40119a:	83 f9 01             	cmp    $0x1,%ecx
  40119d:	7e e4                	jle    401183 <phase_6+0x8f>	
  40119f:	b8 01 00 00 00       	mov    $0x1,%eax				
  4011a4:	ba d0 32 60 00       	mov    $0x6032d0,%edx			;x/24wd 0x6032d0,发现是链表
  4011a9:	eb cb                	jmp    401176 <phase_6+0x82>	
  4011ab:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx			;第一个节点
  4011b0:	48 8d 44 24 28       	lea    0x28(%rsp),%rax			;指向第二个节点的地址
  4011b5:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi			;
  4011ba:	48 89 d9             	mov    %rbx,%rcx				
  4011bd:	48 8b 10             	mov    (%rax),%rdx				
  4011c0:	48 89 51 08          	mov    %rdx,0x8(%rcx)			
  4011c4:	48 83 c0 08          	add    $0x8,%rax				
  4011c8:	48 39 f0             	cmp    %rsi,%rax
  4011cb:	74 05                	je     4011d2 <phase_6+0xde>
  4011cd:	48 89 d1             	mov    %rdx,%rcx				
  4011d0:	eb eb                	jmp    4011bd <phase_6+0xc9>	 
  4011d2:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)
  4011d9:	00 														
  4011da:	bd 05 00 00 00       	mov    $0x5,%ebp				
  4011df:	48 8b 43 08          	mov    0x8(%rbx),%rax			;下个节点
  4011e3:	8b 00                	mov    (%rax),%eax				
  4011e5:	39 03                	cmp    %eax,(%rbx)
  4011e7:	7d 05                	jge    4011ee <phase_6+0xfa>	;(rbx)>=eax 表示要从大到小排序 
  4011e9:	e8 4c 02 00 00       	callq  40143a <explode_bomb>
  4011ee:	48 8b 5b 08          	mov    0x8(%rbx),%rbx			;下个节点
  4011f2:	83 ed 01             	sub    $0x1,%ebp
  4011f5:	75 e8                	jne    4011df <phase_6+0xeb>	;循环6次
  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   

第10行read_six_numbers,读入6个数字
第16行和第26行表示数字要<=6,并且不相等
第38行401164表示把输入数字变成7-i,第43行401174执行完毕,通过gdb观察x/d $rsp[+4,8..],例如输入123456=>654321
第58行x/24wd 0x6032d0,发现是链表结构(24个单位,每个单位4字节,十进制表示)
在这里插入图片描述

这种结构

struct {
    int value;
    int order;
    node* next;
} node;

第44到50行表示取出7-i对应的链表节点地址并保存,例如输入432165(=>345612)=>
在这里插入图片描述

第77行4011e7表示前一个>=后一个值,表示从大到小排序(注意前面7-i,所以要确保345612,应该输入431265)
所以答案为4 3 2 1 6 5

secret_phase

phase_defusedsecret_phase,隐藏关卡,有兴趣的可以自己尝试下

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值