Due: Friday March 4th, 11:59PM
The nefarious Dr. Evil has planted a slew of “binary bombs” on our class 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, which you have no choice but to accept, is to defuse your bomb before the due date. Good luck, and welcome to the bomb squad!
Step 1: Get Your Bomb
You can obtain your bomb by entering the following commands from your Linux account exactly as shown.
cd ~/cs224 curl -o bomb.tar -s -L "https://cs224.cs.vassar.edu/bomblab?username=$USER&usermail=$USER%40vassar.edu&submit=Submit"
Note you only should run the above command once! If you run the command multiple times, you will download multiple binary bombs and the grading server will get confused.
After running the above command, you should see tar file called
Linux> ls bomb.tar
To extract the tar file, run the following command:
tar -xf bomb.tar
This will create a directory called
./bombXX (where XX is your unique bomb number) with the following files:
READMEIdentifies the bomb and its owners.
bombThe executable binary bomb.
bomb.cSource file with the bomb’s main routine and a friendly greeting from Dr. Evil.
passwords.txtYour phrases for each of six stages, one line for each stage.
How_I_Solved_It.txtYour written description of how you solved each phase of the bomb.
MakefileUsed to submit the
Step 2: Defuse Your Bomb
Your job for this lab is to defuse your bomb.
You must do the assignment on one of the class machines. In fact, there is a rumor that Dr. Evil really is evil, and the bomb will always blow up if run elsewhere. There are several other tamper-proofing devices built into the bomb as well, or so we hear.
You can use many tools to help you defuse your bomb. Please look at the hints section for some tips and ideas. The best way is to use a debugger to step through the disassembled binary.
Each time your bomb explodes it notifies the bomblab server, and you lose 1/5 point (up to a max of 10 points) in the final score for the lab. So there are consequences to exploding the bomb. You must be careful!
The first phase is worth 10 points. Phases 2, 3, and 4 are little more difficult and are worth 20 points each. Phase 5 is worth 15 points, and Phase 6 is the most challenging, but only worth 5 points, so you can still do quite well on this lab without solving the last stage. The maximum score you can get from the stages is 90 points. In addition, you will document how you solved each stage
in the file
How_I_Solved_It.txt. This file is worth 10 points, so this lab is worth a total of 100 points.
Although phases get progressively harder to defuse, the expertise you gain as you move from phase to phase should offset this difficulty. However, the last phase is a bit challenging, so please don’t wait until the last minute to start.
The bomb ignores blank input lines. If you run your bomb with a command line argument, for example,
linux> ./bomb passwords.txt
then it will read the input lines from
passwords.txt until it reaches the EOF (end of file) and then switch over to
stdin. In a moment of weakness, Dr. Evil added this feature so you don’t have to keep retyping the solutions to phases you have already defused.
To avoid accidentally detonating the bomb, you will need to learn how to single-step through the assembly code and how to set breakpoints. You will also need to learn how to inspect both the registers and the memory states. One of the nice side-effects of doing the lab is that you will get very good at using a debugger. This is a crucial skill that will pay big dividends for the rest of your career.
gdb to defuse the bomb
Defusing bombs is a high-skill job. There are a number of tools you can use to help you. The most important of them is
gdb The GNU debugger. This debugger allows you to 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. You’ll find in the resource section of the class website.
To debug your bomb using gdb, you run your program inside the debugger. In your bomb directory, run the following command:
gdb -tui bomb
This starts the debugger in “text UI mode”. The screen is divided into two parts. The top part shows you the the C code that we have provided for you, and the bottom half shows you the command interface to the debugger. This window allows you to enter
gdb commands to run and step through your program. Let’s set a breakpoint and run our program.
(gdb) break main
gdb to stop the program execution when it hits the main function. We can now run our bomb program.
An important breakpoint to set is one for the
explode_bomb function. This is the function that gets called when you type in an incorrect password. It alerts me that you have exploded a bomb (and causes you to loose points). You should set a breakpoint here, so if you accidentally explode the bomb, you will stop the program execution before I am notified. You should set this breakpoint every time you start
Now we can run our bomb in the debugger.
(gdb) run passwords.txt
This will run our program and stop at main. You can step through the program one line at a time with the
next command. Try it. As you see, the next command treats a function call as a single line of code. If you want to ‘step into’ a function call, you would use the
step command, which goes into a function.
Try putting in a break point in phase_1, using the
break command that we described above. Now to start the program running again, type the
continue command at the gdb prompt.
When you hit the breakpoint for
phase_1 no source is shown, because we haven’t given that to you! Fear not, you can use
gdb to look at the assembly code, and step through that, just like you did with the C code.
To see the registers and assembly code, you need to change the layout with the following gdb command:
(gdb) layout asm
To see the contents of registers use the gdb command
layout regs. This will
bring up a register window.
To move through the program we can use the
stepi commands. They work just like
step but work at the assembly language level.
For online documentation, type
help at the
gdb command prompt, or type
man gdb, or
info gdb at a Linux prompt and the section on TUI mode in the GDB manual.
Submitting your assignment
This is an individual project. All handins are electronic. Clarifications and corrections will be posted to the class website.
The bomb will notify your instructor automatically about your progress as you work on it. You can keep track of how you are doing by looking at the class scoreboard at:
This web page is updated continuously to show the progress for each bomb.
In your directory where your binary bomb is located, there is a file called
How_I_Solved_It.txt. In this file you will described how you solved each
stage. Discuss how you reverse engineered each stage to get your solution and
describe what you think each stage is doing. We recommend that as soon as you
solve a stage, fill out that stage’s section in
How_I_Solved_It.txt when it is
fresh in your mind. Don’t wait till the end to write this file.
To submit your assigment upload the
How_I_Solved_It.txt file to gradescope.
Hints: Please read this!
There are many ways of defusing your bomb. You can examine it in great detail without ever running the program, and figure out exactly what it does. This is a useful technique, but it not always easy to do. You can also run it under a debugger, watch what it does step by step, and use this information to defuse it. This is probably the fastest way of defusing it.
We do make one request, please do not use brute force! You could write a program that will try every possible key to find the right one. But this is no good for several reasons:
- You lose 1/5 point (up to a max of 10 points) every time you guess incorrectly and the bomb explodes.
- Every time you guess wrong, a message is sent to the bomblab server. You could very quickly saturate the network with these messages.
- We haven’t told you how long the strings are, nor have we told you what characters are in them. Even if you made the (incorrect) assumptions that they all are less than 80 characters long and only contain letters, then you will have 2680 guesses for each phase. This will take a very long time to run, and you will not get the answer before the assignment is due.
Use any function calls you see in assembly code as an anchor point to help you understand what is going on in the code. By convention, the first argument passed in a function is stored in
%rdi, the second argument passed in is stored in
%rsi, and the third argument passed in is stored in
%rdx, the fourth argument in
%rcx, fifth argument in
r8 and the sixth argument in
%r9. If a function returns a value, it is stored in
%rax. See function calling conventions for examples.
You can assume any function that has a descriptive name, such as
explode_bomb, you can assume does what it says it does. It is probably not worth your time stepping into a function like this to understand exactly how it works. However, if a function call has a generic name such as
func4, you are going to figure out how that function works to be able to solve that phase.
If you see a function with a strange name, such as
__isoc99_sscanf@plt this is a function in the standard C library (libc). This example is a call to
sscanf(), and knowing how this function works will help you understand any phase that uses it. To see the documentation for any system call you can use the
man command (short for manual pages).
sscanf() takes a conversion string as its first argument (remember that in C, a string is just a pointer to a list of characters). The conversion string has conversion characters (which start with a %). See understanding how sscanf works for more details.
lea instruction is used to compute an address. However, sometimes the compiler uses this instruction to do simple math.
Most of the instructions you will see in your code we have covered in class. If you see an instruction that is new to you, look it up in the index of the book, it most likely mentions it. Here are a few instructions that you might see that we didn’t go over in class.
movsSign-extending data movement instructions. The
movsfamily of instructions moves a register or memory location of one size to a destination register of a larger different size. The move is sign-extending, which pads out the destination number with all 1s or 0s depending on the sign of the source number.
movsbwMove sign-extended byte to word (2 bytes)
movsblMove sign-extended byte to double word (4 bytes)
movswlMove sign-extended word (2 bytes) to double word (4 bytes)
movsbqMove sign-extended byte to quad word (8 bytes)
movswqMove sign-extended word (2 bytes) to quad word (8 bytes)
movslqMove sign-extended double word (4 bytes) to quad word (8 bytes)
cltqA special version of the
movslqinstruction. It sign-extends
%rax. The registers are not specified in the instruction. This instruction is specific to
movzblMove zero-extended byte to double word. This extends an 8-bit register to a 32-bit register, padding out the extra bits with 0. Remember that instructions that end in
lalso zero out the upper 32-bits as well.
Having trouble seeing the big picture for one of your phases? One thing that I found helpful is to print out the code for the phase you are trying to solve and draw arrows on one side of the page for every forward jump (a jump to a larger memory address). These jumps represent branches. On the other side of the page draw every backward jump (a jump to a smaller memory address). These jumps represent loops. This can help you understand the overall structure of the function, which will be useful in understanding the structure of phase_6.
There are many tools which are designed to help you figure out both how programs work, and what is wrong when they don’t work. We described
gdb above, and here is a list of some of the tools you may find useful in analyzing your bomb, and hints on how to use them.
objdump -dUse 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. Although
objdump -dgives 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 to
sscanfmight appear as:
8048c36: e8 99 fc ff ff call 80488d4 <_init+0x1a0>. To determine that the call was to
sscanf, you would need to disassemble within
objdump -tThis 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!
stringsThis utility will display the printable strings in your bomb.
Looking for a particular tool? The commands
info are your friends. In particular,
man ascii might come in useful.
info gas will give you more than you ever wanted to know about the GNU Assembler. If you get stumped, feel free to ask me or the Coaches for help.