BkPCTF 2013 - space game (250)

The binary named space game was the first of the challenges that drew my attention simply due to its file extension .nds - which is the standard file extension for Nintendo DS ROM images.

That having said, space game seemed to be a good candidate for the first blood candidate. Remembering that my actual background for reversing was originally from hacking both, Nintendo GBA and Nintendo DS systems for many years, I decided that it shouldn’t be to difficult for me to defeat it. :-)

In order to play the game, you need a suited Emulator, preferably one with a debugger included. My candidate of choice therefore was Martin Korth’s excellent (commercial) no\$gba debugger. Loading the binary in no\$gba and pressing several random keys we are presented with the following screen:

Space Game 1

Hmm … so we might want to find some hidden key combination to proceed. It seems that we need to have a look on the binary in its disassembled version. (what a surprise!)

Knowing that the state of the pressed keys of the handheld console is always stored at 0x4000130 (if you don’t, look it up in the tech doc), a breakpoint on read was quickly set up using the no$gba debugger. From there, we trace the value being stored in the ARM9’s (the NDS uses two ARM chips) memory at 0x02024000. The location there initially holds the very interesting string keyishere!. :-)

Now, from looking at that offset in real-time in the debugger while pressing keys resulted in the observations that the “nice try” string always showed up after the first seven key presses and in the following list of key <-> value combinations:

<-  0x5a
->  0x6e
A   0x56
B   0x62
L   0x47
R   0x46
Start   0x73

That’s all we need. Let’s find out where it decided if a key combination is correct. A combination of IDA Pro armed with the ndsldr plugin written by Dennis Elser and the GBA/NDS tech document (again by Martin Korth) is my weapon of choice for this first battle.

A quick search for the string “nice try …” ends at this very interesting location:

RAM:02016B58                 BL      sub_2000FAC
RAM:02016B5C                 MOV     R0, R11
RAM:02016B5E                 BL      sub_200A76C
RAM:02016B62                 LDR     R0, =aEnterTheCorrec ; "Enter the correct key codes for t"...
RAM:02016B64                 BL      sub_200A76C
RAM:02016B68                 MOV     R2, R8
RAM:02016B6A                 LDR     R2, [R2,#4]
RAM:02016B6C                 CMP     R2, #7
RAM:02016B6E                 BEQ     loc_2016B72     ; password is 7 keys
RAM:02016B70                 B       loc_2016A2E
RAM:02016B72 ; ---------------------------------------------------------------------------
RAM:02016B72 loc_2016B72                             ; CODE XREF: sub_20169D4+19Aj
RAM:02016B72                 BL      sub_2000430
RAM:02016B76                 MOV     R3, R8
RAM:02016B78                 STR     R0, [R3,#8]
RAM:02016B7A                 CMP     R0, #1
RAM:02016B7C                 BEQ     loc_2016B86
RAM:02016B7E                 LDR     R0, =aNiceTry___YouR ; "nice try... you're wrong though *<:-)"
RAM:02016B80                 BL      sub_200A76C
RAM:02016B84                 B       loc_2016A2E
RAM:02016B86 ; ---------------------------------------------------------------------------
RAM:02016B86 loc_2016B86                             ; CODE XREF: sub_20169D4+1A8j
RAM:02016B86                 BL      sub_20003EC
RAM:02016B8A                 MOV     R2, R10
RAM:02016B8C                 LDR     R1, [R2]
RAM:02016B8E                 ADD     R0, SP, #0x90+var_8C
RAM:02016B90                 MOVS    R2, #0x10
RAM:02016B92                 BL      sub_2000310
RAM:02016B96                 ADD     R0, SP, #0x90+var_8C
RAM:02016B98                 BL      sub_200046C
RAM:02016B9C                 MOV     R3, SP
RAM:02016B9E                 STRB    R6, [R0,#0xB]
RAM:02016BA0                 MOVS    R1, R0
RAM:02016BA2                 LDR     R0, =aKeyS      ; "key{%s}\n"

Let’s see, we want to end up at loc_2016b86 where it prints out the key. For this to come true, we need to pass the checks at 0x02016b6e and 0x02016b7c. The first one is easy, as it is the the check for the well known length of the combination of keys. (One could also see that from the backwards jump that is executed which basically forms a read()-loop until the needed length is reached.)

Now on to the second check. As we all know, parameters and return values in ARM are passed using registers R0 to R3. Thus, the return value of sub_2000430 needs to become 1.

Fortunately, sub_2000430 in its graphical representation is almost self-explanatory:


The code above basically translates to “return 1 iif the values of the key are

0x5a    0x6e    0x56    0x73    0x62    0x47

and 0 in any other case”. Thus, using the fancy lookup table from above, we now know that we have to press the following keys to unlock the secret: <- -> A Start B L R

Space Game 2

First blood. :-)