拆除二进制炸弹

Wrote by CS 20.4 隋春雨


参考文章:
常见指令

MIPS指令官方文档

gdb调试

stack如何保存现场?
在这里插入图片描述
常见寄存器:

在这里插入图片描述

1. 第一关

在这里插入图片描述
beqz指令那里可以看出,如果是字符串相等的话,那么我们就直接跳到
0x400da4,可以看到0x00400d9c是炸弹爆炸的地方,所以这一关的要点就变成了,查出原来的函数中保存的string的内容,然后输入即可

在这里插入图片描述
本来我最开始看到这个\就不太理解,后来用pycharm输出了一下'asc码发现就是39,才发现是哪个'太小了没看到,所以最终拆除炸弹的结果就是Let's begin now!
在这里插入图片描述
PS:
GDB中X的用法
在这里插入图片描述
x /16c $a0类似于事后诸葛亮了,因为这是我们在知道这个结果是16位的情况下,才能x /16c $a0,才平时做实验的时候,可以多扩展几位看一看结果

2. 第二关

在这里插入图片描述
li
在这里插入图片描述
$v0:子函数调用返回的结果
参考了一下
关于mips-fp(帧指针)寄存器的理解

MIPS汇编角度看C语言的指针

mips中gp寄存器的用法
简单来说,用fp保存栈底的位置
fp:栈基址寄存器
在这里插入图片描述
值得注意的是:
0x00400dc0 <+4>: sw ra,60(sp)
这条指令,按照mips官方文档的解释,是这样的
在这里插入图片描述
个人感觉可能用lw更合适一点,为了验证一下是否保存的是返回地址,找了一下资料
在这里插入图片描述
可以看出作者认为,它保存的确实是返回地址。。。。Ok。。。。。那就先这样

对于move指令,查找了一下资料,
可以发现move $a0 $a1的含义就是把$a1的值送到$a0寄存器
在这里插入图片描述

在这里插入图片描述
思考:为什么

   0x00400dbc <+0>:		addiu	sp,sp,-64
   0x00400dc0 <+4>:		sw	ra,60(sp)
   0x00400dc4 <+8>:		sw	s8,56(sp)
   0x00400dc8 <+12>:	move	s8,sp
   0x00400dcc <+16>:	lui	gp,0x42
   0x00400dd0 <+20>:	addiu	gp,gp,-20080
   0x00400dd4 <+24>:	sw	gp,16(sp)
   0x00400dd8 <+28>:	sw	a0,64(s8)
   0x00400ddc <+32>:	addiu	v0,s8,28
   0x00400de0 <+36>:	lw	a0,64(s8)
   0x00400de4 <+40>:	move	a1,v0
   0x00400de8 <+44>:	jal	0x401ba8 <read_six_numbers>
   0x00400dec <+48>:	nop
   0x00400df0 <+52>:	lw	gp,16(s8)
   0x00400df4 <+56>:	lw	v1,28(s8)
   0x00400df8 <+60>:	li	v0,1
   0x00400dfc <+64>:	beq	v1,v0,0x400e10 <phase_2+84>
   0x00400e00 <+68>:	nop
   0x00400e04 <+72>:	jal	0x4021f0 <explode_bomb>
   0x00400e08 <+76>:	nop
   0x00400e0c <+80>:	lw	gp,16(s8)
   0x00400e10 <+84>:	li	v0,1
   0x00400e14 <+88>:	sw	v0,24(s8)
   0x00400e18 <+92>:	b	0x400ea8 <phase_2+236>
   0x00400e1c <+96>:	nop
   0x00400e20 <+100>:	lw	v0,24(s8)
   0x00400e24 <+104>:	nop

每条指令之间的间隔都是4呢?

解决:查了一下MIPS指令的构成发现,无论是R、I、J型指令,都是
32位的,4个字节,所以MIPS指令的间隔都是4
同时查了一下beqz指令的用法
beqz $v location:若$v寄存器的值为0,那么程序跳转到location
在实验二中的0x00400dfc <+64>: beq v1,v0,0x400e10 <phase_2+84>指令中

如果$v1==$v0,那么跳转到0x400e10,不会爆炸。

如果没有,那么一定会因为0x00400e04 <+72>: jal 0x4021f0 <explode_bomb>而爆炸
在这里插入图片描述
到这里的时候,总是遇到
---Type <return> to continue, or q <return> to quit---q的问题,查了一下,发现设置一下不分页显示就好了
set pagination off

Dump of assembler code for function phase_2:
   0x00400dbc <+0>:		addiu	sp,sp,-64
   0x00400dc0 <+4>:		sw	ra,60(sp)
   0x00400dc4 <+8>:		sw	s8,56(sp)
   0x00400dc8 <+12>:	move	s8,sp
   0x00400dcc <+16>:	lui	gp,0x42
   0x00400dd0 <+20>:	addiu	gp,gp,-20080
   0x00400dd4 <+24>:	sw	gp,16(sp)
   0x00400dd8 <+28>:	sw	a0,64(s8)
   0x00400ddc <+32>:	addiu	v0,s8,28
   0x00400de0 <+36>:	lw	a0,64(s8)
   0x00400de4 <+40>:	move	a1,v0
   0x00400de8 <+44>:	jal	0x401ba8 <read_six_numbers>
   0x00400dec <+48>:	nop
   0x00400df0 <+52>:	lw	gp,16(s8)
   0x00400df4 <+56>:	lw	v1,28(s8)
   0x00400df8 <+60>:	li	v0,1
   0x00400dfc <+64>:	beq	v1,v0,0x400e10 <phase_2+84>
   0x00400e00 <+68>:	nop
   0x00400e04 <+72>:	jal	0x4021f0 <explode_bomb>
   0x00400e08 <+76>:	nop
   0x00400e0c <+80>:	lw	gp,16(s8)
   0x00400e10 <+84>:	li	v0,1
   0x00400e14 <+88>:	sw	v0,24(s8)
   0x00400e18 <+92>:	b	0x400ea8 <phase_2+236>
   0x00400e1c <+96>:	nop
   0x00400e20 <+100>:	lw	v0,24(s8)// 当前循环次数
   0x00400e24 <+104>:	nop
   0x00400e28 <+108>:	addiu	v0,v0,-1//上一次的循环次数
   0x00400e2c <+112>:	sll	v0,v0,0x2
   0x00400e30 <+116>:	addiu	v1,s8,24//v1保存的起始位置
   0x00400e34 <+120>:	addu	v0,v1,v0//找到上一个元素的位置
   0x00400e38 <+124>:	lw	a0,4(v0)//当前的数组中的元素放到了$a0
   0x00400e3c <+128>:	li	v1,12
   0x00400e40 <+132>:	lw	v0,24(s8)//循环次数
   0x00400e44 <+136>:	nop
   0x00400e48 <+140>:	subu	v0,v1,v0//$v0=12-循环次数
   0x00400e4c <+144>:	lw	v1,-32660(gp)//$v1=$gp-32660
   0x00400e50 <+148>:	sll	v0,v0,0x2//$v0=(12-循环次数)*4
   0x00400e54 <+152>:	addu	v0,v1,v0//$v0=$gp-32660+(12-循环次数)*4
   0x00400e58 <+156>:	lw	v0,0(v0)//$v0=Memory[$v0]
   0x00400e5c <+160>:	nop
   0x00400e60 <+164>:	mult	a0,v0
   0x00400e64 <+168>:	mflo	a0 //这里是a0最后一次被改变的位置
   0x00400e68 <+172>:	lw	v0,24(s8)//这里是v0被改变的有效位置,$v0=循环次数
   0x00400e6c <+176>:	nop
   0x00400e70 <+180>:	sll	v0,v0,0x2//$v0=循环次数*4
   0x00400e74 <+184>:	addiu	v1,s8,24//$v1=2147479848
   0x00400e78 <+188>:	addu	v0,v1,v0
   0x00400e7c <+192>:	lw	v0,4(v0)
   0x00400e80 <+196>:	nop
   0x00400e84 <+200>:	beq	a0,v0,0x400e98 <phase_2+220>
   0x00400e88 <+204>:	nop
   0x00400e8c <+208>:	jal	0x4021f0 <explode_bomb>
   0x00400e90 <+212>:	nop
   0x00400e94 <+216>:	lw	gp,16(s8)
   0x00400e98 <+220>:	lw	v0,24(s8)
   0x00400e9c <+224>:	nop
   0x00400ea0 <+228>:	addiu	v0,v0,1
   0x00400ea4 <+232>:	sw	v0,24(s8)
   0x00400ea8 <+236>:	lw	v0,24(s8)
   0x00400eac <+240>:	nop
   0x00400eb0 <+244>:	slti	v0,v0,6
   0x00400eb4 <+248>:	bnez	v0,0x400e20 <phase_2+100>
   0x00400eb8 <+252>:	nop
   0x00400ebc <+256>:	move	sp,s8
   0x00400ec0 <+260>:	lw	ra,60(sp)
   0x00400ec4 <+264>:	lw	s8,56(sp)
   0x00400ec8 <+268>:	addiu	sp,sp,64
   0x00400ecc <+272>:	jr	ra
   0x00400ed0 <+276>:	nop
End of assembler dump.

其中对于
0x00400e18 <+92>: b 0x400ea8 <phase_2+236>:猜也能猜到跳转到
0x400ea8 <phase_2+236>,查了一下官方文档
在这里插入图片描述
发现确实是这样

然后我想像vs那样单步查看变量的值,于是查询了一下单步执行的命令
ni
例子:
在这里插入图片描述

在第一个值得怀疑的地方设置一个断点
在这里插入图片描述
p $v0发现是1,当然从上一行的指令中我们也能看到。所以第一个数字一定是1
然后一步一步使用ni指令一步一步走,如下图
在这里插入图片描述

然后碰到了0x00400eb0 <+244>: slti v0,v0,6
查了一下
这条指令的含义是if $v0<6,then $v0=1,else $v0=0
在这里插入图片描述

继续就这么执行,直到跳转到了0x00400e20 <+100>: lw v0,24(s8)
我们之前手动分析的时候,这个地方保存的值就是1,如果不放心的话可以打印看一看
(gdb) x/1ub $s8+24
结果
在这里插入图片描述

继续执行,发现程序总是在调用
在这里插入图片描述

$gp-32660相当于基址

打印一下发现
在这里插入图片描述

这正好是我输入的ID-number

就 这么一步一步拆,最后发现结果是

170000,当然这组数据可能跟我取的值有关系,我输入的ID-number=996007

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAZTJfK3-1637201619105)(拆除二进制炸弹.assets/image-20211118100337336.png)]

3. 第三关

Dump of assembler code for function phase_3:
   0x00400ed4 <+0>:		addiu	sp,sp,-56
   0x00400ed8 <+4>:		sw	ra,52(sp)
   0x00400edc <+8>:		sw	s8,48(sp)
   0x00400ee0 <+12>:	move	s8,sp
   0x00400ee4 <+16>:	lui	gp,0x42
   0x00400ee8 <+20>:	addiu	gp,gp,-20080
   0x00400eec <+24>:	sw	gp,24(sp)
   0x00400ef0 <+28>:	sw	a0,56(s8)
   0x00400ef4 <+32>:	lw	a0,56(s8)
   0x00400ef8 <+36>:	lui	v0,0x40
   0x00400efc <+40>:	addiu	a1,v0,10112
   0x00400f00 <+44>:	addiu	v1,s8,44
   0x00400f04 <+48>:	addiu	v0,s8,40
   0x00400f08 <+52>:	addiu	a2,s8,36
   0x00400f0c <+56>:	sw	a2,16(sp)
   0x00400f10 <+60>:	move	a2,v1
   0x00400f14 <+64>:	move	a3,v0
   0x00400f18 <+68>:	lw	v0,-32636(gp)
   0x00400f1c <+72>:	nop
   0x00400f20 <+76>:	move	t9,v0
   0x00400f24 <+80>:	jalr	t9
   0x00400f28 <+84>:	nop
   0x00400f2c <+88>:	lw	gp,24(s8)
   0x00400f30 <+92>:	slti	v0,v0,3
   0x00400f34 <+96>:	beqz	v0,0x400f48 <phase_3+116>
   0x00400f38 <+100>:	nop
   0x00400f3c <+104>:	jal	0x4021f0 <explode_bomb>
   0x00400f40 <+108>:	nop
   0x00400f44 <+112>:	lw	gp,24(s8)
   0x00400f48 <+116>:	lw	v0,44(s8)
   0x00400f4c <+120>:	nop
   0x00400f50 <+124>:	sltiu	v1,v0,8
   0x00400f54 <+128>:	beqz	v1,0x401190 <phase_3+700>
   0x00400f58 <+132>:	nop
   0x00400f5c <+136>:	sll	v1,v0,0x2
   0x00400f60 <+140>:	lui	v0,0x40
   0x00400f64 <+144>:	addiu	v0,v0,10124
   0x00400f68 <+148>:	addu	v0,v1,v0
   0x00400f6c <+152>:	lw	v0,0(v0)
   0x00400f70 <+156>:	nop
   0x00400f74 <+160>:	jr	v0
   0x00400f78 <+164>:	nop
   0x00400f7c <+168>:	li	v0,113
   0x00400f80 <+172>:	sb	v0,32(s8)
   0x00400f84 <+176>:	lw	v0,-32660(gp)
   0x00400f88 <+180>:	nop
   0x00400f8c <+184>:	lw	v1,44(v0)
   0x00400f90 <+188>:	lw	v0,36(s8)
   0x00400f94 <+192>:	nop
   0x00400f98 <+196>:	mult	v1,v0
   0x00400f9c <+200>:	mflo	v1
   0x00400fa0 <+204>:	li	v0,777
   0x00400fa4 <+208>:	beq	v1,v0,0x4011ac <phase_3+728>
   0x00400fa8 <+212>:	nop
   0x00400fac <+216>:	jal	0x4021f0 <explode_bomb>
   0x00400fb0 <+220>:	nop
   0x00400fb4 <+224>:	lw	gp,24(s8)
   0x00400fb8 <+228>:	b	0x4011f8 <phase_3+804>
   0x00400fbc <+232>:	nop
   0x00400fc0 <+236>:	li	v0,98
   0x00400fc4 <+240>:	sb	v0,32(s8)
   0x00400fc8 <+244>:	lw	v0,-32660(gp)
   0x00400fcc <+248>:	nop
   0x00400fd0 <+252>:	lw	v1,44(v0)
   0x00400fd4 <+256>:	lw	v0,36(s8)
   0x00400fd8 <+260>:	nop
   0x00400fdc <+264>:	mult	v1,v0
   0x00400fe0 <+268>:	mflo	v1
   0x00400fe4 <+272>:	li	v0,214
   0x00400fe8 <+276>:	beq	v1,v0,0x4011b8 <phase_3+740>
   0x00400fec <+280>:	nop
   0x00400ff0 <+284>:	jal	0x4021f0 <explode_bomb>
   0x00400ff4 <+288>:	nop
   0x00400ff8 <+292>:	lw	gp,24(s8)
   0x00400ffc <+296>:	b	0x4011f8 <phase_3+804>
   0x00401000 <+300>:	nop
   0x00401004 <+304>:	li	v0,98
   0x00401008 <+308>:	sb	v0,32(s8)
   0x0040100c <+312>:	lw	v0,-32660(gp)
   0x00401010 <+316>:	nop
   0x00401014 <+320>:	lw	v1,44(v0)
   0x00401018 <+324>:	lw	v0,36(s8)
   0x0040101c <+328>:	nop
   0x00401020 <+332>:	mult	v1,v0
   0x00401024 <+336>:	mflo	v1
   0x00401028 <+340>:	li	v0,755
   0x0040102c <+344>:	beq	v1,v0,0x4011c4 <phase_3+752>
   0x00401030 <+348>:	nop
   0x00401034 <+352>:	jal	0x4021f0 <explode_bomb>
   0x00401038 <+356>:	nop
   0x0040103c <+360>:	lw	gp,24(s8)
   0x00401040 <+364>:	b	0x4011f8 <phase_3+804>
   0x00401044 <+368>:	nop
   0x00401048 <+372>:	li	v0,107
   0x0040104c <+376>:	sb	v0,32(s8)
   0x00401050 <+380>:	lw	v0,-32660(gp)
   0x00401054 <+384>:	nop
   0x00401058 <+388>:	lw	v1,44(v0)
   0x0040105c <+392>:	lw	v0,36(s8)
   0x00401060 <+396>:	nop
   0x00401064 <+400>:	mult	v1,v0
   0x00401068 <+404>:	mflo	v0
   0x0040106c <+408>:	beqz	v0,0x4011d0 <phase_3+764>
   0x00401070 <+412>:	nop
   0x00401074 <+416>:	jal	0x4021f0 <explode_bomb>
   0x00401078 <+420>:	nop
   0x0040107c <+424>:	lw	gp,24(s8)
   0x00401080 <+428>:	b	0x4011f8 <phase_3+804>
   0x00401084 <+432>:	nop
   0x00401088 <+436>:	li	v0,111
   0x0040108c <+440>:	sb	v0,32(s8)
   0x00401090 <+444>:	lw	v0,-32660(gp)
   0x00401094 <+448>:	nop
   0x00401098 <+452>:	lw	v1,44(v0)
   0x0040109c <+456>:	lw	v0,36(s8)
   0x004010a0 <+460>:	nop
   0x004010a4 <+464>:	mult	v1,v0
   0x004010a8 <+468>:	mflo	v1
   0x004010ac <+472>:	li	v0,228
   0x004010b0 <+476>:	beq	v1,v0,0x4011dc <phase_3+776>
   0x004010b4 <+480>:	nop
   0x004010b8 <+484>:	jal	0x4021f0 <explode_bomb>
   0x004010bc <+488>:	nop
   0x004010c0 <+492>:	lw	gp,24(s8)
   0x004010c4 <+496>:	b	0x4011f8 <phase_3+804>
   0x004010c8 <+500>:	nop
   0x004010cc <+504>:	li	v0,116
   0x004010d0 <+508>:	sb	v0,32(s8)
   0x004010d4 <+512>:	lw	v0,-32660(gp)
   0x004010d8 <+516>:	nop
   0x004010dc <+520>:	lw	v1,44(v0)
   0x004010e0 <+524>:	lw	v0,36(s8)
   0x004010e4 <+528>:	nop
   0x004010e8 <+532>:	mult	v1,v0
   0x004010ec <+536>:	mflo	v1
   0x004010f0 <+540>:	li	v0,513
   0x004010f4 <+544>:	beq	v1,v0,0x4011e8 <phase_3+788>
   0x004010f8 <+548>:	nop
   0x004010fc <+552>:	jal	0x4021f0 <explode_bomb>
   0x00401100 <+556>:	nop
   0x00401104 <+560>:	lw	gp,24(s8)
   0x00401108 <+564>:	b	0x4011f8 <phase_3+804>
   0x0040110c <+568>:	nop
   0x00401110 <+572>:	li	v0,118
   0x00401114 <+576>:	sb	v0,32(s8)
   0x00401118 <+580>:	lw	v0,-32660(gp)
   0x0040111c <+584>:	nop
   0x00401120 <+588>:	lw	v1,44(v0)
   0x00401124 <+592>:	lw	v0,36(s8)
   0x00401128 <+596>:	nop
   0x0040112c <+600>:	mult	v1,v0
   0x00401130 <+604>:	mflo	v1
   0x00401134 <+608>:	li	v0,780
   0x00401138 <+612>:	beq	v1,v0,0x40114c <phase_3+632>
   0x0040113c <+616>:	nop
   0x00401140 <+620>:	jal	0x4021f0 <explode_bomb>
   0x00401144 <+624>:	nop
   0x00401148 <+628>:	lw	gp,24(s8)
   0x0040114c <+632>:	li	v0,98
   0x00401150 <+636>:	sb	v0,32(s8)
   0x00401154 <+640>:	lw	v0,-32660(gp)
   0x00401158 <+644>:	nop
   0x0040115c <+648>:	lw	v1,44(v0)
   0x00401160 <+652>:	lw	v0,36(s8)
   0x00401164 <+656>:	nop
   0x00401168 <+660>:	mult	v1,v0
   0x0040116c <+664>:	mflo	v1
   0x00401170 <+668>:	li	v0,824
   0x00401174 <+672>:	beq	v1,v0,0x4011f4 <phase_3+800>
   0x00401178 <+676>:	nop
   0x0040117c <+680>:	jal	0x4021f0 <explode_bomb>
   0x00401180 <+684>:	nop
   0x00401184 <+688>:	lw	gp,24(s8)
   0x00401188 <+692>:	b	0x4011f8 <phase_3+804>
   0x0040118c <+696>:	nop
   0x00401190 <+700>:	li	v0,120
   0x00401194 <+704>:	sb	v0,32(s8)
   0x00401198 <+708>:	jal	0x4021f0 <explode_bomb>
   0x0040119c <+712>:	nop
   0x004011a0 <+716>:	lw	gp,24(s8)
   0x004011a4 <+720>:	b	0x4011f8 <phase_3+804>
   0x004011a8 <+724>:	nop
   0x004011ac <+728>:	nop
   0x004011b0 <+732>:	b	0x4011f8 <phase_3+804>
   0x004011b4 <+736>:	nop
   0x004011b8 <+740>:	nop
   0x004011bc <+744>:	b	0x4011f8 <phase_3+804>
   0x004011c0 <+748>:	nop
   0x004011c4 <+752>:	nop
   0x004011c8 <+756>:	b	0x4011f8 <phase_3+804>
   0x004011cc <+760>:	nop
   0x004011d0 <+764>:	nop
   0x004011d4 <+768>:	b	0x4011f8 <phase_3+804>
   0x004011d8 <+772>:	nop
   0x004011dc <+776>:	nop
   0x004011e0 <+780>:	b	0x4011f8 <phase_3+804>
   0x004011e4 <+784>:	nop
   0x004011e8 <+788>:	nop
   0x004011ec <+792>:	b	0x4011f8 <phase_3+804>
   0x004011f0 <+796>:	nop
   0x004011f4 <+800>:	nop
   0x004011f8 <+804>:	lb	v0,40(s8)
   0x004011fc <+808>:	lb	v1,32(s8)
   0x00401200 <+812>:	nop
   0x00401204 <+816>:	beq	v1,v0,0x401218 <phase_3+836>
   0x00401208 <+820>:	nop
   0x0040120c <+824>:	jal	0x4021f0 <explode_bomb>
   0x00401210 <+828>:	nop
   0x00401214 <+832>:	lw	gp,24(s8)
   0x00401218 <+836>:	move	sp,s8
   0x0040121c <+840>:	lw	ra,52(sp)
   0x00401220 <+844>:	lw	s8,48(sp)
   0x00401224 <+848>:	addiu	sp,sp,56
   0x00401228 <+852>:	jr	ra
   0x0040122c <+856>:	nop
End of assembler dump.

做实验的时候发生了很多问题,比如说,输出寄存器的值没有得到预期的结果,后来发现,是x的用法有错误,sw指令,读取的时候应该读出来的是一个word而不是byte,像以下的结果就是正确的,输入一个byte,读取一个byte
在这里插入图片描述
在拆除实验三的时候,我跟我数学建模的队(lxr巨巨)发现了一个问题,
在这里插入图片描述
在这条指令中,我们执行后输出$v0发现是2137465136,但是x/1ub $gp-32636发现却是48,最后经过一个形势政策的讨论,也没有结果
经过顽强的debug发现是输出格式的错误,应该是x/1uw %gp-32636,这样就是2137465136了,确认过眼神(下次一定好好看输出格式)
在这里插入图片描述
在这里插入图片描述

我输入的是1 4 6,但是因为它是按照字符读取的,所以我们输出它的4asc
在这里插入图片描述
可以发现,是一样的,同时我们观察stack中保存变量的顺序,正好从低到高
在这里插入图片描述
做到这里我产生了一个疑问,如何知道s8sp中间的东西都是什么?
于是查了一下,
fp和sp的相关知识
简单来说,fpsp都是保存的调用她的函数的栈底和栈顶

然后我继续看汇编代码,发现
在这里插入图片描述
这一行其实是令$v0=Memory[$v0],同时结合上下文我们推断出来$v0=0x400000+10124+a[0]*4,其中a[0]是我们输入的数字的第一位,那么这样以来,实验平台就能检测出来我们输入的第一个数字是什么了
我们调用一下寄存器
在这里插入图片描述
发现$v0保存的是一个地址
在这里插入图片描述
那么问题来了,如果我们输入的第一位数字不是1而是别的数字会怎么办?
在这里插入图片描述
打印输出了10个值,结果发现正符合预期,最后2个乱码是因为8 9是UI直接爆炸,根本不会执行到这里在这里插入图片描述
我们检测一下,
在这里插入图片描述
在这里插入图片描述
发现正好有(当然也必须有),同时看上下文,这个地址后面也只有一个li指令,符合我们的预期
在这里插入图片描述
看到这几行指令,我认为那里保存的是我输入的数据,输出一看,确实是ID-num,同时温馨提示,尽量不要选择特别奇怪的数字,比如连着2个0,你很有可能理解为那个是未初始化的内存单元的值

在这里插入图片描述
在分析的过程中,观察这段代码,最终发现这段其实就做了两件事情
1.将v0寄存器的值放到了Memory[$s8+32]
2. ID-num的最后一位和输入的最后一个数字相乘 ,最终和$v0比较是否相等,若相等,则跳转,否则爆炸。因为我输入的学号的最后一位是7,所以需要找到一个7的倍数的$v0,最终发现是第一个函数段,所以我们输入的第一个数字应该是0

在这里插入图片描述
最终我们成功跳转到了
在这里插入图片描述
从上文的分析中,我们知道Memory[$s8+40]保存的是输入的第2个参数,而Memory[$s8+32]保存的是113在这里插入图片描述
经过分析得出,这个113其实表示的是一个字符,所以我们第2个输入q即可

在这里插入图片描述

4. 第四关

碰到的难点如下
在这里插入图片描述
func4做了什么?我们看一下func4的代码

Dump of assembler code for function func4:
   0x00401230 <+0>:		addiu	sp,sp,-40
   0x00401234 <+4>:		sw	ra,36(sp)
   0x00401238 <+8>:		sw	s8,32(sp)
   0x0040123c <+12>:	sw	s0,28(sp)
   0x00401240 <+16>:	move	s8,sp
   0x00401244 <+20>:	sw	a0,40(s8)
   0x00401248 <+24>:	lw	v0,40(s8)
   0x0040124c <+28>:	nop
   0x00401250 <+32>:	slti	v0,v0,2
   0x00401254 <+36>:	bnez	v0,0x40129c <func4+108>
   0x00401258 <+40>:	nop
   0x0040125c <+44>:	lw	v0,40(s8)
   0x00401260 <+48>:	nop
   0x00401264 <+52>:	addiu	v0,v0,-1
   0x00401268 <+56>:	move	a0,v0
   0x0040126c <+60>:	jal	0x401230 <func4>
   0x00401270 <+64>:	nop
   0x00401274 <+68>:	move	s0,v0
   0x00401278 <+72>:	lw	v0,40(s8)
   0x0040127c <+76>:	nop
   0x00401280 <+80>:	addiu	v0,v0,-2
   0x00401284 <+84>:	move	a0,v0
   0x00401288 <+88>:	jal	0x401230 <func4>
   0x0040128c <+92>:	nop
   0x00401290 <+96>:	addu	v0,s0,v0
   0x00401294 <+100>:	b	0x4012a0 <func4+112>
   0x00401298 <+104>:	nop
   0x0040129c <+108>:	li	v0,1
   0x004012a0 <+112>:	move	sp,s8
   0x004012a4 <+116>:	lw	ra,36(sp)
   0x004012a8 <+120>:	lw	s8,32(sp)
   0x004012ac <+124>:	lw	s0,28(sp)
   0x004012b0 <+128>:	addiu	sp,sp,40
   0x004012b4 <+132>:	jr	ra
   0x004012b8 <+136>:	nop
End of assembler dump.


我们先看这么几个关键点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看这一段汇编代码,我们可以很明显的看出,这一段调用了func4($v0-1)
再看
在这里插入图片描述

它调用了func($v0-2)
这是什么?这不是斐波那契数列吗?!
再看这一段
在这里插入图片描述
果然
所以接下来的问题就变成了,斐波那契的第几项是8
我们打表看一下
在这里插入图片描述
所以答案很明显,是5
在这里插入图片描述

5. 第五关

   0x004013e8 <+0>:		addiu	sp,sp,-72
   0x004013ec <+4>:		sw	ra,68(sp)
   0x004013f0 <+8>:		sw	s8,64(sp)
   0x004013f4 <+12>:	move	s8,sp
   0x004013f8 <+16>:	sw	a0,72(s8)
   0x004013fc <+20>:	lw	a0,72(s8)
   0x00401400 <+24>:	jal	0x401c78 <string_length>
   0x00401404 <+28>:	nop
   0x00401408 <+32>:	move	v1,v0
   0x0040140c <+36>:	li	v0,6
   0x00401410 <+40>:	beq	v1,v0,0x401420 <phase_5+56>
   0x00401414 <+44>:	nop
   0x00401418 <+48>:	jal	0x4021f0 <explode_bomb>
   0x0040141c <+52>:	nop
   0x00401420 <+56>:	sw	zero,24(s8)
   0x00401424 <+60>:	b	0x4014a8 <phase_5+192>
   0x00401428 <+64>:	nop
   0x0040142c <+68>:	lw	v0,24(s8)
   0x00401430 <+72>:	lw	v1,24(s8)
   0x00401434 <+76>:	lw	a0,72(s8)
   0x00401438 <+80>:	nop
   0x0040143c <+84>:	addu	v1,a0,v1
   0x00401440 <+88>:	lb	v1,0(v1)
   0x00401444 <+92>:	nop
   0x00401448 <+96>:	andi	v1,v1,0xff
   0x0040144c <+100>:	andi	v1,v1,0xf
   0x00401450 <+104>:	sll	v0,v0,0x2
   0x00401454 <+108>:	addiu	a0,s8,24
   0x00401458 <+112>:	addu	v0,a0,v0
   0x0040145c <+116>:	sw	v1,12(v0)
   0x00401460 <+120>:	lw	a0,24(s8)
   0x00401464 <+124>:	lw	v0,24(s8)
   0x00401468 <+128>:	nop
   0x0040146c <+132>:	sll	v0,v0,0x2
   0x00401470 <+136>:	addiu	v1,s8,24
   0x00401474 <+140>:	addu	v0,v1,v0
   0x00401478 <+144>:	lw	v1,12(v0)
   0x0040147c <+148>:	lui	v0,0x41
   0x00401480 <+152>:	addiu	v0,v0,12524
   0x00401484 <+156>:	addu	v0,v1,v0
   0x00401488 <+160>:	lb	v1,0(v0)
   0x0040148c <+164>:	addiu	v0,s8,24
   0x00401490 <+168>:	addu	v0,v0,a0
   0x00401494 <+172>:	sb	v1,4(v0)
   0x00401498 <+176>:	lw	v0,24(s8)
   0x0040149c <+180>:	nop
   0x004014a0 <+184>:	addiu	v0,v0,1
   0x004014a4 <+188>:	sw	v0,24(s8)
   0x004014a8 <+192>:	lw	v0,24(s8)
   0x004014ac <+196>:	nop
   0x004014b0 <+200>:	slti	v0,v0,6
   0x004014b4 <+204>:	bnez	v0,0x40142c <phase_5+68>
   0x004014b8 <+208>:	nop
   0x004014bc <+212>:	sb	zero,34(s8)
   0x004014c0 <+216>:	addiu	v0,s8,28
   0x004014c4 <+220>:	move	a0,v0
   0x004014c8 <+224>:	lui	v0,0x40
   0x004014cc <+228>:	addiu	a1,v0,10160
   0x004014d0 <+232>:	jal	0x401cf8 <strings_not_equal>
   0x004014d4 <+236>:	nop
   0x004014d8 <+240>:	beqz	v0,0x4014e8 <phase_5+256>
   0x004014dc <+244>:	nop
   0x004014e0 <+248>:	jal	0x4021f0 <explode_bomb>
   0x004014e4 <+252>:	nop
   0x004014e8 <+256>:	move	sp,s8
   0x004014ec <+260>:	lw	ra,68(sp)
   0x004014f0 <+264>:	lw	s8,64(sp)
   0x004014f4 <+268>:	addiu	sp,sp,72
   0x004014f8 <+272>:	jr	ra
   0x004014fc <+276>:	nop

首先我们要看一下string_length的代码,我们大体猜测,这个函数应该是计算我们输入的字符串的长度,不过还需要看看代码验证一下

   0x00401c78 <+0>:		addiu	sp,sp,-24
   0x00401c7c <+4>:		sw	s8,20(sp)
   0x00401c80 <+8>:		move	s8,sp
   0x00401c84 <+12>:	sw	a0,24(s8)
   0x00401c88 <+16>:	lw	v0,24(s8)
   0x00401c8c <+20>:	nop
   0x00401c90 <+24>:	sw	v0,12(s8)
   0x00401c94 <+28>:	sw	zero,8(s8)
   0x00401c98 <+32>:	b	0x401cb0 <string_length+56>
   0x00401c9c <+36>:	nop
   0x00401ca0 <+40>:	lw	v0,8(s8)
   0x00401ca4 <+44>:	nop
   0x00401ca8 <+48>:	addiu	v0,v0,1
   0x00401cac <+52>:	sw	v0,8(s8)
   0x00401cb0 <+56>:	lw	v0,12(s8)
   0x00401cb4 <+60>:	nop
   0x00401cb8 <+64>:	lb	v0,0(v0)
   0x00401cbc <+68>:	nop
   0x00401cc0 <+72>:	sltu	v0,zero,v0
   0x00401cc4 <+76>:	andi	v0,v0,0xff
   0x00401cc8 <+80>:	lw	v1,12(s8)
   0x00401ccc <+84>:	nop
   0x00401cd0 <+88>:	addiu	v1,v1,1
   0x00401cd4 <+92>:	sw	v1,12(s8)
   0x00401cd8 <+96>:	bnez	v0,0x401ca0 <string_length+40>
   0x00401cdc <+100>:	nop
   0x00401ce0 <+104>:	lw	v0,8(s8)
   0x00401ce4 <+108>:	move	sp,s8
   0x00401ce8 <+112>:	lw	s8,20(sp)
   0x00401cec <+116>:	addiu	sp,sp,24
   0x00401cf0 <+120>:	jr	ra
   0x00401cf4 <+124>:	nop
End of assembler dump.

在这里插入图片描述
做实验的时候,遇到了这行代码,不太理解,翻了一下指令集手册,发现这样
在这里插入图片描述
本来以为,这是个寄存器值和立即数的比较,但是看了一下,发现是两个寄存器,我就不太理解,后来恍然大悟,这个 zero有没有可能是0号寄存器?!
于是输出了一下,果然是
在这里插入图片描述
当然,这个$zero保存的一直都是0
继续分析string_length的代码
在这里插入图片描述
因为lb()的参数一定是一个地址,所以我们往前找,
在这里插入图片描述
我们推测$s8+12的值也一定是一个地址
继续往下看
在这里插入图片描述

这行代码其实是最令我无法理解的,我最开始以为,难道它的循环次数是从负数开始?
其次,那他怎么判断循环终结?(当然,最后我都搞懂了这些东西)
不过分析还是要一步一步来
在这里插入图片描述
我们推测,$v1才是保存的循环次数,因为他有很明显的+1并且保存到了$s8+12,那么原来的$v0就肯定不是了,并且我们结合上下文也能发现,$v0中的值并没有保存,所以我们推测,v0中的保存的值有别的含义
我们想,如果它读取结束了,那么它一定会退出,也就是
在这里插入图片描述
那么我们往前看
什么时候$v0会等于0呢?
在这里插入图片描述
我们突然想起,上一个实验的113其实是qasc
那么这个0是什么?
这个不是'\0'asc码吗?!
我们输出一下看看
在这里插入图片描述
所以这样,这个函数就完全搞清除了
对于第5关,我的输入是half
在这里插入图片描述

在这里插入图片描述
对于这几行代码,我的猜测就是$a0中保存的地址存放着输入的字符串,
输出一看
在这里插入图片描述
确实是

在做实验的时候,也遇到这样的错误
在这里插入图片描述
我想进入string_length函数单步调试,但是使用ni直接跳过,使用step直接爆炸,后来发现,应该使用si命令(或者stepi
同时,对于一个函数,如果被调用了很多次,我们不应该直接在那个位置上设置断电,在它前面的某个位置设置一个断点,然后si即可
否侧一直c会很麻烦
同时
在这里插入图片描述
我最开始读这段代码的时候没有搞懂,为什么v0中存放的是保存的循环次数,你刚开始就+1然后保存,不怕读取到了'\0'吗?
后来仔细阅读发现,这个+1加的其实是上一次读取到的,如果上一次读取到了'\0'
那么它根本不会跳转到这里!
它就直接退出了!
所以它保存的一定是循环次数!也就是,字符串的长度!

然后继续往下看
在这里插入图片描述
不难猜出来,Memory[$s8+24]保存的是for循环的执行次数
在这里插入图片描述
从这两行代码中,我们可以才出来,a0保存的是一个内存地址
那么我们输出一下
在这里插入图片描述

是我们输入的字符串
所以以下这两行的代码的作用就明晰了
在这里插入图片描述
22行是用来保存当前读取到的位置
v1用来保存读取出来的字符

所以

   0x00401448 <+96>:	andi	v1,v1,0xff
   0x0040144c <+100>:	andi	v1,v1,0xf//字符的asc和0xf相与

那我们输出一下我们输入的字符 的asc0xf相与之后的结果
在这里插入图片描述
那么我们在虚拟机上看一看,第一位字符处理之后的结果是不是3
在这里插入图片描述
果然
并且我们知道
在这里插入图片描述
那么我们来调用一下看看
在这里插入图片描述
在这里插入图片描述

对于
在这里插入图片描述
$v1=Memory[$s8+36+4*循环次数],读取到的字符asc0xf相与的结果
查看寄存器
在这里插入图片描述
果然

在这里插入图片描述
对于这一段,基本上看到就能猜到,这肯定是一个地址了,那么我们输出一下,最开始我的猜测是,这个可能是我们输入的信息之类的,比如学号或者你输入的字符串
but…
在这里插入图片描述
又因为
在这里插入图片描述
所以我们再次输出,发现是118,猜测是某个字符的asc
输出一下验证
在这里插入图片描述
的确!也正好是我们推测的结果!
对于

0x00401494 <+172>:	sb	v1,4(v0)

我们知道,把$v1储存到了循环次数在内存中的地址+循环次数

再检验一次
设置断点在0x0040144c <+100>: andi v1,v1,0xf//字符的asc和0xf相与
这里,输出一下register

在这里插入图片描述
我们之前用pycharm输出了scytclasc如下
发现正确
在这里插入图片描述
事实上,形如这种的指令(虽然对解题无帮助,但是个人觉得还是很有必要理解的)
0x0040145c <+116>: sw v1,12(v0)
这种,修改了系统内存的东西(类似于c++中修改类内私有变量的成员的值,曾经在这个点上WA了无数次。。。。)
对于0x0040145c <+116>的指令,验证第1次循环如下(循环从0计数)
在这里插入图片描述

对于0x00401478 <+144>: lw v1,12(v0)//$v1=Memory[$s8+36+4*循环次数]
指令,验证如下
在这里插入图片描述
对于0x00401488 <+160>: lb v1,0(v0)//一个固定的地址+读取到的字符asc和0xf相与的结果
验证如下
在这里插入图片描述
对于0x00401494 <+172>: sb v1,4(v0)//把$v1储存到了循环次数在内存中的地址+循环次数+4
验证如下

在这里插入图片描述
哦对了,验证了时候发生了一点小的事故,其实从我的输入中也能看出来错在了哪里,输出格式不正确(这个也是我数学建模的队友lxr巨巨跟我讨论了一节课的问题),观察一下汇编的输入
在这里插入图片描述
这个是store byte不是store word!!!
再然后就碰到了这么一个函数
在这里插入图片描述

Dump of assembler code for function strings_not_equal:
   0x00401cf8 <+0>:		addiu	sp,sp,-48
   0x00401cfc <+4>:		sw	ra,44(sp)
   0x00401d00 <+8>:		sw	s8,40(sp)
   0x00401d04 <+12>:	move	s8,sp
   0x00401d08 <+16>:	sw	a0,48(s8)
   0x00401d0c <+20>:	sw	a1,52(s8)
   0x00401d10 <+24>:	lw	a0,48(s8)
   0x00401d14 <+28>:	jal	0x401c78 <string_length>
   0x00401d18 <+32>:	nop
   0x00401d1c <+36>:	sw	v0,36(s8)
   0x00401d20 <+40>:	lw	a0,52(s8)
   0x00401d24 <+44>:	jal	0x401c78 <string_length>
   0x00401d28 <+48>:	nop
   0x00401d2c <+52>:	sw	v0,32(s8)
   0x00401d30 <+56>:	lw	v0,48(s8)
   0x00401d34 <+60>:	nop
   0x00401d38 <+64>:	sw	v0,28(s8)
   0x00401d3c <+68>:	lw	v0,52(s8)
   0x00401d40 <+72>:	nop
   0x00401d44 <+76>:	sw	v0,24(s8)
   0x00401d48 <+80>:	lw	v1,36(s8)
   0x00401d4c <+84>:	lw	v0,32(s8)
   0x00401d50 <+88>:	nop
   0x00401d54 <+92>:	beq	v1,v0,0x401dc4 <strings_not_equal+204>
   0x00401d58 <+96>:	nop
   0x00401d5c <+100>:	li	v0,1
   0x00401d60 <+104>:	b	0x401de4 <strings_not_equal+236>
   0x00401d64 <+108>:	nop
   0x00401d68 <+112>:	lw	v0,28(s8)
   0x00401d6c <+116>:	nop
   0x00401d70 <+120>:	lb	v1,0(v0)
   0x00401d74 <+124>:	lw	v0,24(s8)
   0x00401d78 <+128>:	nop
   0x00401d7c <+132>:	lb	v0,0(v0)
   0x00401d80 <+136>:	nop
   0x00401d84 <+140>:	xor	v0,v1,v0
   0x00401d88 <+144>:	sltu	v0,zero,v0
   0x00401d8c <+148>:	andi	v0,v0,0xff
   0x00401d90 <+152>:	lw	v1,28(s8)
   0x00401d94 <+156>:	nop
   0x00401d98 <+160>:	addiu	v1,v1,1
   0x00401d9c <+164>:	sw	v1,28(s8)
   0x00401da0 <+168>:	lw	v1,24(s8)
   0x00401da4 <+172>:	nop
   0x00401da8 <+176>:	addiu	v1,v1,1
   0x00401dac <+180>:	sw	v1,24(s8)
   0x00401db0 <+184>:	beqz	v0,0x401dc8 <strings_not_equal+208>
   0x00401db4 <+188>:	nop
   0x00401db8 <+192>:	li	v0,1
   0x00401dbc <+196>:	b	0x401de4 <strings_not_equal+236>
   0x00401dc0 <+200>:	nop
   0x00401dc4 <+204>:	nop
   0x00401dc8 <+208>:	lw	v0,28(s8)
   0x00401dcc <+212>:	nop
   0x00401dd0 <+216>:	lb	v0,0(v0)
   0x00401dd4 <+220>:	nop
   0x00401dd8 <+224>:	bnez	v0,0x401d68 <strings_not_equal+112>
   0x00401ddc <+228>:	nop
   0x00401de0 <+232>:	move	v0,zero
   0x00401de4 <+236>:	move	sp,s8
   0x00401de8 <+240>:	lw	ra,44(sp)
   0x00401dec <+244>:	lw	s8,40(sp)
   0x00401df0 <+248>:	addiu	sp,sp,48
   0x00401df4 <+252>:	jr	ra
   0x00401df8 <+256>:	nop
End of assembler dump.

我们看这一行

   0x00401d5c <+100>:	li	v0,1
   0x00401d60 <+104>:	b	0x401de4 <strings_not_equal+236>

我们结合函数调用的上下文可以得出,如果这一行被执行了,那么一定会爆炸
如果很幸运,我们没有爆炸
那么我们继续往下看
在这里插入图片描述
毫无疑问,从内存中读取出来了一组数据,我们非常有理由怀疑
读取出来的是我们在phase_5中经过处理后的数据或者是本来我们输入的数据

我们往前找一下,因为s8很少改变
所以我们在phase_5中找一找
我们发现
在这里插入图片描述
所以更坚定了我们认为这里读取到的是经过处理后的数据

我们再往下看

   0x00401d84 <+140>:	xor	v0,v1,v0//按位或
   0x00401db0 <+184>:	beqz	v0,0x401dc8 <strings_not_equal+208>

这两行其实是这个函数的精髓所在(虽然其实也没有多难)
如果$v0 xor $v1==0,那么$v0==$v1

然后
在这里插入图片描述
最后
在这里插入图片描述
判断是否为0,如果是,则跳转,否则$v0=1,爆炸
所以到这里,我们猜测,是要进行处理后的字符串和给定的字符串进行比较,如果处理后的字符串和给定的字符串相同,那么不爆炸,否则爆炸

那么接下来的问题就变成了

  1. 它给定的字符串是什么?
  2. 找到那个转换函数,使得经过映射后的字符串等于给定的字符串

好,知道这些后,我们先来看一下上文中提到的,那个位置存储的是不是我们经过处理后的字符串
我们重新开
在这里插入图片描述
果然

我们再从
在这里插入图片描述
写到这里我突然产生了疑问,如果按位或的话,那岂不是最小值取决于给定的字符串?
于是百度了一下xor
发现是异或

但是我们的思路方向还是正确的,必须相等,否则爆炸

这里,查看一下给定的字符串
在这里插入图片描述
当然,我相信你从我的繁杂的输入中也能看到我错在了哪里
如果没有,请仔细阅读前文
输出这个字符串
可以看出
字符串为giants(当然,如果只知道asc其实不影响我们拆炸弹)
在这里插入图片描述
那么接下来我们就需要找到那个函数

经过分析,函数主要就是这一段

在这里插入图片描述

注释写的比较详细
分析可得,我们只需要找到是giants在内存中的地址即可

好的,问题来了
我们需要查看多少内存空间?
ans:16
因为是输入的字符和0xf相与,所以结果一定是0-e,共16
在这里插入图片描述

在这里插入图片描述
所以我们接下来只需要寻找giants在内存中的地址即可
在这里插入图片描述
我们从这几段代码中可以发现,我们先从一个偏移的位置找到了函数映射后的结果,然后将这个映射后的结果保存到了一个位置,也正是strings_not_equal调用出来的位置

所以这样问题就化简成了,在那段地址中,寻找giants
在这里插入图片描述
可以发现,这段内存中的值包含giants
最终查找发现,偏移量是
15 0 5 12 14 1
那么我们需要输入什么呢?
很显然
在这里插入图片描述

a    1
b    2
c    3
d    4
e    5
f    6
g    7
h    8
i    9
j    10
k    11
l    12
m    13
n    14
o    15
p    0
q    1
r    2
s    3
t    4
u    5
v    6
w    7
x    8
y    9
z    10



最终结果opekma
在这里插入图片描述

6. 第六关

我们猜测$s8+36+4*$v0保存的是我们输入的6个数字,输出一看,果然是在这里插入图片描述

写到这里csdn的 编辑器已经无比的卡,简单说一下思路吧

首先它判定了一下你输入的6个数字是否处于(0,7)之间,并且必须是全排列

然后它看了一下你的学号的最后一位,是奇数还是偶数,

最后你发现它用了一个链表存储,需要在循环中找到单调不减或者单调不增加的一个序列

我的学号最后一位为奇数,所以是单调不减少的

最后结果就是426315

7. 隐藏关卡

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值