整理文档发现了之前的实验报告,鉴于从17级开始才开始使用MIPS实验环境吗,取实验报告精华,整理主要思路如下。该博客叙述风格参考了窦优秀学长的博客。
该博客旨在帮助入门分析,不对整个过程详细介绍。前三个炸弹较为详细。
2018级山东大学计算机LL
1. b * 0x233666
2. info b
3. delete 1
1. x $ra # 与p *$ra 类似
2. p $ra #打印参数
1. BEQZ RS, OFF18 IF RS = 0, PC = OFF18
2. (如果寄存器中值为0,PC指针赋值为立即数)
3. BEQ RS, RT, OFF18 IF RS = RT, PC = OFF18±
4. SLTI RD, RS, CONST16 RD = (RS± < CONST16±) ? 1 : 0
虽然
结束
因此,该炸弹即读入字符串和一预设字符串相同即可拆除。通过GDB工具在400d8c地址处查看$a1寄存器指向地址中的值 x /s $a1,可知该字符串为Let’s begin now!。读入时输入该字符串,即可正常拆除炸弹。
进入第二个炸弹时调用了
循环结束后执行下述指令:
1. 400d8c: 0c10073e jal 401cf8 <strings_not_equal>
2. 400d90: 00000000 nop
3. 400d94: 10400003 beqz v0,400da4 <phase_1+0x38>
4. 400d98: 00000000 nop
5. 400d9c: 0c10087c jal 4021f0 <explode_bomb>
分析可知循环会进行5次。
在每层循环中均有一个
进入函数后,会先执行如下汇编语句:
1. 400f2c: 8fdc0018 lw gp,24(s8) # gp = M[s8+24]
2. 400f30: 28420003 slti v0,v0,3 # v0 = (v0<3)?1:0
3. 400f34: 10400004 beqz v0,400f48 <phase_3+0x74>
其为判断函数读入的参数是否大于三个(实际只需要前三个)
$v0的值为44(s8),猜测其为读入的一个参数,且不能比8小。之后会根据这个值跳转到一个地址:
1. 400f5c: 00021880 sll v1,v0,0x2
2. 400f60: 3c020040 lui v0,0x40
3. 400f64: 2442278c addiu v0,v0,10124
4. 400f68: 00621021 addu v0,v1,v0
5. 400f6c: 8c420000 lw v0,0(v0)
6. 400f70: 00000000 nop
7. 400f74: 00400008 jr v0
分析第一个数和第三个数应为数字,第二个数为字符。(233,将‘2’赋值给第二个参数,33赋给第3个参数)。的第三个参数判断与为学号最后一位相乘判断是不是与当前选参数相同。 777
如学号最后一位为7,应该为0 q 111
与炸弹3类似,开始时程序会先判断读入的是否为一个数字。
1. 401310: 00401821 move v1,v0
2. 401314: 24020001 li v0,1
3. 401318: 14620005 bne v1,v0,401330 <phase_4+0x74>
这里如果输入的第一个数是数字则v1为1,若为字符则v1为0。之后程序会判但学号最后一位是奇数还是偶数。
这里某Y大佬直接看出来是斐波那契,问他为什么,因为递归 -1 -2 ,直接秒出,绝了。
1. 40125c: 8fc20028 lw v0,40(s8)
2. 401260: 00000000 nop
3. 401264: 2442ffff addiu v0,v0,-1
4. 401268: 00402021 move a0,v0
5. 40126c: 0c10048c jal 401230 <func4>
6. 401270: 00000000 nop
7. 401274: 00408021 move s0,v0
8. 401278: 8fc20028 lw v0,40(s8)
9. 40127c: 00000000 nop
10. 401280: 2442fffe addiu v0,v0,-2
11. 401284: 00402021 move a0,v0
12. 401288: 0c10048c jal 401230 <func4>
13. 40128c: 00000000 nop
14. 401290: 02021021 addu v0,s0,v0
会递归的调用fun4($v0 – 1)和 fun4($v0-2)。并将这两个的返回结果相加存储在$v0中。其显然为斐波那契的调用方式。读入数位i是对应的数字是f[i+1](func4索引从零开始,斐波那契索引从1开始)。
奇数情况下会判断函数返回结果是否为8,偶数判断是否为13。则学号末尾为奇数应该输入5,为偶数应该输入6。
目标值位giants,根据对应关系可构造字符串位opekma。
通过查看反汇编代码可以发现含有一个
1. 402288: 24020006 li v0,6
2. 40228c: 14620039 bne v1,v0,402374 <phase_defused+0x110>
查看代码可知,
可以看到,目标字符串为austinpowers,即第四个炸弹出输入 5 austinpowers 即可进入隐藏炸弹。
也是放张图吧:
答案:
# 第一组
20180000777
Let's begin now!
1 7 49 343 0 0
0 q 111
5 austinpowers
opekma
4 2 6 3 1 5
1001
# 第二组
123456111132
Let’s begin now!
1 2 6 6 6 6
4 o 114
5 austinpowers
opekma
5 1 3 6 2 4
($v0-$v1)用于子程序的非浮点结果或返回值。
($a0-$a3)用来传递前四个参数给子程序,不够的用堆栈。$a0-$a3和$v0-$v1以及$ra一起来支持子程序/过程调用,分别用以传递参数,返回结果和存放返回地址。当需要使用更多的寄存器时,就需要堆栈(stack)。
($gp)为了简化静态数据的访问,MIPS软件保留了一个寄存器:全局指针gp,全局指针只想静态数据区中的运行时决定的地址。
($sp)指向当前正在操作的堆栈顶部。
($ra)在函数调用过程中,保持子函数返回后的指令地址。
($s8)也称为($fp)。不同编译器对其解释不同,在龙芯里更像传递给子函数的帧指针,这里不做讨论。
为了更好的的完成实验,我在自己电脑上搭建了MIPS指令集环境。可以采用两种策略,一种是qemu-user,一种是qemu-system。如果说qemu-system是模拟mips的操作系统,qemu-user更像是模拟mips的指令集。为了更快的响应时间,我选择了qemu-user。
并且采用了Ubuntu18.04操作系统。GDB采用了gdb-multiarch。