bupt拆解二进制炸弹bomb

2023-11-11 09:50

本文主要是介绍bupt拆解二进制炸弹bomb,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、实验目的
1.理解C语言程序的机器级表示。
2.初步掌握GDB调试器的用法。
3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现。

  • 实验环境
  1. Windows PowerShell(10.120.11.12)
  2. Linux
  3. Objdump命令反汇编
  4. GDB调试工具
  5. 。。。。。

三、实验内容

登录bupt1服务器,在home目录下可以找到Evil博士专门为你量身定制的一个bomb,当运行时,它会要求你输入一个字符串,如果正确,则进入下一关,继续要求你输入下一个字符串;否则,炸弹就会爆炸,输出一行提示信息并向计分服务器提交扣分信息。因此,本实验要求你必须通过反汇编和逆向工程对bomb执行文件进行分析,找到正确的字符串来解除这个的炸弹。

本实验通过要求使用课程所学知识拆除一个“binary bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。 “binary bombs”是一个Linux可执行程序,包含了5个阶段(或关卡)。炸弹运行的每个阶段要求你输入一个特定字符串,你的输入符合程序预期的输入,该阶段的炸弹就被拆除引信;否则炸弹爆炸,打印输出 “BOOM!!!”。炸弹的每个阶段考察了机器级程序语言的一个不同方面,难度逐级递增。  

为完成二进制炸弹拆除任务,需要使用gdb调试器和objdump来反汇编bomb文件,可以单步跟踪调试每一阶段的机器代码,也可以阅读反汇编代码,从中理解每一汇编语言代码的行为或作用,进而设法推断拆除炸弹所需的目标字符串。实验2的具体内容见实验2说明。

四、实验步骤及实验分析

建议按照:准备工作、阶段1、阶段2¼等来组织内容

各阶段需要有操作步骤、运行截图、分析过程的内容

首先将炸弹解压,用tar -xvf bomb215.tar 命令

拆解完成后进入炸弹文件夹里,

运用gdb调试炸弹,一开始我先将源码打印出来,源码如下

(gdb) list

73          input = read_line();             /* Get input                   */

74          phase_1(input);                  /* Run the phase               */

75          phase_defused();                 /* Drat!  They figured it out!

76                                            * Let me know how they did it. */

77          printf("Phase 1 defused. How about the next one?\n");

78

79          /* The second phase is harder.  No one will ever figure out

80           * how to defuse this... */

81          input = read_line();

82          phase_2(input);

(gdb)

83          phase_defused();

84          printf("That's number 2.  Keep going!\n");

85

86          /* I guess this is too easy so far.  Some more complex code will

87           * confuse people. */

88          input = read_line();

89          phase_3(input);

90          phase_defused();

91          printf("Halfway there!\n");

92

(gdb)

93          /* Oh yeah?  Well, how good is your math?  Try on this saucy problem! */

94          input = read_line();

95          phase_4(input);

96          phase_defused();

97          printf("So you got that one.  Try this one.\n");

100         input = read_line();

101         phase_5(input);

102         phase_defused();

(gdb)

103         printf("Good work!  On to the next...\n");

107         input = read_line();

108         phase_6(input);

109         phase_defused();

(gdb)

113

114         return 0;

115     }

可以看到,第一个炸弹在键盘输入之后会进入phase_1(input) 里面,phase_1会传入我们输入的字符串,而phase_defused() 无参数,因此推断出phase_1 里会判断是否爆炸,而phase_defuse() 则是告知是否拆解炸弹成功

将断点打到phase_1 上,gdb调试进入phase_1 函数里,再查看里面的汇编代码

这个函数在爆炸前会调用<string_not_equal>函数,我们在此处打个断点进入,查看它的汇编代码

这个函数里会接连调用两次<string_length>的函数,因为如果两个字符串长度不同的话,那肯定不是我们想得到的答案。首先进入第一次调用,查看传入的参数,为我们输入的字符串,退出了,再查看第二次调用,x /s $rdi 查看第二次传入的参数,可以看到,此时rdi里的字符串即是本次炸弹的密码。

The bomblab forces students to learn how to use a debugger.

phase_2

objdump -d bomb 指令查看汇编代码

 

之后将这一大串汇编代码复制到文本编辑器里查看,并找到phase_2

phase_2 的前面几句话只是在做调用函数之前的栈缓存和扩容。之后看到调用函数是<read_six_numbers>意味着输入应该是读取6个数字。如果[rsp]里的值等于1 ,则不会爆炸,0x14(%rsp)是把rsp的地址加20,即若把rsp看成数组0号索引,0x14(%rsp) rsp[5] ,因为一个int类型大小是4个字节。前一步操作将[rsp] 里为1的值放入%rbx,再把%rbx放入%eax,说明%eax1400f7c内存指令将eax乘二了,此时eax2,然后再比较0x4(%rbx)里的值。如此循环,每次循环eax里的值都会乘2,所以这个数列是1 2 4 8 16 32.

       

phase_3

同样来看phase_3的汇编代码

进入<__isoc99_sscanf>函数里查看输入的格式

需要输入一个数字 一个字符 一个数字

400fdd那一行告诉我们输入的数要大于2,否则会爆炸,后面又有一个大于7,也爆炸,因此我选择了3.

jmpq是一个跳转到表的指令,相当于c里的switch

查看*0x402760里面的数,为0x400ffa,刚好就在下一行$0x139313  $0x6b 换成ascii码变为k

因此输入答案为3 k 313

phase_4:

下面是phase_4的汇编代码,后面写满了我的注释

同样是查看函数<isoc99_sscanf>函数寄存器里的参数,知道了输入为两个整型。

将汇编代码还原成c语言代码,试运行。从汇编代码中知道第一个参数是9.第一个参数是[rsp],第三个参数是[rsp+4],但是很奇怪的是第三个参数虽然存入了rdx里,但是却没有用。阅读phase_4的汇编代码401186行我知道了输入的一个数必须小于等于4并且大于等于2。将c语言代码运行,得到结果:

改变参数234,得到结果分别为176264352。此时查看phase_4[rsp][rsp+4]的值,发现[rsp]存的是第二个输入的参数,[rsp]为输入的第一个参数。最终得到答案为176 2264 3352 4答案有三组。

phase_5:

最开始比较6<string_length>的返回值,不相等则爆炸,说明输入的必须是6个字符串。之后下面就是一个循环,每次循环都会把输入的第i个字符的低四位字节取出,并将0x4027a0(,%rdx,4)中的值拿出来加到%ecx里。循环六次之后将ecx$0x36也就是54 比较,如果相等的话就说明通过了。这段其实是一个加密的解密过程,查看0x4027a0数组里的元素,发现一种答案是2+10+10+10+10+12,查看ascii编码表的二进制表,答案既可以是一个0,四个1,一个4的任意组合。顺利通过。

这篇关于bupt拆解二进制炸弹bomb的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/389237

相关文章

通信工程学习:什么是2ASK/BASK二进制振幅键控

2ASK/BASK:二进制振幅键控         2ASK/BASK二进制振幅键控是一种数字调制技术,其全称是二进制振幅键控(Binary Amplitude Shift Keying)。该技术通过改变载波的振幅来传递二进制数字信息,而载波的频率和相位则保持不变。以下是关于2ASK/BASK二进制振幅键控的详细解释: 一、2ASK/BASK二进制振幅键控的基本原理 1、振幅键控:

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1:输入:a = "11", b = "1"输出:"100"示例 2:输入:a = "1010", b = "1011"输出:"10101" 算法设计 可以从低位到高位(从后向前)计算,用一个变量carry记录进位,如果有字符没处理完或者有进位,则循环处理。两个字符串对

Leetcode67---二进制求和

https://leetcode.cn/problems/add-binary/description/ 给出的两个二进制,我们可以从最后开始往前运算。 给当前短的一位前面补充0即可。 class Solution {public String addBinary(String a, String b) {//给的就是二进制字符串 最后一位开始遍历 如果没有就补充0?StringBuil

二进制的匹配问题

最近做了点搜索和背包的题目,发现这个二进制的匹配很是好用,所以写一篇二进制的匹配来作为自我总结; 首先我们要知道二进制的运算符,和他们的运算规则; ABA&BA|BA^B00000010111001111110 运算符有三种‘&’ , ‘|’ ,  ‘^'  或,且,异或,运算的规则在表中可以看到,想想这个规则我们可以做很多事情! 首先,每个十进制的数都会对应一个唯一的二进

深入拆解 Java 虚拟机 】Exception异常笔记

【深入拆解 Java 虚拟机 】Exception异常笔记 try-with-resource语法糖finally try-with-resource语法糖 try后对象的close方法都会被运行。 package com.exception.demo;public class Foo implements AutoCloseable {private final Strin

二进制方式安装Helm

二进制方式安装Helm 官网:https://helm.sh/ 1、下载安装包 wget -L https://get.helm.sh/helm-v3.16.0-rc.1-linux-amd64.tar.gz 2、解压 tar -xf helm-v3.16.0-rc.1-linux-amd64.tar.gz 3、移动到/usr/local/bin/目录下 mv linux-am

输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。

/*** 输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。* 思路:第一步求这两个数的异或,第二步统计异或结果中1的位数*@author: Administrator*@date: 2017-1-13 下午09:39:25*/import java.util.Scanner;public class Solution4 {public int CountDifference

【每日一题】LeetCode 1652.拆炸弹(数组、滑动窗口)

【每日一题】LeetCode 1652.拆炸弹(数组、滑动窗口) 题目描述 你有一个炸弹需要拆除,时间紧迫!你的情报员会给你一个长度为 n 的循环数组 code 以及一个密钥 k。 为了获得正确的密码,你需要替换掉每一个数字。所有数字会同时被替换。 如果 k > 0,将第 i 个数字用接下来 k 个数字之和替换。如果 k < 0,将第 i 个数字用之前 k 个数字之和替换。如果 k ==

牛客网《剑指Offer》 二进制中1的个数

题目描述 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 思路 负数用补码,其实就是求一个数据在计算机中是存储是怎么样子的。用位运算,就能很好实现。 class Solution {public:int NumberOf1(int n) {int count = 0;int flag = 1;while (flag != 0) {if ((n & f

Java 二进制,八进制,十进制,十六进制之间的相互转换

package com.sjd.JinzhiZhuanhuan;public class JinzhiZhuanhuan {//二进制转八,十,十六进制---开始public void fromBinaryToOctalSting(String str1) {String result=Integer.toOctalString(Integer.parseInt(str1, 2));System.