🧢 Reverse engineering tool for the Klonoa's GBA game
klo-gba.js is a web Level Editor for Klonoa: Empire of Dreams game. Using this tool, you can extend the limits of this awesome game! Please, buy Klonoa's games to support this franchise.
Do you want to learn how to do reverse engineering? Or more about the front-end side?
Very nice! Let's chat more!
Since this is a study project, I'm writing a manual about how I'm developing it, because I want that more people to learn how to do a rom hacking for others games. It's a very fun challenge!
Are you the type that prefers to watch instead of read? No problem! My friend and I gave a lecture at three conferences about this project. Of course, in a talk the content is much more condensed, because we have less time, so the posts liked above are much more detailed - but these talks bring a far more interactive approach to unraveling the challenges of reverse engineering.
Talk at DEFCON Furs 2021
Since this conference is geared towards security, this talk is focused on the reverse engineering process. Slides.
(there is a brief audio problem, fixed at ~2:00)
For the previous lectures with another focus, see the post on Medium.
Are you liked this project and this talk? I have one about compilers! Do you want to see?
klo-gba.js is a monorepo built with three projects: 🖌 brush
and ✂️ scissors
. These projects are written using JS, will be compiled by Babel and uses Webpack.
It is responsible to provide a web interface for the user to upload the ROM of Klonoa's game and to view/edit the levels.
This project uses the React component library Former-Kit and it uses Scissors as a dependencie.
It is reponsible to provide informations about each level. To do it so Scissors extracts the informations from a buffer of the ROM and also has some hardcoded informations about each level.
1 - Clone this repo:
> git clone https://github.com/macabeus/klo-gba.js.git
2 - At the project root, compile some webassembly. To run this command, you'll need to have docker installed in your machine, in case you don't, check Docker official website:
> cd klo-gba.js
> bash ./shellscript/compile-webassembly.sh
3 - We are using Yarn's Workspaces. So at the project's root, you'll should install the dependencies:
> yarn
4 - So you could build and watch the scissors
project:
> cd klo-gba.js/scissors
> yarn start
5 - And finally, at another terminal tab, go to the path klo-gba.js/brush
, and start the build and watch:
> cd klo-gba.js/brush
> yarn start
6 - Then the service will start at the URL http://localhost:8080/
1 - Deploy on GitHub Pages is a very easy task. Just run it:
> cd klo-gba.js/brush
> yarn run deploy
2 - When it finishs, you can see the new website on http://macalogs.com.br/klo-gba.js/
(or at the respective URL; you can see which is on repository's Settings tab)
The reverse engineering is well explained in these posts, and the codebase and its architecture are mainly explained on the seventh chapter.
Currently, klo-gba.js has only the first visions. If you want to add a new one, you'll need to:
Two files should be created to add a new vision: an info file and the entering gba state on the vision. After creating these two files, you should update scissors/src/visions/index.js
linking your new files.
This file is the GBA state when a new vision is being loaded. To get this data, add a debugger
on brush/src/hooks/useGbaSaveRestoreState.js
before of setSavedState(saveState())
and run this command on the browser's console when a vision is being loaded:
copy(JSON.stringify(saveState()))
Then format the json and save this data on the scissors/src/visions/entering-gba-state
folder.
Create a new file in the folder scissors/src/visions/infos
using as template the file template.js
.
Fill this file following the below instructions:
- Open no$gba and add a brekpoint on
0805143C
- On game, enter on a vision
- You'll stop on the breakpoint. Firstly the game will unpack the vision's assets, not the tilemap. So you'll need to re-run until find when the game start to unpack the tilemap. To check it, look when there are changes on bytes following of ~
020039CC
. When you see it changes by the first time, remember how much times you needed to re-run (for example, if you needed to re-run 4 times to start to see a change on ~020039CC
) - Leave the vision and enter into it again, and then re-run how much times minus 1 you needed to see changes on
020039CC
(for example, 4 - 1 = 3 times), and get the value at r0 (for example, on vision 5 is081B8A28
) - You should put this values on
tilemap
without the first 2 digits. For instance:tilemap: 0x1B8A28
- Go to the previous vision file, and get the address which start the OAM, for example, at the vision 1-3 is
E4DF0
- Go to this address at no$gba (in this example, is
080E4DF0
) - You'll see that there is many zeros between this section and at the next section, so the address of the next section is the OAM map of the next vision, just get this address at put on the vision file
- If not work, add a breakpoint on the address
0804505C
, start again the vision, and replace the start address with the value at r1.
If some object appears as unknown, you'll need to add this new kind on klo-gba.js, at the file objectMaps.js
.
- Add a breakpoint on the address
0800CAF8
- Enter on the vision. So the emulator will stop at the breakpoint, and the start address of portals will be stores at r1
- To discover the last address is just guessing: just add 8 on this address until plot a pretty tilemap.