Skip to main content
Evert's website

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:

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:

Extracted assets
Extracted assets. Note how hints, free puzzles and puzzle pieces are encoded using empty files.

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:

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:

Cairo Focus Point puzzle 1
The first Focus Point puzzle from Cairo. (Copyright Microsoft/Christie's Images)

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 🙂

Putting the penguin back together

In a future post we will take a look at the 928 bytes of metadata prepended to the image.