Complete Solution: Solve floors 1 - 4 (5 for extra credit)
Due before midnight, Tuesday April 3
You've been sleep walking again, and you wake up on the roof of Parrish Hall. You need to find your way through its maze of floors and get out of the building in time for your first class. Due to construction, there is no stairwell that connects more than two floors, so you need to travel along each floor to find the next open stairwell. Watch out for obstacles along your path that can trip you up and impede your progress, forcing you to return back to the roof to try again.
In this assignment, you will receive a binary executable file for a maze program. The maze has 5 phases, one for each floor of Parrish Hall (from the roof to the front door). Each floor is a puzzle that needs to be solved to move on to the next floor. To solve each puzzle you need to enter a passphrase to standard input. If you type the correct string, the puzzle is solved and you proceed to the next floor. If not, you "trip up" and the program terminates. The goal is to solve all phases/floors of the maze, limiting the number of times you trip up along the way. Note that floor 5 is extra credit.
This lab is graded out of 66 points (with 5 possible extra credit points):
You can lose up to 5 points for trip-ups. You lose a point for each 4th trip-up (number 4, 8, 12, ...), so you get a few for free.
You must run your maze on one of the lab machines; the maze will always trip-up if run elsewhere. There are several other tamper-proofing devices built into the maze. In particular, using the gdb set command while trying to solve your maze will cause a trip-up.
To kill your maze executable (to make it exit without tripping-up), type CNTRL-C. This way you can run your maze, solve a puzzle on a floor, and then exit and come back later to try the puzzle on the next floor.
The best tools to help you escape the maze are ddd and gdb, which let you step through the disassembled binary instructions.
Although the puzzles on each floor get progressively harder to solve, the expertise you gain as you move from floor to floor should offset this difficulty.
Once you have solved the puzzle on a floor, we encourage you to run your maze with a soln.txt file containing the input phrases for the floors you have solved. The format of the file should be one phrase per line, in order of the maze floors. Using an input file will help prevent you from accidentally tripping up on a previously solved floor. For example:
$ ./maze soln.txtwill read the input lines from soln.txt and then use stdin for the remaining input. The maze ignores blank input lines, both in the file and on stdin.
To avoid accidentally tripping up in the maze, you will need to learn how to 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.
Edit the file maze_how_we_solved_it to include a short explanation of how you solved each floor. It's okay if you used some amount of "guess and check" to solve a floor, but you should still describe what you saw in the assembly code or the state of the running program that inspired your guessing strategy.
Describe at a high-level what you suspect the original C code was doing for each floor. You do not need to reverse engineer the IA32 code and translate every part of it to equivalent C code. Instead, give a rough idea of equivalent C or pseudo code for the main part of the puzzle on each floor. For example, something like "uses an if-else to choose to do X or Y based on the input value Z" is an appropriate level of explanation. Something like "moves the value at %ebp-8 into register %eax" is too specific.
You should be able to explain each puzzle in a short paragraph or two (maybe with a few lines of C or pseudo code to help explain). We recommend doing the writeups for each floor as you solve them.
If you are unable to solve a floor, you can still receive partial credit by describing what you have determined about that floor in the writeup.
Here are the new partnerships. The course webpage has a section on expectations for working with partners.
Both you and your partner should:
$ cd ~/cs31/labs
git clone [your_Lab6_URL]
$ cd Lab6-you-partner $ ls QUESTIONNAIRE maze_how_we_solved_it
http://water.cs.swarthmore.edu:8000
$ mv ~/mazeX.tar .
$ tar xvf mazeX.tar
water.cs.swarthmore.edu:8000/scoreboardYou will see your maze in this list. The scoreboard displays how many stages you have solved, how many total trip-ups you have had, and your score so far.
This information is updated about every 20 seconds. Reload the page to see the latest information.
There are many ways to solve the maze. You could examine it in great detail without ever running the program, and figure out exactly what it does. However it's probably easier to run the program through a debugger to identify the instructions that determine whether the passphrase is correct, and work backwards from there. The debugger lets you examine what is stored in registers and in memory as the program runs.
Do not use brute force, i.e. don't write a program that tries every possible input string to find the right one. This is a bad approach for several reasons:
You may see some x86 instructions in your maze assembly that are not on the IA32 cheatsheet. In this case, look at some of the IA32 Documentation and References for information about that instruction. The wikipedia page may be most useful.
There is an art to determining how deep to trace through assembly code execution. You will need to trace into some function calls, but can also first try to see what happens before and after the call. You may also assume that C library functions like scanf do what you think they do--tracing into the scanf function, for example, will not help you figure out the solution to a level.
One note about the x command in gdb: its formatting is sticky, so if you want to print out the contents of different memory addresses for different sized values and types, you need to specify the format for each difference. For example:
x/s 0x1234 # print as a string what is stored at memory address 0x1234 x 0x5678 # also prints as a string (x's formatting is sticky) x/wd 0x5678 # to print as an int what is stored at memory address 0x5678 # after printing as a string, need to specify the width and type # w: 4 bytes, d: print as decimal int # (x/wx) would print the 4-byte value in hex x/a 0x9abc # will print what is at memory address 0x9abc as an addressSee the gdb guide above for more examples of using the x command, including the different formatting options.
Although objdump -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 to sscanf might 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 gdb.
Looking for documentation about a particular tool? The the commands apropos and man will help you find documentation about unix utilities, and in gdb the help command will explain gdb commands:
$ man objdump (gdb) help niHere is some more information on man and reading manual pages: man
There is a QUESTIONNAIRE file for you to fill out and submit with your lab solution. Your answers to the questionnaire will not affect your grade.
For the checkpoint, you don't need to submit anything. We will check the scoreboard at the checkpoint date to verify that you've solved at least the first two levels. For the final due date you should push your changes to the following files: