I’ve recently entered, as personal hobby, into the world of game development. And in 2020, what is more cool that trying to code on GameBoy™ platform.

Their is plenty of documentation and code samples out their and you can find a lot of references under Awesome Game Boy Development.

During my learning I found and read a lot of documentation and one of them is Tuto: Programmer sur Gameboy (fr). This guy (alias Furrtek) seems to know a lot about electronics and coding on hardware, by looking some of his work:

But what caught my attention is Super Connard™ (fr) (translated as Super Asshole), which ROM is available, but:

fr:

Comment peut-on y jouer, alors ?

Comme promis, maintenant que les cartouches sont coulées, vous pouvez librement télécharger et partager le ROM. A un détail près: il vous faudra faire sauter la protection anti-émulateur ! Et oui, le jeu porte bien son nom ! ;)

en:

How can we play, then ?

As promised, now that cartridges have been produced, you can freely download and share the ROM. At on small detail: you’ll need to get over anti-emulator protection ! And yes, the game deservers its name ! ;)

So that sounds like a challenge. This game has been release in 2013 and its source have been since then already disclosed. Let’s assume we do not have them !

DISCLAIMER: The views and opinions expressed in Super Connard™ game are those of the authors and do not represent policy or position of this blog post, which only purpose is to provide as educative methodology in binary analysis.

Tools

Radare2

radare2 is an open-source UNIX-like reverse engineering framework and command-line toolset.

It allows basically to play with any kind of binary and analyse it. Since a Game Boy™ cartridge ROM is nothing more than some binary data, this should help us.

GameBoy™ emulator

Any emulator should be able to be used.

Let’s go

At the time the game was released, it was only available on purchase of a physical Game Boy™ cartridge. There is a video showing how Xylit0l made a dump of ROM (Gameboy cartridge dumping (Super Connard)).

Now that the ROM is available, just get it: sc_prod.gb.

Time to launch the game:

$> gngb -a sc_prod.gb
stream 5
Open file sc_prod.gb
Rom Name sc_prod
Name    : SUPERCONNARD
Normal GameBoy
configuration 00 : ROM ONLY
ROM size 0 : 2 * 16 kbyte
NO RAM
Country : Non-Japanese

and a window opens !

Fuck you, emulator!

Dude, that’s so rude.

What does this file contains

strings sc_prod.gb | less
...
Fuck you,
emulator!
...
Code/Graphismes:
         Furrtek
Musique/FX:
       Don Ratta
Remerciements:
            Dyak
         ElBarto
 Marat Fayzullin
    Martin Korth
       Nitro2k01
           Orion
       RayXambeR
        Realmyop
         Robotwo
         Scruffy
     Ville Helin
...

at least, now, we know who insulted us.

I assume that radare2 is already installed, otherwise feel free to download it here.

Now we open the binary with radare2; use -w since we might need to update some data.

$> radare2 -w sc_prod.gb
[0x00000100]> i~format
format   ningb
[0x00000100]> i~machine
machine  Gameboy

It’s a GameBoy™ ROM. We already knew it. 0x100 is the start of any ROM.

[0x00000100]> px
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00000100  00c3 5001 ceed 6666 cc0d 000b 0373 0083  ..P...ff.....s..
0x00000110  000c 000d 0008 111f 8889 000e dccc 6ee6  ..............n.
0x00000120  dddd d999 bbbb 6763 6e0e eccc dddc 999f  ......gcn.......
0x00000130  bbb9 333e 5355 5045 5243 4f4e 4e41 5244  ..3>SUPERCONNARD
0x00000140  0000 0000 3030 0000 0000 0133 00bf 7e70  ....00.....3..~p
0x00000150  f331 f4ff afe0 2621 00c0 01ff 1fcd 7300  .1....&!......s.

Bytes 0x104 to 0x130 are Nintendo® logo which are mandatory for any ROM that is meant to work on real GameBoy™.

;*
;* Nintendo scrolling logo
;* (Code won't work on a real GameBoy)
;* (if next lines are altered.)
NINTENDO_LOGO : MACRO
    DB  $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D
    DB  $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
    DB  $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E
ENDM

Source: https://github.com/gbdev/hardware.inc

Conventionally, GameBoy™ program starts at 0x150. Let’s confirm it.

[0x00000100]> pd 70
            ;-- pc:
/ (fcn) entry0 54
|   entry0 ();
|           0x00000100      00             nop
|       ,=< 0x00000101      c35001         jp main
        |   0x00000104      ceed           adc 0xed
...
|      ||   ;-- main:
|      ||   ; CODE XREF from entry0 (0x101)
|      |`-> 0x00000150      f3             di
|      |    0x00000151      31f4ff         ld sp, 0xfff4

Or we could simply just have jumped to main

[0x00000000]> s main
[0x00000150]>

Looking for Fuck you string leads us to 0x4ef

[0x00000100]> izzq~Fuck
0x4ef 10 9 Fuck you,

So lets just look for where this string is loaded

[0x00000100]> pd 5000 | grep 0x04ef
            0x000007f9      11ef04         ld de, 0x04ef

Jump few instruction before

[0x00000100]> 0x000007f9-50
[0x000007f9]> pd
            0x000007c7      3ee4           ld a, 0xe4
            0x000007c9      e047           ld [0xff47], a
            0x000007cb      3e91           ld a, 0x91
            0x000007cd      e040           ld [0xff40], a              ; LCDC
       ,.-> 0x000007cf      76             halt
       |:   0x000007d0      00             nop
       ``=< 0x000007d1      18fc           jr 0xfc
            0x000007d3      43             ld b, e
            0x000007d4      68             ld l, b
            0x000007d5      65             ld h, l
            0x000007d6      63             ld h, e
            0x000007d7      6b             ld l, e
            0x000007d8      73             ld [hl], e
            0x000007d9      75             ld [hl], l
            0x000007da      6d             ld l, l
        ,=< 0x000007db      2065           jr nZ, 0x65
        |   0x000007dd      72             ld [hl], d
        |   0x000007de      72             ld [hl], d
        |   0x000007df      6f             ld l, a
        |   0x000007e0      72             ld [hl], d
        |   0x000007e1      ff             rst sym.rst_56
        |   ; CALL XREF from entry0 (0x16f)
        |   0x000007e2      f3             di
        |   0x000007e3      cdc400         call 0x00c4
        |   0x000007e6      cd7e03         call 0x037e
        |   0x000007e9      cdc801         call 0x01c8
        |   0x000007ec      3ee4           ld a, 0xe4
        |   0x000007ee      e047           ld [0xff47], a
        |   0x000007f0      210040         ld hl, 0x4000
        |   0x000007f3      110080         ld de, 0x8000
        |   0x000007f6      cd1404         call 0x0414
        |   0x000007f9      11ef04         ld de, 0x04ef

and jump to where we are called from: 0x16f

[0x000007c7]> 0x16f
[0x0000016f]> pd
|           0x0000016f      c4e207         call nZ, 0x07e2
|           0x00000172      cdea05         call 0x05ea
|           0x00000175      cd8201         call 0x0182
|           0x00000178      fe04           cp 0x04
|           0x0000017a      cc660d         call Z, 0x0d66
|           0x0000017d      cd2008         call 0x0820
\       @-> 0x00000180      18fe           jr 0xfe
            ; CALL XREF from entry0 (0x175)

We see that we jump to code with call nZ, 0x07e2, so let’s try to invert the condition. For that, we need to modify z80 opcode: here c4 by cc.

CALL NZ,nn	17/10	18/11	5/3	8/7/3²	C4 nn nn	3
CALL Z,nn	17/10	18/11	5/3	8/7/3²	CC nn nn	3

Source: http://map.grauw.nl/resources/z80instr.php

Enter visual mode, and press i to update first c4 by cc. Press q to quit editing.

[0x0000016f]> v
[0x0000016f [Xadvc]0 0% 1728 sc_prod2.gb]> xc @ main+31 # 0x16f
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF  comment
0x0000016f  c4e2 07cd ea05 cd82 01fe 04cc 660d cd20  ............f..
[0x0000016f]> pd1
            0x0000016f      cce207         call Z, 0x07e2

And start the ROM in emulator…

Checksum error!.

Damned ! It seems that there is some checksum protection.

Try again.

$> radare2 -w sc_prod.gb
[0x00000100]> izzq~Checksum
0x7d3 15 14 Checksum error
[0x00000100]> pd 5000 | grep 7d3
            0x000007b7      11d307         ld de, 0x07d3
[0x00000100]> 0x000007b7-50
[0x00000785]> pd
            0x00000785      7e             ld a, [hl]
            0x00000786      110000         ld de, 0x0000
        .-> 0x00000789      7b             ld a, e
        :   0x0000078a      86             add [hl]
        :   0x0000078b      5f             ld e, a
       ,==< 0x0000078c      3001           jr nC, 0x01
       |:   0x0000078e      14             inc d
       `--> 0x0000078f      23             inc hl
        :   0x00000790      0b             dec bc
        :   0x00000791      78             ld a, b
        :   0x00000792      b1             or c
        `=< 0x00000793      20f4           jr nZ, 0xf4
            0x00000795      214d00         ld hl, 0x004d               ; 'M'
            0x00000798      2a             ldi a, [hl]
            0x00000799      bb             cp e
        ,=< 0x0000079a      c2a207         jp nZ, 0x07a2
        |   0x0000079d      7e             ld a, [hl]
       ,==< 0x0000079e      c2a207         jp nZ, 0x07a2
       ||   0x000007a1      c9             ret
       ``-> 0x000007a2      cd7303         call 0x0373
            0x000007a5      af             xor a
            0x000007a6      e040           ld [0xff40], a              ; LCDC
            0x000007a8      210040         ld hl, 0x4000
            0x000007ab      110080         ld de, 0x8000
            0x000007ae      cd1404         call 0x0414
            0x000007b1      cd7e03         call 0x037e
            0x000007b4      cdc801         call 0x01c8
            0x000007b7      11d307         ld de, 0x07d3

Let’s see if we can prevent code from reaching 0x000007a2 instruction. This time replace c2 by ca (ie jp nz by jp z)

        ,=< 0x0000079a      c2a207         jp nZ, 0x07a2
        |   0x0000079d      7e             ld a, [hl]
       ,==< 0x0000079e      c2a207         jp nZ, 0x07a2

in order to have

[0x0000079a]> pd
        ,=< 0x0000079a      caa207         jp Z, 0x07a2
        |   0x0000079d      7e             ld a, [hl]
       ,==< 0x0000079e      caa207         jp Z, 0x07a2

Exit radare2.

Start the ROM in emulator, and cross fingers…

Voilà !

Super connard

Intro

References