CSAPP--BombLab

BombLab

一、 Lab介绍

  1. 官网地址
    在这里首先给出BombLab的官网地址:http://csapp.cs.cmu.edu/3e/labs.html
    进入官网后即可看到BombLab的介绍:
    在这里插入图片描述
    简单翻译一下:BombLab其实就是只提供给你一个可执行文件,让你利用对可执行文件进行逆向,分析逆向出来的汇编代码,以提高机器级编程的能力。BombLab总共有六关,难度也是越来越高,但一个个分析出来的话,成就感是非常高的!!!


  2. 前置知识

    1、 了解Linux操作系统的基本使用,能熟练使用Linux的基本指令。
    2、 熟练掌握x86汇编语言(如果不熟悉x86汇编语言,可以去CSAPP第三章学习)
    3、 熟练掌握gdb

二、 环境准备

  1. 下载相关资源
    在这里插入图片描述
    我们用到的资源也就两个:Writeup和Self-Study Handout

    • Writeup里面放置着Lab的介绍
    • Self-StudyHandout里面即是资源文件(一个c文件、一个可执行文件、一个README文档)。
      Self-Study Handout下载下来解压完成之后如下:
      在这里插入图片描述
  2. Linux环境搭建
    因为该Lab必须基于Linux操作系统,所以我建议完全不了解Linux的小伙伴先去补一下Linux的基础知识,再返回来做这个Lab。在这里推荐一下韩顺平老师的Linux课程,在B站有视频。
    Linux环境有了之后,之后就是检查Linux系统是否有我们开发所需的工具。
    最关键的两个工具分别是objdumpgdb。这里我们就只演示gdb,objdump也是一样的道理。
    首先需要判断本机是否有gdb。使用命令which gdb
    如果下面显示出gdb的路径来:如usr/bin/gdb,则说明本机已有gdb。如果不是,则使用命令yum install gdb命令下载gdb。
    好的,以上所有关于环境的问题,我们就都解决了,下面我们就可以正式开启BombLab了!!!

三、 具体内容

  1. Level 1

    首先,将资源文件放入Linux系统后,我们需要做的一件事便是查看各个资源文件:

    README文件如下:

    C文件如下:

/***************************************************************************
 * Dr. Evil's Insidious Bomb, Version 1.1
 * Copyright 2011, Dr. Evil Incorporated. All rights reserved.
 *
 * LICENSE:
 *
 * Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
 * VICTIM) explicit permission to use this bomb (the BOMB).  This is a
 * time limited license, which expires on the death of the VICTIM.
 * The PERPETRATOR takes no responsibility for damage, frustration,
 * insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
 * harm to the VICTIM.  Unless the PERPETRATOR wants to take credit,
 * that is.  The VICTIM may not distribute this bomb source code to
 * any enemies of the PERPETRATOR.  No VICTIM may debug,
 * reverse-engineer, run "strings" on, decompile, decrypt, or use any
 * other technique to gain knowledge of and defuse the BOMB.  BOMB
 * proof clothing may not be worn when handling this program.  The
 * PERPETRATOR will not apologize for the PERPETRATOR's poor sense of
 * humor.  This license is null and void where the BOMB is prohibited
 * by law.
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "phases.h"

/* 
 * Note to self: Remember to erase this file so my victims will have no
 * idea what is going on, and so they will all blow up in a
 * spectaculary fiendish explosion. -- Dr. Evil 
 */

FILE *infile;

int main(int argc, char *argv[])
{
    char *input;

    /* Note to self: remember to port this bomb to Windows and put a 
     * fantastic GUI on it. */

    /* When run with no arguments, the bomb reads its input lines 
     * from standard input. */
    if (argc == 1) {  
	infile = stdin;
    } 

    /* When run with one argument <file>, the bomb reads from <file> 
     * until EOF, and then switches to standard input. Thus, as you 
     * defuse each phase, you can add its defusing string to <file> and
     * avoid having to retype it. */
    else if (argc == 2) {
	if (!(infile = fopen(argv[1], "r"))) {
	    printf("%s: Error: Couldn't open %s\n", argv[0], argv[1]);
	    exit(8);
	}
    }

    /* You can't call the bomb with more than 1 command line argument. */
    else {
	printf("Usage: %s [<input_file>]\n", argv[0]);
	exit(8);
    }

    /* Do all sorts of secret stuff that makes the bomb harder to defuse. */
    initialize_bomb();

    printf("Welcome to my fiendish little bomb. You have 6 phases with\n");
    printf("which to blow yourself up. Have a nice day!\n");

    /* Hmm...  Six phases must be more secure than one phase! */
    input = read_line();             /* Get input                   */
    phase_1(input);                  /* Run the phase               */
    phase_defused();                 /* Drat!  They figured it out!
				      * Let me know how they did it. */
    printf("Phase 1 defused. How about the next one?\n");

    /* The second phase is harder.  No one will ever figure out
     * how to defuse this... */
    input = read_line();
    phase_2(input);
    phase_defused();
    printf("That's number 2.  Keep going!\n");

    /* I guess this is too easy so far.  Some more complex code will
     * confuse people. */
    input = read_line();
    phase_3(input);
    phase_defused();
    printf("Halfway there!\n");

    /* Oh yeah?  Well, how good is your math?  Try on this saucy problem! */
    input = read_line();
    phase_4(input);
    phase_defused();
    printf("So you got that one.  Try this one.\n");
    
    /* Round and 'round in memory we go, where we stop, the bomb blows! */
    input = read_line();
    phase_5(input);
    phase_defused();
    printf("Good work!  On to the next...\n");

    /* This phase will never be used, since no one will get past the
     * earlier ones.  But just in case, make this one extra hard. */
    input = read_line();
    phase_6(input);
    phase_defused();

    /* Wow, they got it!  But isn't something... missing?  Perhaps
     * something they overlooked?  Mua ha ha ha ha! */
    
    return 0;
}

通过分析C文件我们可以发现,分别调用6个函数,分别代表六关,每一关都需要我们输入一个字符串,然后将该字符串的首地址传入函数,如果传入的字符串正确,函数正常返回,进入下一关。如果不正确,则闯关失败!

可执行文件不可直接查看,我们将其反汇编并写入bomb.txt中。
使用命令:objdump -S -d bomb > bomb.txt即可完成上面的操作。
查看bomb.txt就可以发现可执行文件所需的所有函数的反汇编代码都可以看到,当然我们只需要对我们有用的就够了。由于代码太多,我这里就不全放过来了。

部分代码如下:
在这里插入图片描述

接下来,我们就可以分析第一关的反汇编代码了。
在这里插入图片描述

400ee0:即对栈帧进行初始化。
400ee4:将$0x402400传入%esi中
400ee9:调用strings_not_equal函数,将%rdi和%rsi传入,%rdi即为我们输入的字符串的首地址,%rsi即为$0x402400
400eee:将strings_not_equal函数的返回值%eax与0进行比较
400ef0:若%eax为0跳转到400ef7,成功返回函数
400ef2:若%eax不为0,执行这句,调用explode_bomb,即引爆炸弹,闯关失败。

通过以上分析,我们可以得出:只需满足$0x402400里存放的字符串与我们输入的字符串相等即可。

我们通过gdb运行程序bomb,在0x400ee9处打上断点。暂时随便输入一个字符串,查看0x402400处存放的字符串。
在这里插入图片描述
在这里插入图片描述
可以看到,0x402400处存放的字符串为:“Border relations with Canada have never been better.”
所以第一关的答案就是"Border relations with Canada have never been better."

我们输入答案,可以看到进入第二关了!!!
在这里插入图片描述

  1. Level 2
    首先,我们分析第二关的反汇编代码:
    在这里插入图片描述
    400efc~400efe:对栈帧进行初始化
    400f02:将栈指针放入%rsi中
    400f05:调用read_six_numbers函数,将%rdi和%rsi传入,%rdi即为我们输入的字符串首地址,%rsi即为栈指针
    400f0a:比较栈指针指向的数据是否等于1,若等于1,跳转到400f30,若不等于1,接着执行400f10,即引爆炸弹,闯关失败。
    400f30:%rsp + 0x4 赋值给 %rbx
    400f35:%rsp + 0x18 赋值给 %rbp
    400f3a:无条件跳转到400f17
    400f17:将(%rbx - 0x4)处的值赋值给%eax
    400f1a:将%eax的值乘2
    400f1c:比较%eax和(%rbx)处的值比较,若相等,则跳转到400f25,若不相等,则继续执行400f20,即引爆炸弹,闯关失败。
    400f25:将%rbx的值+4
    400f29:比较%rbp和%rbx的值,如果不相等,则继续跳转到400f17,如果相等则跳转到400f3c,即成功返回函数。

通过以上分析,我们得出结论,我们需要输入一个包含6个数字的字符串,而read_six_numbers函数会将我们字符串的六个数字保存在栈中,这六个数字需要满足的条件是:1、第一个数字为1。2、 之后每个是之前的2倍。所以得出第二关的答案1 2 4 8 16 32

我们输入答案,可以看到进入第三关了!!!
在这里插入图片描述

  1. Level 3

    首先,我们分析第三关的反汇编代码:
    在这里插入图片描述
    400f43:栈帧的初始化
    400f47:将 %rsp + 0xc 赋值给%rcx
    400f4c:将 %rsp + 0x8 赋值给%rdx
    400f51:将 0x4025cf 赋值给%esi
    400f56:将 0x0 赋值给%eax
    400f5b:调用函数__isoc99_sscanf@plt
    400f60:比较0x1和%eax的大小,若大于1,跳转到400f6a,反之,引爆炸弹,闯关失败。
    400f6a:比较0x7和(0x8 + %rsp)的大小,若大于7,则引爆炸弹,闯关失败,若不大于7,继续执行400f71。
    400f71:将(%rsp + 0x8)赋值给%eax
    400f75:跳转到(0x402070 + 0x8 * %rax)处保存的地址处,即(0x402070 + 0x8 * %rax)是一个地址,我们要去的地方的地址,存在这个地址的数据处。
    400f7c~400fab:这部分即上一步要跳转的地址,将特定数据赋值给%eax,然后跳转到400fbe
    400fbe:比较(0xc + %rsp)中的值和%eax,若等于,则跳转到400fc9,即函数正常结束。若不等于,则继续执行400fc4,即引爆炸弹,闯关失败。

通过以上分析,我们可以得出:我们输入的字符串需要两个整数,(0x8 + %rsp)中存放的便是第一个数字,(0xc + %rsp)中存放的便是第二个数字。第一个数字的取值不可大于7,故取值范围为:0~7。第一个数字的每个对应的第二个数字都在400f7c – 400fab处告诉我们了。所以第三关的答案不止一个
下面列出所有答案:
0 207
1 311
2 707
3 256
4 389
5 206
6 682
7 327

我们输入答案,可以看到进入第四关了!!!
在这里插入图片描述

  1. Level 4

    首先,我们分析第四关的反汇编代码:
    在这里插入图片描述
    在这里插入图片描述
    40100c:栈帧的从初始化
    401010:将 %rsp + 0xc 赋值给%rcx
    401015:将 %rsp + 0x8 赋值给%rdx
    40101a:将 0x4025cf 赋值给%esi
    40101f:将 0 赋值给%eax
    401024:调用函数__isoc99_sscanf@plt
    401029:比较函数返回值%eax和0x2的大小,若不等于2,则跳转到401035,即引爆炸弹,闯关失败。若等于2,则继续执行40102e
    40102e:比较(0x8 + %rsp)处的值和 0xe 的大小,若小于等于,则跳转到40103a。反之,则继续执行,即引爆炸弹,闯关失败。
    40103a:将0xe赋值给%edx
    40103f:将0x0赋值给%esi
    401044:将(0x8 + %rsp)赋值给%edi
    401048:跳转到400fce,调用func4函数,参数分别为%rdi,%rsi,%rdx
    400fce:func4函数栈帧的初始化
    400fd2:将%edx赋值给%eax
    400fd4:%eax减去%esi
    400fd6:将%eax赋值给%ecx
    400fd8:将%ecx逻辑右移0x1f位
    400fdb:将 %eax + %ecx 赋值给 %eax
    400fdd:将 %eax 算术右移一位
    400fdf: 将 %rax + %rsi * 1 赋值给%ecx
    400fe2:比较%ecx和%edi,若%ecx小于等于%edi,则跳转到400ff2。反之,将%rcx - 0x1赋值给%edx,继续递归调用func4函数。
    400ff2: 将0x0赋值给%eax
    400ff7: 比较%ecx和%edi的值,若%ecx大于等于%edi,则跳转到401007,函数正常返回,转而执行40104d。反之,将%rcx + 0x1赋值给%esi,继续递归调用func4函数。
    40104d:比较0x0与返回值%eax的大小,若不等于,则调用401058,即引爆炸弹,闯关失败。反之继续执行401051
    401051:比较(0xc + %rsp)的值与0x0的大小,若相等,函数正常结束,若不相等,引爆炸弹,闯关失败。

通过以上分析,我们可以得出:这一关我们输入的字符串须是两个数字,并且第二个数字必须是0,第一个数字必须小于等于0xe。通过分析func4中的代码,我们可以发现当第一个数字为0x7时,func4函数可以正常返回0。故第四关的答案为7 0

我们输入答案,可以看到进入第五关了!!!
在这里插入图片描述

  1. Level 5
    首先,我们分析第五关的反汇编代码:
    在这里插入图片描述
    401062~40106a:栈帧的初始化
    401073:将%rax存入到(%rsp + 0x18)
    401078:将%rax置零
    40107a:调用string_length函数,将%rdi(我们输入的字符串的首地址)传入
    40107f: 比较%eax与0x6的大小,若相等,则跳转到4010d2,若不相等,则引爆炸弹,闯关失败。
    4010d2:将0x0赋值给%eax
    4010d7:无条件跳转到40108b
    40108b:使用零拓展数据传送指令,将(%rbx + %rax * 1)的值赋值给%ecx
    40108f:将%cl中的值赋值给(%rsp)
    401092:将(%rsp)中的值赋值给%rdx
    401096:将寄存器 %edx 与 0xf 做与运算的值赋值给 %edx
    401099:使用零拓展数据传送指令,将(%rdx + 0x4024b0)的值赋值给%edx
    4010a0:将 %dl 中的值赋值给(0x10 + %rsp + %rax * 1)
    4010a4:将 %rax 的值+1
    4010a8:比较 %rax 的值与0x6,若相等,则继续执行4010ae,若不等,则返回40108b。
    4010ae:将0x0赋值给(0x16 + %rsp)
    4010b3:将0x40245e赋值给%esi
    4010b8:将 0x10 + %rsp 赋值给%rdi
    4010bd:调用函数string_not_equal,第一个参数为我们输入的字符串经修改后的地址,第二个参数为正确答案所在的字符串的地址
    4010c2:测试%eax是否等于0,若等于0,则跳转到4010d9,即函数正常返回,若不等于0,则引爆炸弹,闯关失败。

通过以上分析,我们可以得出,我们输入的字符串的长度必须为6,并且经过变换之后可以得到目标字符串:“flyers”,经计算,最后得出第五关的答案为:ionefg

我们输入答案,可以看到进入第六关了!!!
在这里插入图片描述

  1. Level 6

    第六关的反汇编代码:

00000000004010f4 <phase_6>:
  4010f4:	41 56                	push   %r14
  4010f6:	41 55                	push   %r13
  4010f8:	41 54                	push   %r12
  4010fa:	55                   	push   %rbp
  4010fb:	53                   	push   %rbx
  4010fc:	48 83 ec 50          	sub    $0x50,%rsp
  401100:	49 89 e5             	mov    %rsp,%r13
  401103:	48 89 e6             	mov    %rsp,%rsi
  401106:	e8 51 03 00 00       	callq  40145c <read_six_numbers>
  40110b:	49 89 e6             	mov    %rsp,%r14
  40110e:	41 bc 00 00 00 00    	mov    $0x0,%r12d
  401114:	4c 89 ed             	mov    %r13,%rbp
  401117:	41 8b 45 00          	mov    0x0(%r13),%eax
  40111b:	83 e8 01             	sub    $0x1,%eax
  40111e:	83 f8 05             	cmp    $0x5,%eax
  401121:	76 05                	jbe    401128 <phase_6+0x34>
  401123:	e8 12 03 00 00       	callq  40143a <explode_bomb>
  401128:	41 83 c4 01          	add    $0x1,%r12d
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d
  401130:	74 21                	je     401153 <phase_6+0x5f>
  401132:	44 89 e3             	mov    %r12d,%ebx
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  40113b:	39 45 00             	cmp    %eax,0x0(%rbp)
  40113e:	75 05                	jne    401145 <phase_6+0x51>
  401140:	e8 f5 02 00 00       	callq  40143a <explode_bomb>
  401145:	83 c3 01             	add    $0x1,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>
  40114d:	49 83 c5 04          	add    $0x4,%r13
  401151:	eb c1                	jmp    401114 <phase_6+0x20>
  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi
  401158:	4c 89 f0             	mov    %r14,%rax
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx
  401160:	89 ca                	mov    %ecx,%edx
  401162:	2b 10                	sub    (%rax),%edx
  401164:	89 10                	mov    %edx,(%rax)
  401166:	48 83 c0 04          	add    $0x4,%rax
  40116a:	48 39 f0             	cmp    %rsi,%rax
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>
  40116f:	be 00 00 00 00       	mov    $0x0,%esi
  401174:	eb 21                	jmp    401197 <phase_6+0xa3>
  401176:	48 8b 52 08          	mov    0x8(%rdx),%rdx
  40117a:	83 c0 01             	add    $0x1,%eax
  40117d:	39 c8                	cmp    %ecx,%eax
  40117f:	75 f5                	jne    401176 <phase_6+0x82>
  401181:	eb 05                	jmp    401188 <phase_6+0x94>
  401183:	ba d0 32 60 00       	mov    $0x6032d0,%edx
  401188:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:	48 83 c6 04          	add    $0x4,%rsi
  401191:	48 83 fe 18          	cmp    $0x18,%rsi
  401195:	74 14                	je     4011ab <phase_6+0xb7>
  401197:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx
  40119a:	83 f9 01             	cmp    $0x1,%ecx
  40119d:	7e e4                	jle    401183 <phase_6+0x8f>
  40119f:	b8 01 00 00 00       	mov    $0x1,%eax
  4011a4:	ba d0 32 60 00       	mov    $0x6032d0,%edx
  4011a9:	eb cb                	jmp    401176 <phase_6+0x82>
  4011ab:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx
  4011b0:	48 8d 44 24 28       	lea    0x28(%rsp),%rax
  4011b5:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi
  4011ba:	48 89 d9             	mov    %rbx,%rcx
  4011bd:	48 8b 10             	mov    (%rax),%rdx
  4011c0:	48 89 51 08          	mov    %rdx,0x8(%rcx)
  4011c4:	48 83 c0 08          	add    $0x8,%rax
  4011c8:	48 39 f0             	cmp    %rsi,%rax
  4011cb:	74 05                	je     4011d2 <phase_6+0xde>
  4011cd:	48 89 d1             	mov    %rdx,%rcx
  4011d0:	eb eb                	jmp    4011bd <phase_6+0xc9>
  4011d2:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)
  4011d9:	00 
  4011da:	bd 05 00 00 00       	mov    $0x5,%ebp
  4011df:	48 8b 43 08          	mov    0x8(%rbx),%rax
  4011e3:	8b 00                	mov    (%rax),%eax
  4011e5:	39 03                	cmp    %eax,(%rbx)
  4011e7:	7d 05                	jge    4011ee <phase_6+0xfa>
  4011e9:	e8 4c 02 00 00       	callq  40143a <explode_bomb>
  4011ee:	48 8b 5b 08          	mov    0x8(%rbx),%rbx
  4011f2:	83 ed 01             	sub    $0x1,%ebp
  4011f5:	75 e8                	jne    4011df <phase_6+0xeb>
  4011f7:	48 83 c4 50          	add    $0x50,%rsp
  4011fb:	5b                   	pop    %rbx
  4011fc:	5d                   	pop    %rbp
  4011fd:	41 5c                	pop    %r12
  4011ff:	41 5d                	pop    %r13
  401201:	41 5e                	pop    %r14
  401203:	c3                   	retq 

第六关略显复杂,若要一步一步仔细讲解,会花费大量篇幅,而且也不一定能讲明白(因为太过复杂ε(┬┬﹏┬┬)3)。这里直接给出第六关的答案4 3 2 1 6 5。小伙伴们如果觉得第六关过于复杂,可以看情况跳过,把前五个弄明白就可以了,当然想挑战自己的小伙伴也可以尝试一下,并不难,只是特麻烦,多花点时间也不是问题。

四、 结尾语

以上就是BombLab的全部内容了。通过这个Lab我们可以更加深入的理解了机器级编程,对计算机底层有了更深的认识。希望本人写的这篇文章对您有所帮助,谢谢!!!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值