CS270 Recitation 9.2
LC-3 Hacking

Goals

  1. To extend your knowledge of LC-3 by extending its operating system.
  2. To show the basics of a stack based buffer overflow attack.
  3. To show one way to add macros to the LC3 assembly language.

Setup

Make a subdirectory called R9.2 for the recitation, all files should reside in this subdirectory. Copy geth.asm and overflow.asm to the R9.2 directory. Now follow the directions here to save, extract, and build the linux tar file that contains a LC3 simulator and assembler. The tar file should be saved to your R9.2 directory.

Extending the LC3 OS

Once the install is completed you can now open the lc3os.asm file and see the LC3s operating system assembly code. Take some time to look through the code and get a feel for how the TRAP instructions work. You will notice that the addresses near x25 contain the address of the code that executes the corresponding TRAP subroutine. Now it is time to take the code in geth.asm and splice it into the lc3os.asm file (copy and paste with some slight modifications to the existing lc3os.asm code). Make sure you add link to the newly added geth code in the TRAP table (addresses x0000- x00FF).

Once this is complete use the assembler found in the same lc3CSU folder as lc3os.asm to assemble the modified operating system. The purpose of the new geth TRAP subroutine is to read hexadecimal input from the user and pack the corresponding bits into 16 bit LC3 words. This is similar to R8, except the TRAP subroutine expects R0 to be the address of a buffer that can contain more that one word. The TRAP subroutine will keep processing hex characters in multiples of four characters until the enter key is pressed and signals the end of input in the buffer by appending a NULL word. Currently only 0-9 and uppercase A-F are accepted.

Executing the buffer overflow

Now its time to take a look at overflow.asm currently there are a few lines that need to be filled in, the values for these lines are up to you and you should experiment with changing them to see how that alters the LC3 memory layout. By convention we have been using x3000 for a starting address for our programs and x4000 as the starting address of the stack but you may want change these to make keeping a eye on the OS, user program, and stack possible with minimal scrolling.

The basic idea of overflow.asm is the Main function calls ProcessHexData which allocates a buffer on the stack, then calls the geth TRAP to fill the buffer. If the user enters and amount of data equal to or less than the buffer size everything works normally and the function PrivateFunction will never be called. However there are no size checks associated with the buffer that geth receives and so a clever user can exploit this to access PrivateFunction.

Try a variation

Once you have figured out how to call PrivateFunction using the buffer overflow technique, you can experiment by calling other OS functions/subroutines, and modifying the code to cause overflows of buffers in other locations besides the stack.

Bonus Challenge

This one is a lot of work, but results in a lot of flexibility in terms of what you can do. By modifying the current function's return address on the stack, you can get the PC to go anywhere you want it to. If you set the return address to a function that you write using the buffer overflow, then you can execute any code you want. However, you would need to convert each instruction to it's equivalent hex form, and then input that into the TRAP. It would be best to prepare a file with your input and use redirection to pass this into the simulator so you can repeat/modify it as needed.