SNES Hacking with SNES9X

At prompting from peers, I decided to try to make a guide that incorporates some of the information I've learned that could help someone get past the muddle of being a beginner at assembly hacking.

is: SNES9X Hacking Guide
by: ugetab
on: August 17, 06

1. Intro

2. Making PAR codes with the SNES9X searcher

3. SNES Assembly Chart

4. The actual assembly hacking

5. Advanced PAR code creation

1. Intro

I'll start off with the guts, and rewind to the beginning afterwards.

Here's the basic flow of Assembly hacking with the SNES:

Get a copy of Geiger's SNES9X Debugger (GSHI Downloads section)

Find a copy of Bomberman 1 by yourself.

Run Geiger's SNES9X, and load Bomberman 1

Get into the game, where you can lose a life.

Go to the Cheat > Search for New Cheats menu.

Set 'Comparison Type' to 'Equal to', and 'Compare To' to 'Entered value', then put 5  in the text box.

Click the 'Search' button.
Press OK

Lose a life by blowing yourself up after you're not invincible anymore.

Go back to the Search for New Cheats menu.

Set 'Comparison Type' to 'Equal to', and 'Compare To' to 'Entered value', then put 4 in the text box.

Continue doing this until you get only 1 address left. If you need to, reset the game to start over.

The address that will be left is 7E0D7D

In the Debug Console, press the 'Breakpoints' button.

Replace one of the 000000s with 7E0D7D, and click on the 'Write' checkbox on the same line, then press OK.

Lose a life.

The game should halt, and the Debug Console window should get focused, with a line that starts with:

$C4/19FE D6 3D DEC $3D,x [$00:0D7D]

$C4/19FE is the address C419FE

D6 is the instruction for 'DEC Z,X'
$3D is the 'Zero address', to which the register X will be added. 0x003D + 0x0D40 = 0x0D7D

Your concern is the address, and the instruction.

You want it to keep reading the same address, but stop reducing the amount at 7E0D7D.

Instead of making this hard, I'll start out easy.
D6 is the instruction for 'DEC Z,X'
B5 is the instruction for 'LDA Z,X'

The reason I can use LDA(Load A with ...) is that the A register isn't compared to anything else between the time lives are decremented, and the time the A register is loaded with something that's actually used. In essence, this code makes the game do nothing when it would normally do something. Since that something it to reduce your lives when you die, it's better for you.

Now that it's been explained what the basic reasoning is, you need to put it together:
$C4/19FE D6 3D DEC $3D,x [$00:0D7D]

C419FE is D6
C419FF is 3D


Because we're not changing C419FF, only C419FE, it only takes 1 code to give you infinite lives.

C419FED6, which is what it is normally, gets changed to C419FEB5

C419FEB5 is the code that gives you infinite lives. This can be converted into a Game Genie code, but that's not the biggest concern. The notation C419FEB5 will work until you're sure the code does what you need it to, and doesn't do things like crash the game.

In the game window, go to Cheat > Game Genie, Pro-Action Replay Codes

Put C419FEB5 into the 'Enter Cheat Code:' text box

You can put something in the description field, or not. It's up to you whether you think you'll remember what the code does the next day, or a week from now, in case you forget to record what you were working on when you made the code. I've been fairly lucky, because I rarely lose work due to forgetting the goal of the effort.

Once you've got the Cheat Code and the Description filled as needed, click the 'Add' button.

Press 'OK' to leave the cheat menu.

Click the 'Cheat' menu bar option, and see if 'Apply Cheats' is checked. If it's not, click on it to enable the cheats.

Now, try to lose a life.

If your lives say the same, then you're done. You've got a code for infinite lives in Bomberman 1.

Infinite Lives:

2. Making PAR codes with the SNES9X searcher
This tends to be more hit-or-miss than the assembly work.

If you're looking for something like lives, it's easy to know when you think you've found it. You just make the regular PAR code, and if it works, you use that to try to make a Game Genie code. However, some things range from a little bit harder to a great deal harder.

Not everything is a definitive change in one direction or another.

Some experience point counters count down to the next level. Some count up. Some of the ones that count down to the next level look like they're counting up.

It's important to look for existing PAR codes for the thing you're looking for, because that can save you a lot of effort. It's more challenging to learn everything you need to know to make a Game Genie code than it is to learn how to find PAR codes with the code searcher.

I'll describe a more definitive method of finding PAR codes later on.

The basic strategy is to know when to use an exact number, and when to check for a directional change(like less than or greater than)

If you have a number on the screen for what you want, you can search for it by setting the 'Data Type' in the code search window. Unsigned if it's not a negative number, Signed if it is a negative number. Hexadecimal is also useful, if you can convert between the values easily.

'Data Size' means the number of bytes used to store the number.
0-255 can be 1 byte.
0-65535 is 2 bytes.
0-16777215 is 3 bytes.
0-4294967295 is 4 bytes.

'Greater Than' and 'Less Than' searches are also very useful for values you can't see numbers for.

It's not a simple thing to explain what I know about PAR codes, because most of what I learned, I learned between 1999 and 2000.

If you're desperate, and all else fails, you can use the 'Equal to' and 'Not equal to' options to help find the code, and start editing the addresses to get the effect you want.

For things that you can't easily tell when they've changed, it's better to keep using 'Equal to', when you're sure it hasn't changed, then use 'Not equal to' when you're sure it has.

It's best if anyone actually trying to use this guide be ready to get familiar with finding PAR codes, because those are the basis of finding codes with the SNES9X debugger.

3. SNES Assembly Chart

See the file "!6502asm.htm" (at!6502asm.htm). This has a far more accurate description than I could ever give. It also has HEX codes for looking up the value you can use for the instruction.

I use a program called 'Game Genie Code Converter' version 4.00. It has a forward and backward Assembly lookup table, and I use this for converting Game Genie codes, as well as for the NES and SNES assembly list. The gameboy assembly list in this program in incorrect, just so you know.

Game Genie Code Converter 4.00 can be found in the GSHI Downloads section:

4. The actual assembly hacking

This is where it gets more complicated. It's fairly hard to do anything but point someone in the right direction.

I don't know too many op codes by heart, except for the 'always jump' code, the 'no operation' code, and the 'RTS' code. I usually look up the rest of it, because I remember what the system is capable of doing, and then I see if I can somehow fit that into what code I have available by looking up what types of assembly could do it within the limit of 5 codes. (because a real game genie only has space for 5 codes)

I've managed to do a ton of stuff by exploiting read code to be used for writes instead, and write code to read. TSB and TRB can be used to remove or add sets of bits, without affecting unrelated bits within a byte. Some code I used recently used a total of 5 codes to make an 'enable all weapons' code. One code was used to change a LDA into an ORA, because bits were being tested. This enabled the existing bits from the addresses, and the ones that were being tested. 3 more codes allowed me to write that value back to the location it has been read in from. That left me in the middle of another instruction's data, and I was able to turn a non-working value, followed by a 00 into an 'always jump' code, with 00 bytes as the perameter of the jump, using 1 code. If it hadn't been followed by a 00, it probably would have been harder to do, or not possible using that area of code.

It's important to remember that you have to clean up the code you're replacing. If you have to replace a 3-byte code, and you only have plans to use 2 of the bytes in that code, you still have to do something with the third byte, because it's going to do something unless you tell it not to. If what it does ends up not being an issue, that's a special case. Otherwise, you need to use an 'EA' instruction to NOP it out...or, if it's going to take more than 2 codes, you can use a 'Branch Always' instruction, and be able to move up to 7D bytes forward, until you reach a spot in the code that it would normally run after what you replaced.

The 'RTS' code of '60' stands for 'Return Short'. This code lets you nullify the effects of any routine that was reached through a 'JSR' command. By placing the RTS command at the first byte of the routine, you insure that no other code beyond it is run. This means you don't even have to worry about what comes after the RTS, because the instruction you replaced won't get run, and there's a good chance the code won't be run while your cheat is active. I've used this to make Invincibility codes for games with no built-in invincibility most often. I've used it to do other things too, but that's the most common use I have for an RTS.

Usually, when I get an address to 'break' when using breakpoints, I Disassemble it with a so named button in the Debug Console. I also tend to decompile starting about 0x20 before the default address in the disassembly window. Sometimes it lets me find an easier way to skip some code, such as when there's already a conditional jump(BEQ, BNE, BCC, BPL) that works when I turn it into an unconditional jump (BRA)

This is all cursory though. The real strength behind what makes me better than passable at assembly hacking is that I try to exploit opportunities. I'm pretty good at just absorbing information about the debugging environment for temporary use, like a sense of what the variables will be at a certain address after running through a short routine a half-dozen times. I look at things, follow the path of their activities using simple numbers, then try to find a way to exploit the path to achieve a known goal. I look for the lowest needed underlying cause for something to happen, and try to find the fewest changes needed to achieve it.

It's for these same reasons that I doubt I'll ever do anything large-scale. I can't wrap my brain around the entirety of a program at once without a large goal in mind, and a lot of work. Because I've never found anything worth so much effort(except hacking time-release codes for MAME games), I'll probably never be a game translator, and I'll probably never release any patches, except to fix problems with the systems of other patches. I can understand and fix a variety of small issues, or make minor changes to the fundamental functioning of a program(the program being the game), but that's just detail work to me.

That's probably all I need to say about what mentality I use when working on assembly, so I'll get back to the actual task of it again.

Remember what I said about absorbing a lot of info? If you use the trace logger in combination with a breakpoint, you can be sure you'll need to look at a bunch of code. The 'CPU' checkbox in the 'Logging' frame is something that lets you record all of the commands used up to the point logging is stopped. This makes the game very slow, and uses a very, very high amount of disk space. Using save states to get close to the time the change occurs before enabling the breakpoints and logging is helpful, because just clicking on the debugger console freezes execution, and a few seconds can be the difference between a 3 megabyte log file, and about 20 megabytes over 5 log files.

5. Advanced PAR code creation(File2File)

This contains the program, and a faq on how one can use the program with ZSNES:

Go here to respond to the tool:

I can't really give out much more information than that, because it's more a matter of just noticing things I'm experienced with. A drawn out process of "one thing leads to another", but with hex.

This text was brought to you by, unless someone else gave it to you, in which case it was only written by someone at Heheh.