CS 304, Fall 2015
Lab Assignment L2: Defusing a Binary Bomb
Assigned: 9/22, 2015
Due: 23:59PM, 10/4 (Sunday), 2015

1 Introduction

The nefarious Dr. Evil has created a slew of “binary bombs” for our class. A binary bomb is a program that consists of a sequence of six 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.

Each student in the class will be supplied with a bomb to defuse. The assignment is to defuse your bomb before the due date. Good luck, and welcome to the bomb squad!

Slides for some basics.

Step 1: Getting Your Bomb

The bombs will be numbered from bomb1 to bombn, where n is the number of students in the class. Each bomb is constructed with a random choice of phases, and the bomb numbers are assigned in a random order relative to the class roll (that is, the alphabetically first student on the roll will most probably not be assigned bomb1).

Please visit http://th001-8.cs.wm.edu:15213/ from a DEPARTMENT MACHINE (sorry you have to get it from the department machine). When you enter your user name, please use your cs account name. Then you can download the file and then copy to your working directory.

            mkdir lab2 
            cd lab2           
            cp downloaded_file
            tar xvf bomb.tar

The bomb lab scoreboard can be found: http://th001-8.cs.wm.edu:15213/scoreboard

Step 2: Defuse Your Bomb

Once you have received your bomb, save it in a secure directory. Your job is to defuse the bomb.

You can use many tools to help you with this; please look at the hints section for some tips and ideas. The best way is to use your favorite debugger to step through the disassembled binary.

Each time your bomb explodes it notifies the project logfile, and you lose 1/2 point (up to a max of 20 points) in the final score for the lab. So there are consequences to exploding the bomb. However, as you learn about setting breakpoints in gdb, you will realize that you can protect yourself by setting a breakpoint in explode_bomb.

Phase one is worth 10 points, and phases 2 through 6 are worth 14 points each, for a lab total of 80 points.

There is also a challenging, extra-credit (4 points) “secret” phase that only appears if a student appends a certain string to the solution of one of the earlier phases.

The phases get progressively harder to defuse, but the expertise you gain as you move from phase to phase should offset this difficulty. However, the last phase will challenge even the best students, so please don’t wait until the last minute to start.

The bomb ignores blank input lines. If you run the bomb with a command line argument such as psol.txt (a name chosen arbitrarily), the bomb will read the input lines from psol.txt until it reaches EOF, 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 the rest of your career.

Logistics

Any clarifications and revisions to the assignment will be posted on the Web page for this lab.

You must complete the assignment on the machines in M-S 121 (you can also ssh to a machine in 121 to finish this lab). 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 they say.

Hand-In

There is no explicit hand-in. The bomb will notify your instructor automatically after you have successfully defused it. You can keep track of how you (and the other students) are doing by following the link on the lab web page to the page summarizing the current status of the bomb tests. This web page is updated continuously to show the progress of being made on each bomb. Results are displayed by bomb number. Note: If the update timestamp stops changing, then please send email to liqun@cs.---- to let me know. This means that the autograder daemon has died and needs to be restarted. Successfully debugged phases won’t show up until the autograder daemon is running.

Hints (Please read this!)

There are many ways of defusing your bomb. You can examine a disassembly of it in great detail without ever running the program, and figure out exactly what it does. This is a useful technique, but it may not give you enough information about what the bomb is doing.

You can also run the bomb with a debugger, inspect its memory locations, watch what it does step by step, and use this information to defuse it. This is probably the fastest way of defusing the bomb. Combining this technique with the hard copy of the disassembly of the bomb is probably the strongest combination you can use.

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 two reasons:

There are many tools that are designed to help you figure out both how programs work, and what is wrong when they don’t work. Here is a list of some of the tools you may find useful in analyzing your bomb, and hints on how to use them.

For 64 bits:
       (gdb) disas read_six_numbers
           Dump of assembler code for function read_six_numbers:
           0x0000000000401750 <+0>:     sub    $0x18,%rsp
           0x0000000000401754 <+4>:     mov    %rsi,%rdx
           0x0000000000401757 <+7>:     lea    0x4(%rsi),%rcx
           0x000000000040175b <+11>:    lea    0x14(%rsi),%rax
           0x000000000040175f <+15>:    mov    %rax,0x8(%rsp)
           0x0000000000401764 <+20>:    lea    0x10(%rsi),%rax
           0x0000000000401768 <+24>:    mov    %rax,(%rsp)
           0x000000000040176c <+28>:    lea    0xc(%rsi),%r9
           0x0000000000401770 <+32>:    lea    0x8(%rsi),%r8
           0x0000000000401774 <+36>:    mov    $0x402875,%esi
           0x0000000000401779 <+41>:    mov    $0x0,%eax
           0x000000000040177e <+46>:    callq  0x400c70 <__isoc99_sscanf@plt>
           0x0000000000401783 <+51>:    cmp    $0x5,%eax
           0x0000000000401786 <+54>:    jg     0x40178d <read_six_numbers+61>
           0x0000000000401788 <+56>:    callq  0x4015ef <explode_bomb>
           0x000000000040178d <+61>:    add    $0x18,%rsp
           0x0000000000401791 <+65>:    retq  
        End of assembler dump. 


    and here is the corresponding output from the objdump command:

For 64 bits
       0000000000401750 <read_six_numbers>:
      401750:    48 83 ec 18              sub    $0x18,%rsp
      401754:    48 89 f2                 mov    %rsi,%rdx
      401757:    48 8d 4e 04              lea    0x4(%rsi),%rcx
      40175b:    48 8d 46 14              lea    0x14(%rsi),%rax
      40175f:    48 89 44 24 08           mov    %rax,0x8(%rsp)
      401764:    48 8d 46 10              lea    0x10(%rsi),%rax
      401768:    48 89 04 24              mov    %rax,(%rsp)
      40176c:    4c 8d 4e 0c              lea    0xc(%rsi),%r9
      401770:    4c 8d 46 08              lea    0x8(%rsi),%r8
      401774:    be 75 28 40 00           mov    $0x402875,%esi
      401779:    b8 00 00 00 00           mov    $0x0,%eax
      40177e:    e8 ed f4 ff ff           callq  400c70 <__isoc99_sscanf@plt>
      401783:    83 f8 05                 cmp    $0x5,%eax
      401786:    7f 05                    jg     40178d <read_six_numbers+0x3d>
      401788:    e8 62 fe ff ff           callq  4015ef <explode_bomb>
      40178d:    48 83 c4 18              add    $0x18,%rsp
      401791:    c3                       retq  


    Notice that objdump correctly identifies the sscanf C library call, but the disas command of gdb simply lists the call location as _init+392 in the bomb     executable. The disas command of gdb is more convenient to use if you’re already in gdb, but you may occasionally find it necessary to refer to the objdump output to track down any mysterious C library calls.

    I don’t mean to over-emphasize the read_six_numbers routine here. I am simply pointing out the differences between objdump -d and the disas command of gdb. By the name of this procedure and by a glance at its construction, you can see that the procedure uses sscanf to parse the input string fed to it and place six int values in an array whose address is supplied as one of its parameters. That’s about all you need to know about read_six_numbers.

Looking for a particular tool? How about documentation? Don’t forget, the commands apropos and man are your friends. In particular, man ascii might come in useful. Also, the web may also be a treasure trove of information. If you get stumped, feel free to ask me for help.

Try the following to start:
objdump -t bomb
objdump -t bomb > bomb_sym.txt
#save the symbol table in bomb_sym.txt
objdump -d bomb
objdump -d bomb > bomb_dump.txt
#save the dump file in bomb_dump.txt
string -t x bomb
string -t x bomb > bomb_string.txt
#save the strings in bomb_string.txt
gdb bomb
#use gdb to run bomb
(gdb)b explode_bomb
#set breakpoint at explode_bomb
(gdb)b main
#set breakpoint at main
(gdb)disp /i $rip
(gdb)r
(gdb)r psol.txt
(gdb)c
(gdb)si
(gdb)i r
(gdb)x/10wx $rsp
(gdb)x/10wx $rsp-0x20

It is important to set a breakpoint are explode_bomb: (gdb)b explode_bomb
If you do not, you may unintentionally explode the bomb. If the breakpoint is set, when you are about to explode the bomb, the program will breakpoint at the beginning of the procedure explode_bomb. This way you know you will explode the bomb if you continue. Simply type r (or r psol.txt if you saved your solution in psol.txt) to rerun the progra from the beginning. 


Useful GDB commands

   gdb -h  (lists command line options)
   gdb
  
  Exiting:
   quit
     q
   Ctrl-d
   Note: Ctrl-C does not exit from gdb, but halts the current
   gdb command
  
  
  General commands
  
   run (start your program with no arguments )
     r
  
     r arg1 arg2 arg3  (start your program with 3 arguments)
  
   kill (stop the program)
  
  
  Breakpoints
  
   break FUNCTION (set a breakpoint at the entry to the function)
     b FUNCTION
  
   break ⋆ADDRESS (set a breakpoint at the specified address)
     b ⋆ADDRESS
  
   disable <NUM> (disable the breakpoint with that number)
   enable <NUM> (enable the breakpoint with that number)
  
   clear FUNCTION (clear any breakpoints at the entry to the function)
  
   delete <NUM> (deletes the breakpoint with that number)
     del <NUM>
  
   delete (deletes all breakpoints)
  
  
  Working at breakpoints
  
   stepi (execute one machine code instruction)
     si
  
   stepi <NUM> (execute NUM machine instructions)
     si <NUM>
  
   step (execute one C statement)
     s
  
   nexti (like stepi, but proceed through subroutine calls without stopping)
     ni
  
   nexti <NUM>
     ni <NUM>
  
   next (like step, but proceed through subroutine calls without stopping)
  
   until LOCATION (continue running until LOCATION is reached)
  
   continue (resume execution)
     c
  
   continue <NUM> (continue, ignoring this breakpoint NUM times)
     c <NUM>
  
   finish (run until the current function returns)
  
   backtrace (print the current address and stack backtrace)
   where (print the current address and stack backtrace)
  
  Examining code
  
   print/a $rip (print the program counter)
   print $rsp (print the stack pointer)
   disas (display the function around the current line)
   disas ADDR  (display the function around the address)
   disas ADDR1 ADDR2 (display the function between the addresses)
  
  Examining data
  
   print $rax (print the contents of %rax)
   print/x $rax (print the contents of %rax as hex)
   print/a $rax (print the contents of %rax as an address)
   print/d $rax (print the contents of %rax as decimal)
   print/t $rax (print the contents of %rax as binary)
   print/c $rax (print the contents of %rax as a character)
  
   print 0x100 (print decimal repr. of hex value)
   print/x 555 (print hex repr. of decimal value)
  
   x ADDR (print the contents of ADDR in memory)
   x/NUF ADDR (print the contents at ADDR in memory:
   N = number of units to display
   U = b (bytes), h (2 bytes), w (4 bytes))
   F = display format, x (hex), o (octal), d (decimal -- default)
                    t (binary), s (string), f (float), i (instruction), c (char)
     Examples:  x/20wx $rsp     show top 20 words of the stack
                x/128bx main    show first 128 bytes (in hex) of main pgm
  
  
  Autodisplaying information
  
   display $rip (print contents of %rip every time the program stops)
     disp $rip

  
   display (print the auto-displayed items)
     disp
  
   delete display <NUM> (stop displaying item NUM)
     und <NUM>
  
  Useful information commands
   help info
  
   info program (current status of the program)
  
   info functions (functions in program)
     i f
  
   info stack      (backtrace of the stack)
     i s
  
   info frame (information about the current stack frame)
     i f
  
   info scope  (variables local to the scope)
     i s
  
   info variables (global and static variables)
     i v
  
   info registers  (registers and their contents)
     i r
  
   info breakpoints (status of user-settable breakpoints)
     i b
  
   info address SYMBOL (use for looking up addresses of functions)
     i ad SYMBOL
  
  Using the .gdbinit File to Initialize gdb
  
     At startup, the gdb debugger will execute initialization files
  (usually named .gdbinit) and process command line options
  in the following order
  
     1. Reads the init file (if any) in your home directory(2).
  
     2. Processes command line options and operands.
  
     3. Reads the init file (if any) in the current working directory.
  
     4. Reads command files specified by the ‘-x' option.
  
     For more details, type "info gdb" at the Linux command line,
  then look for "Command Files".
  
     For example, for the bomblab, you will probably want to create
  a .gdbinit file in the directory that contains your bomb to be defused
  that contains at least the following three lines:
  
           b main
           b explode_bomb
           disp /i $rip
  
  Running gdb in emacs
   M-x gdb
   C-h m to see the features of GDB mode