bomblab

实验要求

本次实验设置了一系列“炸弹”需要我们拆除,每个阶段的炸弹需要我们输入相应的字符串,否则炸弹通过打印“BOOM!!!”爆炸。

实验内容

本项目给了三个文件
在这里插入图片描述
bomb:可执行程序,借助gdb进行反汇编和调试
bomb.c:bomb的源程序
README:注意事项

当直接运行时要求输入字符串,不符合标准直接爆炸。在这里插入图片描述
首先生成bomb的反汇编代码

objdump -d bomb > bomb.s

前置知识
寄存器含义

6331
%rax%eax返回值
%rbx%ebx被调用者保存
%rcx%ecx第四个参数
%rdx%edx第三个参数
%rsi%esi第二个参数
%rdi%edi第一个参数
%rbp%ebp第四个参数
%rsp%esp被调用者保存
%r8%r8d第五个参数
%r9%r9d第六个参数
%r10%r10d调用者保存
%r11%r11d调用者保存
%r12%r12d被调用者保存
%r13%r13d被调用者保存
%r14%r14d被调用者保存
%r15%r15d被调用者保存
 /* 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!

由源程序可知phase_1到6都是相同的格式,每个phase需要输入对应的一个字符串。

汇编代码阅读方法

第一步分段翻译理清逻辑,将跳转指令用if-else,goto代替,mov用赋值号代替
第二步将各段整合形成一个可读性良好的程序

如图是内存中一个程序的结构,用户栈是从高地址到低地址,因此汇编代码开始sub $0x28,%rsp是申请栈空间。
在这里插入图片描述

phase_1

0000000000400ee0 <phase_1>:
  400ee0:       48 83 ec 08             sub    $0x8,%rsp
  400ee4:       be 00 24 40 00          mov    $0x402400,%esi
  400ee9:       e8 4a 04 00 00          callq  401338 <strings_not_equal>
  400eee:       85 c0                   test   %eax,%eax
  400ef0:       74 05                   je     400ef7 <phase_1+0x17>
  400ef2:       e8 43 05 00 00          callq  40143a <explode_bomb>
  400ef7:       48 83 c4 08             add    $0x8,%rsp
  400efb:       c3                      retq

在phase_1函数处打一个断点,然后运行

b phase_1
run

进入反汇编窗口

layout a

由上述寄存器含义可知,edi里存储我们写入字符串地址,esi里存储第二个参数供strings_not_equal函数调用。
在这里插入图片描述
打印0x402400处存储的字符串为:Border relations with Canada have never been better.而我们输入的字符串地址在edi中打印为s。
运行到test处查看eax中的值为1。
.

i r #查看所有寄存器的值

由此可知,当输入字符串与目标字符串不等时返回1,否则返回0。
由test和je两个指令可知当eax为0时才会跳转,否则会调用expload_bomb。
因此第一个阶段我们要输入的字符串是

Border relations with Canada have never been better.

在这里插入图片描述

phase_2

0000000000400efc <phase_2>:
  400efc:       55                      push   %rbp
  400efd:       53                      push   %rbx
  400efe:       48 83 ec 28             sub    $0x28,%rsp
  400f02:       48 89 e6                mov    %rsp,%rsi
  400f05:       e8 52 05 00 00          callq  40145c <read_six_numbers>
  400f0a:       83 3c 24 01             cmpl   $0x1,(%rsp)
  400f0e:       74 20                   je     400f30 <phase_2+0x34>
  400f10:       e8 25 05 00 00          callq  40143a <explode_bomb>
  400f15:       eb 19                   jmp    400f30 <phase_2+0x34>
  400f17:       8b 43 fc                mov    -0x4(%rbx),%eax
  400f1a:       01 c0                   add    %eax,%eax
  400f1c:       39 03                   cmp    %eax,(%rbx)
  400f1e:       74 05                   je     400f25 <phase_2+0x29>
  400f20:       e8 15 05 00 00          callq  40143a <explode_bomb>
  400f25:       48 83 c3 04             add    $0x4,%rbx
  400f29:       48 39 eb                cmp    %rbp,%rbx
  400f2c:       75 e9                   jne    400f17 <phase_2+0x1b>
  400f2e:       eb 0c                   jmp    400f3c <phase_2+0x40>
  400f30:       48 8d 5c 24 04          lea    0x4(%rsp),%rbx
  400f35:       48 8d 6c 24 18          lea    0x18(%rsp),%rbp
  400f3a:       eb db                   jmp    400f17 <phase_2+0x1b>
  400f3c:       48 83 c4 28             add    $0x28,%rsp
  400f40:       5b                      pop    %rbx
  400f41:       5d                      pop    %rbp
  400f42:       c3                      retq

将汇编代翻译思路,翻译成相近的C语言
分段翻译

phase_2:
	rsi = rsp
	callq <read_six_numbers>
	if(*rsp == 1)
		goto 400f30;
	else 
		call explode_bomb;
	goto 400f30;
400f17:
	eax = *(rbx-4);
	eax += eax;
	if (eax == *rbx)
		goto 400f25;
	else 
		callq explode_bomb;
400f25:
	rbx += 4;			
	if (rbx != rbp)
		goto 400f17;	
	else 
		goto 400f3c;
400f30:
	rbx = rsp + 4;		
	rbp = rsp + 24;		
	goto 400f17;
400f3c:
	retq

由分段翻译版代码第一段可以得知本阶段我们要读入6个数字,并且如果第一个数字不为1则立即爆炸。
跳转到400f30地址处后进行赋值操作,由于一个数字占4b,因此rbx存储输入的第二个数字的地址,rbp存储结束位置。
跳转到400f17地址处,首先eax重新获取输入的第一个数,进行翻倍并与rbx所指向的第二个数比较,如果不相等则立即爆炸。因此输入的第二个数字应该是第一个数字的两倍。
跳转到400f25地址处,rbx获取下一个数字的地址并判断是否到结束处,如果未到则重新跳转到400f17处,否则结束。
通过以上分析可知这是一个循环结构,输入的第一个数字是1,之后每次判断后一个数是否是前一个数的两倍。
因此本题的答案是1 2 4 8 16 32
在这里插入图片描述

phase_3

0000000000400f43 <phase_3>:
  400f43:       48 83 ec 18             sub    $0x18,%rsp
  400f47:       48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  400f4c:       48 8d 54 24 08          lea    0x8(%rsp),%rdx
  400f51:       be cf 25 40 00          mov    $0x4025cf,%esi
  400f56:       b8 00 00 00 00          mov    $0x0,%eax
  400f5b:       e8 90 fc ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  400f60:       83 f8 01                cmp    $0x1,%eax
  400f63:       7f 05                   jg     400f6a <phase_3+0x27>
  400f65:       e8 d0 04 00 00          callq  40143a <explode_bomb>
  400f6a:       83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)
  400f6f:       77 3c                   ja     400fad <phase_3+0x6a>
  400f71:       8b 44 24 08             mov    0x8(%rsp),%eax
  400f75:       ff 24 c5 70 24 40 00    jmpq   *0x402470(,%rax,8)
  400f7c:       b8 cf 00 00 00          mov    $0xcf,%eax
  400f81:       eb 3b                   jmp    400fbe <phase_3+0x7b>
  400f83:       b8 c3 02 00 00          mov    $0x2c3,%eax
  400f88:       eb 34                   jmp    400fbe <phase_3+0x7b>
  400f8a:       b8 00 01 00 00          mov    $0x100,%eax
  400f8f:       eb 2d                   jmp    400fbe <phase_3+0x7b>
  400f91:       b8 85 01 00 00          mov    $0x185,%eax
  400f96:       eb 26                   jmp    400fbe <phase_3+0x7b>
  400f98:       b8 ce 00 00 00          mov    $0xce,%eax
  400f9d:       eb 1f                   jmp    400fbe <phase_3+0x7b>
  400f9f:       b8 aa 02 00 00          mov    $0x2aa,%eax
  400fa4:       eb 18                   jmp    400fbe <phase_3+0x7b>
  400fa6:       b8 47 01 00 00          mov    $0x147,%eax
  400fab:       eb 11                   jmp    400fbe <phase_3+0x7b>
  400fad:       e8 88 04 00 00          callq  40143a <explode_bomb>
  400fb2:       b8 00 00 00 00          mov    $0x0,%eax
  400fb7:       eb 05                   jmp    400fbe <phase_3+0x7b>
  400fb9:       b8 37 01 00 00          mov    $0x137,%eax
  400fbe:       3b 44 24 0c             cmp    0xc(%rsp),%eax
  400fc2:       74 05                   je     400fc9 <phase_3+0x86>
  400fc4:       e8 71 04 00 00          callq  40143a <explode_bomb>
  400fc9:       48 83 c4 18             add    $0x18,%rsp
  400fcd:       c3                      retq

分段翻译

phase_3
	rcx = rsp + 0xc;
	rdx = rsp + 0x8;
	esi = 0x4025cf;
	eax = 0;	
	call scanf
	if (eax <= 1)
		explode_bomb();
	if(*(rsp + 8) > 7)
		explode_bomb();
	goto *(0x402470+rax*8);
400f7c:
	eax = 0xcf;
	goto 400fbe;
400f83:
	eax = 0x2c3;
	goto 400fbe;
400f8a:
	eax = 0x100;
	goto 400fbe;
400f91:
	eax = 0x185;
	goto 400fbe;
400f98:
	eax = 0xce;
	goto 400fbe;
400f9f:
	eax = 0x2aa;
	goto 400fbe;
400fa6:
	eax = 0x147;
	goto 400fbe;
	eax = 0;
	goto 400fbe;
400fb9:
	eax = 0x137;
400fbe:
	if (eax != *(rsp+0xc))
		explode_bomb();
	retq;
}

查阅资料得知scanf函数需要占位符%s,是用于存放字符串的地址
在这里插入图片描述
打印可知在esi里存储占位符,需要输入两个整数。
打印rsp + 8处的值发现是我们输入的第一个参数。当参数大于7时会爆炸,因此第一个参数时0-7。
在这里插入图片描述
此操作jmpq 0x402470(,%rax,8)用于直接跳转到存储在的绝对地址8 * %rax + 0x402470
由此可知当rax内值不同时会跳转到不同的地址,具体地址就是0x402470+rax
8所存的数值
由于合法输入是0-7,因此打印0x402470后的8个地址即可。

x/8a 0x402470

在这里插入图片描述
由对应关系可知

00x400f7c0xcf207
10x400fb90x137311
20x400f830x2c3707
30x400f8a0x100256
40x400f910x185389
50x400f980xce206
60x400f9f0x2aa682
70x400fa60x147327

最后比较eax和rsp+0xc的大小是否相等,打印rsp+0xc发现是我们输入的第二个参数。
本实验是swich-case语句的汇编代码,合法的输入有

01234567
207311707256389206682327

在这里插入图片描述

phase_4

000000000040100c <phase_4>:
  40100c:       48 83 ec 18             sub    $0x18,%rsp
  401010:       48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  401015:       48 8d 54 24 08          lea    0x8(%rsp),%rdx
  40101a:       be cf 25 40 00          mov    $0x4025cf,%esi
  40101f:       b8 00 00 00 00          mov    $0x0,%eax
  401024:       e8 c7 fb ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  401029:       83 f8 02                cmp    $0x2,%eax
  40102c:       75 07                   jne    401035 <phase_4+0x29>
  40102e:       83 7c 24 08 0e          cmpl   $0xe,0x8(%rsp)
  401033:       76 05                   jbe    40103a <phase_4+0x2e>
  401035:       e8 00 04 00 00          callq  40143a <explode_bomb>
  40103a:       ba 0e 00 00 00          mov    $0xe,%edx
  40103f:       be 00 00 00 00          mov    $0x0,%esi
  401044:       8b 7c 24 08             mov    0x8(%rsp),%edi
  401048:       e8 81 ff ff ff          callq  400fce <func4>
  40104d:       85 c0                   test   %eax,%eax
  40104f:       75 07                   jne    401058 <phase_4+0x4c>
  401051:       83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)
  401056:       74 05                   je     40105d <phase_4+0x51>
  401058:       e8 dd 03 00 00          callq  40143a <explode_bomb>
  40105d:       48 83 c4 18             add    $0x18,%rsp
  401061:       c3                      retq

分段翻译

phase_4
	rcx = rsp + 12;	
	rdx = rsp + 8;	
	rsi = 0x4025cf;	
    rax = 0;
	callq sscanf;
	if (rax != 2) {
		explode_bomb();
	}
	if (0x8(rsp) <= 14) {
		goto 40103a;
	} else {
		explode_bomb();
	}
40103a:
	edx = 14;
	rsi = 0;
	rdi = 0x8(rsp);	
	goto func4;
	if (rax != 0) {	
		explode_bomb();
	}
	if (0xc(rsp) == 0) {
		goto 40105d;
	}
40105d:
	return;
}

首先查看scanf的输入格式,需要输入两个整数。
在这里插入图片描述
rsp+8是第一个参数,当大于14会爆炸
在这里插入图片描述
由上述寄存器含义可知rdi(输入的第一个参数),rsi=0,edx=14分别存储参数1,参数2,参数3调用fun4
当返回值不为0时爆炸。
由于0xc(rsp)处是第二个参数所以必须为0。
接下来分析fun4

0000000000400fce <func4>:
  400fce:       48 83 ec 08             sub    $0x8,%rsp
  400fd2:       89 d0                   mov    %edx,%eax
  400fd4:       29 f0                   sub    %esi,%eax
  400fd6:       89 c1                   mov    %eax,%ecx
  400fd8:       c1 e9 1f                shr    $0x1f,%ecx
  400fdb:       01 c8                   add    %ecx,%eax
  400fdd:       d1 f8                   sar    %eax
  400fdf:       8d 0c 30                lea    (%rax,%rsi,1),%ecx
  400fe2:       39 f9                   cmp    %edi,%ecx
  400fe4:       7e 0c                   jle    400ff2 <func4+0x24>
  400fe6:       8d 51 ff                lea    -0x1(%rcx),%edx
  400fe9:       e8 e0 ff ff ff          callq  400fce <func4>
  400fee:       01 c0                   add    %eax,%eax
  400ff0:       eb 15                   jmp    401007 <func4+0x39>
  400ff2:       b8 00 00 00 00          mov    $0x0,%eax
  400ff7:       39 f9                   cmp    %edi,%ecx
  400ff9:       7d 0c                   jge    401007 <func4+0x39>
  400ffb:       8d 71 01                lea    0x1(%rcx),%esi
  400ffe:       e8 cb ff ff ff          callq  400fce <func4>
  401003:       8d 44 00 01             lea    0x1(%rax,%rax,1),%eax
  401007:       48 83 c4 08             add    $0x8,%rsp
  40100b:       c3                      retq
fun4
	eax = edx;
	eax -= esi;
	ecx = eax;
	
	ecx >>= 31;
	eax += ecx;
	eax >>= 1;		
			
	ecx = rax + rsi;		
	if (ecx <= edi) {
		goto 400ff2;
	}
	edx = rcx - 1;
	goto func4;				
	eax += eax;
	goto 401007;
400ff2:
	eax = 0;
	if (ecx >= edi) {	
		goto 401007;
	}
	esi = rcx + 1;
	goto func4;	
	eax = rax + rax + 1;
401007:
	return;

进一步化简

fun4
	eax = edx - esi;
	eax = (eax + eax >> 31) >> 1;
	ecx = rax + rsi;
	if (ecx <= edi) {
		eax = 0;
        if (ecx >= edi) {
        	//当ecx=edi时返回。
            return;
        }
        esi = rcx + 1;
        rax = func4(edi, esi, edx);
        eax = 2 * rax + 1;
	}
	else {
        edx = rcx - 1;
        rax = func4(edi, esi, edx);
        eax = 2 * rax;	
	}
	retq;

本段代码是一个递归程序,实现的功能是二分查找。上下限已经确定为14和0,由于我们最后要得到eax=0,需要在ecx <= edi里赋值,当ecx >= edi时返回,即ecx = edi 时返回,满足条件的值为7。这里的答案为7 0
在这里插入图片描述

phase_5

0000000000401062 <phase_5>:
  401062:       53                      push   %rbx
  401063:       48 83 ec 20             sub    $0x20,%rsp
  401067:       48 89 fb                mov    %rdi,%rbx
  40106a:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  401071:       00 00 
  401073:       48 89 44 24 18          mov    %rax,0x18(%rsp)
  401078:       31 c0                   xor    %eax,%eax
  40107a:       e8 9c 02 00 00          callq  40131b <string_length>
  40107f:       83 f8 06                cmp    $0x6,%eax
  401082:       74 4e                   je     4010d2 <phase_5+0x70>
  401084:       e8 b1 03 00 00          callq  40143a <explode_bomb>
  401089:       eb 47                   jmp    4010d2 <phase_5+0x70>
  40108b:       0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx
  40108f:       88 0c 24                mov    %cl,(%rsp)
  401092:       48 8b 14 24             mov    (%rsp),%rdx
  401096:       83 e2 0f                and    $0xf,%edx
  401099:       0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx
  4010a0:       88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)
  4010a4:       48 83 c0 01             add    $0x1,%rax
  4010a8:       48 83 f8 06             cmp    $0x6,%rax
  4010ac:       75 dd                   jne    40108b <phase_5+0x29>
  4010ae:       c6 44 24 16 00          movb   $0x0,0x16(%rsp)
  4010b3:       be 5e 24 40 00          mov    $0x40245e,%esi
  4010b8:       48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  4010bd:       e8 76 02 00 00          callq  401338 <strings_not_equal>
  4010c2:       85 c0                   test   %eax,%eax
  4010c4:       74 13                   je     4010d9 <phase_5+0x77>
  4010c6:       e8 6f 03 00 00          callq  40143a <explode_bomb>
  4010cb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
  4010d0:       eb 07                   jmp    4010d9 <phase_5+0x77>
  4010d2:       b8 00 00 00 00          mov    $0x0,%eax
  4010d7:       eb b2                   jmp    40108b <phase_5+0x29>
  4010d9:       48 8b 44 24 18          mov    0x18(%rsp),%rax
  4010de:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4010e5:       00 00 
  4010e7:       74 05                   je     4010ee <phase_5+0x8c>
  4010e9:       e8 42 fa ff ff          callq  400b30 <__stack_chk_fail@plt>
  4010ee:       48 83 c4 20             add    $0x20,%rsp
  4010f2:       5b                      pop    %rbx
  4010f3:       c3                      retq

分段

phase_5
	rbx = rdi;
	rax = fs:0x28;
	*(rsp+0x18) = rax;
	eax = eax ^ eax;
	callq string_length;
	if (eax == 6) {
		goto 4010d2;
	}
	else callq explode_bomb; //因此输入字符串长度必须为6
	goto 4010d2;
40108b:
	ecx = rbx + rax;//rbx存放字符串首地址,ecx = str[rax]
	*rsp = cl; 
	rdx = *rsp;//rdx = str[rax]
	edx = edx & 0xf; //取后四位
	edx = rdx + 0x4024b0; //偏移地址
	*(rsp+rax+0x10) = dl;	
	rax += 1;	//循环
	if (rax != 6)
		goto 40108b;
	*(rsp + 0x16) = 0; //末尾'\0'
	esi = 0x40245e;
	rdi = rsp + 10; //比较新取到的6个字符
	callq strings_not_equal;
	if (eax == 0)
		callq explode_bomb;
	goto 4010d9;
4010d2:
	eax = 0;
	goto 40108b;
4010d9:
	rax = *(rsp + 0x18);
	rax = rax ^ fs:0x28;
	if (rax == 0)			# 栈是否被破坏
		goto 4010ee;
	else
		callq __stack_chk_fail@plt;
4010ee:
	retq;

从第一段可知要求我们输入长度为6的字符串,否则爆炸。4010d2处是将eax重新赋值为0。
打印0x4024b0,得到一串字符串。

打印0x40245e得到字符串
在这里插入图片描述
40108b段的整体逻辑是以输入字符的ASCALL码后四位作为偏移量在“maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?”里选择字符,最终要和“flyers”匹配。答案不唯一,在ASCALL码表里选择符合条件的一组即可。

目标字符flyers
偏移量91514567
输入字符IONEFG

汇编指令:
sub
mov
callq
test
je
add
retq
gdb
lab2
ja
jg
jmp()
lea

gdb指令:
objdump -d bomb > bomb.s
文件类型
stepi
finish
打断点
b 行号,地址,函数
layout a
examine命令(简写是x)来查看内存地址中的值。
x/<n/f/u>
n、f、u是可选的参数。

n是一个正整数,表示需要显示的内存单元的个数,也就是说从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义。

f 表示显示的格式,参见下面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。

u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

表示一个内存地址。

注意:严格区分n和u的关系,n表示单元个数,u表示每个单元的大小。

n/f/u三个参数可以一起使用。例如:

命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示输出三个单位,u表示按无符号十进制显示。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值