计算机系统基础(bomb实验报告)

山东大学 计算机系统基础实验报告

bomblab

一、实验目的

1) 理解arm汇编语言,学会使用调试器。
2) 熟悉安卓开发板的使用和环境配置;
3)熟悉并掌握在linux系统下的shell命令使用。

二、实验环境

linux系统,终端,arm-gdb工具,安卓开发板

三、小组成员及任务分配

四、实验原理

二进制炸弹是作为一个目标代码文件提供给我们的程序,程序运行中有6个关卡(6个phase),运行时,它提示用户输入6个不同的字符串。如果其中任何一个不正确,炸弹就会“爆炸”:打印出一条错误信息。我们首先要在linux下配置好arm-gdb环境并且得到反汇编问卷,然后通过反汇编和逆向工程来确定是哪六个字符串,从而解除他们各自炸弹的雷管。

五、知识储备

在实验过程中我们运用了课上对于ARM部分指令的知识,例如读写指令ldr和str,跳转指令b和bl的区别,以及比较指令cmp等,还有条件域的实践应用。并且为了完成实验我们自学了关于在Linux环境下运用gdb设置断点进行调试,并且了解了更多的ARM指令和与之相关的寄存器和堆栈的使用。在拆炸弹似过程中我也运用到了相关的数学知识,主要是递归的算法和循环算法。

六、实验内容与步骤

步骤一:环境配置

在进行环境配置时,我们按照指导书进行了Linux下的环境配置和gdb安装包的解压安装。在此阶段我们学习了在Linux终端用命令行进行新建,打开,检验文件夹,以及保存文档中的内容。主要运用了sudo来执行一些root命令,cd用来打开或退出文件夹,tar命令进行文件的备份。主要命令行如下:
tar -jxvf gdb-7.10.tar.bz2 解压gdb安装包
sudo gedit ~/.bashrc 修改环境变量
在进行PC与目标板的连接时,先分别获取IP地址,然后在目标板上运行PC中的bomb程序,在PC上运用arm-gdb进行程序的调试。主要运用了调试工具adb,ifconfig配置网络设备来设置IP,gdbserver来让PC可以对目标板进行远程调试。主要命令行如下:
adb push bomb /data/local 将bomb程序push到目标板上
ifconfig eth0 192.168.0.100 设置目标板IP
ifconfig eth1 192.168.0.101 设置PC的IP
gdbserver 192.168.0.101:2345 bombg (ip 为 pc 机机 ip)在目标板上可以运行bomb程序。
步骤二:六个phase的解决
首先是找到main函数,发现它调用了从phase1到phase6这六个函数。这应该就是每一关需要看懂的函数了。

实验三:

开头还是栈的开辟,往下看,首先特别明显注意到sscanf函数,推测应该是一个类似C中的一个函数,然后想要知道将要返回的参数,发现
“84ec: e59f1198 ldr r1, [pc, #408] ; 868c

8890:e50b0048 str  r0, [fp, #-72]  ; 0x48
 8894:e59f3260 ldr  r3, [pc, #608] ; 8afc 
 8898:e50b3010 str r3, [fp, #-16]
 889c:e24b3028 sub r3, fp, #40    ; 0x28
 88a0:e51b0048 ldr r0, [fp, #-72]  ; 0x48”

储存和取值的代码,推测应该是个链表结构,.word中存的应该是链表头。
仔细看了一遍代码后,大概找到了几个循环,推测应该是给链表从小到大的排序,用C语言表示大概是:

for(int i=0;i<=5;i++){
    if(a[i]>6)
       explode_bomb();
    for(int j=i+1;j<=5;j++){
        if(a[i]=a[j])
           explode_bomb();
}}//输入的小于66个整数两两不等
for(int i=0;i<=5;i++){
    l=list;
    for(int j=1;jnext;
    list_array[i]=l;
}//把链表里面数存入数组
l=list_array;
    for(int i=0;i<=4;i++){
         if(*l<*l->next)
        explode_bomb();
    l=l->next;
}//排序
 基本确定好是给链表从小到大排序后,只需找到链表中的数据就可以了。看到“88b8:   e51b200c    ldr   r2, [fp, #-12]”里面把地址减去12经常出现,猜测应该是链表每隔12位存一个数据,所以用打印16进制地址的方式“(gdb)p/x *(0x00091104-12)”依次打印出地址,然后找到数据就可以了。最后打印出链表中数据是:“253,725,301,997,212,432”,然后给他们排序就是“5 1 3 6 2 4”即应该输入的6个整数。

隐藏关卡: —共同完成

隐藏关的开启方式在phase_defused中,由9158: e3530002 cmp r3, #2可以看出需要输入两个字符才能进入隐藏关卡。

9168:   e59f103c    ldr r1, [pc, #60]   ; 
91ac <phase_defused+0x88>
916c:   ebffff04    bl  8d84 <strings_not_equal>

通过gdb查看91ac中的文档,文档中存储的是一个字符串austinpower,通过查看另一文档可知输入的路径密码格式是(d%,s%),因此在前面的六个关卡中,只有实验四是输入一个数字9,因此密码为9 austinpower,从而进入了隐藏关卡。
隐藏关的关键代码如下:

8bb0:   eb0000f5    bl  8f8c   读入一行
8bb4:   e1a03000    mov r3, r0
8bb8:   e50b300c    str r3, [fp, #-12]
8bbc:   e51b300c    ldr r3, [fp, #-12]
8bc0:   e1a00003    mov r0, r3
8bc4:   e3a01000    mov r1, #0
8bc8:   e3a0200a    mov r2, #10
8bcc:   eb000d0b    bl  c000   把数字转化为长整型
8bd0:   e1a03000    mov r3, r0
在读入数字之后,接着调用了另一个文档中的数字:
8bec:   e59f0028 ldr r0,[pc,#40];8c1c
8bf0:   e51b1008    ldr r1, [fp, #-8]
8bf4:   ebffffc1    bl  8b00 
可见从文档中读入的数字和输入的数字一起作为参数进入了函数fun7。接着向下看secret_phase中的代码。
8bfc:   e3530007    cmp r3, #7
因此输出的值应为7,接着就进行fun函数,主要部分如下:
8b18:   e3530000    cmp r3, #0  r3为0时,输出0
8b1c:   1a000001    bne 8b28 0x28>
8b20:   e3e03000    mvn r3, #0
8b24:   ea00001b    b   8b98 0x98>  跳出函数
对于一些寄存器的变换不再赘述。
8b34:   e1520003    cmp r2, r3
8b38:   da000007    ble 8b5c 0x5c>
8b3c:   e51b3008    ldr r3, [fp, #-8]  此时r2>r3
8b40:   e5933004    ldr r3, [r3, #4]  r3取其地址加4的地址所存数字
8b44:   e1a00003    mov r0, r3
8b48:   e51b100c    ldr r1, [fp, #-12]
8b4c:   ebffffeb    bl  8b00   fun7函数是一个循环嵌套
8b50:   e1a03000    mov r3, r0
8b54:   e1a03083    lsl r3, r3, #1  r3=r3*2
8b58:   ea00000e    b   8b98 0x98>
8b68:   e1520003    cmp r2, r3
8b6c:   aa000008    bge 8b94 0x94>
8b70:   e51b3008    ldr r3, [fp, #-8]  此时r2
8b74:   e5933008    ldr r3, [r3, #8]  r3为其地址加8所得地址中存的数字
8b78:   e1a00003    mov r0, r3
8b7c:   e51b100c    ldr r1, [fp, #-12]
8b80:   ebffffde    bl  8b00 
8b84:   e1a03000    mov r3, r0
8b88:   e1a03083    lsl r3, r3, #1
8b8c:   e2833001    add r3, r3, #1  r3=r3*2+1
8b90:   ea000000    b   8b98 0x98>
8b94:   e3a03000    mov r3, #0
8b98:   e1a00003    mov r0,
此时可以看出这是一个if-else的递归循环。C语言代码如下:
 fun7(const int *a, int b)
{
    if (a == NULL)
        return -1;
    int ret = 0;
    if (*a - b > 0)
    {
        ret = fun7(*(a + 4), b);
        ret *= 2
    }
    else if (*a - b == 0)
        return 0;
    else
    {
        ret = fun7(*(a + 8), b);
        ret = ret * 2 + 1;
    }
    return ret;
}

由于最终返回值为7,我们进行逆向递归,7=2*3+1,3=1*2+1,1=0*2+1。所以前三次比较中都是a

七、实验中遇到的问题及解决

1.环境配置过程中我们遇到的主要问题比如安装包与PC的位数不符,无法正确读出bomb的.s文件,在设置IP时因连接其他网络而无法获取地址,运行gdb进行调试时找不到目标文件等,但在我们仔细阅读指导书并且询问助教老师后,都得到了及时的解决。
2.实验三耗费了比较长的时间,关键就是一直在读反汇编的代码,没有去用gdb直接调试,所以总是在猜测哪里会存储什么数据,陷入了瓶颈。后来去机房调试,发现只要找到各个word里面存的数据就很容易知道这个题目答案,问题解决。
3.实验六遇到的问题主要是循环体没搞清楚,r3和r2的重复出现,弄得很混乱。但是在发现是链表结构后,基本上就豁然开朗了,gdb打印出链表内容,估计也就是个排序,按照自己的猜测再来用C语言把汇编翻译出来,整个题目就解决了。
4.隐藏关主要问题有两个,一个是寻找隐藏关打开方式,另一个是弄清楚函数。因为发现每一次成功过一关都会调用defuse函数,所以研究那个函数就搞明白进去的方法了;函数后来是突然想到了第四关的递归,再加上第六关中地址中存放地址的特点,找到了最终需要输入的数据。

你可能感兴趣的:(计算机系统)