CSAPP实验记录(2)--------- Bomb
创始人
2024-01-21 07:38:56

实验简介

本实验需要拆除一个“二进制炸弹”,“二进制炸弹”是一个可执行目标程序。运行时,它会提示用户键入6个不同的字符串。如果其中任何一个错误,炸弹就会“爆炸”。必须通过逆向工程和汇编语言知识,推导出六个字符串分别是什么。从而拆除炸弹。

开始实验

下载实验包后,会解压得到一个bomb.c源码和bomb.o可执行目标文件。bomb.c源码如下:

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 , the bomb reads from  * until EOF, and then switches to standard input. Thus, as you * defuse each phase, you can add its defusing string to  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 []\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;
}

可以看到代码中有许多没有给出定义(其实是定义在spport.h头文件中,这个头文件没有给出)的函数,也就是说我们仅仅通过bomb.c代码是不能得知我们要输入的六个字符串的,不过好在题目给出了代码编译出的可执行目标文件bomb.o,这样我们就有机会通过逆向工程确定bomb.c的源码了。
接下来运行可执行目标文件bomb.o,先随便输入个abc试一试效果:

在这里插入图片描述
果然会爆炸。。
看来现在可以对bomb.o的汇编代码进行分析了,使用objdump工具,将bomb.o的反汇编代码导入到txt文件中,这里我用
下面是主函数的反汇编代码:

0000000000400da0 
:400da0: 53 push %rbx400da1: 83 ff 01 cmp $0x1,%edi400da4: 75 10 jne 400db6 400da6: 48 8b 05 9b 29 20 00 mov 0x20299b(%rip),%rax # 603748 400dad: 48 89 05 b4 29 20 00 mov %rax,0x2029b4(%rip) # 603768 400db4: eb 63 jmp 400e19 400db6: 48 89 f3 mov %rsi,%rbx400db9: 83 ff 02 cmp $0x2,%edi400dbc: 75 3a jne 400df8 400dbe: 48 8b 7e 08 mov 0x8(%rsi),%rdi400dc2: be b4 22 40 00 mov $0x4022b4,%esi400dc7: e8 44 fe ff ff callq 400c10 400dcc: 48 89 05 95 29 20 00 mov %rax,0x202995(%rip) # 603768 400dd3: 48 85 c0 test %rax,%rax400dd6: 75 41 jne 400e19 400dd8: 48 8b 4b 08 mov 0x8(%rbx),%rcx400ddc: 48 8b 13 mov (%rbx),%rdx400ddf: be b6 22 40 00 mov $0x4022b6,%esi400de4: bf 01 00 00 00 mov $0x1,%edi400de9: e8 12 fe ff ff callq 400c00 <__printf_chk@plt>400dee: bf 08 00 00 00 mov $0x8,%edi400df3: e8 28 fe ff ff callq 400c20 400df8: 48 8b 16 mov (%rsi),%rdx400dfb: be d3 22 40 00 mov $0x4022d3,%esi400e00: bf 01 00 00 00 mov $0x1,%edi400e05: b8 00 00 00 00 mov $0x0,%eax400e0a: e8 f1 fd ff ff callq 400c00 <__printf_chk@plt>400e0f: bf 08 00 00 00 mov $0x8,%edi400e14: e8 07 fe ff ff callq 400c20 400e19: e8 84 05 00 00 callq 4013a2 400e1e: bf 38 23 40 00 mov $0x402338,%edi400e23: e8 e8 fc ff ff callq 400b10 400e28: bf 78 23 40 00 mov $0x402378,%edi400e2d: e8 de fc ff ff callq 400b10 400e32: e8 67 06 00 00 callq 40149e 400e37: 48 89 c7 mov %rax,%rdi400e3a: e8 a1 00 00 00 callq 400ee0 400e3f: e8 80 07 00 00 callq 4015c4 400e44: bf a8 23 40 00 mov $0x4023a8,%edi400e49: e8 c2 fc ff ff callq 400b10 400e4e: e8 4b 06 00 00 callq 40149e 400e53: 48 89 c7 mov %rax,%rdi400e56: e8 a1 00 00 00 callq 400efc 400e5b: e8 64 07 00 00 callq 4015c4 400e60: bf ed 22 40 00 mov $0x4022ed,%edi400e65: e8 a6 fc ff ff callq 400b10 400e6a: e8 2f 06 00 00 callq 40149e 400e6f: 48 89 c7 mov %rax,%rdi400e72: e8 cc 00 00 00 callq 400f43 400e77: e8 48 07 00 00 callq 4015c4 400e7c: bf 0b 23 40 00 mov $0x40230b,%edi400e81: e8 8a fc ff ff callq 400b10 400e86: e8 13 06 00 00 callq 40149e 400e8b: 48 89 c7 mov %rax,%rdi400e8e: e8 79 01 00 00 callq 40100c 400e93: e8 2c 07 00 00 callq 4015c4 400e98: bf d8 23 40 00 mov $0x4023d8,%edi400e9d: e8 6e fc ff ff callq 400b10 400ea2: e8 f7 05 00 00 callq 40149e 400ea7: 48 89 c7 mov %rax,%rdi400eaa: e8 b3 01 00 00 callq 401062 400eaf: e8 10 07 00 00 callq 4015c4 400eb4: bf 1a 23 40 00 mov $0x40231a,%edi400eb9: e8 52 fc ff ff callq 400b10 400ebe: e8 db 05 00 00 callq 40149e 400ec3: 48 89 c7 mov %rax,%rdi400ec6: e8 29 02 00 00 callq 4010f4 400ecb: e8 f4 06 00 00 callq 4015c4 400ed0: b8 00 00 00 00 mov $0x0,%eax400ed5: 5b pop %rbx400ed6: c3 retq 400ed7: 90 nop400ed8: 90 nop400ed9: 90 nop400eda: 90 nop400edb: 90 nop400edc: 90 nop400edd: 90 nop400ede: 90 nop400edf: 90 nop

第一个炸弹

在这里插入图片描述

从bomb.c的代码片段可以看出,每道题目都是由一个函数开始的,我们在反汇编代码中找到phase_1的代码:

0000000000400ee0 :400ee0:	48 83 ec 08          	sub    $0x8,%rsp400ee4:	be 00 24 40 00       	mov    $0x402400,%esi400ee9:	e8 4a 04 00 00       	callq  401338 400eee:	85 c0                	test   %eax,%eax400ef0:	74 05                	je     400ef7 400ef2:	e8 43 05 00 00       	callq  40143a 400ef7:	48 83 c4 08          	add    $0x8,%rsp400efb:	c3                   	retq   

可以看到在第二行,程序将一个好像是地址的变量赋给了%esi,然后调用了函数,从字面上可以看出这个函数好像是判断字符串是否相等。
容易想到,mov $0x402400,%esi这句指令是在为调用构造参数,而此时寄存器%rdi的值并没有变,所以可以想到函数有两个参数,一个是位于 0x402400 位置的数据,另一个就是 本身的参数,也就是我们输入的字符串。
返回后,执行test指令,如果返回值不为0,那么就会执行这个显然是让炸弹爆炸的函数,我们不能让程序执行到这里。
然后找到 0x402400:发现其位于可执行目标文件的.rodata节:

在这里插入图片描述
在这里插入图片描述
也就是说,第一个炸弹的逻辑是,输入的字符串与程序中内置的格式串比对,相同就通过测试。观察0x402400处的字节序列,可以发现答案就Border relations with Canada have never been better.,这句话最后的句号坑了我很长时间,因为.rodata节里的不可见字符全都会显示成"."。总的来说第一个炸弹十分简单。

第二个炸弹

找到phase_2的反汇编代码部分:

0000000000400efc :400efc:	55                   	push   %rbp                            //被调用者保存寄存器400efd:	53                   	push   %rbx                            //被调用者保存寄存器400efe:	48 83 ec 28          	sub    $0x28,%rsp400f02:	48 89 e6             	mov    %rsp,%rsi400f05:	e8 52 05 00 00       	callq  40145c 400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)400f0e:	74 20                	je     400f30 400f10:	e8 25 05 00 00       	callq  40143a 400f15:	eb 19                	jmp    400f30 400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax400f1a:	01 c0                	add    %eax,%eax400f1c:	39 03                	cmp    %eax,(%rbx)400f1e:	74 05                	je     400f25 400f20:	e8 15 05 00 00       	callq  40143a 400f25:	48 83 c3 04          	add    $0x4,%rbx400f29:	48 39 eb             	cmp    %rbp,%rbx400f2c:	75 e9                	jne    400f17 400f2e:	eb 0c                	jmp    400f3c 400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp400f3a:	eb db                	jmp    400f17 400f3c:	48 83 c4 28          	add    $0x28,%rsp400f40:	5b                   	pop    %rbx400f41:	5d                   	pop    %rbp400f42:	c3                   	retq  

可以看到有一个叫的函数,字面意思是要读取6个数字的输入。而且注意到400f02: 48 89 e6 mov %rsp,%rsi,它似乎需要栈指针作为第二个参数,和第一个炸弹一样,此时%rdi同样没有改变,说明函数的第一个参数也是我们输入的字符串。

通过观察400f0e一行,可以得知调用后,如果栈指针处的值为1,那么将跳转到400f30(核心代码所在处),否则直接执行炸弹。那么我们可以猜想如果我们以正确的格式输入六个数字的话,栈指针此时一定是等于0x1的。我们可以找到的位置,看看这个函数到底做了什么。

000000000040145c :40145c:	48 83 ec 18          	sub    $0x18,%rsp401460:	48 89 f2             	mov    %rsi,%rdx401463:	48 8d 4e 04          	lea    0x4(%rsi),%rcx401467:	48 8d 46 14          	lea    0x14(%rsi),%rax40146b:	48 89 44 24 08       	mov    %rax,0x8(%rsp)401470:	48 8d 46 10          	lea    0x10(%rsi),%rax401474:	48 89 04 24          	mov    %rax,(%rsp)401478:	4c 8d 4e 0c          	lea    0xc(%rsi),%r940147c:	4c 8d 46 08          	lea    0x8(%rsi),%r8401480:	be c3 25 40 00       	mov    $0x4025c3,%esi401485:	b8 00 00 00 00       	mov    $0x0,%eax40148a:	e8 61 f7 ff ff       	callq  400bf0 <__isoc99_sscanf@plt>40148f:	83 f8 05             	cmp    $0x5,%eax401492:	7f 05                	jg     401499 401494:	e8 a1 ff ff ff       	callq  40143a 401499:	48 83 c4 18          	add    $0x18,%rsp40149d:	c3                   	retq   

可以看到整个函数的前半部分都在进行参数的构造,只是为了能够调用__isoc99_sscanf@plt,而之前我们推导过,这个函数的第二个参数%rsi其实是栈指针,也就是说这些操作%rsi的指令其实都是对栈指针的操作。这里的<__isoc99_sscanf>函数是动态链接进来的C标准库函数,在可执行目标文件里是看不到它的信息的,所以我们只能上网查这个函数的功能了。经过查资料,我大概可以知道这个函数在里的作用是,将输入的六个整数保存在 (%rsp),(%rsp+0x4),(%rsp+0x8),(%rsp+0xc),(%rsp+0x10),(%rsp+0x14),这六个位置。也就是栈上的一片地址连续的空间中。

然后就是从位置400f30处开始的核心代码了,可以看到指令定义了两个指针,%rbx和%rbp,一个指向 0x4(%rsp),一个指向 0x18(%rsp),这中间就是刚才我们输入的六个整数保存的位置。从:

  400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax400f1a:	01 c0                	add    %eax,%eax400f1c:	39 03                	cmp    %eax,(%rbx)400f1e:	74 05                	je     400f25 400f20:	e8 15 05 00 00       	callq  40143a 

这几句可以看出,程序不断将 %rbx 与 -0x4(%rbx) 对比,400f1a 一句表明当且仅当 (%rbx) 是 -0x4(%rbx)的二倍时,炸弹才不会爆炸。

  400f25:	48 83 c3 04          	add    $0x4,%rbx400f29:	48 39 eb             	cmp    %rbp,%rbx400f2c:	75 e9                	jne    400f17 

这三句又说明,%rbx只有和 %rbp 相等时,才能结束程序。否则将%rbx的值加4(一个int的大小),之后跳回400f17。这明显是一个循环语句。刚才我们了解到 %rbp = 0x18(rbx),也就是说当%rbx = %rbp时,程序刚好扫描到我们输入的六个数字,而且每个数字都应该是前一个的二倍,第一个数字等于 (%rsp) = 0x1,那么这个炸弹就被成功解开了。答案是:
1 2 4 8 16 32

第三个炸弹

截至最终更新时,作者已经解开了四个炸弹,但这个实验总归还是比较繁琐,还剩下两个没有解开,而且像这样详细地复盘也比较费时间,剩下的之后再补 😃 。

相关内容

热门资讯

长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
不用扬鞭自奋蹄 乘势而上千帆竞... 思明区正全力向“两个进位”目标发起冲刺,努力为建设高素质高颜值现代化国际化的厦门作出“思明贡献”。(...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
好听的民谣歌曲 2021最火的... #我的年度歌单#在2021年里听过很多民谣,但是最能触及心中温柔的还是下面的几首。不听民谣的理由有很...