The day I reverse engineered a Gameboy Advance game [ReactSP#35]

The day I reverse engineered a Gameboy Advance game [ReactSP#35]

Gameboy Advance was one of the most popular video game platforms of its time and, because of it, many people worked together as a community to study and to document its architecture and develop ROM hacking and other interesting tools.

It turns out that this video game is a fantastic way to start studying reverse engineering: its architecture is very well documented and simpler if compared to the current game console generation – and, of course, it is very fun to work in a game-related project.

So... what do you think of learning reverse engineering through this challenge: developing a level editor for a GBA game called "Klonoa: Empire of Dreams"?
We need to understand the architecture behind ARM hardware, apply reverse engineering in order to discover how the logic of the game works, and then use our front-end knowledge (JS + React.js) to build a level editor.

F380535da59d6cdd5754e2e31bda8a0e?s=128

Bruno Macabeus

June 28, 2019
Tweet

Transcript

  1. The day I reverse engineered a Gameboy Advance game With

    @macabeus
  2. MACABEUS macabeus ____ www.macalogs.com.br _ _ Software Engineer, full-stack @LOGGI

  3. WTF?! THE DAY I REVERSE ENGINEERED A GAMEBOY ADVANCE GAME

  4. None
  5. None
  6. None
  7. None
  8. None
  9. None
  10. http://bit.ly/gba-the-conf-project

  11. Stretching the bridge THE DAY I REVERSE ENGINEERED A GAMEBOY

    ADVANCE GAME
  12. https://www.nogba.com

  13. https://www.hex-rays.com/products/ida

  14. None
  15. None
  16. This is the tile ID. In this example, all tiles

    with the ID 9B are exactly the bridge part, which is the left corner. 9A is the ID of the uninterrupted part of the bridge.
  17. This tells us where the tile is stored in the

    memory. In this example, it is at 0600F1AD.
  18. https://www.coranac.com/tonc/text/hardware.htm

  19. https://www.coranac.com/tonc/text/hardware.htm The address found is expected 0600F1AD given that everything

    between 0600 and 0601 is part of the section known as VRAM.
  20. Our bridge starts here!

  21. And now we grow it bigger!

  22. And now we grow it bigger!

  23. And now we grow it bigger! WTF??!

  24. Understanding the DMA THE DAY I REVERSE ENGINEERED A GAMEBOY

    ADVANCE GAME
  25. None
  26. VRAM pulls the tilemap
 containing exactly what the player has

    to see from somewhere else that has the entire thing.
  27. VRAM pulls the tilemap
 containing exactly what the player has

    to see from somewhere else that has the entire thing.
  28. https://www.coranac.com/tonc/text/regbg.htm

  29. https://www.coranac.com/tonc/text/regbg.htm Direct Memory Access

  30. https://www.coranac.com/tonc/text/regbg.htm Direct Memory Access It is a feature of computer

    systems that allows certain hardware subsystems to access main system memory (random-access memory), independent of the CPU
  31. https://www.coranac.com/tonc/text/regbg.htm Direct Memory Access A copy and paste faster

  32. DMA3: 03000900 0600E000 80000400 DMA3: 03001100 0600E800 80000400 DMA3: 03004DB0

    0600F000 80000200 DMA3: 03004800 07000000 84000048
  33. DMA3: 03000900 0600E000 80000400 DMA3: 03001100 0600E800 80000400 DMA3: 03004DB0

    0600F000 80000200 DMA3: 03004800 07000000 84000048 The closest to the bytes of our bridge (0600F1AD).
  34. DMA3: 03000900 0600E000 80000400 DMA3: 03001100 0600E800 80000400 DMA3: 03004DB0

    0600F000 80000200 DMA3: 03004800 07000000 84000048 This byte is the VRAM data source. It’s located in a region called Fast WRAM.
  35. None
  36. Our bridge starts here!

  37. Stretching it…

  38. Stretching it… And…

  39. Stretching it… …It works! And…

  40. Stretching it… …It works! And… WTF??!

  41. Stretching it… …It works! And… WTF??!

  42. None
  43. None
  44. Our extra tiles disappear when out of the player vision

    range.
  45. LET’S TALK ABOUT PHYSICS THE DAY I REVERSE ENGINEERED A

    GAMEBOY ADVANCE GAME
  46. Object Attribute Memory

  47. OAM

  48. None
  49. This is the address which Klonoa is stored on the

    memory
  50. DMA3: 03000900 0600E000 80000400 DMA3: 03001100 0600E800 80000400 DMA3: 03004DB0

    0600F000 80000200 DMA3: 03004800 07000000 8400003E
  51. DMA3: 03000900 0600E000 80000400 DMA3: 03001100 0600E800 80000400 DMA3: 03004DB0

    0600F000 80000200 DMA3: 03004800 07000000 8400003E We can see exactly the byte that writes on Klonoa’s OAM (07000000).
  52. DMA3: 03000900 0600E000 80000400 DMA3: 03001100 0600E800 80000400 DMA3: 03004DB0

    0600F000 80000200 DMA3: 03004800 07000000 8400003E We can see exactly the byte that writes on Klonoa’s OAM (07000000).
  53. None
  54. None
  55. None
  56. 1 2

  57. None
  58. None
  59. None
  60. None
  61. None
  62. Here is where Y fixes the Klonoa’s position Here is

    where decides if should fix or not the Klonoa’s position
  63. None
  64. https://www.coranac.com/tonc/text/hardware.htm

  65. https://www.coranac.com/tonc/text/hardware.htm

  66. None
  67. None
  68. Let’s find the tilemap on rom THE DAY I REVERSE

    ENGINEERED A GAMEBOY ADVANCE GAME
  69. None
  70. None
  71. swi 11h what?

  72. Swi

  73. SoftWare Interrupt

  74. Input: Exemplifying. . .
 How divider works on ARM Assembly:

    swi 0x06 R0
 numerator R1
 denominator R0
 numerator / denominator R1
 numerator % denominator R3
 abs(numerator / denominator) Output:
  75. None
  76. Huffman + lz77 = deflate

  77. None
  78. None
  79. None
  80. None
  81. Let’s paint the tilemap THE DAY I REVERSE ENGINEERED A

    GAMEBOY ADVANCE GAME
  82. H·W=25023
 H,W ∈ ℕ

  83. 9A 9B 9B 9B 9B 9A 00 00 00 .

    . .
  84. x x x x a x x x x -

    I’m on the tile a
 x x x x b x x x x
 
 x x x x a x x x x "- From the tile a to b there are 9 bytes (= 9 tiles),
 x x x x b x x x x so the length of the tilemap is exactly 9
  85. None
  86. None
  87. None
  88. None
  89. 020085DB - 02008437 = 1A4 (420)
 The length of the

    level is 420!
  90. Jimp

  91. None
  92. None
  93. None
  94. None
  95. None
  96. None
  97. let’s see the project THE DAY I REVERSE ENGINEERED A

    GAMEBOY ADVANCE GAME
  98. Coding THE DAY I REVERSE ENGINEERED A GAMEBOY ADVANCE GAME

  99. Stack

  100. React

  101. Webpack

  102. Ramda

  103. Former Kit ✈

  104. Github Pages ✈

  105. architecture

  106. ✂ Brush Scissors

  107. ✂ Z

  108. ✂ Z

  109. None
  110. Provider Pattern

  111. None
  112. None
  113. None
  114. ROMProvider VisionProvider

  115. None
  116. None
  117. None
  118. None
  119. Custom hooks

  120. None
  121. None
  122. Web assembly

  123. Tilemap compressed

  124. Tilemap compressed Old C code to uncompress it

  125. Tilemap compressed Old C code to uncompress it Tilemap

  126. None
  127. Can’t run C code on browser!

  128. None
  129. None
  130. None
  131. Webassembly code to uncompress it

  132. huffman.c lzss.c huffman.js huffman.wasm lzss.js lzss.wasm

  133. None
  134. None
  135. None
  136. None
  137. None
  138. None
  139. None
  140. None
  141. None
  142. after this magic…

  143. after this magic…

  144. Tilemap

  145. None
  146. ✔ Display tiles and OAM ✔ Allow to user can

    edit it
  147. Konva

  148. VisionContext

  149. VisionContext Map

  150. TilemapLayer OamLayer VisionContext Map

  151. TilemapLayer OamLayer PointOam PointsTile VisionContext Map

  152. TilemapLayer OamLayer Point PointOam PointsTile VisionContext Map

  153. TilemapLayer OamLayer Point PointOam PointsTile Map

  154. TilemapLayer OamLayer Point PointOam PointsTile Map 18.000 COMPONENTS

  155. TilemapLayer Map TilemapLayer OamLayer Point PointOam PointsTile

  156. TilemapLayer memo( ) Map TilemapLayer OamLayer Point PointOam PointsTile

  157. TilemapLayer globalState 0 0#→Ref Point 0 1#→Ref Point 1 0#→Ref

    Point . . . memo( ) Map TilemapLayer OamLayer Point PointOam PointsTile
  158. TilemapLayer globalState 0 0#→Ref Point 0 1#→Ref Point 1 0#→Ref

    Point . . . memo( ) Map TilemapLayer OamLayer Point PointOam PointsTile DrawingLayer
  159. TilemapLayer globalState 0 0#→Ref Point 0 1#→Ref Point 1 0#→Ref

    Point . . . memo( ) Map TilemapLayer OamLayer Point PointOam PointsTile DrawingLayer
  160. TilemapLayer globalState 0 0#→Ref Point 0 1#→Ref Point 1 0#→Ref

    Point . . . memo( ) Map TilemapLayer OamLayer Point PointOam PointsTile DrawingLayer
  161. https://gamedev.stackexchange.com/questions/96789/tile-map-optimization-algorithm

  162. https://gamedev.stackexchange.com/questions/96789/tile-map-optimization-algorithm

  163. BucketPointsTile TilemapLayer memo( ) Map TilemapLayer OamLayer Point PointOam PointsTile

    DrawingLayer
  164. Result THE DAY I REVERSE ENGINEERED A GAMEBOY ADVANCE GAME

  165. None
  166. None
  167. None
  168. None
  169. None
  170. None
  171. Future THE DAY I REVERSE ENGINEERED A GAMEBOY ADVANCE GAME

  172. Hex Editor React Component

  173. Hex Editor React Component

  174. Tilemap React Component https://dribbble.com/shots/5010806-Pixel-Map

  175. WE ARE... THE DAY I REVERSE ENGINEERED A GAMEBOY ADVANCE

    GAME
  176. MATHEUS ALBUQUERQUE YTHECOMBINATOR www.ythecombinator.space LAND@YTHECOMBINATOR.SPACE Senior Software Engineer, Front-End @STRV

    addicted to emojis, memes and beer
  177. Raul peres behance.net/Kniksis illustrator

  178. This talk THE DAY I REVERSE ENGINEERED A GAMEBOY ADVANCE

    GAME
  179. http://bit.ly/gba-reactsp-slides

  180. http://bit.ly/gba-the-conf-project

  181. http://bit.ly/medium-gba

  182. globo: http://pixelartmaker.com/art/da82835a7ab0184
 octocat: dumielauxepices.net

  183. OBRIGADO THANKS macabeus

  184. 0x10 0x01 0xC0 0x01 0x01 0x01 0x00 0x00 0x28 0x06

    0x68
 0x01 0x01 0x01 0x1C 0x00 0x78 0x08 0x80 0x01 0x01 0x01
 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x1C 0x00 0x00
 0x00 0x00 0x00 0x00 0x01 0x1C 0x00 0x0E 0x76 0x00 0x00
  185. 0x10 0x01 0xC0 0x01 0x01 0x01 0x00 0x00 0x28 0x06

    0x68
 0x01 0x01 0x01 0x1C 0x00 0x78 0x08 0x80 0x01 0x01 0x01
 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x1C 0x00 0x00
 0x00 0x00 0x00 0x00 0x01 0x1C 0x00 0x0E 0x76 0x00 0x00 First x position
 First y position
 Second x position Second y position Third x position Third y position Fourth x position Fourth y position Fifth x position Fifth y position Kind
  186. const [ xFirstPosition, yFirstPosition, xSecondPosition, ySecondPosition, xThirdPosition, yThirdPosition, xFourthPosition, yFourthPosition,

    xFifthPosition, yFifthPosition, kind, ] = qunpack.unpack('v2 x4 v2 x4 v2 x4 v2 x4 v2 x5 c', bytes);
  187. const { xFirstPosition, yFirstPosition, xSecondPosition, ySecondPosition, xThirdPosition, yThirdPosition, xFourthPosition, yFourthPosition,

    xFifthPosition, yFifthPosition, kind, } = binary.parse(memory) .word16lu('xStage1') .word16lu('yStage1') .skip(4) .word16lu('xStage2') .word16lu('yStage2') .skip(4) .word16lu('xStage3') .word16lu('yStage3') .skip(4) .word16lu('xStage4') .word16lu('yStage4') .skip(4) .word16lu('xStage5') .word16lu('yStage5') .skip(5) .word8lu('kind') .vars, memory, }))
  188. None