Tuesday, November 4, 2014

Microcorruption - Whitehorse


I probably should have read the manual (right, who does that?) before now. But better late than never. The manual on pages on 4 and 5 talks about how 0x7F is the code to unlock the door – not a function call but basically a hardware interrupt that accomplishes the same thing. Additionally there is mention of 0x7D and 0x7E which set a byte in memory if the entered password matches. Look for those to come into play at some point. We actually already saw these in Cusco, although that knowledge wasn't fully necessary at that point.

As in a Cusco, there is still an instruction (after the password has been checked and after the “wrong password” message is displayed) that adds 10 to the stack pointer. So the stack pointer jumps forward x10 to address 3cc6, and the next instruction is to return to the value held at the address 3cc6. The assumption is apparently that you have not entered a password longer than x10 bytes and put your own value in that address. But as the saying goes: when you assume you make an 'ass' out of 'u' and 'me'..

So we can put what we want in 3cc6 because nothing prevents us from entering a longer password than 16 characters – that is nothing prevents us from overflowing the buffer. Last time we did this we put the starting address of the “unlock door” function. This time however there is no unlock door function, but there is ample room to put code that we write in assembly.

So first we want to get control of the instruction pointer. Put the address at that point to the area of the buffer that we have overflowed, that is point the instruction pointer at the code we are overflowing into the buffer. This is called injecting code.

So what do we want to do? As you may recall from Cusco, hardware interrupt x7e when placed in the SR (stack register) and called with the interrupt trap causes the password to be checked. Hardware interrupt x7d sets a password in memory indicating that the password was correct, and x7f straight up unlocks the door.

Let's do the following:
Point the instruction pointer at memory we control.
Get x7f into the SR **
Call the interrupt trap.

We can look at the existing instructions in the code to cobble the bits and pieces together – or if you want a project you can learn this version of assembly and roll your own. But the basic structure of the code we can use is as follows

3e40 007f mv #x7f00, r14
0f4e mv r14, r15
024f mv r15, sr
32d0 0080 bis (highbit), sr **
b012 1000 call 0x10

**Note: the manual says x7F opens the door, but on my version of the game they had an extra part in there that set the high bit to 1 yielding xFF as the value required to unlock the door. The only way you figured this out was by looking at the code within <INT>


453e:  32d0 0080      bis       #0x8000, sr
so while you were examining <conditional_unlock> where it loads x7e onto the stack and calls <INT> you can see as you step through it that x7e gets loaded into the SR (from r15) and they flip the high bit on and then call the trap.

You can trim down the code above if you work through it – I don't want to take all the fun out – but a successful entry based on the code above can look like:

41414242434344444545464647474848c83c3e40007f0f4e024f32d00080b0121000

No comments:

Post a Comment