BombLab 实验详解
2024/10/22
一、文件/工具
- bomb38(可执行文件名)
- bomb.c
- gdb
二、准备工作
1. 生成反汇编文件
执行:
objdump-d bomb38 > bomb38.asm
获得反汇编文件bomb38.asm,便于整体阅读。
2. 阅读bomb.c
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;
}
通过阅读bomb.c
,可以知道拆弹过程共分7阶段,phase_1~6以及最后的隐藏阶段。每一阶段系统从输入中读一行字符串,输入可以是标准输入stdin
或从命令行参数中指定的文件中获得。我们在程序目录下新建一个文本文档solution.txt
作为运行时的命令行参数,每解开一阶段,将该阶段的答案追加到其中。注意,将每一题的答案写入solution.txt
后,行尾需要有一个换行符。
3. 用到的C库函数
phase_1~6中用到的不熟悉的C库函数有sscanf
和strtol
。
-
sscanf
声明
int sscanf(const char *str, const char *format, ...)
参数
sscanf
与scanf
相似,只是scanf
的字符串源为标准输入,而sscanf
的字符串源是传入的第一个参数str
。第二个参数为解读格式,后面的附加参数即为解读后的变量要存储的地址。
返回值
如果成功,该函数返回成功匹配和赋值的个数,否则返回
EOF
。 -
strtol
(即string to long)声明
long strtol(const char *str, char **endptr, int base)
参数
str
为要转换成long
类型的字符串,endptr
的值由函数指向str
中有效数字后的下一个字符(如果字符串是纯数字*endptr == '\0'
),base
决定把str
转为几进制。返回值
返回转换成的
long
类型值。如果输入字符串不是纯数字,返回0
。
4 . 常用gdb命令
参考yanbinghu.com/2019/04/20/41283.html。
5. 约定
把寄存器%rdi
,%rsi
,…中存放的变量依次称为arg1
,arg2
,…。
三、实验过程
phase_1
00000000000015e7 <phase_1>:
15e7: f3 0f 1e fa endbr64
15eb: 48 83 ec 08 sub $0x8,%rsp # 维护栈帧
15ef: 48 8d 35 5a 1b 00 00 lea 0x1b5a