NDH 2018 : Wargame
Challenge details
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
NDH 16 Wargame | Geode | Reverse | ? | ? |
Download: Geode.gb
TL;DR
Reversing a Gameboy Advance game, searching for a string with Radare2, then analyzing the instruction that call this string.
Methodology
Find the type of file :
> $ file geode.gb ⬡ 10.5.0
geode.gb: Game Boy ROM image: "CRACKME" (Rev.01) [ROM ONLY], ROM: 256Kbit
Then I searched à way to execute it, I choose Visual Advance Studio
So let’s execute it :
It’s an interface that require a password and validate it.
Let’s try a password :
Now, it’s time to static analysis with Radare2 :
r2 -A geode.gb
First let’s find our Wrong Password string’s reference :
[0x00000100]> izzq~Wrong
0x569 21 20 ===Wrong password===
Now the strings xref :
[0x00000100]> pd 1024~569
--------> 0x0000051c 216905 ld hl, 0x0569
||||||| 0x00000569 3d dec a
Next we need to find into which function the string is used :
0x00000100]> afl
0x00000018 1 8 sym.rst_24
0x0000007e 1 1 fcn.0000007e
0x00000100 12 210 -> 137 entry0
0x00000200 9 136 fcn.00000200
0x00000288 73 566 fcn.00000288
0x0000057e 1 9 fcn.0000057e
0x00000587 1 9 fcn.00000587
0x00000590 1 11 fcn.00000590
0x000005bd 6 64 fcn.000005bd
0x000005fd 14 166 fcn.000005fd
0x000006a3 6 31 fcn.000006a3
0x000006c2 6 31 fcn.000006c2
0x000006e1 10 48 fcn.000006e1
0x00000711 6 25 fcn.00000711
0x0000072a 1 20 fcn.0000072a
0x0000073e 1 7 fcn.0000073e
0x00000745 24 159 fcn.00000745
0x000007e4 1 5 fcn.000007e4
0x000007e9 1 36 fcn.000007e9
0x0000081e 3 23 fcn.0000081e
0x00000835 6 29 fcn.00000835
0x00000852 4 163 fcn.00000852
0x00000a07 8 214 fcn.00000a07
0x00000add 96 816 -> 787 fcn.00000add
0x00000d6e 27 159 fcn.00000d6e
0x00000e0d 7 53 fcn.00000e0d
0x00000e42 13 100 fcn.00000e42
0x00000f67 1 16 fcn.00000f67
0x00000f77 1 6 fcn.00000f77
0x00000f7d 1 6 fcn.00000f7d
0x00000f83 1 6 fcn.00000f83
0x00000f89 1 6 fcn.00000f89
0x00000f8f 1 6 fcn.00000f8f
0x00000f95 4 73 -> 17 fcn.00000f95
0x00000f9b 4 67 -> 17 fcn.00000f9b
0x00000fa1 4 61 -> 17 fcn.00000fa1
0x00000fa7 4 55 -> 17 fcn.00000fa7
0x00000fad 4 49 -> 17 fcn.00000fad
0x00000fb3 4 21 -> 32 fcn.00000fb3
0x00000fef 5 23 fcn.00000fef
0x00001006 4 23 fcn.00001006
0x000010f1 1 25 fcn.000010f1
0x00001113 4 53 fcn.00001113
0x00001148 6 55 fcn.00001148
0x0000120a 6 72 fcn.0000120a
0x0000129a 1 13 fcn.0000129a
0x000012a7 5 25 fcn.000012a7
0x000012c7 1 9 fcn.000012c7
0x000012d0 7 82 fcn.000012d0
0x0000133f 3 34 fcn.0000133f
0x00001361 6 27 fcn.00001361
0x0000137c 5 23 fcn.0000137c
0x00001393 4 21 fcn.00001393
0x000013a8 8 46 fcn.000013a8
0x000013d6 9 46 fcn.000013d6
0x00001404 3 41 fcn.00001404
0x0000142d 1 16 fcn.0000142d
0x0000143d 3 102 fcn.0000143d
0x00001f5e 1 10 fcn.00001f5e
0x00001f68 3 55 fcn.00001f68
0x000020ed 3 14 fcn.000020ed
0x0000211f 1 13 fcn.0000211f
0x00002137 3 15 fcn.00002137
0x00002159 1 15 fcn.00002159
0x00002175 3 32 -> 17 fcn.00002175
0x00002195 9 49 fcn.00002195
0x000021df 5 16 fcn.000021df
0x000021ef 1 45 fcn.000021ef
0x0000221c 2 7 fcn.0000221c
0x00002232 1 13 fcn.00002232
0x0000224a 1 1 fcn.0000224a
So the string xref is so located at 0x51c
and the function where it used is fcn.00000288
All that rest to do is a quick analysis of this function :
[0x00000100]> pd @fcn.00000288
/ (fcn) fcn.00000288 566
| fcn.00000288 (int arg_7h);
| ; var int local_0h @ sp+0x0
| ; var int local_2h @ sp+0x2
| ; var int local_3h @ sp+0x3
| ; arg int arg_7h @ sp+0x7
| ; CALL XREF from 0x000004f8 (fcn.00000288 + 624)
| 0x00000288 c5 push bc
| 0x00000289 e8fd add sp, 0xfd
| 0x0000028b f807 ld hl, sp + 0x07
| 0x0000028d 2a ldi a, [hl]
| 0x0000028e 66 ld h, [hl]
| 0x0000028f 6f ld l, a
| 0x00000290 e5 push hl
| 0x00000291 cd4811 call fcn.00001148
| 0x00000294 42 ld b, d
| 0x00000295 4b ld c, e
| 0x00000296 e802 add sp, 0x02
| 0x00000298 79 ld a, c
| 0x00000299 fe16 cp 0x16
| ,=< 0x0000029b c2a502 jp nZ, 0x02a5
| | 0x0000029e 78 ld a, b
| | 0x0000029f b7 or a
| ,==< 0x000002a0 c2a502 jp nZ, 0x02a5
| ,===< 0x000002a3 1803 jr 0x03
| ||| ; CODE XREF from 0x0000029b (fcn.00000288)
| ||| ; CODE XREF from 0x000002a0 (fcn.00000288)
| ,=``-> 0x000002a5 c3b704 jp 0x04b7
| || ; CODE XREF from 0x000002a3 (fcn.00000288)
| |`---> 0x000002a8 f807 ld hl, sp + 0x07
| | 0x000002aa 2a ldi a, [hl]
| | 0x000002ab 5e ld e, [hl]
| | 0x000002ac f800 ld hl, sp + 0x00
| | 0x000002ae 22 ldi [hl], a
| | 0x000002af 73 ld [hl], e
| | 0x000002b0 2b dec hl
| | 0x000002b1 5e ld e, [hl]
| | 0x000002b2 23 inc hl
| | 0x000002b3 56 ld d, [hl]
| | 0x000002b4 1a ld a, [de]
| | 0x000002b5 23 inc hl
| | 0x000002b6 77 ld [hl], a
| | 0x000002b7 7e ld a, [hl]
| | 0x000002b8 fe74 cp 0x74
| | ,=< 0x000002ba c2bf02 jp nZ, 0x02bf
| | ,==< 0x000002bd 1803 jr 0x03
| | || ; CODE XREF from 0x000002ba (fcn.00000288)
| |,=`-> 0x000002bf c3b704 jp 0x04b7
| ||| ; CODE XREF from 0x000002bd (fcn.00000288)
| ||`--> 0x000002c2 f800 ld hl, sp + 0x00
| || 0x000002c4 5e ld e, [hl]
| || 0x000002c5 23 inc hl
| || 0x000002c6 56 ld d, [hl]
| || 0x000002c7 13 inc de
| || 0x000002c8 1a ld a, [de]
| || 0x000002c9 4f ld c, a
| || 0x000002ca 79 ld a, c
| || 0x000002cb fe48 cp 0x48
| || ,=< 0x000002cd c2d202 jp nZ, 0x02d2
| ||,==< 0x000002d0 1803 jr 0x03
| |||| ; CODE XREF from 0x000002cd (fcn.00000288)
| ,===`-> 0x000002d2 c3b704 jp 0x04b7
| |||| ; CODE XREF from 0x000002d0 (fcn.00000288)
| |||`--> 0x000002d5 f800 ld hl, sp + 0x00
| ||| 0x000002d7 5e ld e, [hl]
| ||| 0x000002d8 23 inc hl
| ||| 0x000002d9 56 ld d, [hl]
| ||| 0x000002da 13 inc de
| ||| 0x000002db 13 inc de
| ||| 0x000002dc 1a ld a, [de]
| ||| 0x000002dd 4f ld c, a
| ||| 0x000002de 79 ld a, c
| ||| 0x000002df fe34 cp 0x34
| ||| ,=< 0x000002e1 c2e602 jp nZ, 0x02e6
| |||,==< 0x000002e4 1803 jr 0x03
| ||||| ; CODE XREF from 0x000002e1 (fcn.00000288)
| ,====`-> 0x000002e6 c3b704 jp 0x04b7
| ||||| ; CODE XREF from 0x000002e4 (fcn.00000288)
| ||||`--> 0x000002e9 f800 ld hl, sp + 0x00
| |||| 0x000002eb 5e ld e, [hl]
Here we can make the hypothesis just by looking the structure that the character check is checking one by one each char of the flag and they are hardcoded.
Let’s concatenate all cp
opcode values (for this part I used VV @fcn.00000288
to navigate into the code)
Once done we have the following result :
744834545a5f344e5f653453595f4e44485f664c3447
Once converted to ascii :
>>> "744834545a5f344e5f653453595f4e44485f664c3447".decode('hex')
'tH4TZ_4N_e4SY_NDH_fL4G'
@Areizen