实验介绍

  • 使用课程知识拆除一个“Binary Bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等理解。
  • 一个“Binary Bombs”(二进制炸弹,简称炸弹)是一个Linux可执行C程序,包含phase1~phase6共6个阶段。
  • 炸弹运行各阶段要求输入一个字符串,若输入符合程序预期,该阶段炸弹被“拆除”,否则“爆炸” 。
  • 实验目标是你需要拆除尽可能多的炸弹。

实验步骤:

第一步:反汇编
将自己的炸弹文件复制到share目录下
解压炸弹文件,并 cd 到解压出的子目录
bomb进行反汇编并将汇编代码输出到asm.txt中:objdump –d bomb > asm.txt
查看生成的asm.txt文件,结合bomb.c中的代码框架和汇编代码,找出:函数之间的调用关系、传递的参数;
第二步:查看汇编源代码asm.txt文件
第三步:执行 gdb bomb,找到拆弹字符串。

一句话:通过阅读执行判断操作的汇编代码,得出正确输入。


实验内容:

<phase_1> :字符串比较

08048b33 <phase_1>:    #字符串比较8048b33:  83 ec 14                sub    $0x14,%esp8048b36:   68 2c a1 04 08          push    0x804a12c       #(gdb) x/s 0x804812c,便找到输入的字符串;8048b3b:ff 74 24 1c                pushl  0x1c(%esp)8048b3f:   e8 7c 04 00 00          call   8048fc0 <strings_not_equal>8048b44:    83 c4 10                add    $0x10,%esp8048b47:   85 c0                   test   %eax,%eax        #判断两个字符串是否相等。8048b49:   74 05                   je     8048b50 <phase_1+0x1d>8048b4b:e8 ad 06 00 00          call   80491fd <explode_bomb>8048b50: 83 c4 0c                add    $0xc,%esp8048b53:    c3                      ret

gdb调试,找到判断时所对照的正确字符串,便是正确输入。
gdb bomb :进入bomb文件的调试界面;
x/s 0x804812c:找到该位置中存放的正确字符串。
找到的字符串为:When I get angry, Mr. Bigglesworth gets upset.


<phase_2>:循环

//例1:
08048b54 <phase_2>:   #循环8048b54: 56                      push   %esi8048b55: 53                      push   %ebx     #没有修正ebp,还在main函数底部8048b56:  83 ec 2c                sub    $0x2c,%esp8048b59:   65 a1 14 00 00 00       mov    %gs:0x14,%eax    #gs段寄存器,保存段内地址8048b5f:   89 44 24 24             mov    %eax,0x24(%esp)   #检测栈帧有没有被破坏8048b63:    31 c0                   xor    %eax,%eax8048b65:    8d 44 24 0c             lea    0xc(%esp),%eax8048b69:   50                      push   %eax8048b6a: ff 74 24 3c             pushl  0x3c(%esp)           #修正到main函数栈帧中取参数,相当于ebp+88048b6e:   e8 c7 06 00 00          call   804923a <read_six_numbers>     #从input分离出6个数字8048b73:  83 c4 10                add    $0x10,%esp           8048b76:    83 7c 24 04 01          cmpl   $0x1,0x4(%esp)       #判断第一个数是否为18048b7b:74 05                        je     8048b82 <phase_2+0x2e>8048b7d:e8 7b 06 00 00              call   80491fd <explode_bomb>8048b82: 8d 5c 24 04             lea    0x4(%esp),%ebx       #现在ebx存的是数1所在位置8048b86: 8d 74 24 18             lea    0x18(%esp),%esi      #设置esi为为ebx循环的终止位置
//循环部分8048b8a:  8b 03                   mov    (%ebx),%eax          #把ebx中存的数赋给eax8048b8c:  01 c0                   add    %eax,%eax            #eax+=eax;8048b8e: 39 43 04                cmp    %eax,0x4(%ebx)       #看ebx+4位置上的数是否为eax;8048b91: 74 05                   je     8048b98 <phase_2+0x44>8048b93:    e8 65 06 00 00          call   80491fd <explode_bomb>8048b98: 83 c3 04                add    $0x4,%ebx            #找下一个位置上的数,ebx+=4;8048b9b:39 f3                     cmp    %esi,%ebx            #判断ebx是否已经到达终止位置,是否要继续循环8048b9d:75 eb                        jne    8048b8a <phase_2+0x36>    #继续的话,跳转到8048b8a;8048b9f: 8b 44 24 1c             mov    0x1c(%esp),%eax8048ba3:  65 33 05 14 00 00 00 xor    %gs:0x14,%eax       #无影响,不管8048baa:  74 05                   je     8048bb1 <phase_2+0x5d>8048bac:    e8 df fb ff ff          call   8048790 <__stack_chk_fail@plt>8048bb1:83 c4 24                    add    $0x24,%esp8048bb4:5b                         pop    %ebx8048bb5:5e                           pop    %esi8048bb6:c3                           ret

call 804923a <read_six_numbers> 可知,输入的字符串包括 6 个数。

8048b9d上的指令jne 8048b8a <phase_2+0x36>,又跳转回了上面的位置,可以知道这段是循环过程:
ebx 从第一个数所在的位置开始循环,esi 存放最后一个数所在的位置。
每次将 ebx 中的数赋值为到 eax 上,eax*=2,判断下一位置上的数是否和 eax 中的值相等。也就是说,后面一个数的位置一定是前面一个数的2倍。

而由 cmpl $0x1,0x4(%esp) 可知第一个数为1,那么最终的答案便为1 2 4 8 16 32

//例2:
08048b8c <phase2>:8048b8c:    55                      push   %ebp8048b8d:89 e5                        mov    %esp,%ebp8048b8f:    56                      push   %esi8048b90: 53                      push   %ebx8048b91: 83 ec 28                sub    $0x28,%esp8048b94:   8d 45 e0                lea    -0x20(%ebp),%eax8048b97: 50                      push   %eax8048b98: ff 75 08                pushl  0x8(%ebp)8048b9b:e8 ca 05 00 00              call   804916a <readsixnumbers>8048ba0:   83 c4 10                add    $0x10,%esp8048ba3:   83 7d e0 00             cmpl   $0x0,-0x20(%ebp) #判断第一个值是否为08048ba7: 75 06                   jne    8048baf <phase2+0x23>8048ba9: 83 7d e4 01             cmpl   $0x1,-0x1c(%ebp) #判断第二个值是否为18048bad: 74 05                   je     8048bb4 <phase2+0x28>8048baf: e8 8e 05 00 00          call   8049142 <explodebomb>8048bb4:8d 5d e0                  lea    -0x20(%ebp),%ebx #将0的地址放入ebx8048bb7:8d 75 f0                     lea    -0x10(%ebp),%esi #设置ebx的循环终止地址8048bba:   eb 07                   jmp    8048bc3 <phase2+0x37> #跳过第一次循环的初始值判断部分,直接进行操作
//循环部分8048bbc:  83 c3 04                add    $0x4,%ebx    #ebx+=4,地址更新8048bbf:   39 f3                   cmp    %esi,%ebx    #判断是否循环到终止位置了8048bc1:   74 11                   je     8048bd4 <phase2+0x48> #如果是,退出循环8048bc3:    8b 43 04                mov    0x4(%ebx),%eax   #把下一位置的值放到eax中8048bc6:  03 03                   add    (%ebx),%eax      #把当前位置的值累加到eax8048bc8:  39 43 08                cmp    %eax,0x8(%ebx)   #判断下下位置是否是eax,即其前面两位置之和8048bcb:  74 ef                   je     8048bbc <phase2+0x30> #如果是,继续循环;否则爆炸。8048bcd:   e8 70 05 00 00          call   8049142 <explodebomb>8048bd2:eb e8                     jmp    8048bbc <phase2+0x30>8048bd4:8d 65 f8                     lea    -0x8(%ebp),%esp8048bd7:5b                        pop    %ebx8048bd8:5e                           pop    %esi8048bd9:5d                           pop    %ebp8048bda: c3                      ret

<phase_3>:跳转

08048bb7 <phase_3>:    #跳转8048bb7:83 ec 1c                 sub    $0x1c,%esp8048bba:   65 a1 14 00 00 00    mov    %gs:0x14,%eax8048bc0:   89 44 24 0c             mov    %eax,0xc(%esp)8048bc4:   31 c0                   xor    %eax,%eax8048bc6:    8d 44 24 08             lea    0x8(%esp),%eax8048bca:   50                      push   %eax8048bcb: 8d 44 24 08             lea    0x8(%esp),%eax8048bcf:   50                      push   %eax8048bd0:68 8d a3 04 08           push   $0x804a38d       #(gdb) x/s 0x804a38d,得到 "%d %d",可知输入的是数字,数字;8048bd5:ff 74 24 2c              pushl  0x2c(%esp)8048bd9:e8 32 fc ff ff         call   8048810 <__isoc99_sscanf@plt>8048bde: 83 c4 10                add    $0x10,%esp8048be1:   83 f8 01                cmp    $0x1,%eax        #判断输入数字的个数,一定要大于1;8048be4:    7f 05                   jg     8048beb <phase_3+0x34>8048be6:    e8 12 06 00 00          call   80491fd <explode_bomb>8048beb: 83 7c 24 04 07          cmpl   $0x7,0x4(%esp)   #判断输入的第一个值是否大于7,因为只有0~7八个分支;8048bf0:  77 3c                   ja     8048c2e <phase_3+0x77>8048bf2:    8b 44 24 04             mov    0x4(%esp),%eax   8048bf6:    ff 24 85 8c a1 04 08 jmp    *0x804a18c(,%eax,4)     //#(gdb) p/x *0x804a18c,得到下一条指令的地址0x8048c3a;
# 因为一共8个跳转分支,所以需要得到其跳转位置。(gdb) x/8x 0x804a18c,得到其8个分支的位置
# 跳转表:8048bfd:   b8 e7 03 00 00          mov    $0x3e7,%eax      #第1个,如果输入1的话,跳到此处;8048c02: eb 3b                   jmp    8048c3f <phase_3+0x88>8048c04:    b8 83 03 00 00          mov    $0x383,%eax      #第2个8048c09:    eb 34                   jmp    8048c3f <phase_3+0x88>8048c0b:    b8 9a 03 00 00          mov    $0x39a,%eax      #第3个8048c10:    eb 2d                   jmp    8048c3f <phase_3+0x88>8048c12:    b8 f0 01 00 00          mov    $0x1f0,%eax      #第4个8048c17:    eb 26                   jmp    8048c3f <phase_3+0x88>8048c19:    b8 31 01 00 00          mov    $0x131,%eax      #第5个8048c1e:    eb 1f                   jmp    8048c3f <phase_3+0x88>8048c20:    b8 d2 03 00 00          mov    $0x3d2,%eax      #第6个8048c25:    eb 18                   jmp    8048c3f <phase_3+0x88>8048c27:    b8 6b 01 00 00          mov    $0x16b,%eax      #第7个8048c2c:    eb 11                   jmp    8048c3f <phase_3+0x88>8048c2e:    e8 ca 05 00 00          call   80491fd <explode_bomb>8048c33: b8 00 00 00 00          mov    $0x0,%eax8048c38:    eb 05                   jmp    8048c3f <phase_3+0x88>8048c3a:    b8 ad 01 00 00          mov    $0x1ad,%eax      #第0个 如果跳转到此处,eax赋值为(1ad)_16,即429;8048c3f:  3b 44 24 08             cmp    0x8(%esp),%eax   #判断第二个数是否为eax。8048c43:  74 05                   je     8048c4a <phase_3+0x93>8048c45:    e8 b3 05 00 00          call   80491fd <explode_bomb>8048c4a: 8b 44 24 0c             mov    0xc(%esp),%eax8048c4e:   65 33 05 14 00 00 00 xor    %gs:0x14,%eax8048c55:   74 05                   je     8048c5c <phase_3+0xa5>8048c57:    e8 34 fb ff ff          call   8048790 <__stack_chk_fail@plt>8048c5c:    83 c4 1c                add    $0x1c,%esp8048c5f:   c3                      ret

给出了一个地址 push $0x804a38d,那么gdb调试 #(gdb) x/s 0x804a38d,得到 "%d %d",可知输入的是数字,数字,两个数。
cmpl $0x7,0x4(%esp)可以知道,输入的第一个数最大不超过7,说明只有0~7八个分支。
通过gdb调试指令:x/8x 0x804a18c,便能找到所有分支的地址。

可见,第0个分支的地址为 0x8048c3a,跳转到该位置,eax 赋值为(1ad)_16,即十进制的 429;所以最终的答案可以为:0 429
同理,可以找到第1分支,第2分支…上的数,答案不唯一。


<phase_4>:递归调用

08048c60 <func4>:8048c60:  57                      push   %edi8048c61: 56                      push   %esi8048c62: 53                      push   %ebx8048c63: 8b 5c 24 10             mov    0x10(%esp),%ebx  #x = 78048c67: 8b 7c 24 14             mov    0x14(%esp),%edi  #y = d28048c6b:    85 db                   test   %ebx,%ebx8048c6d:    7e 2b                   jle    8048c9a <func4+0x3a>  #如果x<=0的话,返回08048c6f:    89 f8                   mov    %edi,%eax8048c71:    83 fb 01                cmp    $0x1,%ebx        #否则,若x=1,返回y8048c74: 74 29                   je     8048c9f <func4+0x3f>  8048c76:    83 ec 08                sub    $0x8,%esp8048c79:    57                      push   %edi8048c7a: 8d 43 ff                lea    -0x1(%ebx),%eax8048c7d:  50                      push   %eax8048c7e: e8 dd ff ff ff          call   8048c60 <func4>    #以x-1作为形参继续调用func(x-1,y);8048c83:   83 c4 08                add    $0x8,%esp8048c86:    8d 34 07                lea    (%edi,%eax,1),%esi   #esi = y + sub_8048C60(x - 1, y);8048c89: 57                      push   %edi8048c8a: 83 eb 02                sub    $0x2,%ebx8048c8d:    53                      push   %ebx8048c8e: e8 cd ff ff ff          call   8048c60 <func4>    #以x-2作为形参继续调用func(x-2,y);8048c93:   83 c4 10                add    $0x10,%esp8048c96:   01 f0                   add    %esi,%eax        #否则 x!=1, 返回 esi + func(x-2,y),即y + func(x-1,y) + func(x-2,y)。8048c98:   eb 05                   jmp    8048c9f <func4+0x3f>8048c9a:  b8 00 00 00 00          mov    $0x0,%eax8048c9f:    5b                      pop    %ebx8048ca0: 5e                      pop    %esi8048ca1: 5f                      pop    %edi8048ca2: c3                      ret    08048ca3 <phase_4>:8048ca3:    83 ec 1c                sub    $0x1c,%esp8048ca6:   65 a1 14 00 00 00    mov    %gs:0x14,%eax8048cac:   89 44 24 0c             mov    %eax,0xc(%esp)8048cb0:   31 c0                   xor    %eax,%eax8048cb2:    8d 44 24 04             lea    0x4(%esp),%eax8048cb6:   50                      push   %eax8048cb7: 8d 44 24 0c             lea    0xc(%esp),%eax8048cbb:   50                      push   %eax8048cbc: 68 8d a3 04 08          push   $0x804a38d8048cc1:   ff 74 24 2c             pushl  0x2c(%esp)8048cc5:   e8 46 fb ff ff          call   8048810 <__isoc99_sscanf@plt>8048cca: 83 c4 10                add    $0x10,%esp8048ccd:   83 f8 02                cmp    $0x2,%eax    #判断,如果输入数的个数小于等于2的话,爆炸8048cd0:    75 0c                   jne    8048cde <phase_4+0x3b>8048cd2:    8b 44 24 04             mov    0x4(%esp),%eax8048cd6:   83 e8 02                sub    $0x2,%eax8048cd9:    83 f8 02                cmp    $0x2,%eax8048cdc:    76 05                   jbe    8048ce3 <phase_4+0x40>    #判断,第二个数是否大于等于2,小于4 8048cde:  e8 1a 05 00 00          call   80491fd <explode_bomb>8048ce3: 83 ec 08                sub    $0x8,%esp8048ce6:    ff 74 24 0c             pushl  0xc(%esp)8048cea:    6a 07                   push   $0x78048cec: e8 6f ff ff ff          call   8048c60 <func4 >   #func(7,d2)8048cf1: 83 c4 10                add    $0x10,%esp8048cf4:   3b 44 24 08             cmp    0x8(%esp),%eax   #判断第一个数是否为函数返回值8048cf8: 74 05                   je     8048cff <phase_4+0x5c>8048cfa:    e8 fe 04 00 00          call   80491fd <explode_bomb>8048cff: 8b 44 24 0c             mov    0xc(%esp),%eax8048d03:   65 33 05 14 00 00 00 xor    %gs:0x14,%eax8048d0a:   74 05                   je     8048d11 <phase_4+0x6e>8048d0c:    e8 7f fa ff ff          call   8048790 <__stack_chk_fail@plt>8048d11:    83 c4 1c                add    $0x1c,%esp8048d14:   c3                      ret

根据func4函数的汇编代码,还原出其C++程序为:

int __cdecl sub_8048C60(int a1, int a2)
{int result; // eaxint v3; // esiif ( a1 <= 0 )return 0;result = a2;if ( a1 != 1 ){v3 = a2 + sub_8048C60(a1 - 1, a2);result = v3 + sub_8048C60(a1 - 2, a2);}return result;
}

最初状态,a1为定值7,a2为第二个输入的数。
所以,如果第二个输入2的话,函数递归过程为:func(7,2)调用func(6,2)和func(5,2),func(6,2)再调用func(5,2)和func(4,2),func(5,2)再调用func(4,2)和func(3,2)…
所以,为了计算func(7,2),则需依次计算出func(0,2), func(1,2), func(2,2), func(3,2), func(4,2), func(5,2), func(6,2).
结果依次为:2 4 8 14 24 40,那么最终答案为2 + 24 + 40 = 66。
所以,一种答案可为66 2

计算机系统基础实验2——bomb相关推荐

  1. 华中科技大学计算机系统基础实验3报告,华中科技大学计算机系统基础实验报告...

    华中科技大学计算机系统基础实验报告 1 课 程 实 验 报 告 课程名称: 计算机系统基础 专业班级: 学 号: 姓 名: 指导教师: 报告日期: 2016年 5月 24 日 计算机科学与技术学院2 ...

  2. 计算机系统基础实验报告

    计算机系统基础实验报告 语言 C++ 编译器 Dev C++ 实验一:数的机器级表示 编写无符号数的转换: unsigned int unsignedToValue(char binary[],int ...

  3. 《深入理解计算机系统》实验二Bomb Lab

    前言 <深入理解计算机系统>实验二Bomb Lab的下载和官网文档的机翻请看 <深入理解计算机系统>实验二Bomb Lab下载和官方文档机翻 用的调试工具是gdb,用到的指令如 ...

  4. 计算机系统基础实验-LinkLab实验

    这是大三时的实验课,很久以前的东西,应要求放出来,做的不是很好.linux永远都是很重要的,希望我和大家都记得这个.实际上做到第五阶段我就不会了. 实验课程名称:计算机系统基础 实验项目名称:Link ...

  5. 华中科技大学计算机系统基础实验3报告,华中科技大学计算机系统基础实验报告.doc...

    文档介绍: 课程实验报告课程名称:计算机系统基础专业班级:学号:姓名:指导教师:报告日期:2016年5月24日计算机科学与技术学院目录实验1: 2实验2: 9实验3: 22实验总结 30 实验1:数据 ...

  6. 《深入理解计算机系统》实验二Bomb Lab下载和官方文档机翻

    前言 <深入理解计算机系统>官网:http://csapp.cs.cmu.edu/3e/labs.html 该篇文章是实验二Bomb Lab的Writeup机翻. 原文:http://cs ...

  7. 计算机系统基础实验01运算器算术运算

    计算机系统基础 运算器算术运算 实验目的 掌握ALU的算术运算原理,熟悉ALU数据传送通路和数据传送方式. 实验环境 微机,配置Windows操作系统.LC-3仿真机软件. 实验内容 ALU数据传送通 ...

  8. 计算机系统基础实验:认识logisim软件、门电路逻辑功能测试(仿真)

    通过logisim对逻辑电路进行分析 文章目录 目录 文章目录 前言 一.使用工具 二.实验过程 1.门电路绘制 2.真值表 总结 前言 计算机系统基础也开了实验课,实验内容是利用logisim软件进 ...

  9. 北京邮电大学计算机系统基础实验,第1章 计算机系统基础85666.ppt

    第1章 计算机系统基础85666 盘青梅 gdpqm@126.com 总结:计算机的发展阶段 冯·诺依曼计算机模型(P14) 总线系统结构图 总线(Bus)是计算机各部件传输信息的公共通道.有数据总线 ...

  10. 计算机系统基础实验:二进制拆弹实验

    一.实验目的: 学习并熟练使用 gdb 调试器和 objdump 理解汇编语言代码的行为或作用 提高阅读和理解汇编代码的能力 二.实验要求 实验共包括七个阶段,每个阶段考察机器级语言程序的不同方面,难 ...

最新文章

  1. Anconda PyCharm TensorFlow
  2. python散点图拟合曲线-【python常用图件绘制#01】线性拟合结果图
  3. Mysql索引基本概念及案例总结(含索引的使用注意事项)
  4. 宿迁学计算机的学校,宿迁计算机学校
  5. 360——新式的流氓
  6. 实验2-3-3 信号处理总结以及Linux下支持的信号列表
  7. 企业微信API之通讯录同步
  8. Badboy 录制脚本提示“当前页面的脚本发生错误”解决
  9. 1114 计算营业额
  10. 归并排序 (递归 非递归)
  11. MATLAB源码-GRABIT从图像文件中提取数据点。
  12. 自旋锁(spinlock)
  13. SV,class学习笔记五、参数化类(parameterized class)
  14. BBEdit—HTML文本编辑器
  15. CDS 获取系统日期时间
  16. 小i机器人用AI打造金融业认知智能企业
  17. 【子桓说】从阿里、百度分析,教你判断一家企业是否适合自己
  18. css怎样给网页加页脚,在移动Web页面中使用CSS固定页脚
  19. tuned-adm性能优化的配置文件详解
  20. H265编码 SPS分析

热门文章

  1. python自动化开发-[第九天]-异常处理、进程
  2. Java如何实现贪吃蛇小游戏
  3. IT领域的罗马帝国——微软公司
  4. Qt 弹出对话框选择图片并显示
  5. 如何在国内快速访问Github
  6. 解决服务器空间满/var/lib/docker/overlay2占用很大,千万慎用 docker system prune -a清理 mongodb等数据库容器及镜像可能被删,找回恢复数据
  7. 要么忙于生存,要么忙于去死
  8. Jira+Confluence+Fisheye+Crucible安装步骤清单
  9. 棋牌游戏判断牌型算法---适合所有的棋牌游戏
  10. python爬虫小说爬取