tonyhax

Software backup loader exploit thing for the Sony PlayStation 1.

Why?

The first question that might pop up on your mind regarding this project is “why the fuck didn’t you just install a modchip?”.

The answer is simple: I didn’t want to mod my mint, boxed PSone, but I didn’t want to leave it rotting on a shelf either.

Also, as an owner of a SCPH-102 console, these are a pain in the ass when it comes to chipping - in addition to the generic SCEx wobble check performed by the CD controller that is easily patchable, the boot menu on these also checks for the region string, which involve installing even more wires and a full sized Arduino Pro Mini or AtMega328 chip to patch the CPU BIOS to play out of region games. Not cool.

On top of that, and unlike Action Replay or swap discs, this does allow CD-DA games and multi-disc games to work flawlessly.

Download

Releases are available at the GitHub releases page.

Source code is also fully available under the WTFPL license at GitHub.

Installation

To install this exploit, you’d need a means of copying the required save files to a PS1 memory card. For this at the moment you have essentially two options:

All you have to do is copy the game’s crafted save file and the tonyhax SPL file into the card. That’s it.

Once installed, you can freely copy it to other cards using the PS1 and the memory card management menu, and distribute it freely amongst friends.

Please note the save games expect the BESLEM-99999TONYHAX file to be in the first memory card slot. It will not work if the memory card is inserted in the second card slot.

Video from MrMario2011 installing it using uLaunchELF on a memory card:

Save games

These have been tested to work on real hardware:

Game Region Code MCS file Raw file
tonyhax SPL required - - tonyhax.mcs BESLEM-99999TONYHAX
Brunswick Circuit Pro Bowling NTSC-U SLUS-00571 brunswick1-us.mcs BASLUS-00571
Brunswick Circuit Pro Bowling PAL-E SLES-01376 brunswick1-eu.mcs BESLES-01376
Brunswick Circuit Pro Bowling 2 NTSC-U SLUS-00856 brunswick2-us.mcs BASLUS-00856
Brunswick Circuit Pro Bowling 2 PAL-E SLES-02618 brunswick2-eu.mcs BESLES-02618
Castrol Honda Superbike Racing NTSC-U SLUS-00882 castrolsb-us.mcs BASLUS-00882CHSv1
Castrol Honda Superbike Racing PAL-E SLES-01182 castrolsb-eu.mcs BESLES_01182CHSv1
Castrol Honda VTR PAL-E SLES-02942 castrolvtr-eu.mcs BESLES-02942CHSVTRv1
Cool Boarders 4 NTSC-U SCUS-94559 coolbrd4-us.mcs BASCUS-9455916
Cool Boarders 4 PAL-E SCES-02283 coolbrd4-eu.mcs BESCES-0228316
Crash Bandicoot 2: Cortex Strikes Back NTSC-U SCUS-94154 crash2-us.mcs BASCUS-9415400047975
Crash Bandicoot 2: Cortex Strikes Back PAL-E SCES-00967 crash2-eu.mcs BESCES-0096700765150
Crash Bandicoot 3: Warped NTSC-U SCUS-94244 crash3-us.mcs BASCUS-9424400000000
Crash Bandicoot 3: Warped PAL-E SCES-01420 crash3-eu.mcs BESCES-0142000000000
Sports Superbike PAL-E SLES-03057 superbike1-eu.mcs BESLES-03057SSBv1
Sports Superbike 2 PAL-E SLES-03827 superbike2-eu.mcs BESLES-03827SSII
Tony Hawk’s Pro Skater 2 NTSC-U SLUS-01066 thps2-us.mcs BASLUS-01066TNHXG01
Tony Hawk’s Pro Skater 2 PAL-DE SLES-02910 thps2-de.mcs BESLES-02910TNHXG01
Tony Hawk’s Pro Skater 2 PAL-E SLES-02908 thps2-eu.mcs BESLES-02908TNHXG01
Tony Hawk’s Pro Skater 2 PAL-FR SLES-02909 thps2-fr.mcs BESLES-02909TNHXG01
Tony Hawk’s Pro Skater 3 NTSC-U SLUS-01419 thps3-us.mcs BASLUS-01419TNHXG01
Tony Hawk’s Pro Skater 3 PAL-DE SLES-03647 thps3-de.mcs BESLES-03647TNHXG01
Tony Hawk’s Pro Skater 3 PAL-E SLES-03645 thps3-eu.mcs BESLES-03645TNHXG01
Tony Hawk’s Pro Skater 3 PAL-FR SLES-03646 thps3-fr.mcs BESLES-03646TNHXG01
Tony Hawk’s Pro Skater 4 NTSC-U SLUS-01485 thps4-us.mcs BASLUS-01485TNHXG01
Tony Hawk’s Pro Skater 4 PAL-DE SLES-03955 thps4-de.mcs BESLES-03955TNHXG01
Tony Hawk’s Pro Skater 4 PAL-E SLES-03954 thps4-eu.mcs BESLES-03954TNHXG01
Tony Hawk’s Pro Skater 4 PAL-FR SLES-03956 thps4-fr.mcs BESLES-03956TNHXG01
XS Moto NTSC-U SLUS-01506 xsmoto-us.mcs BASLUS-01506XSMOTOv1
XS Moto PAL-E SLES-04095 xsmoto-eu.mcs BESLES-04095XSMOTO

Usage

For Cool Boarders 4

Supported since v1.2.

  1. Boot the game. It should say the records and settings have been automatically loaded.
  2. Click on “ONE PLAYER”.

The exploit should then launch.

For Crash Bandicoots

Supported since v1.2.

  1. Boot the game.
  2. On the title menu, choose LOAD GAME.
  3. On the save game list, select “TONYHAX” and press X.

The exploit should then launch.

For Brunswick games

Supported since v1.1.

  1. Boot the game as you’d normally do.
  2. On the main menu, select “LOAD GAME”.
  3. Select “MEMORY CARD 1”.

After about three seconds tonyhax should be running.

For Castrol Honda Superbike Racing and Sports Superbike 1

Supported since v1.2.

  1. On the language selection screen, if prompted to, select the English language.
  2. Enter the Memory Card menu.
  3. Load game from the Memory Card. Click accept after it’s done loading.
  4. On the main menu, select “Race”.
  5. Click on “Single race”.

The exploit should then launch.

For Castrol Honda VTR, Sports Superbike 2 and XS Moto

Supported since v1.2.

  1. If you are using the European version, on the language selection screen select the English language.
  2. On the main menu, choose Options.
  3. Select Load game and choose the memory card where the save is stored.
  4. Back on the main menu, click on either “Single Race” or “Championship”.

The exploit should then run.

For Tonyhawk’s games

  1. Boot the game as you’d normally do.
  2. On the main menu, wait until the save file is automatically loaded (it should say “Loading TONYHAX EU/US/DE/FR”, depending on the game’s region).
  3. After it’s done, choose the “CREATE SKATER” menu and press X.

After a couple seconds, tonyhax should boot.

For all

During the exploit launch, since v1.1.2 the screen will flash with different colors depending on which phase it is:

The console should spend no more than a couple seconds with each color. If it spends more time (specially with the green screen), it’s probably crashed. Please report it.

Compatibility

Consoles

After receiving multiple reports testing on different consoles, it seems that tonyhax works with:

However, this will not work with:

These consoles might be able to boot the exploit, but the CD patch that allows booting from burned media will not work.

Incompatible games

This is a short, non-exhaustive list of games that have been report not to work:

Please note that, despite the ability of tonyhax to patch games with antipiracy, only a very small subset of games are currently supported, since it’s a pretty manual and laborious task. As a general rule, if the game can be copied in a manner that doesn’t trigger antipiracy (for instance, by properly copying the subchannel data for games that are EDC- or libcrypt-protected), I will not look into patching them. If you want to do it yourself and make a PR, that’s fine though.

Screen displaying the "SOFTWARE TERMINATED" message

If the game displays a message like the one above, this means the game has an explicit modchip check, and the only way to fix this would be to patch the game. In that case, please file a report on GitHub.

Other

Please note the console can only read CD-R media, not CD-RW discs.

How does this work?

In layman terms, this exploit uses an oversight from the programmers: the game does not check that text in the save file hasn’t been tampered and fits in the space the program allocated for it. If we externally change that text to something longer, we can overwrite other vital parts of the system’s memory and run our own code.

For Tonyhawk’s games

THPSx save games have been modified to have the following two separate parts:

Skater name

When entering the skater customization menu, the menu is dinamically generated to include the saved skater names in a way like:

void trim_string(char * buffer, int len) {
	char trimmed[x];

	// Copy to our local buffer
	strcpy(trimmed, buffer);

	// Trim it
	trimmed[len - 4] = '.';
	trimmed[len - 3] = '.';
	trimmed[len - 2] = '.';
	trimmed[len - 1] = 0;

	// Copy back to the original buffer
	strcpy(buffer, trimmed);
}

void create_skater_entry(int id) {
	char menutext[x];
	int textlen;

	sprintf(menutext, "Skater %c: %s", 'A' + id, custom_skater_data[id].name);
	while ((textlen = strlen(menutext)) > MAX_LEN) {
		trim_string(menutext, textlen);
	}

	// ...
}

Essentially, if a string that’s too long to overflow the buffer is specified, the buffer overflows and overwrites part of the stack as we want to, but then it gets hammered with periods.

However, as trim_string is a a subcall and has a local buffer, if we specify a character name with the right length (165 characters, exactly), the null terminator in the trimmed buffer overlaps the first character of menutext, resulting in a menu entry with length of 0, thus sparing the rest of the stack contents.

After some more menu-related stuff, the return address is finally pulled from the stack and the code jumps to it. This return address points to the beginning of the high scores menu, whose contents are also loaded with no checks from the memory card, and where we have the first-stage payload.

High scores with first-stage payload

For Brunswick games

This is a super simple exploit. The program loads the entire save file contents at an static memory location, then blindly sprintfs into a stack buffer. Using a string long enough with the address of first stage loader at the correct position gets us executing our own code.

Brunswick save game modified

Above, the long username, with the memory location (0x80110AA4) of the first stage bootloader.

Common to all

The first stage payload’s sole purpose is to load the secondary program loader (or SPL for short) from an additional save file in the memory card using the PS1 BIOS calls. Once loaded, it jumps straight to it. If for some reason it fails to load the SPL, a red screen is displayed, indicating that the exploit was successfully triggered but the it couldn’t continue.

As the console is left in an inconsistent state, the SPL then first reinitializes the system kernel (RAM, devices…), by using the very same calls the ROM executes during the booting of the console.

After that, the GPU is reset. Once the GPU is ready again, the sets up the video to a resolution of 320x240, unpacks the 1bpp font from the BIOS ROM into VRAM, and draws the basic border and program name to know everything is working fine until this point.

With a fully working screen, it then proceeds to unlocks the CD drive to accept discs missing the SCEx signature, leveraging the CD BIOS unlock commands found by Martin Korth. These unlock commands are a sort of backdoor, and the drive, probably in order to keep them secret, returns an error instead of a success message. The SPL is coded to expect a particular error to be returned, and will actually abort if the drive returns that it succeeded or if it returns another unexpected error code.

After unlocking it, it waits for the lid to be opened and closed, allowing the user to insert a new CD.

After that, the CD filesystem is reinitialized. It proceeds to read the SYSTEM.CNF configuration file, reinitializes the kernel with the parameters the game needs, and finally loads and runs the game’s main executable.

Pending games

This is just a list of games that have been suggested to be checked but I’ve still not had time to look at them.

Unexploitable games

This is just a short list of games I’ve glanced over and determined they are unlikely to be exploitable:

Acknowledgements

In alphabetical order:

On the media

Sorted from older to newer.