My usual trick for passcode screens is to enter a distinctive string and then search for its ASCII representation in a memory snapshot. That often works on games from Western developers, but it didn't for this one.
Player input has to have some sort of effect on the game's memory, so the next step is to use a cheat finder to locate which addresses update when you change the passcode characters. I use RALibetro's Memory Inspector for this, but other people like Cheat Engine.
For this game, input updates the two 4-byte values at 800aa6a4 and 800aa6a8 (NTSC version). Setting a write breakpoint for those in Mednafen leads to the code that updates them. That function lives at 80031cdc, and it's doing the inverse of the function I showed in the article.
It's messy in the decompilation, but it simplifies to something like:
```
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
CHAR_TO_VAL = {char: index for index, char in enumerate(ALPHABET)}
def encode_passcode(passcode):
combined = 0
for char in passcode:
combined = (combined << 5) | CHAR_TO_VAL[char]
low_word = combined & 0xFFFFFFFF
high_word = (combined >> 32) & 0xFFFFFFFF
return low_word, high_word
```
It's packing the index of each character into the two 4-byte values, essentially.
The game stores the packed representations of each of the valid codes. I fed those into de-obfuscation function to produce the list.
How did you figure out how to de-obfuscate the cheat function?
My usual trick for passcode screens is to enter a distinctive string and then search for its ASCII representation in a memory snapshot. That often works on games from Western developers, but it didn't for this one.
Player input has to have some sort of effect on the game's memory, so the next step is to use a cheat finder to locate which addresses update when you change the passcode characters. I use RALibetro's Memory Inspector for this, but other people like Cheat Engine.
For this game, input updates the two 4-byte values at 800aa6a4 and 800aa6a8 (NTSC version). Setting a write breakpoint for those in Mednafen leads to the code that updates them. That function lives at 80031cdc, and it's doing the inverse of the function I showed in the article.
It's messy in the decompilation, but it simplifies to something like:
```
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
CHAR_TO_VAL = {char: index for index, char in enumerate(ALPHABET)}
def encode_passcode(passcode):
combined = 0
for char in passcode:
combined = (combined << 5) | CHAR_TO_VAL[char]
low_word = combined & 0xFFFFFFFF
high_word = (combined >> 32) & 0xFFFFFFFF
return low_word, high_word
```
It's packing the index of each character into the two 4-byte values, essentially.
The game stores the packed representations of each of the valid codes. I fed those into de-obfuscation function to produce the list.