Reverse Engineering Pandora’s Box (2)
Introduction #
This article is a continuation of a previous post. If you haven't read it, I recommend you start there!
In the previous post we started our journey of reverse engineering Microsoft's Pandora's Box, a PC game from 1999. Today, we will look into the following steps:
- Extracting or dumping the contents of the .rof files
- Repacking the .rof files so our modifications can be seen in-game
- Analyzing and modifying the Focus Point puzzle file (.ZOO file)
Let's get started!
Extracting the pandora.rof file #
In the previous post we listed the contents of the pandora.rof file. Let's modify the script so it extracts the directories and files contained in a given .rof file:
(Note: I have pushed the the scripts used to GitHub, and modified the earlier scripts to take the path to the .rof file as a command-line argument.)
Running the scripts on the pandora.rof file leaves us with a ~300 MB directory containing the extracted assets:
Next, we will write a packer that can rebuild .rof files, as we not only want to view the assets but also modify them. As we have fully decoded the metadata format in the previous post, we can easily implement the packer:
To get the game to use our repacked file, we must take into account a few considerations:
- The
CDPATH
registry key trick from the previous post is required. Without it the game will load the.rof
file from the CD, even if a full installation was performed. - Started puzzles are cached in the save files ('
r<name>.ply
' and 'r<name>.bly
' located in the installation directory ('%PROGRAMFILES(X86)%\Microsoft Games\Pandora's Box
', or '%LOCALAPPDATA%\VirtualStore\Program Files (x86)\Microsoft Games\Pandora's Box
' if the game is running without Administrator privileges, assuming a 64 bit Windows installation)). As we have not yet decoded the save file format, this means that we will need to delete the save file between tests, if we have modified a puzzle that has already been started. - The game extracts the
.RIM
files for a puzzle type fromscreens.rof
when the first puzzle of that type is started. The extracted files are placed in the installation directory. When we're going to modify thescreens.rof
we will need to clean up the extracted files between tests.
Note that while the file packed by the above script is perfectly valid, it is not identical to the original file due to the order of its contents. The original file is packed breadth first, while our script packs depth first. As long as the metadata describing the internal structure is correct the game will happily use our modified file.
Next, let's look at the first Focus Point puzzle ('pandora.rof/LEVEL.01.MAUI/CITY.06.CAIRO/PUZZLE.01.FPN
'). Inside the directory we find a single file 'PUZZLE.ZOO
'. Let's inspect it using binwalk:
$ binwalk pandora.rof/LEVEL.01.MAUI/CITY.06.CAIRO/PUZZLE.01.FPN/PUZZLE.ZOO
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
928 0x3A0 JPEG image data, JFIF standard 1.01
Until now we have only seen images in the PNG format, however the puzzle image in this case is encoded as a JPEG. Let's extract it using dd
:
$ dd if=PUZZLE.ZOO of=puzzle.jpeg bs=1 skip=928
Having opened the file, we see that this is indeed the first Focus Point puzzle from the city of Cairo:
Next, let's try replacing the image. I grabbed a random CC0 licensed penguin from the internet, resized it to 336x480 (the size of the original image) and saved it as JPEG. Through trial and error I found that the game requires the image to have valid JFIF metadata, specifically the X and Y resolutions and unit need to be set. The original images use JFIF version 1.01 but files using the latest version (1.02) work just fine. As JFIF and EXIF are incompatible we first need to strip any EXIF metadata from the new file, and then we can set the required properties. We can use ExifTool for this:
$ exiftool -all= image-new.jpeg
$ exiftool -JFIF:XResolution=300 image.jpeg
$ exiftool -JFIF:YResolution=300 image.jpeg
$ exiftool -JFIF:ResolutionUnit=inches image.jpeg
The original file was also saved with 4:2:0 chroma subsampling and 85% quality, but this is not a requirement: 4:4:4 files with 100% quality load just fine.
We now need to get the original metadata and append the new image to it:
$ dd if=PUZZLE.ZOO of=metadata bs=1 count=928
$ cat metadata puzzle.jpeg > PUZZLE.ZOO
Next, repack the .rof file and move it to the game directory. Remember to clean up save games and extracted data as described earlier!
Launch the game and start the first Focus Point puzzle in Cairo to see our penguin in all its glory - at least after we put him back together 🙂
In a future post we will take a look at the 928 bytes of metadata prepended to the image.