tonyhax with a game exploit

The original, well-tested method, which leverages an exploit in supported games to launch tonyhax.

Installation

This method requires copying to the memory card:

These files behave like regular game save files:

When installing:

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
Castlevania Chronicles NTSC-U SLUS-01384 cc-us.mcs BASLUS-01384DRACULA
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

This video from MrMario2011 explains pretty well how to install it using uLaunchELF on a memory card:

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.

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: