ARM指令经典拆炸弹

计算机系统原理 课程实验报告

实验题目:ARM汇编指令

实验学时:16 实验日期:2019.04.04

实验目的:

① 熟悉ARM汇编指令集,能够阅读与调试汇编代码。
② 学会并理解可执行文件的反编译过程。
③ 进一步认识汇编语言在硬件层面的执行。
④ 对代码的编译执行层面有更深刻的认识。

硬件环境

:实验室PC、笔记本电脑

软件环境

:Linux下的qemu模拟器+树莓派系统,

实验步骤与内容:

1, ## 环境安装与配置

在Linux操作系统下安装Qemu并在模拟器上搭建ARM模拟环境。

2, 反编译可执行文件与gdb调试

我们通过使用objdump –d命令反编译得到.s文件并通过gdb调试一步步探索题目的解决方案。通过阅读反编译得到的.s文件。bomb汇编程序由以下几部分构成,分别是:,,,,…,,,, 等。这对下面调试破解的进行提供了依据。

3,关卡破解

该实验总计7个关卡,在我们各自具备独立完成前四个实验之后。5,6,7关卡内容通过合力合作分析完成关卡内容理解,最后分工阐释7个关卡的破解机理。分工如下:

分析

下面便按关卡顺序进行阐释

Phase_1

我们在Phase_1处设置断点以观察每条指令执行的过程
在这里插入图片描述
首先我们观察两处炸弹爆炸的地方,
ARM指令经典拆炸弹_第1张图片
在第一处cmp命令处,我们比较了r3寄存器中的值与1的大小,同时在前两处的str与ldr命令中,我们将r0处的值给了r3。
往前查看
在这里插入图片描述
在bl命令执行之前 我们打出r0,r1,r2,r3的值
ARM指令经典拆炸弹_第2张图片
而在bl执行完成后
ARM指令经典拆炸弹_第3张图片
r0的值为1
根据sscanf函数,我们猜测r0,r1中为sscanf的两个参数,最后r0为该函数的返回值。
此处暂且不表,我们继续检查第二个炸弹爆炸处。
在这里插入图片描述
此处将(r11-12)处的值给了r3,并将此值进行比较,
我们将r3的值打印出来,即可发现r3为我们输入的int整数。(输入14
ARM指令经典拆炸弹_第4张图片
所以此处应为比较输入的值和188是否相等。
输入188
在这里插入图片描述
炸弹拆除成功,我们验证之前关于sscanf处的猜测,我们此次输入“188 14”两个数,在执行到bl处,依然可以发现,并且炸弹拆除成功
ARM指令经典拆炸弹_第5张图片在这里插入图片描述
而输入空字符串则r0返回错误值
ARM指令经典拆炸弹_第6张图片ARM指令经典拆炸弹_第7张图片

所以在Phase_1中sscanf函数大概为 。在读入后返回
至此我们拆除了第一个炸弹。
其大概为判断读入的int值是否为188.

Phase_2

依然将断点设置在phase_2
在这里插入图片描述
查看第一个炸弹爆炸的地方
ARM指令经典拆炸弹_第8张图片
按照之前的经验我们在bl处执行之前,我们打出各个寄存器的值
ARM指令经典拆炸弹_第9张图片
我们猜测需要读入两个数,继续执行。在sscanf执行结束后,我们继续检查r0的值
在这里插入图片描述
所以此处应为
继续查看第二个爆破处
ARM指令经典拆炸弹_第10张图片
其为将r2 r3的值相加并与10进行比较
我们将r2 与r3 打出来
ARM指令经典拆炸弹_第11张图片
r2和r3 分别为我们输入的两个数。
所以此炸弹应为读入两个数,进行相加,判断和是否为10

phase_3

ARM指令经典拆炸弹_第12张图片
首先,先看到前三行 ,根据之前拆解炸弹的知识再加上push指令,可知前几行是将相关的数据加载进堆栈中,fp应该是堆栈的首地址,通过相应偏移量转到相应的堆栈地址
整个程序开始从107a4开始看起

  1. 107a4:将r0的值放到fp-24里
  2. 107a8:r2=fp-12
  3. 107ac:r3 = fp-16
  4. 107b0: 将fp-24地址里保存的值给寄存器r0,此时r0=r2的值
  5. 107b4:将地址为pc-60的值取出加载进入r1寄存器,
  6. 107b8:进入sscanf函数里,经过猜想和之前的验证,证明出该函数的作用是 判断并返回输入参数的个数,并且推测将参数个数作为返回值结果给啦r0
    于是在执行完该函数设置断点,打印r0的值为2,
    ARM指令经典拆炸弹_第13张图片
    为啦验证我们的猜想正确,选择输入参数1,执行到该断点处,并显示r0的值
    ARM指令经典拆炸弹_第14张图片
    果然如同猜测一般,该函数返回我们输入的参数个数,并将其值加载到r0寄存器中
  7. 107bc:将r0的值保存进fp-8的地址
  8. 107c0:将fp-d8地址里的内容加载到r3里//此时r3的值就是r0的值,代表输入参数的个数
  9. 107c4:比较r3和立即数2,如果相等的话就跳转到107d0的位置。如果不相等,就会跳转到炸弹爆炸程序。所以经过分析可知,为啦使此处的炸弹不爆炸,我们应该限制输入参数个数为两个,可以将其看作该题的输入要求。
  10. 107d0:将fp-12 地址里的值加载进入r3寄存器。也就是r2的值,此处根据经验猜测r2
    的值是输入的某一个数,当我们输入6 2时,发现此时r3获得值就是6,也就是第一个参数值通过设置断点检测fp-12里保存的是我们输入的第一个参数的值,此时r3里的值也是输入的第一个参数的值。
    ARM指令经典拆炸弹_第15张图片
  11. 107d4:将r3的值(第一个输入参数的值)算术右移一位并
    保存到r2中,
    asr是“算术”右移指令,因此用它来操作数据时,指令会认为被操作的数是有符号数,而二进制中有符号数的最高位即为符号位。因此为了保留数据符号,用符号位来填充因移位而导致的空缺位。举例是这样的:
    MOV R0 , #0x90 ;(10010000)
    asrR0 , R1 , #3
    则R0 = 11110010 。
    比如我们输入的时6,00000110,算术右移一位得到00000011.将算术移位之后的值放入r2寄存器,让r3取获取fp-16
    地址里所保存的值,此时我们猜测可能是第二个参数
    于是将fp-16里的值打印,果然等于我们输入的第二个参数
    在这里插入图片描述

12.107dc-107de:将r3里的内容和r2比较,如果相等,则跳到正常程序,如果不相等就爆炸
此时弄清题目要求我们输入两个数,其中第二个数必须是第一个数算术右移一位之后得到的值。
如果第一个数输入6 那么第二个数就该输入3
ARM指令经典拆炸弹_第16张图片

phase_4:

  1. 一起看一下源代码:
    ARM指令经典拆炸弹_第17张图片
    看起来是一个需要我们输入字符串的函数,原因是来自10820那里的上,于是我们随便输入一个字符串看看
    2.输入字符串开始调试:

在这里插入图片描述ARM指令经典拆炸弹_第18张图片
在这里,它将pc+48的值加载到r3上,又随即存储到r11-8上。我们来打印一下r3中存放了什么:
在这里插入图片描述
由于我们输入的是abc,其实可以推断出hello world已经是正确答案了,为了验证我们的猜想是否是正确的,我们接着往下分析。
ARM指令经典拆炸弹_第19张图片
打印r0中的存储值,结果是我们输入的abc。
一步步stepi,我们可以看到之前的hello world字符串又加载到r1上,然后我们就进入了
ARM指令经典拆炸弹_第20张图片
可以看到,最终是abc加载到r2当中,而hello world加载到r3中,然后两者进行了比较,我们的推断是正确的。
3.输入hello world,拆除成功

Phase_5

ARM指令经典拆炸弹_第21张图片

  1. 10850-10858可视为相关初始化操作可以忽略不看。
  2. 1058c:将寄存器r0的值保存到地址fp-48里。
  3. 10860:r3=fp-40
  4. 10864:将fp-48的值加载进入r0
  5. 10868:r1 = r3;//也就是将r3的值加载进r1;
  6. 1086c:t跳转执行read six numbers函数操作;执行完还会回来哦
  7. 假如先不看函数具体内部,光靠猜想先猜想要输入6个数字,执行完之后
  8. 10870:r3 = fp-40里获取的值加载进r3;先打印r3看看里面是啥

ARM指令经典拆炸弹_第22张图片

我先输入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_6:

  1. 先看一下源码:
    ARM指令经典拆炸弹_第23张图片
    重点是在func4上,我们看func4:
    ARM指令经典拆炸弹_第24张图片
    由10ba8那里,我们推断这是一个递归程序,但是到底递归的是什么,我们还需要仔细分析。
  2. 由10910那里可知,我们应该是有2个输入变量。
    初始值保存在了fp-8并加载到r3中,将r3与0比较,当r3不等于0,则跳转到10b9c,往下,r3减去了1,然后又进入到了递归。
    r3等于0的时候,让r3等于1,跳转到10bb8,我们知道程序开始返回。
    跳出递归,我们看出是将之前减一的数和保存好的数相乘存储到r3中,依次递归,于是得出结论这是个求阶乘的程序。
    返回到phase_6,在10928那里,我们之前知道阶乘的值最终保存在r0当中,在往后又加载到r2上,而r3加载了我们输入的数据,在这里比较他们是否相等。
    3.我们得出结论:输入的两个变量分别是数字和将其阶乘得到的结果,于是我们尝试输入3 6以及4 24和5 120,结果都是正确的。

Phase_7

将断点设置在phase_7处并查看指令
ARM指令经典拆炸弹_第25张图片
依次查看每个炸弹爆破的地方。
ARM指令经典拆炸弹_第26张图片
在执行bl之前我们打出各寄存器的值,我们发现r0中存放输入的字符串。
在这里插入图片描述
此处先执行了strlen函数,所以猜测为我们输入字符串的长度,在执行的地方我们输入了apps.我们将r3打印出来。
ARM指令经典拆炸弹_第27张图片
r3的值为5,此后炸弹爆炸,’\n’也被算在字符串内
ARM指令经典拆炸弹_第28张图片
所以我们重新输入app
在这里插入图片描述
通过第一个爆破点。
第二个地方
ARM指令经典拆炸弹_第29张图片
此处进行了一个字符串比较。所以我们看中间的操作代码。
ARM指令经典拆炸弹_第30张图片
可以观察到此处有一个大循环,先将r3赋值为0,小于等于2则执行,每次加一,总共执行3次。
细看执行过程中的代码:
ARM指令经典拆炸弹_第31张图片
先将(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异或后的值。
继续执行两次后,将所有的字符位都进行运算。
ARM指令经典拆炸弹_第32张图片
执行此处之前,我们将寄存器的值打印出来
ARM指令经典拆炸弹_第33张图片
所以最后需要我们做的是输入长度为4的字符串经过变换后为sdu
在这里插入图片描述
设数组为a,则a[5]=u,a[15]=’d’,a[9]=s.
所以只需输入的字符串的值的ASCII码与15按位与得到9,5,15即可。
编写C语言程序,获去对应的字符编码
在这里插入图片描述
得到结果
ARM指令经典拆炸弹_第34张图片
所以输入的字符串各位对应的ASCII码为以上即可。(33以下的ASCII码字符无法被打印,忽略)
验证
ARM指令经典拆炸弹_第35张图片
至此炸弹拆除完成。

结论分析与体会:

通过这次实验,我们熟悉并掌握了部分arm汇编指令集,能够阅读与调试不复杂的汇编代码,学会了反编译可执行文件,更加深入的理解了高级语言的编译与汇编语言在硬件上执行的过程。同时各个关卡的考察点让我们在地址与寄存器的微观层面分析加减逻辑移位操作,递归算法,字符串处理与运算操作,地址查找与映射。使我们更加深刻的认识到目前学到过的数据结构与算法在硬件上的存储与运作方式。为之后的代码效率优化,系统性编程打下了坚实的基础。
其中在实验过程中,通过小组合作,通过每个成员各自对题意的理解和猜测的分享,很容易找到自己没有考虑到的点和不同的解析思路,就比如在第六题中对递归过程中的寄存器内容的理解,在第七题中不同解题思路的交融使各自对题目的理解过程得以加强。同时在实验中,对代码的debug和分析能力得到锻炼。

成果来源于以下三人

姓名:张馨艺 班级:AI17
姓名:姚云志 班级:大数据17
姓名:唐佳文 班级:AI17

你可能感兴趣的:(深入理解计算机系统,深入理解计算机系统)