Binary Bomb
Introduction
The nefarious Dr. Evil has planted a slew of “binary bombs” on our machines. A binary bomb is a program that consists of a sequence of phases. Each phase expects you to type a particular string on stdin. If you type the correct string, then the phase is defused and the bomb proceeds to the next phase. Otherwise, the bomb explodes by printing “BOOM!!!” and then terminating. The bomb is defused when every phase has been defused.
There are too many bombs for us to deal with, so we are giving each student a bomb to defuse. Your mission, whom you have no choice but to accept, is to defuse your bomb before the due date. Good luck, and welcome to the bomb squad!
Get Your Bomb
通过SVN获得,之前已经进行了连接,所以只需$ svn update
即可获得lab2文件夹,包含以下三个文件:
- README: 主要是用于判断这个Bomb是不是你的,里面包含bomb的编号和你的学号
- bomb: 就是一个可执行文件,但是可以通过反汇编
objdump -d bomb > <object_file>
得到汇编文件 - bomb.c: bomb主线的源文件,其实没什么东西,但是看着挺有趣的,有一些作者自言自语的话,自带萌点(嘤)。主要的提示就是不要直接双击运行bomb文件,因为这样相当于什么参数都不给,所以它就会一直爆炸(T^T)。代码贴在下面:
/***************************************************************************
* Dr. Evil's Insidious Bomb, Version 1.0
* Copyright 2002, 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 "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;
}
Defuse Your Bomb
- 一共有6个phase(各10分)加一个secret_phase(5分),从第四次爆炸开始一次bomb扣一分,所以可以白炸三次2333(为了少扣分,先把explode_bomb和phase_defused两个函数加上断点,发现即将爆炸就kill调试进程)
- 可以将已经知道的答案写在文档里面,在命令行运行bomb直接读取,例如:
$./bomb psol.txt //psol.txt的每一行分别为一个phase的答案
Tools
- gdb
The GNU debugger, this is a command line debugger tool available on virtually every platform. You can trace through a program line by line, examine memory and registers, look at both the source code and assembly code (we are not giving you the source code for most of your bomb), set breakpoints, set memory watch points, and write scripts. Here are some tips for usinggdb
.- To keep the bomb from blowing up every time you type in a wrong input, you’ll want to learn how to set breakpoints.
- For other documentation, type
help
at the gdb command prompt, or typeman gdb
, orinfo gdb
at a Unix prompt. Some people also like to run gdb under gdb-mode in emacs. - http://ipads.se.sjtu.edu.cn/courses/ics/tutorials/gdb-ref.txt
- objdump -t
This will print out the bomb’s symbol table. The symbol table includes the
names of all functions and global variables in the bomb, the names of all the functions the bomb calls, and their addresses. You may learn something by looking at the function names! - objdump -d
Use this to disassemble all of the code in the bomb. You can also just look at individual functions. Reading the assembler code can tell you how the bomb works. Althoughobjdump -d
gives you a lot of information, it doesn’t tell you the whole story. Calls to system-level functions are displayed in a cryptic form. For example, a call toprintf
might appear as:
To determine that the call was to171d: e8 6e f8 ff ff callq f90 <printf@plt>
printf
, you would need to disassemble withingdb
. - strings
This utility will display the printable strings in your bomb.
Special
objdump -d
之后的地址并不一定是真的地址,但是相对偏移量是对的。所以可以先gdb bomb
,在main函数这里设一个断点break main
,然后运行程序run
,程序会在断点处停止并显示main的真正地址,计算真正地址与反汇编后的地址之间的偏移量,将反汇编文件中的地址加上偏移量可以得到真正的地址,之后就可以进行正常的设置断点和调试了
Phase 1
- 代码如下:
00000000000013b0 <phase_1>: 13b0: 48 83 ec 08 sub $0x8,%rsp 13b4: 48 8d 35 55 10 00 00 lea 0x1055(%rip),%rsi # 2410 <_IO_stdin_used+0x150> 13bb: e8 43 04 00 00 callq 1803 <strings_not_equal> 13c0: 85 c0 test %eax,%eax 13c2: 75 05 jne 13c9 <phase_1+0x19> 13c4: 48 83 c4 08 add $0x8,%rsp 13c8: c3 retq 13c9: e8 45 0c 00 00 callq 2013 <explode_bomb> 13ce: eb f4 jmp 13c4 <phase_1+0x14>
- 分析:
这个bomb比较简单,首先联网拿到对应的string
然后调用函数,从名字上来看是判断两个字符串是否相等lea 0x1055(%rip),%rsi # 2410 <_IO_stdin_used+0x150>
用13bb: e8 43 04 00 00 callq 1803 <strings_not_equal>
test
判断返回值是否为0
不为0就爆炸13c0: 85 c0 test %eax,%eax
所以这个时候猜都能猜到是要输入13c2: 75 05 jne 13c9 <phase_1+0x19> 13c9: e8 45 0c 00 00 callq 2013 <explode_bomb>
%rsi
中的字符串,直接x $rsi
或者一个字符一个字符的print
出来也行。如果不放心,可以到<strings_not_equal>
函数里面再去看一看,代码如下:
发现就是先比较两个字符串的长度,如果相等再逐个比较字符,并没有什么用0000000000001803 <strings_not_equal>: 1803: 41 54 push %r12 1805: 55 push %rbp 1806: 53 push %rbx 1807: 48 89 fb mov %rdi,%rbx 180a: 48 89 f5 mov %rsi,%rbp 180d: e8 d3 ff ff ff callq 17e5 <string_length> 1812: 41 89 c4 mov %eax,%r12d 1815: 48 89 ef mov %rbp,%rdi 1818: e8 c8 ff ff ff callq 17e5 <string_length> 181d: ba 01 00 00 00 mov $0x1,%edx 1822: 41 39 c4 cmp %eax,%r12d 1825: 74 07 je 182e <strings_not_equal+0x2b> 1827: 89 d0 mov %edx,%eax 1829: 5b pop %rbx 182a: 5d pop %rbp 182b: 41 5c pop %r12 182d: c3 retq 182e: 0f b6 03 movzbl (%rbx),%eax 1831: 84 c0 test %al,%al 1833: 74 27 je 185c <strings_not_equal+0x59> 1835: 3a 45 00 cmp 0x0(%rbp),%al 1838: 75 29 jne 1863 <strings_not_equal+0x60> 183a: 48 83 c3 01 add $0x1,%rbx 183e: 48 83 c5 01 add $0x1,%rbp 1842: 0f b6 03 movzbl (%rbx),%eax 1845: 84 c0 test %al,%al 1847: 74 0c je 1855 <strings_not_equal+0x52> 1849: 3a 45 00 cmp 0x0(%rbp),%al 184c: 74 ec je 183a <strings_not_equal+0x37> 184e: ba 01 00 00 00 mov $0x1,%edx 1853: eb d2 jmp 1827 <strings_not_equal+0x24> 1855: ba 00 00 00 00 mov $0x0,%edx 185a: eb cb jmp 1827 <strings_not_equal+0x24> 185c: ba 00 00 00 00 mov $0x0,%edx 1861: eb c4 jmp 1827 <strings_not_equal+0x24> 1863: ba 01 00 00 00 mov $0x1,%edx 1868: eb bd jmp 1827 <strings_not_equal+0x24>
- 结果:
When I get angry, Mr. Bigglesworth gets upset.
Phase 2
- 代码如下:
00000000000013d0 <phase_2>: 13d0: 55 push %rbp 13d1: 53 push %rbx 13d2: 48 83 ec 28 sub $0x28,%rsp 13d6: 48 89 e6 mov %rsp,%rsi 13d9: e8 71 0c 00 00 callq 204f <read_six_numbers> 13de: 83 3c 24 01 cmpl $0x1,(%rsp) 13e2: 74 05 je 13e9 <phase_2+0x19> 13e4: e8 2a 0c 00 00 callq 2013 <explode_bomb> 13e9: 48 89 e5 mov %rsp,%rbp 13ec: bb 01 00 00 00 mov $0x1,%ebx 13f1: eb 09 jmp 13fc <phase_2+0x2c> 13f3: 48 83 c5 04 add $0x4,%rbp 13f7: 83 fb 06 cmp $0x6,%ebx 13fa