CSAW 2013 – Reversing Impossible – 500 Points

WTF, his hp is over 9000! Beat the game to get your key.

I had a go at doing this CTF as part of the Swinburne Cyber Security Team back in 2013. While I didnt finish it inside the competition, I continued to work on it the following week.

Originally, we are given a Nintendo DS game, where we have to kill the boss to obtain the key or flag. 10_start

Since the free version of IDA wont load ARM, you will need an emulator to test out the game. There is a plugin for NDS roms, but it wont work unless you have the full license.


This is what the game looks like. We have our ship, which is a green triangle, and a big BOSS character called WTF. He sends forth a series of red missles, which we need to avoid, while trying to kill him. I had difficulty playing the game, as my ship wouldnt move, so would die straight away.


Typical Schmup, we are in bullet hell.


Since this isnt a legit NDS game, we can assume that they are using the open source libraries. You will want to download the devkit pro package. Inside you will find an objdump utility to rerverse the libraries/objects back into assembler.

Fortunately, no$nds emu has a built in debugger. You will need to dump the game memory, or rather the disassembly of the game. My original dump was close to 100kb of data. ProTip, trim this file down, so your editor doesnt struggle.


The game programmer was kind enough to use debug print statements, to let us know what the game is doing. This helps us figure out what the game loops are, what the function calls are doing some of the time.


I set break points at the start of main loops, and function calls. Here it is initialising the WTF boss. Not clear to us at the moment.


At the end of what appears to be the main loop, is a check to see if we have won. I was clued into this, because one of the function includes a print statement to “”INIT WINSTATE” at 1c40.


Originally, I inserted a nop over the check, to force the game into the WIN state. However, I dont think some registers are set properly, and the game would crash straight after. Looking back, I do think it does the flag stuff, but it isnt obvious to the player. I had assumed the vector art would merge to display the flag in wireform.


At 3d9e, it begins its winning decrypt loop, that will print out the key in memory. Notice that the bottom left window shows some of the key words used in debug print. Of interest is the INIT WINSTAT.


Here I have set a break point on the ExlusiveOR opcode. The game is decrypting the flag into memory, which is visible in the lower left window.


Here is the completed loop. I have put  a break point at the end of the function call, to save having to single step through each letter. key is ou6UbzM8fgEjZQcRrcXKVN


The game will clear the screen, and show the following nonsense. This key is not the one the competition expects. KEY IS ONESTATICRC ??


Here you can see how I have *manually* documented each function in my dis-assembly listing using find and replace.


Here you can see that the boss has over 9,000 health, 1 million to be exact. To force the game into win mode, I would put a break point on this instruction at 2df6, and change his health to 1 or 0. As I said, the game was unplayable in the emulator, so hitting him once was not really an option.


More clues as to what each function did. Got to thank the programming for leaving bread crumbs like this.


Here is my analysis of the decryptor loop. There is only 1 occurrence of EOR in the entire ROM listing.


I hand pieced the function names, using the objdump tool, and searching for the opcodes in the 2nd column.


Looks to be game setup. Init Renderer and Init Debug.


I would put break points on random functions while playing the game, to see what effect skipping them might have. Looking for God mode, or collision detect, etc.


Beginning of WINSTATE.


The game would would add enemies in groups of two. This was made apparent by the Add ENT in the debug statements.


Here you can see it setup the boss character and his health, followed by 2 rows of enemies.


02003D78 B500       push     {r14}
02003D7A B087       add     sp,-#0x1C
02003D7C 9001       str     r0,[sp,#0x4]
02003D7E 9B01       ldr     r3,[sp,#0x4]
02003D80 1C18       mov       r0,r3
02003D82 F010F86F       bl       #0x2013E64
02003D86 1C03       mov       r3,r0
02003D88 9304       str       r3,[sp,#0x10]
02003D8A 9B04       ldr       r3,[sp,#0x10]
02003D8C 3301       add       r3,#0x1
02003D8E 1C18       mov       r0,r3
02003D90 F01BFB4A       bl       #0x201F428
02003D94 1C03       mov       r3,r0
02003D96 9303       str       r3,[sp,#0xC]
02003D98 2300       mov       r3,#0x0
02003D9A 9305       str       r3,[sp,#0x14]
02003D9C E00F       b       #0x2003DBE

02003D9E 9B05       ldr       r3,[sp,#0x14]
02003DA0 9A03       ldr       r2,[sp,#0xC]
02003DA2 18D3       add       r3,r2,r3
02003DA4 9A05       ldr       r2,[sp,#0x14]
02003DA6 9901       ldr       r1,[sp,#0x4]
02003DA8 188A       add       r2,r1,r2
02003DAA 7812       ldrb       r2,[r2]
02003DAC 2132       mov       r1,#0x32
02003DAE 4249       neg       r1,r1
02003DB0 404A       eor       r2,r1             // strange
02003DB2 0612       lsl       r2,r2,#0x18
02003DB4 0E12       lsr       r2,r2,#0x18
02003DB6 701A       strb       r2,[r3]             // r3=02032210 = KEY BUFFER STRING
02003DB8 9B05       ldr       r3,[sp,#0x14]             // v3 = var_14;
02003DBA 3301       add       r3,#0x1 // v3++ (position?)
02003DBC 9305       str       r3,[sp,#0x14]             // var_14 = v3
02003DBE 2301       mov       r3,#0x1 // v3 = 1;
02003DC0 9905       ldr       r1,[sp,#0x14]             // v1 = var_14 == 2023614 hidden key.
02003DC2 9A04       ldr       r2,[sp,#0x10]       // v2 = var_10;
02003DC4 4291       cmp       r1,r2             // v2 = pos?? // debug = 1d
02003DC6 DB00       blt       #0x2003DCA             // if so bail/break

02003DC8 2300       mov       r3,       #0x0       // write trailing null?

02003DCA 061B       lsl       r3,       r3,       #0x18             // v0 = 0;
02003DCC 0E1B       lsr       r3,r3,#0x18
02003DCE D1E6       bne       #0x2003D9E
02003DD0 9B04       ldr       r3,       [sp,#0x10]
02003DD2 9A03       ldr       r2,       [sp,#0xC]
02003DD4 18D3       add       r3,       r2,       r3
02003DD6 2200       mov       r2,       #0x0
02003DD8 701A       strb       r2,       [r3]
02003DDA 9B03       ldr       r3,       [sp,#0xC]
02003DDC 1C18       mov       r0,       r3
02003DDE B007       add       sp,       #0x1C
02003DE0 BD00       pop       {r15}
02003DE2 46C0       nop
02003DE4 4B01       ldr       r3,       =#0x2030620       // checkIfText
02003DE6 5C18       ldrb       r0,       [r3,r0]
02003DE8 4770       bx       r14
02003DEA 46C0       nop


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s