Contents
|
LegalAll files (HTML, CSS, images) included in EnHacklopedia are licensed under the Creative Commons Attribution-ShareAlike 3.0 License. All authors contributing to EnHacklopedia should be made aware of the license before contributing. If the author does not agree to the licensing, his or her contributions will not be accepted into the project. History
|
The hardware cheat devices for N64 come in the form of a cartridge which plugs into the N64, allowing a game cartridge to connect to the top of it. The only downside to this is that jarring the N64 typically causes the game to crash. Like the cheat devices for most other systems, they come preloaded with many codes and the ability to add more. These devices come in a few flavors: Action Replay, Equalizer, Gameshark, Gameshark Pro, and Xploder64.
NOTE: Some games will NOT work on earlier versions of these devices. This is due to protections added to certain games.
Some emulators also offer support for GS/AR codes. Project64 and 1964 are the more popular options for built-in cheating. However, some external programs/plugins can allow cheating on other emulators and sometimes even support additional code types. Note that enable codes are NOT required when cheating on emulators.
Gameshark and Action Replay for N64 are the exact same device with different names. Action Replay was originally developed by Datel in the UK It was then sold by Interact with the Gameshark label in the U.S. Madcatz now owns that label. They're also called GameBuster in Germany.
Like the GS and AR, these were both developed by the same company, just sold under different labels in different parts of the world. The difference between these and the older devices of the same brand are that they include a code generator, memory editor, and DB25 connector (v3.1+) on the back for PC connection. The code gen can be used by itself or connected to the PC in order to hack your own codes. See later sections for more info on utilizing these hacking tools.
These were the last incarnation of the GS/AR on N64. They are almost identical to GS/AR Pro in cheating functionality, but the code generator and DB25 port are missing.
This is the alternative to Datel's assortment of N64 cheat devices. It was developed by Fire International (Blaze USA). Unfortunately, information about this device is difficult to find at this point.
Renegade is a powerful hacking and cheating tool written by Viper187. It currently supports cheating/hacking on Project64, 1964, Mupen64, and Nemu. It supports all the standard GS/AR code types and a few extra ones. See the ReadMe included with the program for a current list.
PCS (by Parasyte) is a plugin for N64 emulators that can be used to find codes.
Adding new games is pretty straightforward; there's a "New Game" item at the top of the list or in the sub-menu (Z button). BEWARE: Rapidly deleting games is not advised and has been known to cause corruption of the device. Deleting a game here and there works, just don't overdo it trying to "organize" the list.
Adding new codes shouldn't be an incredibly challenging task, but it does take a little getting used to. The Edit Code screen can be accessed by pressing Z with an existing code selected or choosing "New Code" in the code list of a game. Upon selecting "New Code," the user is presented with a box to enter a name for the code. Enter a name and press the B button. This brings up the standard Edit Code screen. Select the box on the left and press A. There's a box on the right to select numbers and letters with the D-Pad and press A to enter them. The code entered appears in the box on the left. The L and R buttons will move the cursor in the code box left or right for editing. Once finished, press B to exit from the code entry. There are 3 options: Default On/Off, Exit & Save, Exit & Discard. Default On/Off tells the device to always have the code on or off each time the device is booted. The other two options are pretty much self-explanatory.
This consists of two boxes listing all controllers with memory cards plus "GamePak". It allows you to copy saves between cards, format them, or delete specific saves.
This is only available in the "Pro" (v3.0+) versions of the GS/AR line. The expansion pack is required to utilize it. The purpose of the Code Generator is to allow the user to hack new codes. The difficulty of this task can range from easy to psychotic, depending on a few things: the user's programming knowledge, user skill, good old fashioned luck, and the type of code being attempted. This discussed more in-depth later.
Enablers (aka "(M) Must Be On") come in many forms. Some simply disable the expansion pack (CC/DD/EE) forcing the game to run in low resolution mode. Others disable protections that would otherwise cripple/crash the device (F0/F1). Finally, there's one enabler type (FF) that simply tell the device where to store its active codes, because some games overwrite the default location. Most games that require a key code will also require a DE type enabler; apparently, the device can't find the game's entry point on its own. More in-depth information on these is available in the section about hacking them.
Some games have added protection that prevents cheat devices from functioning. Key codes were first introduced on GS/AR version 1.08 to bypass some of these protections. They're present in all versions after that, as well. Due to these protections, some games will never work on an older version cheat device. To boot a game that requires a key code, the device must first be booted with any unprotected game. In v3.0+ of the GS, there's a menu option for setting key codes. In older versions you have to hold L+R on the main menu. Once set, the key code is only active for 1 boot up. Turn off the N64, put the protected game on the shark, and boot up. After booting the protected game once, the key code flips back to default. In devices v2.2 and higher, the key codes have an additional 32-Bit value attached to them. This is an additional special instruction, which is believed to set the default destination of the code engine. It was first required by Ocarina of Time. Xploder64 uses "boot modes" in pretty much the same way GS/AR uses key codes. A list of all the preloaded key codes in each version of GS/AR follows.
Key Code | Games |
---|---|
Gameshark Version 1.08 | |
? | Super Mario 64 & Others |
4E F8 4D D6 0A B3 D6 0A B8 | Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest |
? | Yoshi's Story, Cruis'n World, F-Zero X |
Gameshark Version 1.09 | |
? | Super Mario 64 & Others |
59 A6 31 F5 13 B3 DA 50 FA | Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest |
05 63 14 98 D5 E4 CF CD 1A | Yoshi's Story, Cruis'n World, F-Zero X |
Gameshark Version 2.00 | |
63 34 F1 61 A7 2C 20 1C 2E | Super Mario 64 & Others |
50 F2 49 08 7C 07 EE 6C 25 | Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest |
8D 9A 8C DA F5 F2 B6 07 92 | Yoshi's Story, Cruis'n World, F-Zero X |
Gameshark Version 2.10 | |
EB 03 0C 2C D2 3A AF C3 CE | Super Mario 64 & Others |
78 69 4F BD AC EF E9 DD 79 | Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest |
85 A2 B3 44 44 4C F1 C1 E4 | Yoshi's Story, Cruis'n World, F-Zero X |
Gameshark Version 2.21 | |
3E 75 22 68 00 99 BE BE F6 80 20 10 00 |
Super Mario 64 & Others |
2C 48 29 16 D4 3E 90 61 47 80 20 10 00 |
Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest |
94 CB D4 8E 52 9A 30 89 E7 80 20 10 00 |
Yoshi's Story, Cruis'n World, F-Zero X |
14 A8 3B CA CD F8 11 BE 50 80 19 00 00 |
Legend of Zelda: Ocarina of Time, Legend of Zelda: Majora's Mask, Perfect Dark, Conkers Bad Fur Day, Jet Force Gemini, Mickey's Speedway, Banjo-Tooie |
Gameshark Version 3.0/3.1 | |
70 14 FF AB 1A 91 14 49 B4 80 18 00 00 |
Super Mario 64 & Others |
5B E5 5F CE 93 89 D7 11 9F 80 20 00 00 |
Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest, Super Smash Bros, Paper Mario, Pokemon Snap, Excitebike 64 |
33 31 66 BD 04 ED E3 62 DF 80 20 04 00 |
Yoshi's Story, Cruis'n World, F-Zero X |
56 72 19 E1 9D 62 82 28 C9 80 19 00 00 |
Legend of Zelda: Ocarina of Time, Legend of Zelda: Majora's Mask, Perfect Dark, Conkers Bad Fur Day, Jet Force Gemini, Mickey's Speedway, Donkey Kong 64, Banjo-Tooie |
Gameshark Version 3.2 | |
AF FA 90 67 C2 49 22 D0 12 80 18 00 00 |
Super Mario 64 & Others |
BD B8 AF 1A E9 C2 8B 3B 30 80 20 10 00 |
Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest, Super Smash Bros, Paper Mario, Pokemon Snap, Excitebike 64 |
B6 F4 6A E1 8B 0F C8 AB 67 80 20 04 00 |
Yoshi's Story, Cruis'n World, F-Zero X |
85 87 29 C5 3A 85 F7 50 F0 80 19 00 00 |
Legend of Zelda: Ocarina of Time, Legend of Zelda: Majora's Mask, Perfect Dark, Conkers Bad Fur Day, Jet Force Gemini, Mickey's Speedway, Donkey Kong 64, Banjo-Tooie |
Gameshark Version 3.3 | |
8F 89 AB A0 C3 4C 26 10 A4 80 18 00 00 |
Super Mario 64 & Others |
95 AC 21 BE 58 B0 4E F6 A8 80 20 10 00 |
Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest, Super Smash Bros, Paper Mario, Pokemon Snap, Excitebike 64 |
C4 6F 1B C2 6C 6C 1F 67 1D 80 20 04 00 |
Yoshi's Story, Cruis'n World, F-Zero X |
A9 24 53 52 5F 73 77 37 7D 80 19 00 00 |
Legend of Zelda: Ocarina of Time, Legend of Zelda: Majora's Mask, Perfect Dark, Conkers Bad Fur Day, Jet Force Gemini, Mickey's Speedway, Donkey Kong 64, Banjo-Tooie |
GS/AR Pro versions 3.1 and higher have a DB25 connector on the back for linking up with a PC through the parallel (printer) port. A DB25 male to DB25 female cable (IEEE-1284 compliant) is required to do this, along with the N64 Version 3 Utilities released by Datel or Game Software Code Creator. With the console off, insert the GS/AR with a game a top, and hook up the cable. Boot the device with the DB25 cable connected (one end to the device, the other to the PC), and leave it at the main menu. Next, open the N64 Utils. Click the Detect button to see if everything is connected properly. If the device is not detected, there is a problem.
TroubleshootingAfter detecting the hardware to be sure it's connected properly, go to the Other Utilities tab, and click the Upgrade button. There is checkbox above that button with the option to overwrite the code list with the default (official) list or not. It will take a moment to send the upgraded software to the device.
Reflashing a Defective DeviceThe "Piggyback Reflash" was something discovered by someone that was just messing around, and it has given users a chance at reviving corrupted (unbootable) devices. This is like a defibrillator for GS/AR. Beware, however, it can be hazardous to the working device used in the procedure. The authors and device manufacturers are not liable for any damage caused to devices by attempting this.
A working GS/AR is required to do this. It is advisable to backup the code list before beginning. To begin, place a working device in the N64 and connect it to the PC with the DB25 cable. Then, put the defective device on top of the working one, and put the game on top of that. Now go to the Other Utilities in the N64 utils and click the Upgrade button just like normal. The result is BOTH devices being reflashed to that version! This has even been know to work for reflashing older (pre v3.1) hardware to v3.3. Of course, there's no DB25 port on the back of an old shark to hack with the PC programs, but the code generator and code type upgrades are nice.
If a working GS/AR with a port on the back is not available, but a GS/aR without an LPT is, it's worth a shot booting the good shark once with the fried one on top. Sometimes, it brings the dead one back to life.
Altered GS/AR SoftwareThere can be altered versions of the GS/AR rom. The only one currently known is Perfect Trainer. It has some nice enhancements over the regular GS/AR. It's mostly geared toward hacking of high resolution games (like Perfect Dark) without crashing so much. It also supports a pointer code type. Flashing it is as simple as backing up ar3.enc in the N64 utils folder, and placing the altered rom there instead. Then flash as normal. It can be flashed back to the regular software, so don't worry about being stuck with anything. This will probably be mentioned in more detail later.
Grabbing ScreenshotsThe remaining item on the Other Utilities tab is pretty self-explanatory. Click the Grab Video Image button to get an image of what's currently on the screen (during a game).
Code List Editing/BackupEverything on the Code List tab is for use at the main menu of the GS/AR only. The code list on the device can be backed up by setting a filename (through browsing or just type it in) and clicking the Download Codes button. Editing a code list is as easy as opening a backup of it in a text editor. Just follow the basic syntax of file to add/remove codes and games. After editing is complete, the code list must be compiled before uploading to the device. Simply browse for the newly edited file in the Code List Compiler frame here, Then click the Compile Codes button. If the Compilation Results box lists errors, fix them and compile again. Once the list is compiled properly, all that's left is to hit the Upload Codes button and wait a moment for it to update the GS/AR.
Game Software Code Creator by Code Master (aka CMX) is much like the N64 Utils. It's primary function is hacking codes, but it has the ability to upload/download code lists as well. Getting GSCC connected to the GS/AR properly starts out the same as with the official utils. One of the perks of GSCC though is better Windows XP/2000 support; however, communication still times out randomly on XP. It includes a special driver called Totalio. It seems to auto-detect the operating system being run on and activate totalio on its own, but if it doesn't there's a Totalio submenu located in the Debug menu with a Start/Stop option. The program must also be configured for N64 GS/AR. Below is a picture of the Configuration Menu (File > Configuration). The only part for beginners to worry about is the System + Communication Options frame. Notice the "Auto Detect Settings" button there. With a little luck, this will work. If not, try configuring manually like below. Note that GSCC cannot be used to upgrade/reflash the cheat device.
Code List UpdaterThis is used basically the same as the one in the N64 Utils; however it compiles the list automatically before uploading. There are also edit boxes for viewing/editing the list within the program.
Detailed information about the Xploder64's functionality is currently unavailable. Documentation about the Xploder64 has been pretty hard to come by.
Boot modes appear to be the equivalent of key codes on GS/AR. As with key codes, the device must be booted with an unprotected game first. Set the boot mode for the protected game of choice, power off, and power back on with that game plugged into the device.
Mode | Game(s) |
---|---|
1 | Super Mario 64 & Others (Default) |
2 | Diddy Kong Racing, 1080 Snowboarding, Kobe Bryant In NBA Courtside, Banjo-Kazooie, MLB Featuring Ken Griffey Jr, Ken Griffey Jr.'s Slugfest, Super Smash Bros, Paper Mario |
3 | Yoshi's Story, Cruis'n World, F-Zero X |
4 | Legend of Zelda: Ocarina of Time, Legend of Zelda: Majora's Mask, Perfect Dark, Conkers Bad Fur Day, Jet Force Gemini |
Type | Description | Version |
---|---|---|
RAM Writes | ||
Note: Any code prefixed with numbers not listed here is interpreted by the code handler as a regular 8-Bit or 16-Bit write. | ||
8-Bit 80XXXXXX 00?? |
Writes 1 byte (??) to the specified address (XXXXXX) repeatedly. | All |
16-Bit 81XXXXXX ???? |
Writes 2 bytes (????) to the specified address (XXXXXX) repeatedly. | All |
8-Bit GS Button 88XXXXXX 00?? |
Writes 1 byte (??) to the specified address (XXXXXX) each time the GS Button is pressed. | All |
16-Bit GS Button 89XXXXXX ???? |
Writes 2 bytes (????) to the specified address (XXXXXX) each time the GS Button is pressed. | All |
Conditional Codes | ||
8-Bit Equal To D0XXXXXX 00?? YYYYYYYY ZZZZ |
If the byte at XXXXXXX is equal to ??, then the code on the next line is executed. | All |
8-Bit Equal To (GS Button) D8XXXXXX 00?? YYYYYYYY ZZZZ |
If the byte at XXXXXXX is equal to ?? and GS button is being pressed, then the code on the next line is executed. | All |
16-Bit Equal To D1XXXXXX ???? YYYYYYYY ZZZZ |
If the 2 bytes at XXXXXXX are equal to ????, then the code on the next line is executed. | 3.0+ |
16-Bit Equal To (GS Button) D9XXXXXX ???? YYYYYYYY ZZZZ |
If the 2 bytes at XXXXXXX are equal to ???? and GS button is being pressed, then the code on the next line is executed. | 3.0+ |
8-Bit Different To D2XXXXXX 00?? YYYYYYYY ZZZZ |
If the byte at XXXXXXX is NOT equal to ??, then the code on the next line is executed. | 3.0+ |
8-Bit Different To (GS Button) DAXXXXXX 00?? YYYYYYYY ZZZZ |
If the byte at XXXXXXX is NOT equal to ?? and GS button is being pressed, then the code on the next line is executed. | 3.0+ |
16-Bit Different To D3XXXXXX ???? YYYYYYYY ZZZZ |
If the 2 bytes at XXXXXXX are NOT equal to ????, then the code on the next line is executed. | 3.0+ |
16-Bit Different To (GS Button) DBXXXXXX ???? YYYYYYYY ZZZZ |
If the 2 bytes at XXXXXXX are NOT equal to ???? and GS button is being pressed, then the code on the next line is executed. | 3.0+ |
Special Codes | ||
8-Bit Write On Boot F0XXXXXX 00?? |
Writes 1 byte (??) to the uncached address (XXXXXX) only once. These are most often used to disable certain types of protection that some games use to disable cheat devices. F0/F1 only works on boot, but they are handled AFTER the CIC checksums are calculated (allowing the codes to patch the executable code without causing a checksum failure, interrupting the boot process). A maximum of 50 F0/F1 type codes can be used at one time. Hackers should also be aware that F0/F1 codes aren't added to the active codes list once the game starts. This can allow for more active codes alongside assembly hacks on some games. | 3.0+ |
16-Bit Write On Boot F1XXXXXX ???? |
Writes 2 bytes (????) to the uncached address (XXXXXX) only once. These are most often used to disable certain types of protection that some games use to disable cheat devices. | 3.0+ |
Disable Expansion Pack EE000000 0000 |
Attempts to keep the game from using the expansion pack. Can also increase code generator stability with some older games. The actual effect of the code is the same as using: F1000318 0040 F100031A 0000 It can be helpful to know those addresses. For example, Zelda requires that you have the code generator on or use EE000000 0000, but using F0000319 0078 instead allows the game to run just fine whether the code generator is on or not. |
3.2+ |
Additional Enable Code 20000000 0000 |
Clears Memory 0x80000200 - 0x80000300. This might have been added as a precaution for games that check that area on boot. To the writers' knowledge, this code has never actually been needed. | 3.2+ |
Change Exception Handler CC000000 0000 |
The GS/AR patches the exception handler in order to get the code engine running. This code type changes the default patching method, probably for a non-standard exception handler (like for a newer PSYQ lib). Another code type that slipped through the cracks. It has never been used. | 3.2+ |
Enabler DEXXXXXX 0000 |
Used to select the executable entry point (0x80XXXXXX). This is necessary with games that utilize certain protection chips. This code is typically used in conjunction with a key code. The address specified can only be 0x80000000 - 0x80100000. Any address above 0x80100000 (EG 0xDE100400 0000) will default the entry point down to 0x80000400. | 1.08+ |
Set Store Location FFXXXXXX 0000 |
Tells the device to store active codes starting at XXXXXX. This is required on some games that use the expansion pack. | 3.3+ |
Repeater/Patch Code 5000XXYY ???? 8ZZZZZZZ VVVV |
Used to make extremely long, sequenced codes shorter. XX is the number of addresses to be written, YY is the offset between addresses, ???? is the amount to increment the value (VVVV). Note that this increment is signed, so values higher than 0x8000 will subtract from VVVV rather than being added. These can be preceded by any 'D' code type (EG 0xD0144604 0022) to enable them on demand. The code to be repeated is not limited to constant writes. Any 80/81/88/89 code type appearing below a '50' code should work. | 3.0+ |
Code | Description |
---|---|
The following codes will work on a GS/AR v3.0+ with the code generator active. | |
81791DF6 ???? 81791E02 ???? |
Lowest goto address (normally 0x80000400) |
81791E06 ???? 81791E12 ???? |
Highest goto address (normally 0x803FFFFF) |
81791E32 ???? 81791E36 ???? |
Lowest scroll to address (normally 0x80000400) |
81791E3A ???? 81791E3E ???? |
Highest scroll to address (normally 0x803FFFFF) |
81791E42 ???? 81791E4A ???? |
This is the address returned to when attempting to go to an invalid address (normally 0x80000400). |
807FFDE7 000? | Is controller active? |
817FFDE8 ???? | Button Pressed Data |
817FFDEA ???? | Joystick Data |
817E9C98 ???? 817E9C9A ???? |
Cursor X Coordinate |
817E9C9C ???? 817E9C9E ???? |
Cursor Y Coordinate |
817E9CA0 ???? 817E9CA2 ???? |
Cursor Mode |
0x807E9D34 - 0x807E9D44 | Text Searched For -- This can be used to turn Text Search into a string search. It will allows searching for any hex value higher than 0x1F. Anything less than 0x20 will crash it because these are special control bytes, not text. If the values are 0x41-0x5A, it will search for the value and the value + 0x20. This is due to the case insensitive searching; it searches both lowercase and uppercase. |
Other Information | |
0x807C5C00 | This is where active codes are stored when the code generator is on. See below for more info on editing the area. |
0x80000204 | This is where active codes are stored when the code generator is off. See below for more info on editing the area. |
The code handler is what runs through active codes and keeps applying them. It can be altered with some assembly knowledge. The active codes list starts at 0x807C5C00 with expansion pack and 0x80000204 without it. Those who are familiar with assembly, might notice that the way the GS/AR writes each code to be handled if very inefficient. This also shows why the handler needs so much memory for active codes. The list ends when it hits a jump return to 0x80000120. If it doesn't find one, the game will crash. See Hacking Assembly (r4300i) for more information about using assembly on N64.
Opcode | Arguments | Comments |
---|---|---|
'80' Code Type (Constant 8-Bit Write) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address. With 0x801450D0 for example, the value would be 0x8014. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address. With 0x801450D0, that would be 0x50D0. |
ADDIU | $K1,$ZERO,0x00ZZ | ;ZZ is the value to be written. |
SB | $K1,0x0000($K0) | ;Writes the value ($K1) to the location specified ($K0). |
'81' Code Type (Constant 16-Bit Write) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address. With 0x801450D0 for example, the value would be 0x8014. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address. With 0x801450D0, that would be 0x50D0. |
ADDIU | $K1,$ZERO,0xZZZZ | ;ZZZZ is the value to be written. |
SH | $K1,0x0000($K0) | ;Writes the value ($K1) to the location specified ($K0). |
'88' Code Type (8-Bit Write on GS Button Press) | ||
LUI | $K0,0xBE40 | ;Sets $K0 to the upper halfword of the GS button address (0xBE40). |
ORI | $K0,$K0,0000 | ;Sets the lower halfword of the GS button address (0x0000). Those who know assembly will realize this was pointless. |
LH | $K1,0x0000($K0) | ;Load the GS button value. |
SYNC | ||
ANDI | $K1,$K1,0x0400 | ;$K1 = $K1 AND 0x0400. |
BNE | $K1,$ZERO,0x0028 | ;If GS button isn't being pressed, skip the 8-bit write. |
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address. With 0x801450D0 for example, the value would be 0x8014. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address. With 0x801450D0, that would be 0x50D0. |
ADDIU | $K1,$ZERO,0x00ZZ | ;ZZ is the value to be written. |
SB | $K1,0x0000($K0) | ;Writes the value ($K1) to the location specified ($K0). |
'89' Code Type (16-Bit Write on GS Button Press) | ||
LUI | $K0,0xBE40 | ;Sets $K0 to the upper halfword of the GS button address (0xBE40). |
ORI | $K0,$K0,0000 | ;Sets the lower halfword of the GS button address (0x0000). Those who know assembly will realize this was pointless. |
LH | $K1,0000($K0) | ;Load the GS button value. |
SYNC | ||
ANDI | $K1,$K1,0x0400 | ;$K1 = $K1 AND 0x0400. |
BNE | $K1,$ZERO,0x0028 | ;If GS button isn't being pressed, skip the 16-bit write. |
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address. With 0x801450D0 for example, the value would be 0x8014. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address. With 0x801450D0, that would be 0x50D0. |
ADDIU | $K1,$ZERO,0xZZZZ | ;ZZZZ is the value to be written. |
SH | $K1,0x0000($K0) | ;Writes the value ($K1) to the location specified ($K0). |
'D0' Code Type (8-Bit If Equal) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address to be checked. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address to be checked. |
LB | $K0,0x0000($K0) | ;Loads the value from the address to be checked. |
ADDIU | $K1,$ZERO,0x00ZZ | ;ZZ is the value to be compared to. |
BNE | $K0,$K1,0x0024 | ;If value loaded from memory is not equal to the value specified by the code, then skip executing the following code. |
'D1' Code Type (16-Bit If Equal) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address to be checked. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address to be checked. |
LH | $K0,0x0000($K0) | ;Loads the value from the address to be checked. |
ADDIU | $K1,$ZERO,0xZZZZ | ;ZZZZ is the value to be compared to. |
BNE | $K0,$K1,0x0024 | ;If value loaded from memory is not equal to the value specified by the code, then skip executing the following code. |
'D2' Code Type (8-Bit If Not Equal) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address to be checked. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address to be checked. |
LB | $K0,0x0000($K0) | ;Loads the value from the address to be checked. |
ADDIU | $K1,$ZERO,0x00ZZ | ;ZZ is the value to be compared to. |
BEQ | $K0,$K1,0x0024 | ;If value loaded from memory is not equal to the value specified by the code, then skip executing the following code. |
'D3' Code Type (16-Bit If Not Equal) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address to be checked. |
ORI | $K0,$K0,0xYYYY | ;YYYY is the lower halfword of the address to be checked. |
LH | $K0,0x0000($K0) | ;Loads the value from the address to be checked. |
ADDIU | $K1,$ZERO,0xZZZZ | ;ZZZZ is the value to be compared to. |
BEQ | $K0,$K1,0x0024 | ;If value loaded from memory is not equal to the value specified by the code, then skip executing the following code. |
List End | ||
LUI | $K0,0x8000 | ;$K0 = 0x80000000 |
ORI | $K0,$K0,0x0120 | ;$K0 = 0x80000120 |
JR | $K0 | ;Jump to the address stored in $K0. |
ADD | $ZERO,$ZERO,$ZERO | ;One of the many ways to do nothing. |
Type | Description | |
---|---|---|
RAM Writes | ||
8-Bit 80XXXXXX 00?? |
Writes 1 byte (??) to the specified address (XXXXXX) repeatedly. | |
16-Bit 81XXXXXX ???? |
Writes 2 bytes (????) to the specified address (XXXXXX) repeatedly. | |
8-Bit XP Button 88XXXXXX 00?? |
Writes 1 byte (??) to the specified address (XXXXXX) each time the XP Button is pressed. | |
16-Bit XP Button 89XXXXXX ???? |
Writes 2 bytes (????) to the specified address (XXXXXX) each time the XP Button is pressed. | |
8-Bit Write Once F0XXXXXX 00?? |
Writes 1 byte (??) to the uncached address (XXXXXX) only once. These are most often used to disable certain types of protection that some games use to disable cheat devices. | |
16-Bit Write Once F1XXXXXX ???? Or 2AXXXXXX ???? |
Writes 2 bytes (????) to the uncached address (XXXXXX) only once. These are most often used to disable certain types of protection that some games use to disable cheat devices. | |
Conditional Codes | ||
8-Bit Equal To D0XXXXXX 00?? YYYYYYYY ZZZZ |
If the byte at XXXXXXX is equal to ??, then the code on the next line is executed. | |
16-Bit Equal To D1XXXXXX ???? YYYYYYYY ZZZZ |
If the 2 bytes at XXXXXXX are equal to ????, then the code on the next line is executed. | |
Special Codes | ||
Enabler 3CXXXXXX ???? |
The exact effect of this code type is still a mystery. |
Code | Description |
---|---|
The following codes were tested on an Xploder64 v1.000E | |
817527FA 0000 | Change Lowest address accessible in the Memory Viewer to 0x80000000 (normally 0x80000400). |
817527F2 807F | Change Lowest address accessible in the Memory Viewer to 0x807FFFFF (normally 0x803FFFFF). |
81757B48 XXXX 81757B4A YYYY |
Set The location of the Memory Viewer to XXXXYYYY. |
The code handler is what runs through active codes and keeps applying them. The following is a an incomplete listing of the assembly the code handler uses.
Opcode | Arguments | Comments |
---|---|---|
'80' Code Type (Constant 8-Bit Write) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address. With 0x801450D0 for example, the value would be 0x8014. |
ORI | $K1,$ZERO,0x00ZZ | ;ZZ is the value to be written. |
SB | $K1,0xYYYY($K0) | ;YYYY is the lower halfword of the address. With 0x801450D0, that would be 0x50D0. |
'81' Code Type (Constant 8-Bit Write) | ||
LUI | $K0,0xXXXX | ;XXXX is the upper halfword of the address. With 0x801450D0 for example, the value would be 0x8014. |
ORI | $K1,$ZERO,0xZZZZ | ;ZZZZ is the value to be written. |
SH | $K1,0xYYYY($K0) | ;YYYY is the lower halfword of the address. With 0x801450D0, that would be 0x50D0. |
Unlike the other devices available for cheating on N64, Xploder64 has encrypted codes. It supports some GS/AR code types, but most of the preloaded codes are encrypted for some reason. Simple encryption though...
Encryption Algorithm |
---|
A0A1A2A3 D0D1 A0 = (a0 XOR 0x68) A1 = (a1 XOR 0x81) - 0x2B A2 = (a2 XOR 0x82) - 0x2B A3 = (a3 XOR 0x83) - 0x2B D0 = (d0 XOR 0x84) - 0x2B D1 = (d1 XOR 0x85) - 0x2B Alternate: A0 = (a0 XOR 0x68) A1 = (a1 XOR 0x01) - 0xAB A2 = (a2 XOR 0x02) - 0xAB A3 = (a3 XOR 0x03) - 0xAB D0 = (d0 XOR 0x04) - 0xAB D1 = (d1 XOR 0x05) - 0xAB |
Decryption Algorithm |
A0A1A2A3 D0D1 A0 = (A0 XOR 0x68) A1 = (A1 + 0x2B) XOR 0x81 A2 = (A2 + 0x2B) XOR 0x82 A3 = (A3 + 0x2B) XOR 0x83 D0 = (D0 + 0x2B) XOR 0x84 D1 = (D1 + 0x2B) XOR 0x85 Alternate Method: A0 = (A0 XOR 0x68) A1 = (A1 + 0xAB) XOR 0x01 A2 = (A2 + 0xAB) XOR 0x02 A3 = (A3 + 0xAB) XOR 0x03 D0 = (D0 + 0xAB) XOR 0x04 D1 = (D1 + 0xAB) XOR 0x05 |
Activators are used to execute codes ONLY when a particular condition is met. This can be used to prevent problems with certain effects being active at the wrong time, give the user the ability to turn a code on/off without resetting the console, etc. This is done with the D0,D1,D2, and D3 code types.
Example:
D0064F31 0020
800326E2 0001
The code "800326E2 0001" is only executed when the value at 0x00064F31 is equal to 0x20.
Button activators allow you to turn codes on/off by pressing a button or combination of buttons on the controller. One of the most common uses for this are moon jump codes. The user holds a button (typically L) to rise up and lets go to fall. They work by checking the location in memory where the game keeps track of what controller buttons are being pressed at any given time. This is almost always done with a halfword (16-bit) value. Each button is represented by 1 bit in this value. These activators appear on websites in 3 variations. The digits are as follows:
Value | Button |
---|---|
Activator 1 (8-Bit) Digits | |
0x00 | No Buttons |
0x01 | D-Pad Right |
0x02 | D-Pad Left |
0x04 | D-Pad Down |
0x08 | D-Pad Up |
0x10 | Start |
0x20 | Z |
0x40 | B |
0x80 | A |
Activator 2 (8-Bit) Digits | |
0x00 | No Buttons |
0x01 | C-Right |
0x02 | C-Left |
0x04 | C-Down |
0x08 | C-Up |
0x10 | R |
0x20 | L |
Dual Activator (16-Bit) Digits | |
0x0000 | No Buttons |
0x0100 | D-Pad Right |
0x0200 | D-Pad Left |
0x0400 | D-Pad Down |
0x0800 | D-Pad Up |
0x1000 | Start |
0x2000 | Z |
0x4000 | B |
0x8000 | A |
0x0001 | C-Right |
0x0002 | C-Left |
0x0004 | C-Down |
0x0008 | C-Up |
0x0010 | R |
0x0020 | L |
To combine button values, simply add them together. Down+A would be 0x84, for example.
Control stick activators are a little more complicated than button activators and significantly less useful. The control stick basically has X/Y coordinates, which the game keeps track of in memory. These are signed bytes or halfwords, usually found just above the button activator location in memory. The problem with using them the same as button activators is that it's so hard to duplicate exact values. However, you can use them with the D2/D3 code type to check that the stick is being pressed left/right, up/down, or both. Pushing up on the stick will be stored in memory as anything from 0x00-0x7F or 0x0000-0x7FFF in the case of games using 16-bit ones. Here's where it gets tricky. These are signed hex. Positive numbers indicate the stick is being pressed right/up, and negative values mean it's being pushed left/down. Values for commonly posted stick activators range as follows:
Range | Direction |
---|---|
Activator 1 (8-Bit) | |
0x00-0x7F | Right |
0x80-0xFF | Left |
Activator 2 (8-Bit) | |
0x00-0x7F | Up |
0x80-0xFF | Down |
Activator 1 (16-Bit) | |
0x0000-0x7FFF | Right |
0x8000-0xFFFF | Left |
Activator 2 (16-Bit) | |
0x0000-0x7FFF | Up |
0x8000-0xFFFF | Down |
Dual Activator (16-Bit) | |
0x0000-0x007F | Up |
0x0080-0x00FF | Down |
0x0000-0x7F00 | Right |
0x8000-0xFF00 | Left |
Sometimes, a code only works on a particular level or should only be active when a certain event is happening. Using addresses other than controller data can sometimes be helpful in these cases. For example, if a user only wanted a code enabled on level 2 of a game they could use the level modifier as an activator. Say the level modifier address is 0x00024640, the value for level 2 is 0x02, and the code to enable only on that level is 0x8104856A 270F.
Code | Comment |
---|---|
D0024640 0002 | level modifier with an 8-bit equal to (D0) code type. |
8104856A 270F | code to be executed when level modifier is equal to 0x02. |
This section contains some introductory notes for new hackers to the system.
Out of the factory, the N64 has 4MB of RAM (0x00000000-0x003FFFFF). An expansion pack was later released to give the N64 an additional 4MB (0x00400000-0x007FFFFF) for a total of 8MB of RAM (0x00000000-0x007FFFFF). Games that take advantage of this extra memory are generally said be Hi-Res, while games that don't are referred to as Lo-Res.
Dynamic (random) addresses can be a problem on some N64 games, particularly with object/enemy hacking. This can really only be worked around with assembly hacks, but there are plenty of N64 games that are perfectly hackable using normal methods. Many N64 games will change the location of certain things on a per level basis, but the codes will always be the same for that level. Hackers should keep these things in mind.
Most N64 games use IEEE-754 float values to some extent (coordinates, timers), but some even use them for health and ammo values (100.0 for max health instead of 100). The majority of floats that normal users will have to deal with are stored as 32-bit values, however, there are a few games that use 64-bit (double precision). Star Wars Racer, for example uses a lot of double precision floats. This is good to remember in cases where a simple known value search should work and it doesn't; hopefully, it'll be remembered before the game and/or cheat device is smashed out of frustration.
Having a game just freeze and refuse to run anymore while code searching is an all too common occurrence when hacking N64 games on the console. Some games are very hard to keep running long enough to hack more complex codes. This is one reason hacking with emulators is sometimes preferred over messing with the hardware. Games requiring a key code are especially notorious for crashing easily. Tip: Try not to break anything when theses things happen; N64 hardware is in limited supply these days.
Turn on the code generator in the "Start Game Options" menu of a v3.0+ GS/AR (expansion pack required) before starting a game to enable the code creation functionality of the device. While in the game, you can press the GS/AR button at any time to bring up the in-game menu. It's laid out as follows:
For those who have hacked before, this about the same as any other trainer. If hacking a value that's shown on screen, try Known Value Search. If it's a health bar or something, you'd use Unknown Value. Alright, here's the classic "health bar" example. With the health bar on the screen, press the GS button. Enter the code generator, and select Unknown Value Search. Move on down the menu and select "Start." Now return to the game, and lose some health. Press the GS button again and bring up the unknown value search menu again. This time, there's some new search options. Obviously, since health decreased, the one to choose is Less Than Last. After this, the View Results item is added to the menu. If there are a lot (and there probably are), repeat the losing health - Less Than Last combination to narrow it down. Occasionally just walking around without losing health and searching Equal To Last is a good way to drop some junk possibilities. Once the results are narrowed down (hopefully 30 or less), go into the view results menu.
The box on the left lists first 100 results found. The box on the right shows active codes, but only the ones from searching. Codes that were activated from the main GS menu before booting won't be listed here. The data displayed here is similar to actual codes, but is just a list of addresses and values. Notice the values aren't padded and the prefix is not 81 for 16-bit codes.
Controls:
Lets you edit RAM. Displays a typical hex editor interface (address, values, ASCII) at 8 bytes per line, 0x60 bytes per page, and usually gets cut off a little at the edges of the screen. Display starts at 0x80010000 and can go from 0x80000400 to 0x803FFFFF.
Controls:
See the PC Connection and Utilities section for notes on getting a GS/AR connected to the PC, if it was somehow skipped by. Remember to enable the code generator in order to utilize either of the following software trainers.
This is a fairly simple, but effective, trainer that can be used while the GS/AR is connected to the PC. It should be noted that neither the trainer nor the in-game code generator can search in hi-res (0x80400000-0x807FFFFF) region. There is a patch that can allow it though. There are a few differences in this compared to the in-game code generator...
After getting a search going, the user has access to (surprise) the Results tab. This slightly resembles the one in the in-game code generator, but it's a little more user friendly. The hacker can test search results or manually enter codes to test/activate.
Game Software Code Creator is slightly more advanced than the N64 utils. There are some special options to tweak with in the configuration. The most notable is a checkbox that says "Treat Values As Signed." This means that all values read, whether 8-bit or 32-bit are sign extended. The typical Hex/Decimal input option is there too. There are far too many search options to try to document them all here, but the help file with the program explains most of them anyway; hence, new users should read that help file because it's actually useful. The regular Known Value search is a little hard to spot though. It's part the Advanced Searching Options frame. Check the box beside "Do," locate "Equal To" dropdown list, and enter a value in the box beneath it.
PossibilitiesThe Possibilities window looks similiar the the N64 Utils reults window. Same basic features.
RAM EditThe last window for hacking is RAM Edit. The main purpose of this is to view/edit memory just like the Memory Editor in the GS/AR can. There a few nifty options.
Hacking codes with an emulator can be easier with some games, since they're so buggy on the hardware. It doesn't make the codes any easier to find, it just makes games with crap programming more stable (in most cases). Now the downside to N64 hacking with emulators is there are no good emulators with the search tools needed. Nemu has a simple known value and text search, which cannot be continued to narrow results. That makes it sort of useless for most purposes, but it comes in handy to some of us on occasion. Nemu is also important because it's currently the only N64 emulator with a debugger, a must have for assembly hackers. More on that later. No other emulators currently have anything resembling built-in search tools. So how is it done? Well, there are 3 ways right now...
Renegade is program by itself. It can be used to grab the N64 RAM from an emulator. It can also be used to compare save state files from emulators it doesn't support. This is just the tip of the iceberg, as far as Renegade goes. It has many features that don't just apply to N64. See Renegade section of Generic Code Hacking and the program's readme file for more information.
PCS is plugin for Project64. It shows up as a video plugin under PJ64's settings. Set it as the plugin and configure it to use an actual video plugin. Choosing Configure Graphics from the Options menu while a game is running will bring up the PCS window (shown above) instead of the PCS config.
Sometimes an emulator's memory can't be accessed for whatever reason, or it just isn't supported by programs made for doing so. Save states, which most emulators have the option for, are the equivalent of an RAM dump with a few extra bytes added. The following is some quick info about the more popular N64 emulators' save states.
An Infinite Ammo type code is almost always a simple task, but some games have a few tricks...
The Typical ApproachFor the majority of games, finding ammo is a simple task. Do a known value search for the current amount of ammo, cap somebody, search for the new value, repeat. Test results, and enjoy Infinite Ammo.
Complicating ThingsWhen the typical method of finding ammo fails, this may mean the game is using a float value. Floats are 32-bit hex values, which the N64's co-processor reads as decimal numbers (like 100.0). These can be found by using a 16/32-bit unknown value search and just doing less than searches while losing ammo. This is how it was done in the old days. However, there is a shortcut, and it's called FloatConvert. Now, say the game is Star Wars Shadows of the Empire. Dash has 10 Seekers. Punch 10 (or 10.0) into FloatConvert and click Convert to Hex. It spits out 0x41200000. Now do a 32-bit search for that value, shoot something, and repeat. Results will probably be down to one or two after the second search, so try them. If the result is 0x801A7174, setting the upper 16-bits there will change Dash's ammo. Use FloatConvert to find a suitable value, like 100.0 (0x42C80000). Writing a 32-bit value on N64 requires two 16-bit codes:
811A7174 42C8 811A7176 0000 |
Writing the full 32-bits isn't required in most cases. The second line (lower 16-bits) can be omitted. |
FF enablers are normally only used on games which utilize the expansion pack. They tell the device where to store active codes so that the cheating routines won't interfere with the game's normal operation. Basically, the FF code is just that address of an empty part of the memory for the GS/AR to use. This can't be found with the console. Get the game running in an emulator and save a couple of memory dumps (or just search). Search for 0 with the largest search type available in the trainer (32/64-bit recommended). Look for the biggest blocks of consecutive results that stay 0 throughout the game. The objective is to find at least 256 bytes that the game isn't using. The address where this empty area begins becomes the FF enabler (FF567890 0000 for instance).
Some games write to special registers in the system to disable the GS/AR. This is done by setting values to WatchLo and WatchHi, which the cheat devices require. Disabling these is done with an assembly hack, but very little assembly knowledge is actually needed to pull it off. GSCC actually has a feature to search for them automatically. The manual approach requires an emulator and some basic knowledge. Run the game long enough to boot up, and save a dump of the memory or open a search tool (like Renegade). Now use a 32-bit known value, in-range or wildcard search to find all instances of 0x40??9000 and 0x40??9800 where ?? is 0x80 to 0x9F. In a disassembler, these appear as MTC0 $xx,WatchLo and MTC0 $xx,WatchHi. Any instances of these need to be disabled by setting the address to 0x00000000 or just setting the upper half to 0x2400 as a shortcut. Say 0x80055684 is MTC0 $A0,WatchLo (0x40849000). An F1 code type is required to disable it.
Long Version |
---|
F1055684 0000 F1055686 0000 |
Short Version |
F1055684 2400 |
There are some games that attempt to disable cheat devices another way. These games write to some special parts of the memory which effect the functionality of cheat devices. Hacking these is going to seem a bit complicated to beginners, but there's not really an easier way; it's an assembly hack. See the N64 assembly or Assembly Hacking in the Generic Code Hacking section for help with these sort of hacks. Renegade has a few search options that could help locate possible enablers of this type, but that's hardly an accurate way to do it. One needs to understand what to look for and, perhaps more importantly, where to look. The basic idea here is to start at the entry point and look for opcodes storing to addresses below 0x80000400.
Opcode | Arguments | Comments |
---|---|---|
Starting at 0x80000450 (each opcode is 32-bits) | ||
LUI | $V0,0x8000 | ;$V0 = 0x80000000 |
ORI | $V0,$V0,0x0180 | ;$V0 = $V0 OR 0x180 |
SH | $A1,0x0000($V0) | ;Store $A1 to the address in $V0 (0x80000180) + 0x0000. |
Enable Code F1000456 0120 |
Certain games need the expansion pack to be "hidden" from them to work with GS/AR. This is usually done with the EE000000 0000 code. The actual effect of that code is writing the 4 bytes at 0x80000318 to 0x00400000 the same way an "F1" code type would. That address sets the highest address the game is allowed to write. The code generator is automatically disabled when "EE" enablers are used though. This is why some people prefer to custom enablers with F1 codes and that same address. Some examples follow.
F0000319 0040 | Force 4MB (low-res) mode. |
F0000319 0080 | Force 8MB (hi-res) mode. |
F0000319 0078 | Force the game into using most of the expansion pack, but 1/8th is left free for the GS/AR. It will think it's running 8MB mode. This is useful for hacking hi-res codes but should only be attempted with the PC utils, not the in-game code generator. |
Other values can be used to give a game access to different amounts of memory. Some values will work better than others. Codes hacked with a game being forced to use less than the full 4MB or 8MB of memory may not work in full 4MB/8MB mode. If attempting to force 8MB mode with a value less than 0x80 causes the game to report that no expansion pack was found, the game is probably reading that location to ensure it's 0x00800000. This could be defeated by watching reads of 0x80000318 with a debugger as the game boots, and forcing or killing a conditional check. These can also be found by using the steps for Non-MTC0 Enablers (above) and looking for ORI/ADDIU $XX,$XX,0xYYYY or SB/SH/SW $XX,0xYYYY($ZZ) when YYYY is 0x0318. A conditional check shouldn't be very hard to spot. It would likely set a register (variable) to 0x00400000 or 0x00800000 and branch (jump) to another location accordingly. An example is shown below.
Opcode | Arguments | Comments |
---|---|---|
Starting at 0x80000420 (each opcode is 32-bits) | ||
LUI | $V1,0x8000 | ;$V1 = 0x80000000 |
LW | $A0,0x0318($V1) | ;Load word from address ($V1) + 0x318 into $A0. $A0 would now contain the 32-bit value at 0x80000318. |
LUI | $T0,0x0080 | ;$T0 = 0x00800000. This is what the value at 0x800000318 should be if the expansion pack exists. |
BEQ | $T0,$A0,0x800004B4 | If $T0 is equal to $A0 then branch (jump) to 0x8000004B4. This means to go there if the expansion pack exists. If not, it continues on. |
Change the opcode at 0x8000042C (BEQ) to force it to where it goes if the expansion pack is found. | ||
BEQ | $ZERO,$ZERO,0x800004B4 | ;This says jump to 0x800004B4 if $ZERO equal $ZERO. Obviously, it does, so the game always thinks it's running 8MB mode. Notice when changing the opcode that only the upper 16-bits has changed, so the whole word need not be set. |
Enable Code F100042C 1000 |
Some games also try to force 8MB mode before checking for the expansion pack. To find these, walk through the whole entry point routine the same as the steps for Non-MTC0 Enablers above. This time look for ORI/ADDIU $XX,$XX,0xYYYY or SB/SH/SW $XX,0xYYYY($ZZ) where YYYY is anything from 0x0300 to 0x031F. Ignore any SB/SH/SW where $ZZ is $SP. For any others, look for an LUI $XX, 0x8000 or LUI $XX, 0xA000 just before it. NOP the opcode that's SB/SH/SW $XX,0xYYYY ($ZZ) by setting the whole 32-bits to 0x00000000 or just set the upper half to 0x2400.
Opcode | Arguments | Comments |
---|---|---|
Starting at 0x80000480 (each opcode is 32-bits) | ||
LUI | $V1,0x8000 | ;$V1 = 0x80000000 |
ORI | $V1,$V1,0x0318 | ;$V1 = $V1 OR 0x318 |
SH | $A0,0x0000($V1) | ;Store $A0 to $V1 (0x80000318) + 0x0000. |
Enable Code F1000488 2400 |
Button activators are relatively simple to hack. To do so, setup for a 16-bit known value search. Hold a button, and search for its value. Then hold a different button and search for its value. Repeat until only a few results remain. Most of these are probably button activators, as the majority of games have more than one. Testing is just a matter of using it as a 'D1' code type with an existing code. Activators for P2-P4 on multi-player games will usually appear 0x6 or 0x8 after the one for P1.
While control stick activators could be hacked with greater/less searches with the stick pushed in a direction or centered, there's really no point. They're right beside most button activators in memory. Use a memory viewer to confirm by watching the values next to the activator address when the stick is being pressed in any direction or centered. It should be easy enough to see which bytes keep changing. Those bytes would be control stick activator 1 and 2 (or both as a 16-bit code).
Another way to find button activators is to search for a special value in memory. Do a 32-bit known value search for 0xFF010401. This value appears with the main set of activators on most games, for some reason. There should only be about 4 results. If there are more, the 4 to look for are 8 bytes apart. Look at these in 16-bit form below for an easy breakdown.
0x800440B0 | FF01 | |
0x800440B2 | 0401 | |
0x800440B4 | 0000 | Player 1 button activator. |
0x800440B6 | 0000 | Player 1 control stick activator. |
0x800440B8 | FF01 | |
0x800440BA | 0401 | |
0x800440BC | 0000 | Player 2 button activator. |
0x800440BE | 0000 | Player 2 control stick activator. |
0x800440C0 | FF01 | |
0x800440C2 | 0401 | |
0x800440C4 | 0000 | Player 3 button activator. |
0x800440C6 | 0000 | Player 3 control stick activator. |
0x800440C8 | FF01 | |
0x800440CA | 0401 | |
0x800440CC | 0000 | Player 4 button activator. |
0x800440CE | 0000 | Player 4 control stick activator. |
Hacking the assembly of N64 games is no beginner task, but it's not too difficult to do some of the easier stuff. ASM hack can do a lot of things that normal codes can't. Getting around random memory in some games is the primary (and usually easiest) use though. There are cases where the ASM in a game is randomly placed in memory and some cases where a routine is always located in the same place, but only at certain times (like only while in a level). Having the GS/AR connected to the PC and using GSCC is the only way to make assembly codes with the console. On the emulation side of things, Nemu is currently the only N64 emulator that can be used to make ASM codes.
Documentation of the R4300i instruction set will be essential to new ASM hackers. The N64 Tool Kit is what most of us used to get started. There's also the R4300i Data Sheet. Each instruction in R4300i is 32-bits (aligned), but that doesn't always mean a GS/AR code will change all 32-bits. It's usually only necessary to change the bytes that are altered by whatever change the hacker is making.
Before starting any projects, hackers will need to have an R4300i assembler/disassembler at their disposal. Renegade has one. Other popular options include Niew and LemASM. Both have their limitations.
R4300i utilizes two co-processors (COP0 and COP1) for special tasks. COP0 is something most hackers will never need to worry about because it's mainly for exception and virtual address handling, but COP1 is used for floating point operations. It has its own instructions that use opcodes like ADD.S/ADD.D for single and double precision math.
Regs are the variables used by the processor. Each register holds a 32-bit value. which can be sign-extended. Each co-processor has their own set of 31 registers. There are instructions to move/copy values from one set of registers to another. Most assemblers can display the main CPU registers by their names or by R0-R31. A list is provided below, with some notes.
Main CPU (GPR) | COP0 | COP1 (FPR) |
---|---|---|
R0/$ZERO | Index | FPR0/F0 |
R1/$AT | Random | FPR1/F1 |
R2/$V0 | EntryLo0 | FPR2/F2 |
R3/$V1 | EntryLo1 | FPR3/F3 |
R4/$A0 | Context | FPR4/F4 |
R5/$A1 | PageMask | FPR5/F5 |
R6/$A2 | Wired | FPR6/F6 |
R7/$A3 | Reserved | FPR7/F7 |
R8/$T0 | BadVAddr | FPR8/F8 |
R9/$T1 | Count | FPR9/F9 |
R10/$T2 | EntryHi | FPR10/F10 |
R11/$T3 | Compare | FPR11/F11 |
R12/$T4 | Status | FPR12/F12 |
R13/$T5 | Cause | FPR13/F13 |
R14/$T6 | EPC | FPR14/F14 |
R15/$T7 | PRevID | FPR15/F15 |
R16/$S0 | Config | FPR16/F16 |
R17/$S1 | LLAddr | FPR17/F17 |
R18/$S2 | WatchLo | FPR18/F18 |
R19/$S3 | WatchHi | FPR19/F19 |
R20/$S4 | XContent | FPR20/F20 |
R21/$S5 | Reserved | FPR21/F21 |
R22/$S6 | Reserved | FPR22/F22 |
R23/$S7 | Reserved | FPR23/F23 |
R24/$T8 | Reserved | FPR24/F24 |
R25/$T9 | Reserved | FPR25/F25 |
R26/$K0 | PErr | FPR26/F26 |
R27/$K1 | CacheErr | FPR27/F27 |
R28/$GP | TagLo | FPR28/F28 |
R29/$SP | TagHi | FPR29/F29 |
R30/$S8 | ErrorEPC | FPR30/F30 |
R31/$RA | Reserved | FPR31/F31 |
Routines are like functions in PC programing languages. They can call other functions and get rather confusing to follow. Functions are called in R4300i by jumping to a specific address with a J/JAL/JR/JALR instruction. Routines usually end with JR $RA. The return location is the address in $RA. Branch instructions are conditional checks used to skip parts of a routine based on a condition being true or false. Jumps and branches all have a delay slot. This means they execute the instruction immediately following them before going to the address given.
NOP instructions do absolutely nothing. Yes, nothing. NOP is actually pseudo instruction. On N64 it assembles as SLL $ZERO,$ZERO,0x00. However, there's a shortcut to NOP anything by only changing the upper 16-bits. 0x2400XXXX is a Short NOP. The XXXX can be anything, which is why it can be done with a single 16-bit code. What the 0x2400 does is change the instruction to ADDIU $ZERO,$ZERO,0xXXXX, essentially making it do nothing because $ZERO can't be changed. This is useful for making shorter ASM hacks in a lot of cases.
Breakpoints are used to find the assembly that reads/writes to a specific memory location or to find out when an instruction is executed. When a break occurs, the game halts until the user chooses to continue. Breakpoints come in 3 types, each with a purpose. Read breakpoints (BPR) cause the game to halt when the location being watched is read from by assembly. Write breakpoints (BPW) halt the game when an address being watched is written to. When setting read/write breakpoints, a previously hacked code is needed. This is the address to watch in order to make an ASM hack. Breakpoints on execute (BPX) are used to halt the system when CPU executes the instruction at the address being watched. These are typically used once a BPR/BPW has already been done and the user wants to see what's going on at a certain point in the routine.
Setting Read/Write Breakpoints on GSCCGSCC lacks the ability to set breakpoints on execute, but it's still possible to get the effect of one.
Some games are difficult to ASM hack because they use virtual addresses. The virtual addresses are mapped to physical addresses through the translation lookaside buffer (TLB). Currently, the only way to work around the TLB is to view the mapped address in the memory viewer (Nemu)/RAM Edit (GSCC) to get the 32-bit hex value of the instruction where the break occurred while the game is still halted. Then search for it in the memory, checking each result in the memory viewer against the surrounding bytes at the TLB mapped address until the routine is found. Keep in mind this won't work on Goldeneye, because the physical location of most of the assembly changes randomly each time a level is loaded.
To Do
To Do
To Do
Some of the player data in SSB changes location based on what arena/mode is being played, etc. This is a problem for those of us hacking the game, but it's not a huge problem in this case. To get started, take a known location of the invincibility status modifier for P1. Peach's castle (vs mode) is 0x8025E6FF, for example. Setting a BPW on this yields 0x800E8AD8.
Looks simple enough, but BPX on it to find that it's not reading only P1. It reads ALL players. Now note the pointer (base address) it's loading from when reading P1's invincible status ($A1=0x8025E150). Do a 32-bit RAM search for that value to find possible pointers, then check other levels to verify which pointer address accurately points to P1's data all the time (0x80130D84). Now back on our routine that's reading invincible status, find a place to jump out. There's a branch right where this is taking place, so a jump would need to occur a few opcodes before this. Keeping in mind that $A1 needs to be set to a player pointer, so it can be checked by out new code. Scroll up a few opcodes to find where $A1 was set. It's at 0x800E8AC0. Also notice that ugly bit of code at 0x800E8AC8. It loads $RA there, so doing a JAL after that won't work out too well. Let's just jump from 0x800E8AC0 then. Remember to load $A1 in this subroutine first though, since we're replacing that op.
Opcode | Arguments | Comments |
---|---|---|
.ORG | 0x000E8AC0 | |
JAL | 0x00000060 | |
.ORG | 0x00000060 | |
LW | $A1,0x001C($SP) | |
LUI | $AT,0x8013 | |
LW | $AT,0x0D84($AT) | ;Load the consistent P1 pointer. |
ADDIU | $A0,$ZERO,0x0002 | ;Set the value to write to P1's invincibility status. |
BEQL | $A1,$AT,0x00000078 | ;Compare the current pointer to P1's pointer. Only write invincible if this is P1. |
SW | $A0,0x05AC($A1) | ;Write invincible. |
JR | $RA | |
NOP |
That's one way to do it. Looking back on this hack, it wasn't a very good one, but it works. It can be done shorter by simply loading the P1 pointer and storing to it.
Opcode | Arguments | Comments |
---|---|---|
.ORG | 0x000E8AC0 | |
JAL | 0x00000060 | |
.ORG | 0x00000060 | |
LUI | $AT,0x8013 | |
LW | $AT,0x0D84($AT) | ;Load the consistent P1 pointer. |
ADDIU | $A0,$ZERO,0x0002 | ;Set the value to write to P1's invincibility status. |
SW | $A0,0x05AC($AT) | |
JR | $RA | |
LW | $A1,0x001C($SP) |
This ends up 14 lines of codes vs 17. It could possibly be done even shorter on some games by setting a BPR on that constant P1 pointer address (0x80130D84) and finding a routine that only reads P1. It won't work that way on this game though because there aren't any constant reads. Something to keep in mind on other games though.
810E8AC0 0C00
810E8AC2 0018
81000060 3C01
81000062 8013
81000064 8C21
81000066 0D84
81000068 2404
8100006A 0002
8100006C AC24
8100006E 05AC
81000070 03E0
81000072 0008
81000074 8FA5
81000076 001C
Here's how the original Jesus Mode code was hacked (based on a post by Parasyte). In Mario 64, the engine determines whether Mario should walk or swim based on Mario's position relative to the water level. If Mario is below the water level, he is put into swim mode.
This first thing to do is to determine how the game decides when Mario is touching the ground. The easiest way to do this is to watch the Mario's "action" (0x8033B17C). Jumping into the air, then setting a BPW on that location causes the game to break when Mario hits the ground. The break occurs at 0x80252E18. Stepping out of the routine (finding the jr $ra which is at 0x80252E54 here), and scrolling up to find that the jump (jr $t6) is part of a jump table. The table contains our 0x8026B4B0 in index 1, so that is the value we want. $t6 contains the address of a routine to jump to depending on what even is occurring. t6 is 0x8026B4B0 when Mario lands on the ground. Now we need to determine how the game chooses $t6. Scrolling upwards, $t6 is set at 0x8026B474 (LW $t6, 0x001C ($sp)), by loading from the stack. This stack location is set at 0x8026B470 (SW $v0, 0x001C($sp)). $v0 is always used as the return value for subroutines that return integers. Just above at 0x8026B468 is that routine. We want $v0 to be 1, because that is the index of the jump table we want to force. So we must look inside 0x8026B468 (JAL 0x80256B24) to see where $v0 is set to 1.
Nothing of note occurs until 0x80256CBC (LW $v0, 0x0018 ($sp)). This happens to be the last instruction before exiting (JAL 0x8037897C). The next task is to find how 0x0018($sp) is set. Scrolling up, 0x80256BD4 does this (SW $t4, 0x0018($sp)), with $t4 being set in the previous instruction (LW $t4, 0x001C($sp)). Scrolling up to determine how that is set, we find 0x80256BC0 does this (SW $v0, 0x001C (SP)). Again, $v0 is the return value of a subroutine. The previous subroutine occurs at 0x80256BB8 (JAL 0x802560AC). We must find where inside this subroutine $v0 is set.
Inside this subroutine, $v0 is set to 1 at two different places: 0x80256180 (ADDIU $v0, $r0, 0x0001) and 0x80256274 (ADDIU $v0, $r0, 0x0001). Setting a BPX on each and having Mario jump and hit the ground, 0x80256274 hits. Now the task is to figure out how the game determines when this occurs. Scrolling up to find a branch that skips this instruction we find 0x80256200 (BC1F 0x80256278). Setting a BPX on this will determine that this instruction breaks as soon as Mario jumps; it occurs when he falls. This instruction is checking to see if Mario has hit solid ground yet. Now we need to figure out how the game tells. Scrolling up we find a comparison at 0x802561f8 (C.LE.S $f8, $f10). This is the comparison used to figure out if Mario has hit the ground or not when he falls.
Set a BPX at 0x802561f8 at watch the registers that instruction is comparing. $f8 decreases as Mario falls and increases as he rises; it's his Y-coordinate. Therefore, $f10 must be the coordinate of the solid ground. The next step is to determine how $f10 is set. Backtracing, we find that at 0x802561f4, $f10 is loaded (LWC1 $f10, 0x0028($sp)) and at 0x802561D0, $f4 is stored into that same place (SWC1 $f4, 0x0028($sp)). However above this, at 0x802561C4, there is a branch (BC1F 0x802561EC), which means the stack location can be set elsewhere. Setting a BPX on this location does not break. The other possible stack write location is way up a 0x80256110 (SWC1 $f0, 0x0028($sp)). Just as $v0 is the integer return value, $f0 is the floating-point return value. Just above here is a subroutine (JAL 0x80381900).
Inside the subroutine, f0 is loaded from the stack at 0x803819B8 (LWC1 $f0, 0x002C($sp)). Scrolling up to 0x80381A84, we find that the pointer to this stack location is stored into $t6 (ADDIU $t6, $sp, 0x002C). We now know that the game stores the coordinate for solid ground below Mario to that address. The question is: how? Setting a breakpoint on 0x80381A88, we find the exact pointer that is loaded into $t6. For this example it's 0x80206BAC, but it will be different every time. Setting a watchpoint on that address leads to 0x80381764.
Now that we know where the game sets the coordinate of the solid ground, we can complete the hack. Just change the value of the coordinate if Mario's Y-coordinate is below the water-level, forcing him to land on solid ground. The hack simply involves replacing the swc1 instruction with a jump into unused RAM where the coordinate is replaced.
Opcode | Arguments | Comments |
---|---|---|
lui | $a0, 0x8034 | |
lh | $a0, 0xB1E6($a0) | ; Load water level |
mtc1 | $a0, $f6 | ; Move it to cop1 |
nop | ||
cvt.s.w | $f4, $f6 | ; Convert it to a floating point number |
c.lt.s | $f18, $f4 | |
nop | ||
bc1f | end | ; if (waterlevel > ground_y) |
nop | ||
mov.s | $f18, f4 | ; ground_y = waterlevel |
end: | ||
j | 0x8038176C | |
swc1 | $f18, 0x0000($t8) | ; Taken from the break out location |
Code:
81381764 0800
81381766 0024
81000090 3C04
81000092 8034
81000094 8484
81000096 B1E6
81000098 4484
8100009A 3000
810000A0 4680
810000A2 3120
810000A4 4604
810000A6 903C
810000AC 4500
810000AE 0002
810000B4 4600
810000B6 2486
810000B8 080E
810000BA 05DB
810000BC E712