计算机系统原理 课程实验报告
实验学时:16 实验日期:2019.04.04
① 熟悉ARM汇编指令集,能够阅读与调试汇编代码。
② 学会并理解可执行文件的反编译过程。
③ 进一步认识汇编语言在硬件层面的执行。
④ 对代码的编译执行层面有更深刻的认识。
:实验室PC、笔记本电脑
:Linux下的qemu模拟器+树莓派系统,
在Linux操作系统下安装Qemu并在模拟器上搭建ARM模拟环境。
我们通过使用objdump –d命令反编译得到.s文件并通过gdb调试一步步探索题目的解决方案。通过阅读反编译得到的.s文件。bomb汇编程序由以下几部分构成,分别是:,
该实验总计7个关卡,在我们各自具备独立完成前四个实验之后。5,6,7关卡内容通过合力合作分析完成关卡内容理解,最后分工阐释7个关卡的破解机理。分工如下:
我们在Phase_1处设置断点以观察每条指令执行的过程
首先我们观察两处炸弹爆炸的地方,
在第一处cmp命令处,我们比较了r3寄存器中的值与1的大小,同时在前两处的str与ldr命令中,我们将r0处的值给了r3。
往前查看
在bl命令执行之前 我们打出r0,r1,r2,r3的值
而在bl执行完成后
r0的值为1
根据sscanf函数,我们猜测r0,r1中为sscanf的两个参数,最后r0为该函数的返回值。
此处暂且不表,我们继续检查第二个炸弹爆炸处。
此处将(r11-12)处的值给了r3,并将此值进行比较,
我们将r3的值打印出来,即可发现r3为我们输入的int整数。(输入14
所以此处应为比较输入的值和188是否相等。
输入188
炸弹拆除成功,我们验证之前关于sscanf处的猜测,我们此次输入“188 14”两个数,在执行到bl处,依然可以发现,并且炸弹拆除成功
而输入空字符串则r0返回错误值
所以在Phase_1中sscanf函数大概为 。在读入后返回
至此我们拆除了第一个炸弹。
其大概为判断读入的int值是否为188.
依然将断点设置在phase_2
查看第一个炸弹爆炸的地方
按照之前的经验我们在bl处执行之前,我们打出各个寄存器的值
我们猜测需要读入两个数,继续执行。在sscanf执行结束后,我们继续检查r0的值
所以此处应为
继续查看第二个爆破处
其为将r2 r3的值相加并与10进行比较
我们将r2 与r3 打出来
r2和r3 分别为我们输入的两个数。
所以此炸弹应为读入两个数,进行相加,判断和是否为10
首先,先看到前三行 ,根据之前拆解炸弹的知识再加上push指令,可知前几行是将相关的数据加载进堆栈中,fp应该是堆栈的首地址,通过相应偏移量转到相应的堆栈地址
整个程序开始从107a4开始看起
12.107dc-107de:将r3里的内容和r2比较,如果相等,则跳到正常程序,如果不相等就爆炸
此时弄清题目要求我们输入两个数,其中第二个数必须是第一个数算术右移一位之后得到的值。
如果第一个数输入6 那么第二个数就该输入3
在这里,它将pc+48的值加载到r3上,又随即存储到r11-8上。我们来打印一下r3中存放了什么:
由于我们输入的是abc,其实可以推断出hello world已经是正确答案了,为了验证我们的猜想是否是正确的,我们接着往下分析。
打印r0中的存储值,结果是我们输入的abc。
一步步stepi,我们可以看到之前的hello world字符串又加载到r1上,然后我们就进入了
可以看到,最终是abc加载到r2当中,而hello world加载到r3中,然后两者进行了比较,我们的推断是正确的。
3.输入hello world,拆除成功
我先输入7个数,然后打印执行完read six numbers函数获得的r3值,发现里面应该保存的是一个地址,接着往下执行
10.10874:将fp-8地址里的数加载进r3
11.10878:将r3的值存入地址fp-8里。
12.1087c:这一步,r3 = r3+20,可能是地址,也可能是数据,但地址可能性更大,如果为地址的话,就相等于往后偏移,如果把int类型视为四个字节的话,可以偏移五个int类型数据
13.10880:此时将修改后的r3的值存入fp-12的地址中。之后跳转到108c0处。
14.108c0:将fp-8的值加载进r2,为一开始从read函数出来的r3的值。
15.108c4:将偏移后的r3的值加载进r3.
16.108c8:让两者相减,用r2-r3 bcc代表的是无进位跳转。跳转到10888
17.10888:将地址fp-8里的值加载进r3寄存器
18.1088c: 将r3地址里的加载到寄存器r3里,可见原来的r3里保存的是一个地址。证明啦之前的猜测。
19.10890; 将现在r3里保存的数逻辑左移两位,相当于乘以4.,再将该数存入r3里。
20.10894:将r3的值存入fp-16里,此时fp-6里保存的是数据,
21.10898:将fp-8地址里保存的之前r3的地址取出,再加载进r3里,于是此时的r3又变回啦地址。
22.1089c:r3作为地址自己相加4,相当于偏移啦一个int类型单位,
23.108a0:将r3偏移一个int类型的新地址加载进r2寄存器里,
24.108a4:将fp-16里保存的之前r3地址里存数的四倍加载到r3寄存器里,
25.108a8:将两者进行比较,只有相等才不爆炸,并跳转到1084b
26.108b4-108bc: 将fp-8地址里保存的最开始的r3地址偏移一个字节后还保存在fp-8里,可以理解为将fp-8里的地址进行啦一个int的偏移,此时猜想可能最初的从read函数里出来保存的是6个数字的首地址,每一次偏移一个数,同时将将其当前偏移后的地址加载进r2寄存器中。
11. 108c4:从fp-12里提取出放到寄存器r3里,fp-12里保存的是数字首地址在加上五个偏移量,那么应该代表的是数组的边界,之后的比较可以理解为循环条件,这样即使没有看readsixnumber里面的内容,这道题的大概含义就出来啦,
程序执行;
输入6个数字;
{
初始化;//分配位置
Readsixnumber();
获得输入数字的首地址;
将首地址偏移五个字节代表输入数字的边界;
While(当前地址没有超过数字边界)
{
If(当前地址里保存的数的四倍= 输入数字串的下一个数);
炸弹不会爆炸;
Else
触发炸弹;
当前地址++(往后偏移一个数字)
}
}//要求输入的数必须是等比数列;公比为4;
将断点设置在phase_7处并查看指令
依次查看每个炸弹爆破的地方。
在执行bl之前我们打出各寄存器的值,我们发现r0中存放输入的字符串。
此处先执行了strlen函数,所以猜测为我们输入字符串的长度,在执行的地方我们输入了apps.我们将r3打印出来。
r3的值为5,此后炸弹爆炸,’\n’也被算在字符串内
所以我们重新输入app
通过第一个爆破点。
第二个地方
此处进行了一个字符串比较。所以我们看中间的操作代码。
可以观察到此处有一个大循环,先将r3赋值为0,小于等于2则执行,每次加一,总共执行3次。
细看执行过程中的代码:
先将(r11-24)的值给了r2,然后将r3的值修改为(r2+r3)
第一次执行时r3=0 所以此时(r2)=(r3)
获取r3的前8位二进制数,
即为r3的第一个char字符的ASCII码。
然后将该值与15进行按位与运算。r3为1
而后将r2的值改为地址pc+116处的值
我们将r2存放的地址位置的字符串打印出来
再后一步中
r3的值改为了(r2+r3<<1)由于char数组占4个字节,所以左移了两位
并将前八位赋值给r1
即为第一个地址处的ASCII码
后续操作中
r3的值还原为进入循环的值,r2返还为输入字符串的地址,将r3进行偏移
我们将r3给了r2,所以以r2为首指针的字符串的首字符被更改为新的值
所以
该值即为(pc+116)处的首指针偏移了输入字符串对应的ASCII码与15异或后的值。
继续执行两次后,将所有的字符位都进行运算。
执行此处之前,我们将寄存器的值打印出来
所以最后需要我们做的是输入长度为4的字符串经过变换后为sdu
设数组为a,则a[5]=u,a[15]=’d’,a[9]=s.
所以只需输入的字符串的值的ASCII码与15按位与得到9,5,15即可。
编写C语言程序,获去对应的字符编码
得到结果
所以输入的字符串各位对应的ASCII码为以上即可。(33以下的ASCII码字符无法被打印,忽略)
验证
至此炸弹拆除完成。
通过这次实验,我们熟悉并掌握了部分arm汇编指令集,能够阅读与调试不复杂的汇编代码,学会了反编译可执行文件,更加深入的理解了高级语言的编译与汇编语言在硬件上执行的过程。同时各个关卡的考察点让我们在地址与寄存器的微观层面分析加减逻辑移位操作,递归算法,字符串处理与运算操作,地址查找与映射。使我们更加深刻的认识到目前学到过的数据结构与算法在硬件上的存储与运作方式。为之后的代码效率优化,系统性编程打下了坚实的基础。
其中在实验过程中,通过小组合作,通过每个成员各自对题意的理解和猜测的分享,很容易找到自己没有考虑到的点和不同的解析思路,就比如在第六题中对递归过程中的寄存器内容的理解,在第七题中不同解题思路的交融使各自对题目的理解过程得以加强。同时在实验中,对代码的debug和分析能力得到锻炼。
姓名:张馨艺 班级:AI17
姓名:姚云志 班级:大数据17
姓名:唐佳文 班级:AI17