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:
- The common loader program, available inside the
loader/
folder. - One or more game-specific saves, available inside the
entrypoints/
folder.
These files behave like regular game save files:
- You can keep the memory card plugged after launching the exploit.
- You can keep using the same memory card for other games just fine.
- You can have more than one exploit save per memory card.
- tonyhax can be easily copied to other memory cards by just copying the save files.
- tonyhax can be uninstalled easily by removing the save files.
When installing:
- If you are using any sort of visual memory card editor (such as OrionSoft's PS1 Memory Card Manager, Dexdrive, etc...), consider using the MCS file.
- If you are copying it using a PS2 console and uLaunchELF, you'll need to use the raw file. The name is important - do not rename them.
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.
- Boot the game. It should say the records and settings have been automatically loaded.
- Click on "ONE PLAYER".
The exploit should then launch.
For Crash Bandicoots
Supported since v1.2.
- Boot the game.
- On the title menu, choose LOAD GAME.
- On the save game list, select "TONYHAX" and press X.
The exploit should then launch.
For Brunswick games
Supported since v1.1.
- Boot the game as you'd normally do.
- On the main menu, select "LOAD GAME".
- 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.
- On the language selection screen, if prompted to, select the English language.
- Enter the Memory Card menu.
- Load game from the Memory Card. Click accept after it's done loading.
- On the main menu, select "Race".
- Click on "Single race".
The exploit should then launch.
For Castrol Honda VTR, Sports Superbike 2 and XS Moto
Supported since v1.2.
- If you are using the European version, on the language selection screen select the English language.
- On the main menu, choose Options.
- Select Load game and choose the memory card where the save is stored.
- Back on the main menu, click on either "Single Race" or "Championship".
The exploit should then run.
For Tonyhawk's games
- Boot the game as you'd normally do.
- 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).
- 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:
- Blue: the SPL is being loaded from the memory card into main memory.
- Green: the SPL is done loading and will execute immediately. The SPL immediately reinitializes the screen so this color should be barely visible.
- Red: indicates that a fatal error occured loading the SPL. For example: the file isn't on the first memory card, the filename isn't correct or some other reason.
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:
- The highscores have been replaced with a small first-stage payload of a couple hundred bytes.
- The first custom character name has an abnormally long name, which contains at an specific position the memory address of the first-stage payload.
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.
For Brunswick games
This is a super simple exploit. The program loads the entire save file contents at an static memory location, then blindly sprintf
s 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.
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.
- Crash Team Racing: suggested by Patrick Vogt and Bowser Zeki.
- Cart World Series: has character naming. Suggested by Filiberto on a YouTube comment.
- Jade Cocoon: has character naming. Suggested by Shin m0h on a YouTube comment.
- Spec Ops: Stealth Patrol (SLES-00844) & Spec Ops: Ranger Elite (SLES-03157). Suggested via e-mail by Mew Mew.
- Rally Championship (also known as Mobil 1 Rally Championship and Rally Championship 2000 Edition): has text input in multiple places for user names. Suggested by gamer4maker via e-mail.
Unexploitable games
This is just a short list of games I've glanced over and determined they are unlikely to be exploitable:
- Breath of Fire III: every text field is fixed length.
- Driver 2: tested by Patrick Vogt. Causes the same graphical issues than on Hogs of War, but nothing exploitable.
- Hogs of War: has names that when overwritten just cause graphical issues in the team edition menu, but that's about it.
- International Socer Pro '98: text is packed and the payload would have to use only the lowest 7 bits of a byte. Aside from this, everything seems to be copied using strncpy. Interestingly, using an ASCII control character seems to cause the game to go nuts and it starts self-destructing the RAM endlessly.
- Mat Hoffmans Pro BMX: uses the same engine as THPS, but there is no place where user can introduce text.
- Micro Machines V3: the game uses the save text as the user's name, extracting it from between the parentheses. Removing these parentheses or spacing them beyond what the game expects causes a good part of RAM to be overwritten with '?', which isn't really useful.
- Spiderman: has text but increasing their length just causes graphical issues. Savefiles have checksums too.