Northsec 2024
Genetic System Writeup (GBA ROM Reverse)
This challenge was part of the Northsec CTF 2024. The theme was the human body.
Going up to the challenge post, we were greeted with theses instruction :
For starter, a simple file command tell us that we are dealing with a Game Boy Advance ROM image. So to run it, I used the mGBA emulator : https://mgba.io/
The game is pretty simple, we need to find the 4 letter code that will generate a genetic construction. If we do not give the right answer, the game just print out FAILURE and we need to reload it to try again.


If we search a bit, there are Ghidra extension available on the internet that helps in reversing .gba rom. But we do not really need them, because we also have a .elf version of that file. Throwing this into Ghidra, we easily find the main function, containing the main_loop of the game. So let’s look at thoses 2 functions.

We see


Not much in main.
In the loop, we see classic key events for enabling the user to change the 4 letters using the standards keys. The things we are interested in, is the enter key event and how the 4-letters code is validated. We can make the assumption that the key_hit(8) at the end of the main loop is the enter key event and the function inside, process_blood_type , does the validation. Let’s look at it :

Now theres a couple thing that poke my eyes. First, what is this long random string at the beginning ? DNA ? Then we see a call to evaluation_routine (?), the FAILURE string, some random loops and finaly we see where the FLAG is printed. How can we reach it ? My first thought was that we only need to make the If statement on line 22 false. Easy. Lets note the address of the assembly check (0x08000704), and go patch it in the GBA ROM file!

Now we open the .gba file in Ghidra, look for the address 0x08000704, use Ghidra patching function to change the beq to a bne.

Now, we can go to files -> Export Program, and it will create us a new ROM with that instuction patch. Let’s run it!

We have a FLAG! But… the northsec system does not accept it.. Looking back at the code, it all makes sense. The flag is generated based on the 4 letters we enter in the game. In summary, the 4 letters key will make the program compute the Stem Cell sequence that we want, based on the big string at the beginning of the process_blood_type function. That sequence will be our real flag.
We need to reverse engineer the evaluation_routine function to know what code will give us the flag. Let’s look at it:

So, to make the code a little bit more understandable, we see that key_chars is probably an array that stores the 4 letters of our code and the variables DAT_03000250, DAT_0300025c and DAT_03000268 are potentially elements of that array. So renaming key_chars and the 3 DAT_030002** to the respective keys we get :\

So, now its pretty basics conditions. To solve it, we can look at each conditions and manually compute the respective byte (like my stupid ass did), or we can also use a script generate by chatGPT (and modified a bit) that will go over every characters possible and check every conditions to find which ones will make the function return 1.
\
def find_matching_characters():
for key_1 in range(0x41, 0x5B):
if (key_1 & 0xf0) == 0x40:
if (key_1 & 0xf) == 5:
for key_2 in range(0x41, 0x5B):
if (key_2 & 0x40) != 0 and (key_2 & 0x20) == 0 and (key_2 & 0x10) == 0 and (key_2 & 8) == 0:
if (key_2 & 4) != 0 and (key_2 & 2) != 0 and (key_2 & 1) != 0:
for key_3 in range(0x41, 0x5B):
if (key_2 ^ key_3) == 0x16:
for key_4 in range(0x41, 0x5B):
if (key_4 & 0x40) == 0x40 and (key_4 & 0xf) == 0xb:
print(f"{chr(key_1)} {chr(key_2)} {chr(key_3)} {chr(key_4)}")
break
# Print the matching characters and their key values
find_matching_characters()
Running it give us the code we wanted!

Now we enter thoses 4 letters in the game and the FLAG will appear :

Thank you for reading!