in-place rom hacking
Ever since receiving one as a Christmas present in ‘98 I’ve been enamoured with the Sony PlayStation, AKA the PS1 or PSX. It spawned a lifelong love of gaming and many of my favourites were originally released on the system. These days I mostly play using an emulator as it is far more convenient than playing using original hardware or my PS3. I use the PCSX-ReARMed1 emulator (via Retroarch2) on a PC I have connected to the TV in the living room. I use this machine to also play things via Steam3 and GOG4 (via Lutris5); it is nice to have one machine handling most of the games I want to play.
When playing games via an emulator you typically require a ROM6, which is a file representing the game on its original storage medium such as a cartridge or CD-ROM. This can manifest in various formats such as .bin
or .iso
. If you own a copy of the game it is possible (and legal in the UK 7 8) to make a backup of the game media to a file which can then be used with an emulator 9. This process is known as Dumping 10. With the game ‘dumped’ to a file it is possible to modify the contents to produces changes in the game itself. What can be modified is entirely dependent on the game and how it was programmed, so some initial detective work is necessary to find the relevant areas of interest.
Finding strings
My original motivation for modifying ROMs was to change in-game text to make some comedic screenshots. For this example, I’ll be using Spyro 2: Gateway to Glimmer11, one of my all time favourites. I’ll be attempting to modify the name and dialogue of the first character Spyro meets:
The first character Spyro meets upon starting Spyro 2: Gateway to Glimmer
In order to find strings within the ROM I used the strings
12 utility on Linux and ran it against the ROM file.
$ strings spyro_2.bin -n 8 --radix=x
Here -n
is used to only output strings if they are at least 8 characters long. The flag --radix=x
is used to display the offset (in bytes) where the string is located in the file. This is particularly useful for finding where to modify later. The command can be taken further by piping the output to grep
13 in order to find specific strings:
$ strings spyro_2.bin -n 8 --radix=x | grep -i "Gemcutter"
The flag -i
is used to search case insensitive to widen the criteria. Executing the commands in the terminal outputs the following data:
$ strings spyro_2.bin -n 8 --radix=x | grep -i "Gemcutter"
14b2944 Whiskers the Gemcutter
14b2962 We Gemcutters are a bit too short to climb these ladders... looks like you are too. After you learn to climb, come back to Glimmer to see me.
14b2f27 *Still here? Why don't you help the Gemcutters and they'll show you the way to Summer Forest.
14b513c Twitchy the Gemcutter
14b6f44 Bounsa the Gemcutter
14b8714 Pogo the Gemcutter
14b8850 Kanga the Gemcutter
14b8d40 Roo the Gemcutter
The output shows the string Pogo the Gemcutter is located at offset 0x14B9714
in the ROM. Experimentation will be necessary to locate the relevant area for modification and some games may not have text data encoded as strings at all! You may want to tinker with the --encoding=
and --unicode=
flags to investigate further to try and find the strings you want to modify.
Upon finding the location of the Pogo the Gemcutter string I’m going to modify it in-place to change text data in the game. ‘In-place’ here means that I will be modifying the string without changing any offsets or locations in the ROM. This is crucial for the game to run correctly as the compiled binary will be expecting specific things at specific addresses (locations).
Modifying Text
My tool of choice for modifying ROMs is hexedit
14, which provides a nice command line interface for modifying hexadecimal data in files. Use TAB
to switch between Hex mode and ASCII mode and CTRL+S
to search for a specific string. Searching for Pogo the Gemcutter takes me to location 0x14b8714
, which contains the full name and the accompanying dialogue:
Viewing the ROM in hexedit
prior to editing
I then replaced Pogo the Gemcutter with Dylan Thomas and the accompanying dialogue with the ending lines from Thomas’ famous poem Do Not Go Gentle into That Good Night15. The unused characters are replaced with spaces so that offsets in the file are unchanged. For example Pogo_the_Gemcutter
would be replaced with Dylan_Thomas______
(spaces replaced with an underscore for emphasis).
Hexedit
helpfully highlights the changes in bold as shown in the following screenshot:
Viewing the ROM in hexedit
post editing
Upon execution of the modified ROM file, approaching the character now shows the following dialogue:
Voilà!
Conclusion
While the term ROM-hacking here might be tenuous (due to the fact the actual game experience isn’t being modified), it was nonetheless an interesting exercise to modify game data and to see the changes reflected at runtime. While my original motivation was to make silly screenshots to send my mates it was fun to explore the data contained inside a ROM and to see what I could change without breaking the game.
Thanks for reading!
-
Read Only Memory ↩
-
Note: I’m aware that the procurement of ROMs for use in emulators is a legal grey area. While it may be possible to acquire ROMs via other means, this article assumes the reader is creating (dumping) their own ROMs using their own legal copies of the game. ↩
-
Ripto’s Rage if you’re in the US. ↩