(超详细版)山东大学计算机系统原理 实验三 bomb(拆炸弹)

这个实验算是我最喜欢的实验了,感觉跟闯关一样很有意思,第六个炸弹我还是在出去玩的高铁上拆完的,所以想记录一下自己完成这个的思路和过程,也算是给后面的学弟学妹们一个参考,大家还是要自己完成,这个真的很有意思

一些常见指令:

BNE rs, rt, lable 不等则跳转 if (rs = rt) goto lable

BGTZ rs, lable 大于 0 跳转 if (rs > 0) goto lable

LB R1, 0(R2)R1 中的一个字节存入 r2 中偏移 0 的地方

SLTI rt, rs, immediate 小于设置 if GPR[rs] < immed then GPR[rd]=1 else GPR[rd]=0

SLT R1,R2,R3 如果R2 的值小于 R3,那么设置 R1 的值为 1,否则设置 R1 的值为 0

 

SB R1, 0(R2)R1 中的一个字节存入 r2 中偏移 0 的地方

炸弹一:

首先观察代码,中说明应该是要输入的字符串和内置的字符串相等,因此我们打断点调试,先输入测试字符串“test”,

输出 a0 中的内容:

然后我们惊奇地发现a0寄存器里面放的居然就是我们输入的"test"

代码中在 a1 中存入一个非常奇怪的地址,那么我们可以“合理猜测”(助教的原话)这里面存储的就是内置用来比对的字 符串,输出 a1 中存储的内容试试:

里面的确存了一段字符串,那么继续合理猜测,这个应该就是我们要输入的正确答案了,退出调试, 输入“Let’s begin now!”,顺利拆除第一个炸弹

炸弹二:

那么我们正式的拆炸弹之旅开始喽

温馨提示:查看代码过程中发现要不停按回车键,输入“set pagination off”可以设置一次性显示全部代码,懒得按回车了

 

首先通过观察代码:

通过这条指令得知需要输入 6 个数字,先随意输入 6 个数字,打印出v0 和 01 中的内容

发现 v0 中的内容为 1,由此可以判断第一个数字应该就是 1,继续调试

设置循环变量 i,并让 i=1,进入循环,那么这里如何判断是一个循环呢,我们看到<+236>处:

这里执行完上面的各种操作后(什么操作也不知道),v0(i)++,从$s8+24 处取出 i,并更新回去,然后在<+244>行中判断 i 是不是小于 6,如果小于 6 就继续执行循环,现在回到循环中间的内容查 看循环里面到底干了什么,我们来看看:

这里是为了取出输入的数字中的第i个

看到-32660(gp)就知道用到了学号,-32660(gp)+12 正好是学号的最后一位,而 v0=v1+v0 说明从学号倒数第一位逐次往前取,用学号的倒数第 i 位乘输入的第i 个数放在 a0 里面

这里 v0 是取了输入的第 i+1 个数,得知第三个炸弹的输入条件: 第一个数一定为 1,之后的第i+1 个数等于学号倒数第i 位乘输入第i 位 下面的方法二是用逐次调试输出 a0 得到每次应该输入的值

此处发现 beq 语句中是把 a0 与 v0 作比较,如果两个值相等那么炸弹就不会炸,因为在前面发现 v0 中存储的是输入的 6 个数字,因此 a0 在此处就应该为该位的正确答案,打印 a0和 v0 中存储 的值

输入的六个数:

测试第一次:

可知 v0 中的确存的就是我们输入的 6 个数,而 a0 中为正确答案,因此退出调试,逐次输入得到正确答案(这个方法比较作弊,有的同学是通过逻辑判断出来的)

第二次:

第三次:

第四次,第五次都是0

由此可知第二关的答案为:1 4 24 48 0 0

第二个炸弹被拆除!:

炸弹三:

首先查看 disas phase_3 中的代码,没看懂到底要干啥,因此打开了 bomb.s 中,发现如下:

可知输入的规则应该为 3 位,类型为“数字+字符+数字”,随意输一组:

进行调试,首先来到第一个炸弹处:

Slti 指令中将 v0 和 3 作比较,不等于 3 就炸,由 phase_2 的第一个炸弹猜测这里应该是检验输入的合理性,经过验证也的确如此,继续向下:

该处比较了v0 和 8 的值,该处打印 v0 中的值:

发现 v0 中存的是输入的第一个值,经过后边输入不同的值验证,确认了 v0 的确存储的是输入的第一个数字,sltiu 中比较的 v0 和 8,由此可知第一个输入的第一个数字必须小于 8,并且第一个数输入不一样就会对应不同的判断语句

 

继续向下,再输入一组第一个数字小于 8 的组合,查看该处代码

输入为 4 q 111

当执行到jr 时,继续向下执行,发现跳转到了该处:

查看此处代码,发现存在一个炸弹点,且要让 v0 和 v1 相等,首先 v0 是个很奇怪的数字, 此处一开始并没有思路,那么继续向下调试试试,可以看到这里也和学号有关,v1 中存放 了学号中的最后一个数,v0 中存放了输入的第一个数,让 v0 和 v1 相乘,然后和 228 对比,就是说第三个数字是输入的第一个数字和学号最后一位相乘,因此在此处第三个输入的数   应该为 57

继续调试进到如下代码:

炸弹爆炸条件为v0 和v1 不相等,所以我们分别输出 v0 和v1 中的内容输出 v0 中的内容:

发现 V0 中存的是我们输入的第二个字符,输出 v1 中的内容,发现 v1 中存的是另一个字符 o 推出调试,输入 4 o 57 ,顺利通过第三关!!:

 

炸弹四:

学聪明了,首先,打开bomb.s:

发现第四颗炸弹需要输入一个数字

 

进入程序,看第一个条件语句和炸弹点:

这里将 v0 和v1 作对比,如果不相等,就会爆炸

这里输出 v1,发现v1 中就是 1,一开始我以为是判断输入的是不是 1 个数字,但是我后面输入了两个数字v1 也是 1,所以估计这里是用来判断是不是进行了输入操作

继续向下,来到 bgtz 中 ,v0 中存的就是输入的数字,这里判断条件为如果输入的数字大于 0 就跳转,否则爆炸,因此输入的数字必须大于 0:

跳转到<phase_4+132>:

在这一步中将学号的最后一位存入了 v0 中:

继续向下

在这一步中判断输入数字的奇偶性, 我学号的最后一位是偶数, 所以置零, 跳转到

<phase_4+224>:

这段代码中将输入的值存在 v1 中,将 v0 的值存入 13,比较 v1 和 13 是不是相等,这里将 v0 的 值存入了 a0 中,即把输入的数作为了函数的传入参数,这里问题在于不知道 fun4 的作用到底是什么,因此来看一下 func4 函数的作用

Func(4):

V0 中放着每次函数每次递归结束后返回的结果

每次结束后把结果放在 a2 中再次进入函数,观察此段代码可知这是一个斐波那契数列的递归函数,那 么就可以知道最后一个炸弹判断的条件如果学号最后一位是偶数,那么斐波那契的第几个数字是 13, 如果是奇数,那么第几个数字是 8,由此可知答案为 6,退出调试输入答案,成功拆除炸弹四!!!

 

炸弹五:

这一段输出a0,发现 a0 中存储中的就是我们输入的字符串:

进入到 beq 指令,发现这里是和 6 对比,也就是说输入的字符串长度必须为 6,否则炸弹就会爆炸

+84 是依次取输入字符串中第 i 位之后开始的所有字母,<+88> lb v1 是用来存储被剪切后的第 1 位 的字母,即这两行代码是用来取输入的第 i 个字母

上述两步用来取出 v1 中存储的字母的 ascll 码二进制值的低四位,v0 是用来记录执行次数的,必 须执行 6 次才能退出函数,继续向下:

此处将后四位存储在了s8+36+i*4 的地方

取出刚存进去ascll 码二进制的后四位

该代码中 v0 的地址有点奇怪,于是输出 v0 存储的地址中的东西,发现是内部存储的字符串,(盲猜输入的字符串和这个字符串有一个映射关系):

因此推测正确答案需要根据之前取的 ascll 码的二进制后四位数字在内部存储的字符串中找到正确 字符输入,继续向下,+156 中是在内部字符串中取出根据后四位所有字符并把第一个字母存在v1 中:

如上,v1 是 3,因此从第四位开始截取字符串,并取出了 v(v 的 ascll 码为 118)离开循环后来到如下 代码

输出 a1 中的内容:

也是一个内置字符串,而且也是 6 位,和我们输入后经过处理的字符串位数相同,因此接下来的操 作肯定和这两个字符串有关(猜的)

在 v0 中存储了经过处理转化后的字符串:

看了好久,终于看懂了,熬了一个大夜啊家人们

逻辑是这样的:

逆向推断,要在内置字符串中找到giants,对应数字为 15,0,5,11,13,1 对应二进制为:1101,0000,0101,1011,1101,0001,找到对应的字母可以为: o(0110 1111),p(0111 0000),e(0110 0101),k(0110 1011),m(0110 1101),a(0110 0001)

所以这一题答案不唯一,对应上就行了

退出调试,输入:opekma

顺利拆除炸弹五!!!

 

炸弹六:

这个我是在旅游的高铁上做的,一次全新的体验...

首先看到第一个跳转,从这里可以知道是要读取 6 个数字,因此输入的规则为输入 6 个数, 输入 1 2 3 4 5 6 作为测试, 猜测 v0 中应该是存储输入的数字,输出 v0 中的内容:

发现输入的数字是以链表的结构储存的,每个结点存了一个数字和指向下一个结点的地址,继续向下,跳转到<phase_6+316>:

这里 v0 是循环次数,没有循环 6 次就跳转到<phase_6+80>:

这里 v0 指向了第 i 个结点,beqz 节点中,如果 v0 是 0 就会爆炸,v0 和 7 进行比较,如果 v0 大 于 7,那么就会被置零,则 v0 必须小于 7,所以输入的数字必须小于 7,否则就会爆炸

继续向下:

还是取出第i 位,如果小于 0 就会爆炸,所以输入的数字的范围必须是(0,7)继续向下:

这里是判断循环是否结束,这里继续向下:

这里 v0 是第 2 层循环的第 j 个数,v1 是第一层循环的第 i 个数,比较两个数如果相等就会爆炸, 所以由该代码得知输入的 6 个数字不能相同,

由上可知,<phase_6+80>—<phase_6+328> 是第一个二重循环,用来判断输入是否合法,

1. 输入的值必须小于 7

2. 输入的值必须大于 0

3. 输入的值两两不相等

 

继续向下调试,当输入符合规则时,从phase_6+300 开始往下:

这段汇编代码中把地址 0x41 存在 v0 中,然后置了一个偏移量,把 node1 存入的新开的空间中, 然后把 v0 中存的东西放在栈中,把 1 赋给 v0 在把 v0 存在栈中,s8+24 中存的是 j的值

继续向下:

这里取出了结点中的第 j 个结点放在 v1 中,然后把该结点和 j 作比较,如果 v0 小于 v1,就会 跳转到+376 中开始下一次循环:

这段代码的作用是比较每个结点中是数据和 j 的大小关系,目的是让 j 等于输入的第 i 个数,即这个循环的作用是把输入的六个数存入存入新开辟的空间中,相当于把六个节点中的值 存入新的数组中 ($s8+36):

继续往下:

熟悉的取学号最后一位的操作,然后判断奇偶性,我的学号最后一位是偶数,所以跳转到+792:

从数组地址中取出第 i 个存入 v1 中,第 i+1 个放入 v0 中,slt 和 beqz 语句说明该数组必须按照 升序排序,因此根据前面节点中存的值可以得出答案应该为:513624

炸弹六总结:

至此,显式炸弹被全部拆除喽!!

还有一个隐藏炸弹的拆除过程就不放在这里了,大家自己去玩一玩,隐藏炸弹是一个树,加油!

  • 38
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值