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:
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
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
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
First blood. :-)