Contents

Lesson 1 - An introduction to ASM
Lesson 2 - Processors, registers, opcodes
Lesson 3 - Let's get cracking
Lesson 4 - Bending the rules
Lesson 5 - 1 code to rule them all part I
Lesson 6 - 1 code to rule them all part II
Lesson 7 - The dreaded maths lesson
Lesson 8 - Make those codes!
Lesson 9 - Master codes
Lesson 10 - Breaking the limits
Dealing with DMA - Part I
Dealing with DMA - Part II
Pokémon Fire Red - Down in the dumps
Pokémon Fire Red - Warp off
Pokémon Fire Red - Walk through walls!
Pokémon Fire Red - Item properties

All tools mentioned can be found here

Lesson 1 - An introduction to ASM

I've run out of things to talk about code-hacking wise using the VBA Code-Searcher for the time being anyway. So, we can finally get stuck into some ASM Hacking! A word of warning: This lesson gets very technical and you may not understand many of the things that are dealt with here - but eventually you should figure out by yourself what I'm talking about.

A second word of warning: This is not intended as an ASM programming tutorial, in fact, I would recommend you go find a good ASM tutorial - there are plenty out there.

I'd also like the apoligise for some of my explanations (or lack of) - I'm not really that good at explaining stuff and as I'm sure you've encountered before, it's hard to explain things that you know well to beginners (the 'get frustrated - why don't you get this?!?!? factor). I'll try my hardest...

You will need the following things:

The GBA Technical Document - http://www.work.de/nocash/gbatek.htm
Kenobi's VisualBoyAdvance SDL Version (if you get this you don't really need the normal version) - http://www.gscentral.com/lib/downloads/SDLk.zip now superceded by VisualBoyAdvance for Hackers)
Mappy Virtual Machine - http://www.bottledlight.com/
Optional: no$gba

A note about no$gba: There used to be three versions of this program - a cutdown freeware version with colour support, a cutdown freeware version with sound support, and the commercial version. After this was cracked the author discontinued the freeware versions - though the cracked version can still be found on the net. Out of respect for the author, Martin Korth, I will not be posting a link but you should be able to find it if your web searching skills are adequate. It isn't essential, as for most of the things we will be doing the other tools will be fine - I may write some no$gba-only tutorials however, as it's an excellet tool and it would be a shame not to show a few tricks you can do with it.

Things that will help
Being a programmer is a definite advantage here, as most of ASM hacking involves looking at and understanding ASM Instructions [source code]. I also find that cracking experience helps a lot here - there are a lot of parallels that can be drawn between the two. And if you already know the ARM7TDMI insturction sets then you probably won't have to read [and waste time puzzling out] much of this.

What is ASM?
Assembly Language [ASM], or Machine Code, is a low-level programming language. The GBA reads in Assembly instructions and interprets them. Machine Code is just numbers - though we use a DISASSEMBLER to convert the numbers into ASM instructions that we can understand. All of the emulators listed above come with built in Disassemblers.

What is ASM Hacking?
I loosely define ASM Hacking as any form of Code Hacking which uses ASM in some way - this includes merely tracing through ASM instructions to modifying instructions.

The Nintendo Gameboy Advance uses the ARM7TDMI 32-bit RISC (Reduced Instruction Set Computer) CPU, which is designed by a company called ARM (Advanced RISC Machines). It has 2 CPU states (operating modes), ARM and THUMB. ARM mode uses full 32-bit opcodes (each 'opcode' or operation code is 32 bits long) while THUMB uses cut-down 16-bit opcodes.

Before you begin you need to know a bit about how the GBA's processor works (and processors in general).

As I said above, machine code is just numbers (in this case, hex numbers - computers love hex), for example, this is an ASM instruction:

464e

Ha! What does that mean? Well, that's the job of a disassembler, to tell us what that number means. In this case, that means

mov r6, r9

Of course, you won't have a clue what that means unless you've worked with ASM before (mov is one of the basic ASM instructions that all forms of ASM will have).

Here's another example:

2f58

means...

cmp r7, #0x58

Confused? Good, because...

...next lesson, it gets even more confusing! You'd think that all instructions are the same length, 4 digits (though in most ASM languages opcodes can be of different lengths). The problem is... GBA has 2 instruction sets! And they can be interchanged just like *that* [snaps fingers]. But stick with it, if you can figure out all these ramblings (or find a better tutorial on GBA ASM, nevermind the hacking part), you'll have the power to do... mwahahahaha!

In case you were wondering about my odd 'buoyant tone' in this lesson, it's because I'm currently watching 'World Idol' and it'd damn funny....

Lesson 2 - Processors, registers, opcodes

ASM Lesson Two - Processors, Registers, Opcodes, Caffeine, Arms, Thumbs (no I'm not joking), Stacks, Branches, To be Continued...

Well, now that I've just delivered the longest [and most absurd] title for a tutorial I have ever seen, let's get stuck in ( /me is now watching "The Gift", so I think this may be slightly more controlled )

It's hard to know when to start with Assembly language, so I'm going to go through two important 'concepts', for lack of a better word, and then get into the hacking.

But first - ARMs and THUMBs (I was deadly serious).

The ARM7TDMI has 2 instruction sets, the ARM set and the THUMB set. What this means, is that there there are 2 cpu states. In one, the processor interprets instructions as ARM instructions, in the second in interprets them as THUMB instructions.

Why have 2 instruction sets? The major difference is that ARM opcodes are 32-bits long, THUMB opcodes are only 16-bits long.
As a result, THUMB opcodes execute a lot faster - up to 160% faster. The other differences will be explained as we go along

Registers
You can think of registers as variables that you can use to play around with. Most opcodes require you to move data into registers before you can manipulate them, then restore them back into memory. There are 16 registers that you will encounter. They are named (and reference in assembly) by the letter 'r' followed by the number in decimal, e.g. r9 .

The registers r0-r12 are known as the general purpose registers. They have no specified purpose and you are free to use them for whatever you want.

The other 3 are special.

r13 is the stack pointer (sp)
r14 is the link register (lr)
r15 is the program counter (pc)

Don't worry about r13, but the other two are important.

When a program calls a sub-routine (with bl [branch with link]), the return address is stored in the link register. The program counter ALWAYS contains the address of the next instruction to be executed. However, when you are reading in this value the actual value that is returned will most likely be a few instructions ahead of the actual pc (due to pipe-lining). Don't modify this value unless you knkow what you're doing or else you'll probably stuff up the game.

The Stack
The ARM7TDMI processor has a stack like other processors - it is helpful to understand how it works.

This analogy is often used in programming books: Think of the stack as a stack of plates, being piled a top each other. When you add a plate to the stack it is added to the top. If you want to take a plate off, you take it off from the top.

Items are removed from the stack in reverse-order

The ASM instruction to add items to the stack is push, to remove, pop.

If you are playing around with the stack, e.g. you've added a subroutine which uses the stack, you MUST remember to remove items that you push on, or else when the rest of the program executes it will be taking the wrong data off.

Lesson 3 - Let's get cracking

Quote: The best way to learn is by doing.

So that is what we will be doing. I've grown tired of all of these odd explanations about ASM - you'll learn a lot better if you find out what they are by hacking a code. So, today we are going to hack our first ASM code. It is a variation of the tutorial written by Kenobi in the Hacking Text (which is the first, and in fact only GBA ASM tutorial I've seen). By all means you can go and look at the original if you wish - but if you haven't had any cracking or ASM experience before it might seem a bit tricky.

The game: The Invincible Iron Man
The code: Blue Orb Quantity never decreases.

Okay, let me explain - in the game there is an uber cool item called the blue orb which does wicked stuff. The code we'll be hacking today ensures that when you use it, it doesn't disappear. The blue orb is first encountered at the start of level 3, so you'll have to play/cheat your way to get there (if you remember way back, we did some hacking on Iron Man earlier).

So, once you've got a savesate with you at the start of level 3, load up the game in VBA SDL (either version will do).

Now, to hack this code we need to find the piece of code that decreases your Blue Orb quantity when you use it. How do we find this? Well, we could scan through the entire source code of the game but that would be a bit time consuming and probably
wouldn't work too well - what we need is a starting point. Introducing, breakpoints!

Breakpoints

A Breakpoint tells the game to halt the execution (this means to stop it running, not stop it being be-headed) of the game under a certain condition. VBA SDL has 4 types of breakpoints:

BPR: Breakpoint on Read. The debugger (VBA SDL is a debugger) will stop the game when the memory address specified is READ FROM (this is only in Kenobi's version of VBA SDL).
BPW: Breakpoint on Write. The debugger will stop the game when the memory address specified is WRITTEN TO.
BT: Breakpoint on Thumb. The debugger will stop the game when opcode at the specified address is executed in THUMB mode.BA:

Breakpoint on Arm. The debugger will stop the game when opcode at the specified address is executed in ARM mode.

So, we want to catch the game decreasing the Blue Orb address, so we'll use a BPW. But what's the address? Well, you'll have to hack it. It think the value stays constant as long as you're playing the same level - e.g. for me it's always 0201fb24. If you're having problems finding it - when you don't have the orb it is 0, when you do it is 1, if you manage to pick up a second orb while you have the first, it's 2, etc... If you manage to narrow it down to 3 results, it'll be the bottom one. It does NOT visually affect the game - i.e. it won't show that you have it, but the game will act as if you did.

Okay, you've got the game loaded in SDL, you're at the start of the third level, go grab the blue orb. Now, we want to enter the debugger, so press F11. The game will stop and you'll be taken to the debugging console. It will look something like this:

R00=00000000 R04=02001f94 R08=00000000 R12=0000008e 
R01=00000000 R05=02010d4c R09=00000000 R13=03007d1c 
R02=02a70000 R06=02010cc0 R10=00000000 R14=0804cae1 
R03=0804cae1 R07=00000006 R11=00000000 R15=08045bde 
CPSR=4000003f (.Z....T Mode: 1f) 
08045bdc d311 bcc $08045c02 
debugger>

A quick explanation. All of those Rxx=xxxxxxxx shows what values the registers currently hold. Ignore the next line coz it'll just confuse you more. The line below that (08045bdc d311 bcc $08045c02) tells you the rom address the game stopped at (08045bdc), the value at that address (d311) and what that means in ASM (bcc $08045c02). This is the next opcode that the emulator will execute.

Okay, we want to set that breakpoint. The format for a BPW is:

BPW <address> <size>

How do I know this? I just typed in BPW at the prompt and it returned the syntax (because it isn't a valid instruction if you don't have the two parameters). By the way, now is a good time to mention that if you type 'h' without the quotes at the prompt it will display the help menu.

So, we want to break on write at $0202CCF4, with a size of 1 byte (this means that if any of the bytes from <address> to <address + size> is written to the debugger will break.

So, at the prompt, type

BPW 0201fb24 1

or whatever your address is (if it is different, from now on I'll assume you're using this address). Now type c to Continue execution.

You will return to the game. Now press [L] to use the orb. The game should break, because the value at 0201fb24 changed. Back in the debugging console you will see:

Breakpoint (on write) address 0201fb24 old:00000001 new:00000000 
R00=00000000 R04=00000000 R08=0201f930 R12=00000001 
R01=0201fb24 R05=00000001 R09=0201fa00 R13=03007ba4 
R02=0201f9b4 R06=0201fa00 R10=0201f9fc R14=0802c5fd 
R03=080365bf R07=0201f9fc R11=00000000 R15=0802c63e 
CPSR=6000003f (.ZC...T Mode: 1f) 
0802c63c 9004 str r0, [sp, #0x10] 
debugger>

You should recognise the same format, except for the first line, which tells you which address it breaked on and what the values were. The address we stopped at was 0802c63c. Remember, this is the NEXT ADDRESS TO BE EXECUTED. That means that the actual adress that caused the break was the previous opcode.

Now we're going to take a closer look at the source code that caused this. VBA SDL is a bit tricky to use, so we're going to go back to the normal VBA (if you have no$gba then you can use this as well, though i'm not going to tell you how to, it's not that hard )

Open VBA, load up the game, then go to Tools->Disassemble. It'll open up a window. In the edit box type in 0802c63c then click 'Go' (if you press enter, then, unlike the memory viewer, the window will close which is really annoying). Set the mode to THUMB, because the emulator was in THUMB mode when it broke (how do we know? The value at the address is only 16-bits [2 bytes] long, remember ARM opcodes are 32-bit). The top line should be:

0802c63c 9004 str r0, [sp, #0x10]

which incidentally is what it was in the SDL version.

Scroll up a couple of lines. These are the instructions you see:

0802c630 21fa mov r1, #0xfa 
0802c632 0049 lsl r1, r1, #0x01 
0802c634 4441 add r1, r8 
0802c636 6808 ldr r0, [r1, #0x0] 
0802c638 3801 sub r0, #0x1 
0802c63a 6008 str r0, [r1, #0x0]

This is where the GBA Technical Document comes in handy - if you look up 'THUMB Instruction Set' then you'll see explanations of what all of this means. But I'll try and tell you anyway.

0802c630 21fa mov r1, #0xfa

The mov opcode basically moves a value from one place to another. Here, the value 0xfa is moved into r1.(Important: the syntax of mov is mov rd, rs. This means that the value (or register) on the RIGHT is moved into the register on the left.)

0802c632 0049 lsl r1, r1, #0x01

This is a logical shift left, which is one of those nasty maths operations that normal high-school maths students won't know - I'll explain it later, it's not important now. Here, the value in r1 is left shifted by 1 (which is the equivalent of multiplying by 2).

0802c634 4441 add r1, r8

Here the value in r8 is added to the value in r1, with the result being stored in r1. If you were to look further into this, this holds the key to why addresses are always changing.

0802c636 6808 ldr r0, [r1, #0x0]

Okay, now it gets interesting, the value in r1 is used as a pointer, i.e. take the value in r1. Add 0 to it (kinda pointless ) Now, put the value at the address which is held in r1, and put that into r0 (confused?) If you look at the registers in SDL, r1 is the blue orb address. So r0 now contains your blue orb quantity.

0802c638 3801 sub r0, #0x1

This is the important one! Guess what the 'sub' opcode does! It subtracts the second value from the first, storing the result in the original. So, what this does is it minuses one from your blue orb quantity. This is probably what we will change. 08

02c63a 6008 str r0, [r1, #0x0]

Now it stores your orb quantity back into the correct address.
---

Okay, remember what code we're hacking? We don't want the quantity to decrease. So, we could change the 'sub r0, #0x1' into something like 'sub r0, #0x0'. This way, the value doesn't get decreased.

So, now we're going to 'construct' an opcode. Open the GBA tech document, goto THUMB instruction set, and find the add/subtract section. You will see this:

Opcode Format 
Bit Expl. 
15-11 Must be 00011b for 'add/subtract' instructions 
10-9 Opcode (0-3) 
0: ADD Rd,Rs,Rn ;add register Rd=Rs+Rn 
1: SUB Rd,Rs,Rn ;subtract register Rd=Rs-Rn 
2: ADD Rd,Rs,#nn ;add immediate Rd=Rs+nn 
3: SUB Rd,Rs,#nn ;subtract immediate Rd=Rs-nn 
Pseudo/alias opcode with Imm=0: 
2: MOV Rd,Rs ;move (affects cpsr) Rd=Rs+0 
8-6 For Register Operand: 
Rn - Register Operand (R0..R7) 
For Immediate Operand: 
nn - Immediate Value (0-7) 
5-3 Rs - Source register (R0..R7) 
2-0 Rd - Destination register (R0..R7)

Return: Rd contains result, N,Z,C,V affected (including MOV).
Execution Time: 1S

Okay, to understand this you have to understand binary. This is how I do opcodes (some people may do it differently. I open the windows calculator and set it to binary mode. Now, as I enter each bit I say out the bit number it is, i.e., for this one I'll put in 0, say 'fifteen', type in another 0, say '14', etc... So, let's go through this step by step (it is VERY important you understand what I'm doing here).It tells me what bits 15 to 11 have to be, so I enter them in the same order (as shown below)

Bit 15:0
Bit 14:0
Bit 13:0
Bit 12:1
Bit 11:1

Now, for bits 10 to 9, it tells us to put in the number representing the opcode we want. We need a sub immediate, which is 3, which is 11 in binary. So, we have:

Bit 10:1
Bit 9:1

Now, we want to subtract a number, not a value in a register - which is 'immediate', so for bits 8 to 6 we put in the value we want (0)

Bit 8:0
Bit 7:0
Bit 6:0

Okay, bits 5 to 3 are the source register. We want r0, so it's 0.

Bit 5:0
Bit 4:0
Bit 3:0

The destination register is the same, so we have

Bit 2:0
Bit 1:0
Bit 0:0

So, we type this all into the calculator (0001111000000000 in binary), typing in the 15th bit first, then the 14th, etc...Convert it to hex, and we get 1E00 . So, that is what the opcode 'sub r0, #0x0' looks like as raw data (complicated, ain't it?).

I'm not going to show you how to make a code from this just yet, but we will test that it works. The address this goes at is 0802c638, so open up the memory editor, put it into 16-bit mode and replace the 3801 with 1e00

Now, go back into the game, reload your save (changes to the ROM only get reset when you CLOSE the rom, not just reset it), grab the blue orb and use it. If everythings gone right, it won't disappear! Cool, you just hacked your first ASM code (well, we're yet to make the code but who cares).

Lesson 4 - Bending the rules

In this lesson, (and in the lessons to come, I want to give as many examples as possible), I'll walk you through one of the first ASM codes I hacked - a code for Harry Potter Quidditch. I'm putting off explaining how to write ROM patch codes because it's kinda odd - it can't be done for the CBA and the GSA/PAR V.1/2 and V3 codes are quite different.

The code itself is kinda pointless - it changes the value of a goal - instead of scoring ten points you score fifty.

Okay, it's important to know the process you should go through in hacking an ASM code, so this is basically what I thought:

1. The bit of code I'm looking for modifies the score.
2. So, I could do a BPW on my score and find the routine that adds to it.

Now, cast your mind back all the way to Lesson Six, when we hacked a score mod (yeah, I've been planning this for a while). The address we had was $03002B5D for your score. Just quickly, hack a code for your opponents score. In fact, don't hack the code. Use a bit of zen. Open the memory editor, go to your score, and you can bet that the opponents score will be near by (remembering that 1=10 points).

Just to make sure we're on the same path, it's the next byte! $03002B5D. Well, this step wasn't too important in the code we're hacking, but it will become important shortly.

Right, open the game up in SDL (remember that you can't set Breakpoints if you've got cheats enabled, so disable them all in the normal VBA before you open it up in SDL).

Now, you should know what to do next. Load up a save with you in-game, go into a debugger, and set a breakpoint on your score like this.

bpw 03002b5d 1

Now c to get back into the game.

Play a bit, until you score a goal, and the game will halt. In the debugging console we see something like this (some values will vary)

Breakpoint (on write) address 03002b5e old:00 new:01 
R00=00000001 R04=00000001 R08=00000040 R12=03002b30 
R01=03002b5e R05=03002b30 R09=03002a32 R13=03007cf4 
R02=03002b5d R06=fffff04e R10=00000000 R14=085e1c87 
R03=03002730 R07=03002b65 R11=00000000 R15=085e656e 
CPSR=0000003f (......T Mode: 1f) 
085e656c 7809 ldrb r1, [r1, #0x0] 
debugger>

So, let's go back to normal VBA, Tools->Disassemble, and go to $085e656c

Now, I'm not going to go into what everything does because I don't have to. We know that if you score a goal your score value is increased by 1. As you may guess, the opcode to add values is... add. So, we're looking for an add rx, #0x1 (where x is any register, I don't what it will be yet). A quick look should show you that at 085e6568 we have

085e6568 3001 add r0, #0x1

Now, we want to change it to add 50 to your score, so we want to make it

add r0, #0x5

We could now look up the GBA tech doc to find out how to make this, but I'm going to teach you a quick trick. To add an immediate (a number) to a register, the format is

3rxx

where r is the register and xx is the amount. So in this case, out opcode would be 3005, because instead of adding 1 to the r0 register we want to add 5.So, open up the mem editor, go to 085e6568, and change it to 3005.

Back in the game, score a goal and... it's worth 50 points! Okay, so that worked. Here's the interesting bit. If your opponent scores a goal, it's also worth 50 points. It is possible to make a code so that, regardless of who scores, it gets added to your total, but as that requires 2 patch codes, I won't be doing it today (GSA V.1/2 hardware can only handle 1 custom patch code at a time). If you want to have a go at this yourself, it's quite simple. r2 always holds your score address, regardless of whether it was you or your opponent who scored. So, if you change

085e6566 7808 ldrb r0, [r1, #0x0]

to

085e6566 7810 ldrb r0, [r2, #0x0]

it will load your address regardless, and then change

085e656a 7008 strb r0, [r1, #0x0]

to

085e656a 7010 strb r0 [r2, #0x0]

it will always update the address to your score.

Alternatively, there are tons of other codes you could do. For example, you could change

3001 add r0, #0x1

to something like

mov r0, #0x19

and you'll freeze the scores at 250 points

Lesson 5 - 1 code to rule them all part I

No, we're not going to do a LOTR code... maybe some other day. Today, I'm going to show you how just ONE ASM code can replace 96 codes.

The game - Max Payne.
The code - Unlimited Ammo.

There are 8 types of Ammo in the game. Usually, this wouldn't be too bad - they're 16-bit values so you could combine it all into 4 32-bit codes (We're talking Gameshark here - with CBA we can do a slide which reduces this to two lines).

The bad news is, there's 12 levels in the game - and the addresses are different for each level.

However, with ASM we can save a lot of hard work. I'm *guessing* that the same routine is used to decrease the ammo of each weapon - if we can find this routine and make a small modification to it we can get unlimited ammo for all of the weapons - regardless of the level you're playing.

Okay, so let's get hacking. I'll be basing my hack on the first level. First we need to find somewhere to start - I'll be setting my bpw on the M9 (to save you some time - $0200C5F4).

So, load the game up in SDL, get into the first level, press F11 and set your breakpoint by typing in at the console

bpw 0200c5f4 2

Back in the game, pop a cap somewhere. The game will break because your ammo value changes. In the console we see that it breaks at

080228ac 783a ldrb r2, [r7, #0x0]

Go back to normal VBA, open the Disassembly and go to 080228ac. Scroll up a couple of lines. Now, since your ammo decreased, we're looking for a sub opcode. We see

080228a8 1a5b sub r3, r3, r1

This means that r1 is taken away from r3, and stored in r3. I'm not going to worry about what the registers mean, I know all I have to do is mod this address. We want to keep the address constant, so we could replace that with

mov r3, #0xff

Now, you could open up the GBA Tech doc and find out how to make this, but I'll teach you another trick. For a mov, register, immediate, the shortcut is

2rii

where r is the register and ii is the immediate. So, our opcode is

080228a8 23ff mov r3, #0xff

Open up the mem editor, go to that address and mod it in 16-bit mode. Back in the game, and you can shoot as much as you like - but your ammo won't decrease (in fact, it'll just get set to 255). It'll also work on any level - for every weapon.

So, there's a cool example of how you can save typing in a lot of codes, with a spot of ASM trickery.

Lesson 6 - 1 code to rule them all part II

Well, I've been getting a bit lazy recently, so we're going to do what we did last lesson except change the addresses, to give you a bit more practice.

This time it's the Inf Health code for Max Payne, I'll be working, as usual, on Level 1. Quickly hack an Inf health code in normal VBA and then load up the game in SDL.

Same thing as usual, get into the debugger and set a breakpoint on the health address (I won't be writing in as much detail for this lesson as you should start thinking for yourself).

Okay, if you get shot, the game will break. Take note of the address and go to the dis***embler in normal VBA. Scroll up a couple of lines, and you should know by now what you have to do: NOP the sub, or str a different value into your HP.

You could NOP the sub, because it's the simplest (NOP means 'Do nothing', if you read the Tech doc you'll see it under 'Pseudo instructions and directives', this means that there is another instruction that means the same thing, in this case, mov r8, r8). The value for this is 46C0.

However, if you play the game you'll notice your HP meter becomes a very low value, so instead, change the str so that it str's a large value. As is standard, I'll replace it with r4 as this holds your HP address. The instruction I want to change it to is

str r4, [r4, #0x0]

I'm not going to tell you what the opcode is, you should get some practice and make it by yourself.

So, here ends a short and sparse lesson in which I haven't told you much at all... CV suggested I write some tutorials on reversing compression algorithms next... I've decided that I'll deal with things you can make ASM codes for first, and then move on to using ASM techniques in hacking (not necessarily modifying instructions).

Lesson 7 - The dreaded maths lesson

warned you this was coming It's not really that hard - most people involved with computers should already know this, and if you understand it all it'll definitely make a difference in your hacking.

Most of the operations deal with binary numbers - so make sure you're up with those. Also, don't get too worked up about them - you won't need to get your pen and paper out, the windows calculator can do all of this stuff for you.

Bitwise Operators
I remember seeing the name in the PHP manual, so I'll call them that . They are known as 'bitwise' because they are transformed as binary numbers.

AND
If the bits are both set to 1, then the resultant is set to 1, else it is 0.

For example, take 48 AND 92

48 in binary is 110000
92 in binary is 1011100
=======================
0010000

which is 16

Notice how the least significant bits are aligned, it's important to remember this.

Another example - 28 AND 78

28 in binary is 11100
78 in binary is 1001110
=========================
0001100

which is 12.

The AND operator is very useful for 'masking' numbers, for example if you had a 32-bit number and you wanted just the least significant byte you would AND the number with $ff.

NOT
This is a simple one, it only deals with one number - bits set to 1 are set to 0, bits set to 0 are set to 1 (they get switched).

e.g. NOT 43

43 in binary is 101011
======================
010100

which is 20. You have to be careful when using the windows calculator for this because the resulting number will be signed if the calculations are just performed in decimal mode. To get the correct result you have to make sure you're in binary mode and the data size is set correctly - because it will pad it with 0's, and therefore when you NOT these padded 0's will be changed into 1's.

To complicate things - the datasizes aren't the same as in GBA.

A byte is 8 bits
A word is 16 bits
A DWord is 32 bits
A QWord is 64 bits

For example, if you were to NOT 43, and it was set to Word

43 as a DWord is 0000000000101011
NOT it and you get 1111111111010100

which is 65492 in decimal. So, the moral of the story - be careful, do them by hand if you're not sure.

OR
If either of the bits is set to 1, then the resultant is set to 1.

For example, 218 OR 92

218 in binary is 11011010
92 in binary is 1011100
=========================
11011110
which is 222

OR is useful for setting bits without affecting the original (CBA has an OR code - in a later lesson I'll show you some uses for some of the more obscure code types).

XOR
If ONE of the bits is set to 1 then the resultant is set to 1.

For example, 153 XOR 74

153 in binary is 10011001
74 in binary is 1001010
=========================
11010011

which is 211.
XOR is quite useful because it works in reverse, i.e.

211 XOR 74

11010011
1001010
========
10011001

which is 153! This fact means that it is often used in encryption algorithms.

Shift Left
An extra x 0 bits is/are added to the end.

For example, 25 SL 3

25 in binary is 11001
Add 3 0's to the end and you get 11001000

which is

Now you can see why it's called 'shift left'. The bits have been shifted to the left and padded with 0's.

Important point: shifting left by 1, is the same as multiplying by 2. Shifting left by 3 is the same as multiplying by 8.

Shift Right
x bits are truncated from the end.

For example, 173 SR 4

173 in binary is 10101101
Take 4 bits off and you get 1010

which is 10.

Important point: To shift right with the Windows calculator, check the Inv(ert) box, and left shift. If you are working in Decimal, then it will actually divide by 2 for each bit taken off (opposite of shift left). However, this allows it to go into floating point values - to keep it proper, convert to binary then back to decimal if you must work in decimal (most of the time you'll be working in hex).

Lesson 8 - Make those codes!

I probably should have done this earlier, but I did need to get the maths lesson out of the way first. In this lesson I'll be showing you how to make 'Patch Codes' for the two devices that support them - GSA/AR V.1/2 and AR V.3

V.1/2

This has one small trick to it. The format is

6xxxxxxx 0000yyyy

where xxxxxxx is the address to be patched >> 1 (shifted right by 1) and yyyy is the 16-bit value to patch. So basically, take the address you want to be patched, divide it by 2 and stick it in.

For example, the first code we hacked for Ironman:

The address we want to patch is 0802c638
The value we want to make it is 1e00

0802c638 / 2 = 401631C

Our RAW code is 6401631C 00001E00

If you encrypt that you get 2DE6A975 A2ACE3D7

V3

Taken straight from the V3 Code types doc...

Type z0C
0.3.0.x.x
XXXXXXXX : (02024EA4 -> 18224EA4)
0000ZZZZ : Patches ROM Adress (XXXXXXXX << 1) with Halfword ZZZZ.

So, this is the same. It patches the address shifted LEFT by 1, so we have to enter the address shifted RIGHT by 1. However, in the latest version of ARCrypt it does this automatically for us, so you should type in

0802c63800001e00

Select Type z0C, make sure the values are right, and click create.

You will get (with special and unused set to 0):
75749062 29F0603B
625632D4 8418E7B0

If your V3 codes don't 'create' properly, the bottom two lines (with special and unused set to 0) should be set to

00000000 18xxxxxx
0000yyyy 00000000

where xxxxxx is the (address >> 1) AND $003FFFFF and yyyy is the 16-bit value to patch.

e.g. in the above example it would be

00000000 1801631c
00001E00 00000000

If it isn't - set it manually (the new versions of AR Crypt should fix this).

Important points to remember
On actual hardware (HARDWARE, not upgraded software on old hardware):
V.1/2 can handle a maximum of 1 patch code, depending on master code.
V.3 can handle a maximum of 4 patch codes, depending on master code. Each code must be a different patch type - either z0C, z0D, z0E or z0F. What this means, is that you can only have one patch code encrypted using the z0C type - if you want to have two ROM patch codes, you need to use one of the other types (they're all equivalent in terms of what actually happens).

It is dependant on master code because some (very rarely) also require a patch code component to achieve a 'hook', which takes up one space on the chip.

Codes remain active until they are replaced (another code is entered) or the game is hard reset (i.e., cart physically taken out, not just pressing the reset button).

On VBA (VisualBoy Advance)
Unlimited codes (though VBA can only handle a certain number of codes (whatever format) at a time, so this has to be taken into account - I think it's around 100). ROM must be re-opened (not reset) for changes to be reversed (cannot be reversed by disabling/removing code).

On CBA (CodeBreaker Advance)
I know I said CBA doesn't support patch codes - and it doesn't, however you can use normal RAM write codes in VBA for areas
in ROM (this is due to the way the emulator stores data internally), for example, the iron man code:

8801631C 1E00

Remember - this will definitely not work on an actual CBA, don't bother trying.

Lesson 9 - Master codes

Finally, the Master Code Lesson.

You will need:

The game you want to make a M Code for.
Mappy Virtual Machine OR no$gba
For CBA - crcgen

For this lesson I'll be using Rockman EXE 4 Blue Moon [J] (the Japanese version of the Megaman Battle Network series of games).

Okay, let's get into the general theory:

A Master Code has two parts - a 'hook' and an ID code.

The hook is a ROM patch, it overwrites an Assembly instruction in the game, replacing it with a branch to the Code handling routine. Every time this routine is executed, RAM is modified depending on the codes that have been entered in the device. Therefore, for the codes to work well, the jump has to be in an area of the game that is executed many times over - we usually use a place where input is read in (the state of the buttons you press), which this tutorial focuses on. However, as long as you can find a piece of code that executes many times per second it should be able to be used as a hook.

The ID code tells the device what game is being played, which is used for different functions in the device.

Finding a place to hook
First, we need a disassembly of the game (a text file that contains the ASM instructions in the game). You don't have to disassemble the whole game, the first 20kb is usually enough. There are two methods of getting a disassembly - one uses Mappy, the other, no$gba.

Using Mappy
Boot up Mappy, File->Load the game you're hacking.
File->Export Disassembly. Set the destination to the text file you want to dump the disassembly to.
Put anything you like in the textbox under the 'Label' column, for the address put in 08000000 (the start of ROM) and for length put in 200000 (20,000 bytes, not quite 20kb). Under mode select THUMB. Click Add, then O.K. The file should be created and you can close Mappy.

Using no$gba
File->Load Cartridge Menu(filename), and select the game you're hacking.
Right click in the disassembly view (the big area with all the opcodes in it) and Goto... 08000000.
Utility->Disassemble to File and type in 20000 for the length. Click O.K. and save the file somewhere.
---

Okay, you now have a disassembly. Open it up in your favourite text editor. Now, we're looking for a place that reads in the button state, and if you remember, whenever we do button jokers it is on the address $4000130 because that is where this information is stored. So, in your text editor search for "4000130".

If you don't get any results, re-dump the file, this time making the length larger, e.g. 40000 bytes.

First, we want to check that this instruction is executed often in the game (this step isn't necessary, but can save you some time). Open up the game in SDL, get into the debugger and put a breakpoint on thumb for the address that the instruction was at. For example, I'd type in bt 080003c0. Now, try to position the debugging console so you can still see the screen and type in c. Press enter and the game should hopefully break immediately. Repeat this, and the game should continue to break - this means that this piece of the code is executed a lot - if you do this on an intro screen you may be able to see the graphics advance frame by frame.

Another test to do, if you're following this method and searching for the input handler, is to NOP the instruction in VBA (46C0) - if the piece of code is in fact the code handler then the game will act weirdly and won't respond to controls.

Okay, you've found a working result. Now scroll down until you find an opcode with a 'b'. Copy the text between the '4000130' and this into another file. For example, with Rockman EXE 4, I had this (disassembly is from no$gba, Mappy has a slightly different format):

080003C0 4C14 ldr r4,=4000130h 
080003C2 8824 ldrh r4,[r4] 
080003C4 43E4 mvn r4,r4 
080003C6 8805 ldrh r5,[r0] 
080003C8 80C5 strh r5,[r0,6h] 
080003CA 8004 strh r4,[r0] 
080003CC 1C26 mov r6,r4 
080003CE 402E and r6,r5 
080003D0 2108 mov r1,8h 
080003D2 2300 mov r3,0h 
080003D4 2201 mov r2,1h 
080003D6 409A lsl r2,r3 
080003D8 4032 and r2,r6 
080003DA D00B beq 80003F4h

Why did we scroll down to a branch? Because a branch is like a jump, it jumps to a different part of the code, so we can't be sure anything below it will be executed whenever our instruction with 4000130 is. However, anything between that opcode and the branch must be executed whenever the load is executed.

So, now we can choose any opcode between the ldr and the branch to hook onto, so long as it does not contain an '='. In this example, this means any opcode from 080003c2 to 080003D8. Write down the address you want to hook, for this example I'll choose to hook on 080003C2.

Okay, now to create the code:

The RAW format is

Faaaaaaa 0000xxxx

where aaaaaaa is the ROM address to hook and xxxx are the flags. The flags are:

0001 - Executes code handler without backing up the $lr register. Must turn GSA off before loading game.
0002 - Executes code handler and backs up the $lr register. Must turn GSA off before loading game.
0003 - Replaces a 32-bit pointer used for long-branches. Must turn GSA off before loading game.
0101 - Executes code handler without backing up the $lr register.
0102 - Executes code handler and backs up the $lr register.
0103 - Replaces a 32-bit pointer used for long-branches.

Generally it's best to use one of the last 3. Try 101 first, and if that crashes the game try 102.

Now you can encrypt the code with ARCrypt.

For example, my RAW code for MMBN4 was
F80003C2 00000101

encrypted: A34973F0 C5290CCD

From the V3 Code type doc:

Type 62
2.0.3.x.x
XXXXXXXX : (Adress to patch -> Adress 000YYYY : Master Code settings

So, in ARCrypt set it to Type 62, make sure the values are correct and type in your RAW code in the left box. For example, my one was

080003C200000101

(The flags are the same as V.1/V.2)

Click Create. The encrypted code is 1F03E8F9 886A21C0.

The format is

1aaaaaaa xxxy

where aaaaaaa is the address to hook AND $0FFFFFF (i.e. ignore the leading '8'), and xxxy are the flags.

For, interest, the flag settings are:

'y' is the CBA Code Handler Store Address (0-7) [address = ((d << 0x16) + 0x08000100)]
1000 - 32-bit Long-Branch Type (Thumb)
2000 - 32-bit Long-Branch Type (ARM)
3000 - 8-bit(?) Long-Branch Type (Thumb)
4000 - 8-bit(?) Long-Branch Type (ARM)
0020 - Unknown (Odd Effect)

Generally, you should set xxxy to '0007' - in fact I haven't seen any other codes that use different flags, so there you go [XXX]
Just for example, my code for MMBN4 was

100003c2 0007

Now, that's that part done for now, let's hack the ID code. The problem is Gameshark/PAR and Codebreaker do things a bit differently when it comes to ID codes.

This is really easy. Open up the memory viewer, into 32-bit mode and goto 080000AC (if you've been reading the GBA tech doc you'll know that this is the game ID, which is unique for every game). Write it down.

For both versions of GSA/PAR we use this RAW code format

xxxxxxxx 001DC0DE

For example, in Megaman 4, it's

4A423442 001DC0DE

This can then be encrypted (set the 'To' and 'From' correctly in ARCrypt and click Proceed).

This one is a bit annoying. The code is dependent on a CRC for the ROM - this means that if the ROM has been modified, e.g. has had an intro added (if even one bit has been changed from the original then there will be problems) the CRC will not be the same.

There are two methods of finding this. The first is not so reliable as you need a ROM.

- With ROM and CRCGen

Download the program called CRCGen, put it in your ROM directory, get into a dos prompt in that directory and type

crcgen romname.gba

The program should spit out your ID code.

- With original game and Codebreaker
Courtesy of Sappharad

Quote:
"Start your GBA with the cart inserted you're looking for the 2nd line of the enable for, and at the screen with the list of games, hold down both triggers (L+R) and while you're doing this, press A and B at the same time. A hidden screen will come up, and on the bottom of it is the Game ID. Take the number it gives you, and convert it to hex. Insert it into the following code type: 0000IIII 000A."

e.g., my code was (I have a clean eurasia dump of MMBN4 Blue Moon) 0000A23E 000A

Now, for the completed master code, you combine the Hook and ID code into a code (nothing special, just write one under the other ).

And that's it - you know how to make master codes based on the input handler. Remember - you can find the hook in many different ways, for example (I've done this before, coz I was lazy), open SDL, play the game and just randomly press F11 and see what the debugger stops at. Do this a couple of times and then you can try bt'ing an address and see if it's executed often, if you're lucky you'll find an address to hook (though the danger with this method is that this code may not execute everywhere in the game - it's safer if you just stick to finding the input handler).

Note: this lesson is technically incomplete as it does not deal with the Link Register (LR) and its impact on master codes.

Lesson 10 - Breaking the limits

Two things gave me the idea for this lesson - a tutorial in The Hacking Text (I'm sure I've mentioned it before - it's the Hackers bible, get it from GSCentral.com), and hacking Baldur's Gate: Dark Alliance.

The code we will be doing today, allows you to hold more stuff in your pack than you're allowed to. We first need to find two addresses which will help us find the code: Current Pack Weight, and Max Pack Weight.

These codes are quite interesting, and I encourage you to hack them yourself because they use different methods to what you would usually see.

The Current Weight modifier is the word at $03000998. This value is actually your weight multiplied by 100 (not sure why 100, seeing as it only goes to 1 decimal place, 10 should be sufficient). For example, if your weight was 48.3, the value would be 48.3*100=4830, converted to hex is $000012de.

The max weight value is the halfword at $03000b58 (after hacking a couple of codes for this game it becomes apparent that most, if not all user data is stored in IRAM). It is stored as-is.

We now have enough information to get hacking. Open the game in VBA SDL. Go into the inventory dialog. Now we have a choice - which address to breakpoint? Well, as I see it we have two paths to go down:

1. Put a bpw on the current pack weight. Pick up a new item, let it break, and trace backwards to check for a comparison between that address and the max weight.

2. Put a bpr on the max pack weight, and trace forwards from there to look for the comparison.

I'm going to go with the first option - if you try bpr'ing the max pack weight you'll see it breaks many times when you go to pick up an item. It'll also give us some practice at tracing backwards through code, which is an important skill to have.

Okay, stick a bpw on 03000998 and go to pick up an item. It'll go to the screen where you select the item to pick up. Press , and the game will break.

You'll see it breaks at $08686530, which means that the opcode that triggers this

is at $0868652E.

Back in normal VBA, go to this address and scroll upwards until you find a branch.

You can see that it is an unconditional branch (just 'b'), which means that our routine probably starts at the next instruction - 08686508.

Just to give us an idea of what's going on, clear the bpr (bprc, in case I haven't mentioned this before), stick a BT on this address, reload your save and pick up the item.

Arghhh, it doesn't break. For some reason, there is a branch in the game that goes to one of the instructions between 08686508 and 08686530. We have to try and find this. One option is to bt every instruction between 08686506 and 08686530 - the first one that breaks will be the one then get's jumped to.

The above method does work, but I'm going to take a bit of a guess - notice that the opcodes from 0868508 to 0868650e are:

09b0 lsr r0, r6, #0x06 
0300 lsl r0, r0, #0x0c 
0b50 lsr r0, r2, #0x0d 
0300 lsl r0, r0, #0x0c

Now, if you convert those to 32-bit values, you get

030009b0
03000b50

which, are very likely pointers to memory addresses, and therefore not opcodes that the game would execute.

So, the start of the routine is 08686510. We need to find out where the branch to this is. We have a number of choices - we could disassemble the game and search for 08686510, but disassemblies of entire games tend to be very large. The easiest thing to do would be to enable the display of the last state of the registers (type last at the debugging console). This shows us what the last instruction that was executed was, along with what the registers were then.

So, bt on 08686510, pick up an item and it'll break - you'll see that the last instruction was at 086864f6. So, open up the disassembler and let's take a look. If we scroll up I can see quite a few cmps with conditional branches after them... hmmmm.

Now you can see why tracing backwards can get sometimes tricky - I'm now going to go back and try plan 2 (if it seems like I've just wasted your time, I haven't - now you know how to trace backwards).

So, reload the save, and put a bpr on 03000b58 for 2 bytes. Go and pick up an item. When the screen that shows the item begins to load, the game breaks.

Continue. It breaks again. Keep on doing this, and you'll notice it continues to break at the same two addresses: $0868a9e6 and $0868a99a. This is a routine that continually reads in the max weight, and probably not what we're looking for. So we're going to NOP the instructions that are causing the debugger to break.

In SDL, the command to modify halfwords of data (modify the data in 16-bit mode), is eh <address> <data> . The addresses we want to modify are the instructions BEFORE the ones that the debugger break at, because it was these that triggered the break. The value we want to change it to is NOP, which is the same as mov r8, r8, which is 46c0. So, at the prompt you will type

eh 0868a9e4 46c0

and press enter, followed by

eh 0868a998 46c0

This will delete the two opcodes that were triggering the break, allowing us to catch the instruction we're looking for.

In case you're wondering, NOPping out instructions is a bit dangerous and may cause the game to act weirdly or crash. Hopefully the game will manage to continue so that we can at least find the right address - then when the game is re-opened the ROM will be reset to it's proper values.

Ok, continue.

Select the item and the game will break at 086864cc. Continue, just to check that this is the only break, which it is, then close SDL and restart it, so that our NOPping won't affect anything (in this case it doesn't, but it's best to be safe).

Now we're going to trace through the the instructions, keeping an eye on what's happening and seeing how the value is manipulated.

In the debugging console, bt 086864ca, because that was the address that triggered the break. Pick up an item and it will break:

086864ca 892a ldrh r2, [r5, #0x8]

Here the address of the max weight (r5+0x8) is loaded into r2. Trace to the next instruction (n).

086864cc 2064 mov r0, #0x64

This moves 100 into r0 (a good sign - remember the current weight is multiplied by 100?)

086864ce 4350 mul r0,r2

As expected - this multiplies the max weight by 100 and stores the result in r0.

086864d0 4281 cmp r1, r0

This looks promising - the max weight is compared with r1 - which happens to be our current weight.

086864d2 d90f bls $086864f4

Depending on the previous cmp, it's a branch if less or same as to $086864f4.

We now have enough info to crack this baby! Here's what's going on: The last instruction will jump to 086864f4 IF the current weight is less or equal to the max weight. So, we want to change this so that it will always jump - so we need to make a new opcode: b $086864f4 .

Bit Expl. 
15-11 Must be 11100b for this type of instructions 
N/A Opcode (fixed) 
B label ;branch (jump) 
10-0 Signed Offset, step 2 ($+4-2048..$+4+2046)

Return: No flags affected, PC adjusted. 
Execution Time: 2S+1N

Okay, we know bits 15-11 are 11100, now we need to work out the offset. This is how we do it: Take the address you want to branch from, take away the address you want to branch to, add 4, then divide by 2 (that's basically what it says up there).

So, we are at 086864d2, we want to jump to 086864f4.

086864f4-086864d2=22
22-4=1e
1e/2=F

F in binary is

00000001111

So, with the calculator in binary mode, type in 1110000000001111

Converted to hex, we have E00F.

Let's make the change - open up the mem editor in 16-bit mode, go to 086864d2, and change it to e00f.

Now to test that this works, in the memory editor, set your current weight to 64 (which is 1) and set your max weight to 1 (which is 1 ). Pick up an item, and it should get added to your inventory, and your weight will increase past the max!
---
Yay! It works!

Now to make a code. For Gameshark, the RAW code would be
64343269 0000E00F

encrypt it and you get
F9CDC907 47B47FCE

For AR V3, type in
086864d20000e00f on the left, select Type z0C and Create.

You get:
15B7EEC8 E3D02E2B
D58503CA 5871360F

Test 'em in VBA! They work!

Dealing with DMA - Part I

Well, the latest Pokemon Games - Fire Red and Leaf Green - are the biggest things out at the moment, so I've jumped onto the bandwagon and will be writing a series of tutorials based around Fire Red (only because it was dumped first, so most code hacking for the two games was based on Fire Red - the two games are identical RAM wise, and most of the ASM routines we will be going into are in the same place in both).

The Pokemon games make a good study for hackers, as Nintendo have attempted (vainly, I may add) to keep us hackers out so that the integrity of the tournaments they sponsor can be maintained. In the two new remakes, they have implemented the use of DMA, so the ASM tutorials I was going to be writing on that will be incorporated into this series.

These tutorials assume that you are a competent hacker, and are able to hack static data (that which does not move - more later) easily. It also requires that you have a rudimentary knowledge of ARM7TDMI Assembly and have done a little ASM hacking (reading my ASM lessons should suffice).

This series of lessons will include lessons on both 'normal' hacking - such as items, teleport codes and so on - as well as ASM hacking, some of which is required to hack some of the 'normal' codes (you'll see what I mean next lesson ). We'll also hopefully be looking into the pokemon datablock, which is probably one of the most complex 100 bytes (that we understand) you'll ever see on the GBA.

Pokemon Fire Red - Dealing with DMA Part I

In this lesson, I'll be introducing you to the scourge of hackers everywhere: Direct Memory Access (DMA). Why? I'll explain.

Normal RAM hacking, relies heavily on the fact - whether you realise it or not - that the data you are searching for is static (stays in the same place), at least for the duration of the search (this doesn't include games where addresses are different for each level - though this is a less drastic variation of this).

Now, to combat hackers, some games store data in dynamic locations - i.e. it is moving constantly, e.g. whenever you open a menu. Such games are the latest in the Megaman Series, and the newly released Pokemon Fire Red and Leaf Green.

The method is called DMA, as this is the name of the BIOS function which allows the transfer of large amounts of data with a few instructions (it is usually used for inter-device communications, or for sound data).

This presents a huge problems to us - it can be cirumvented, by finding points in the game where data is always stored in the same place, for example in Pokemon FR there is a small weakness to their scheme - I can't go into details at the moment, however once the US version is out I will be able to release this information.

The weakness to this scheme is thus: Somewhere in the RAM, there must be a value that tells the game where the data in question is currently stored (a pointer) . We can modify this value so that the data stays in the same place, or (the usually more reliable method) modify the ASM that affects this value to keep it in one place.

To find this pointer, we usually have to know the general area of RAM where the data is stored: there are a number of ways we can do this, some of which involve ASM. If you are able to find the data through a search (usually this is only possible if you can find it without exiting a menu/room), then you can open up the memory viewer, and 'watch' the data move about in the game. If the data moves 'deeper' into RAM (i.e. the address get's larger) then do an greater than search, if it moves up then do a less than (I used this method successfully to find the master folder record for MMBN4).

If this doesn't work, and you have a savesate where you KNOW the address of the data, you can put a bpr on it in VBA SDL and trace to find the routine that moves the data.

Alternatively, you can use another starting point for an ASM trace - for example, in MMBN4, there is address that holds the chip that you win from a battle. (This address is static, and if you didn't want to modify the folder then you could just use this to create codes to get chips you want). You could bpr this, and trace to see how this value is used, and where it is written to.

Dealing with DMA - Part II

If you've been using Fire Red codes, you'll know that we've come up with a DMA disabler code, which keeps the data in 1 place. In this lesson, I'll be walking you through how this code *could have been hacked* (the actual code that we use is a mod for the Random Number Generator, which means you have to reset your game or else the game is non-random, the code we're doing today is the actual pointer to the datablock).

Warning: This lesson is very complicated. I would say only 10% of the hackers at CMGSCCC, if that, would understand this lesson so don't be discouraged if you don't get it - after a lot of experience this you'll find this kind of stuff easy (hopefully )

The first thing to do is to locate a datablock we can hack. Open up your box, make sure you've got a couple of pokemon in the first box. We'll be trying to find the first slot - simply do equal/not-equal searches, moving the pokemon around (don't leave the box, or else the data will move) until you've narrowed it down to a couple of hundred addresses. Look at the results - we need to guess which one it is. As the entire datablock for the first slot is being changed, we'll be looking for a group of consecutive addresses - they should be around the 02029200 range.

So, open up the memory editor and go to the first address (for me the address is 020292A8, I'll be using this address from now on - you use yours). Make a savestate here.

Now, open up the game in VBA SDL. Put a bpr on $020292A8. c, then leave the box menu. The debugger will break at $081c9db8.

Breakpoint (on read) address 020292a8 word:9ba5b04c 
R00=9ba5b04c R04=02004c64 R08=000083d0 R12=00000040 
R01=02004c68 R05=02004c64 R09=00000f24 R13=03007dc4 
R02=000083d0 R06=03005050 R10=03005048 R14=0804b8af 
R03=020292ac R07=00003d40 R11=00000000 R15=081c9dba 
CPSR=0000003f (......T Mode: 1f) 
081c9db8 c101 stmia r1!, {r0} 
debugger>

Back in normal VBA open the disassembler and go to the address that it breaked at. Scroll up a couple of lines, and you'll see that there is a bunch of instructions like this:

ldmia r3!, {r0} 
stmia r1!, {r0} 
ldmia r3!, {r0} 
stmia r1!, {r0} 
ldmia r3!, {r0} 
stmia r1!, {r0} 
ldmia r3!, {r0} 
stmia r1!, {r0}

These are multiple load/store functions. These load/store multiple registers into memory. The base register is incremented each time this occurs (see the GBA tech doc for more info).

Basically, we're interested in the fact that data is being loaded from the address in r3 into r0, then stored to the address at r1. We want to know where the address in r3 came from

So, in normal VBA scroll up in the disassembler until you come across an unconditional branch (b or bl) or a pop pc (this means that the r15/pc has been stored in the stack and is now being popped off it, giving the effect of a branch). We need to check if between here, and 081c9db8, r3 is affected in anyway. I see a pop {r4,pc} at 081C9D98. Below that at 081C9D9E is add r3, r1, #0x0, which is the same as mov r1, r3. Looking down further I see that r3 hasn't been manipulated further in anyway, so now wee need to find out how r1 was calculated.

We need to trace backwards from 081C9D98, so reload your save, stick a bt on it, deleting your other breaks, then exit the menu.

The game will break again:

Breakpoint 0 reached 
R00=02000000 R04=03003130 R08=00000000 R12=00000040 
R01=02024540 R05=02000000 R09=00000f24 R13=03007dd0 
R02=00000f24 R06=00000000 R10=00000000 R14=081c988c 
R03=00000000 R07=00000000 R11=00000000 R15=0804b88e 
0804b88a fa86 blh $050c

R00=02000000 R04=03003130 R08=00000000 R12=00000040 
R01=02024540 R05=02000000 R09=00000f24 R13=03007dd0 
R02=00000f24 R06=00000000 R10=00000000 R14=0804b88d 
R03=00000000 R07=00000000 R11=00000000 R15=081c9d9a 
CPSR=0000003f (......T Mode: 1f) 
081c9d98 b530 push {r4,r5,lr} 
debugger>

Okay, we're getting close. Once again, go to 0804b88a in the disassembly then scroll up. At 0804B87E I see

ldr r1, [r0, #0x0]

So, r1 is the value contained at the address contained in r0 (get that?)

The previous line is:

ldr r0, [$0804b924] (=$0300504c)

Bingo! So, the pointer to the start of the box data is stored at $0300504c. Just to make sure, load up your save in normal VBA, open the mem editor in 32-bit mode, go to 0300504c and exit the box. The value will change.

Now, we need to figure out how 0300504c get's written. Back in VBA SDL, reload your save, then stick a bpw for 4 bytes on 0300504c.

Exit the box and the debugger breaks at

Breakpoint (on write) address 0300504c old:02024540 new:020244f0 
R00=020244f0 R04=03005048 R08=000083d0 R12=00000040 
R01=00000008 R05=020254e4 R09=00000f24 R13=03007dc4 
R02=0300504c R06=03005050 R10=03005048 R14=0804b81b 
R03=02031674 R07=00003d40 R11=00000000 R15=0804b828 
CPSR=0000003f (......T Mode: 1f) 
0804b826 480a ldr r0, [$0804b850] (=$0202548c) 
debugger>

What we are going to do now, is modify the ASM so that we can control the value that is stored here. Here's the routine, I'll explain what's going on.

0804b81a 217c mov r1, #0x7c 
0804b81c 4001 and r1, r0 
0804b81e 4a0a ldr r2, [$0804b848] (=$0300504c) 
0804b820 480a ldr r0, [$0804b84c] (=$020244e8) 
0804b822 1808 add r0, r1, r0 
0804b824 6010 str r0, [r2, #0x0] 
0804b826 480a ldr r0, [$0804b850] (=$0202548c)

At 0804b81e, the pointer address is loaded into r2. The value 020244e8 is then loaded into r0.
The next address is the important one: The value in r1 is added to 020244e8 (which is probably the 'base' address of the box datablock). Therefore it's safe to assume that r1 is the offset, the value that makes the datablock move. We now have a couple of options, the easiest being replace 0804b81c with mov r1, #0x0, so that the offset is 0, therefore keeping the data in the same place.

Remember the shortcut for mov immediate opcodes? It's 2rii. So, our code would be 2100.

Back in the mem editor check that when we leave the menu, the data stays in the same place all the time. You will find that it always goes to 020292CC and stays there. So, we've defeated the DMA protection for the box!

Now, that's all and well for VBA or Gameshark/AR users, but what about CBA? Well, in this case, we can create a code to change the value at 0300504c to whatever we want, in this case, a pointer to the place where we want to keep the box data. However, there is a problem. As you will know, a master code is usually hooked onto the input handler. However, what if between the time the piece of ASM above is executed, and the time 0300504c is read in for use, the input handler doesn't run? In that case, at the time 0300504c is read in, it most likely won't have the value we want it to be. Therefore we need to create a special master code, for use with this code so that we know for sure that the correct value will be in 0300504c.

In this case we would hook the address directly after the store - 0804b826. Now, the 'normal' address will be stored, then the CBA will execute, and 0300504c will be direcly over written.

So, we'll make 0300504c the same value as it is with the patch codes, so the data stays at 020292cc. Our codes will be

8300504c 92cc
8300504e 0202

If you don't know why this is, you need to read some of the earlier lessons

Now for the Master code. The hook line will be
1004b826 0007

so that it hooks right after the pointer is stored. You'll also need to find out the ID line, following the methods in the master code lesson.
---

So, that's it! We've managed to get the box data to stay in one place. Next lesson we'll be playing about with Ram dumps to do some cool stuff, and maybe hack the teleport code as well.

Pokémon Fire Red - Down in the dumps

In this lesson, we'll be messing around with RAM Dumps in VBA, and you'll get to use a program I've created that works with dmp files.

We will be using the other DMA disabler codes - the ones which were released that actually affect the Random Number Generator - if we had traced further up in our previous lesson it would have led to this.

The modification is

08044496 1840 add r0, r0, r1

to

08044496 2000 mov r0, #0x0

If you're interested, take a look at the routine, it'll give you a good idea of how random numbers are produced. The data will stay at $02029250.

When a Pokemon is in the box, the size of the datablock is 0x50 bytes, i.e. 80 bytes. You can verify this by having one pokemon in the first slot (of the 1st box) and one in the third - you'll see a gap between 020292a0 and 020292f0 which is the empty slot.

So, let's try transferring some data around. The 'Load DMP' but in V1.7 has been fixed in 1.7.1, so feel free to use that.

Make sure slot 2 is empty, then open the memory viewer in 16-bit mode and go to the start of the 3rd slot - 020292f0. Click on the address ->Save..., make sure the address is $020292F0, and set the size to 50 (80 bytes in hex). Click OK and stick the file somewhere.

Now click on the 0000 at 020292a0 - the start of the 2nd slot. Load... -> Open the file and make sure the Address is correct.

Exit the box then go back in... you'll have a duplicate of your 3rd pokemon in the second slot!

For the next part of the lesson you'll have to download a program I made called DMP2Code - you can get it at http://metawire.org/~labmaster/files/
This program takes VBA Ram Dumps, and turns them into codes. I'll show you how it works.

Boot up the program and click the browse button, then select the dump file you just made.
---

Next you can select the code type - it supports VBA, CBA and GSA/PAR V.1/2 and 3. Gameshark SP (Mad Catz) is not supported.

Then you can choose the 'Data Format', this means how much data one code represents. As CBA doesn't have a 32-bit code type, this option is disabled if you select CBA. Usually you'd want to go 32-bit so as little codes as possible are created.

Now, this is the important step, the base address. This is the address (in hex) that the first unit of data in the dump file will be written to. It must be correctly aligned to the data format, i.e. a multiple of 2 for 16-bit, and 4 for 32-bit.

Click Process and the codes will be created! If you chose GSA or PAR the codes will be automatically encrypted as well

This was my output (I chose V3 32-bit, and set the base address as the start of the 1st slot)

DMP file conversion for D:\GBA\Dumps\rattata.DMP - PAR V3 32-bit

BDC18DA8 1CA99675 
75DFF4D5 C0B7AFEA 
7FF684D7 FF9BCECA 
FD6E9514 A73847F7 
D177937D 60138812 
5529F6C2 10A2F3C8 
55A785DD E82D5AEB 
C002F3C8 CB3C3F86 
904AFF1B 9868CA66 
777269B4 24D0F1E1 
B78AC105 42917B1C 
740CDD0A EE48EFFA 
CFC070F5 C3731AFE 
9217F6FD 2D371F7B 
A4C6759D 64ED309E 
AFAAD271 8721E992 
D29C3264 8851F3FE 
E8194EFC CB9A8E81 
DC81800C D6FA1D57 
CBDFAF87 50B86501

Put those codes in as-is into VBA and you'll get... a crappy level 3 Rattata in the 1st slot of box 1

It is important to remember to remove these codes as soon as they are put in, remembering NOT to check 'Restore previous values'. This way the slot will be able to be used as normal again, and you'll be able to put other pokemon in there (if the codes are still active the data for Rattata will overwrite anything you try to move in there.

Pokémon Fire Red - Warp off

This is quite a simple code, though takes some intuition to hack. What it does is modify a value in RAM that tells us what map we are currently on. How do we do this? Easy - lot's of Not-Equal searches in 16-bit mode hexadecimal (Why 16-bit mode? Well, there'll be more than 255 maps, but less than 65535)

I'm not going to talk you through the process, as it would be very boring - basically, if you change map, do a not-equal, a couple of equals, change map again etc... Note: When you're outside, if you change area, you're changing map, for e.g. walking out of Pallet Town. So you can do a couple of not-equals with that as well. Once you've narrowed down the results to less than 1000 (i.e. the addresses are being displayed), you won't cull it much further so we have to use a bit of 'zen' to guess which address is the correct one.

If you're up with your Pokemon ROM hacking then this may be a bit easier. Firstly, maps can be divided into groups called 'banks' - when you're in 16-bit mode the least significant byte signifies the bank. So, as I'm currently in Pallet Town it's reasonable to assume that it will be a pretty low bank number.

Secondly, when we do these searches, we're changing maps. So it follows that the area where the current Map Data is stored is also changing. If you look at our results, you'll see a large area starting around $02031d00. To test the theory that this is the Map data, stick in a Codebreaker code -

42031d30 0000
00000fff 0002

I think I've neglected to mention this code type so far, and it's quite important - it's known as a Slider. I'll explain it in a later lesson, as there's lots of cool things you can do with Sliders, but this one will fill the area of RAM from 02031d30 to 02033D30 with 0000, therefore removing most of the map data.

Go back in the game, and you'll notice the map has been filled with something that vaguely resembles the ocean. You can walk around on it and all of the NPC's are still there (note - as you can see the collision detection seems to have gone, meaning that it is dependent on the map data loaded in RAM - we may use this info later for a WTWs code).

So, reload a save to turn everything back to normal. Now, combining the two pieces of information above we'll find the address. It's a pretty safe assumption that the map ID will be stored somewhere close to the Map data, most likely before it. Looking at our results, I see that the first addresses that start with 0203xxxx are 02031ce8 and 02031cf0. It's probably one of these two, I'm going to take a punt on 02031cf0 just because it seems like a nice number I'm in Pallet Town and it's current value is 0003. So, Add Cheat, and I'll keep the value at 0003. I walk through a door.... and I teleport back into Pallet Town (out of my front door in fact).

So, that's it, we've found it! To complete the code you'll have to compile a list of IDs - I'm usually too lazy to do these kind of things so I just post the code and get others to do it for me

Pokémon Fire Red - Walk though walls!

This lesson we will be using the knowledge we gained last lesson, to hack a ROM Patch Walk Through Walls code. You'll need to know some basically map editing terminology - viz 'Tile', 'Row', 'Column' and 'Left' and 'Right'

I'll be basing my search on an indoors map as the borders are more easily defined - in this case the School in Viridian City (I'm assuming that's what it is, despite the fact there's only one student in there).

My general strategy for this is: Figure out what address of the map data corresponds to which tile. Make a certain tile passable (if it isn't already), put a BPR on it, then run a trace. Make the tile unpassable, then trace again. Look for a difference.

This is what I call 'comparitive tracing' for lack of a better term, and can come in quite handy in situations such as these.

Okay, first, we're going to figure out that map data. Open the mem-editor in 16-bit mode, and go to 02031d00. As you'll see, the actual data starts at 02031d30, and 03FF seems to be the value for empty tiles. Scroll down until you see something more interesting.

The school room is 10 tiles wide, and starting at 02031e9c I find 10 non-03FF values. This is a good sign. Then there's a block of 03FF's (which makes up the blank spaces to the right and left), and then there's some more interesting stuff, which makes up the next row down.

The tile I'm going to choose to do the trace on, is the bottom left tile of the wall (which is two tiles high). To find it's address I go to the second block of non-03FF values, and it'll be the first one ($02031ECE). To test this, I replace the hword with '068e', which is unpassable. I then refresh the map by taking a look at my team, and when I get back I see an odd tile there, which I can walk on. Make a save with your player on the tile below, facing the tile you just modded.

Now we've got all the information we need, let's start tracing! You'll need to copy the text in VBA SDL's debugging console in a text file, and as I'm using XP, I need to run it from the command prompt to be able to do this (if you use different operating systems this step may differ). I've actually written a little batch file to do this for me, so all I have to do is open-with the ROM using the batch file.

Right-click on the window title-bar, -> Properties->Layout and set the Screen buffer size to the max value. Now load up your save, and put a bpr on 02031ECE for 2 bytes.

Dang - it breaks immediately, and continues to. So, we're going to use a nifty little function in Kenobi's version of SDL, db - 'Don't Break' (we no longer have to use NOP's anymore. w00t!). The address the debugger has stopped at is 08058736, so it was the previous opcode that triggered the break. At the prompt, type in

db 08058734

Now, return to the game, and press . The game should break.

Breakpoint (on read) address 02031ece halfword:068e 
R00=02031ece R04=00000008 R08=00000002 R12=020205b8 
R01=0000068e R05=00000007 R09=00000007 R13=03007d50 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000008 R11=00000000 R15=080586ac 
CPSR=0000003f (......T Mode: 1f) 
080586aa e01b b $080586e4 
debugger>

Here's the boring part, you're going to have to n through a couple of instructions, 30 should do for this one.

Note: VisualBoyAdvance for Hackers now includes the command 'lf' which allows this to be done automatically.

Now copy all of the text from where you are to the address above, and stick it in a text file.

Okay, we've done the trace with an upassable tile, now for a passable one. Back in normal VBA I replace 068E with 3295, which is a floor tile and make a save state.

In SDL, disable the bpr with bprc, reload the state then stick it back on. Walk up again and the game will break. n through another 30 instructions then stick the text into another file.
---

Open up both text files, next to each other. You'll need to go through line by line, and look for a point where the game deviates, i.e. the instruction that is executed is different. If you've done everything right, you'll get to this

1st file (unpassable)

R00=01000000 R04=00000008 R08=00000002 R12=020205fc 
R01=08062fab R05=00000007 R09=00000007 R13=03007d64 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000002 R11=00000000 R15=08062fae 
CPSR=0000003f (......T Mode: 1f) 
08062fac 2800 cmp r0, #0x0 
debugger> n 
R00=01000000 R04=00000008 R08=00000002 R12=020205fc 
R01=08062fab R05=00000007 R09=00000007 R13=03007d64 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000002 R11=00000000 R15=08062fb0 
CPSR=0000003f (..C...T Mode: 1f) 
08062fae d119 bne $08062fe4 
debugger> n 
R00=01000000 R04=00000008 R08=00000002 R12=020205fc 
R01=08062fab R05=00000007 R09=00000007 R13=03007d64 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000002 R11=00000000 R15=08062fe6 
CPSR=0000003f (..C...T Mode: 1f) 
08062fe4 2002 mov r0, #0x2 
debugger> n

2nd file (passable)

R00=00000000 R04=00000008 R08=00000002 R12=020205b8 
R01=08062fab R05=00000007 R09=00000007 R13=03007d64 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000002 R11=00000000 R15=08062fae 
CPSR=0000003f (.Z....T Mode: 1f) 
08062fac 2800 cmp r0, #0x0 
debugger> n 
R00=00000000 R04=00000008 R08=00000002 R12=020205b8 
R01=08062fab R05=00000007 R09=00000007 R13=03007d64 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000002 R11=00000000 R15=08062fb0 
CPSR=0000003f (.ZC...T Mode: 1f) 
08062fae d119 bne $08062fe4 
debugger> n 
R00=00000000 R04=00000008 R08=00000002 R12=020205b8 
R01=08062fab R05=00000007 R09=00000007 R13=03007d64 
R02=00000007 R06=02036d6c R10=00000008 R14=08062fab 
R03=00000019 R07=00000002 R11=00000000 R15=08062fb2 
CPSR=0000003f (.ZC...T Mode: 1f) 
08062fb0 1c28 add r0, r5, #0x0 
debugger> n

As you can see, if r0=0, then we're all sweet, you can walk. If it's not, then you can't. So, we'll change the previous instruction (08062faa) to mov r0, #0x0, which is 2000. Edit it in the mem-editor and... it works!

Awesome! There are however, some restrictions: You can't walk in the black area (03ff) - if you scan through the trace you'll see that there is a cmp to this value earlier, if you changed this then you'd be able to, but you may encounter problems when you reach the edge of the map, so it's best we leave it at that. Also, you can't walk through certain objects or people - there's a separate routine for that.

Actually... there's an idea - an NPC modifier, we may do that in a later lesson.

Pokémon Fire Red - Item properties

One of the posts in another thread gave me the idea for this lesson. I haven't actually tried doing this before, so it's a learning curve for me as well.

Warning: This lesson is very technical, complex, etc... If you understand it, you are a true computer geek.

Note: For this lesson you will need no$gba, there's a hacked version out there which is technically classed as warez, so I won't be posting a link.

We'll be working with good ol' Potion, as that should be pretty straightforward.

First we need to find the address for the first Pokemon in your team's HP - using the RNG DMA Disabler code (FF7D4B57 25D1D6AD 8E883EFF 92E9660D as a AR V3) it is at $0202423a

If you haven't guessed already, we'll be doing a trace on your Pokemon's HP in battle, bpw-ing it when you use a potion on it. Get into battle, and make sure your Pokemon's HP is MORE than 20 LESS than it's max (make sense? I didn't think so ). This is because there's bound to be a routine that checks if using a Potion would take your HP higher than it's max, and I want to make sure your trace is the same as mine (If for some reason it's 'impossible' for your Pokemon to lose that much health - mod it manually.

Okay, go to your pack screen and make a savestate then load it up in SDL. Stick a bpw on $0202423a, then return to the game and use the potion. The game freezes at $081c9dba, but this obviously isn't the right one because we haven't chosen the pokemon to use the potion on yet!

Select your first pokemon and the game will break again

Breakpoint (on write) address 0202423a old:0002 new:0016 
R00=00000016 R04=00000039 R08=020241e4 R12=00000008 
R01=0202423a R05=00000000 R09=00000000 R13=03007d44 
R02=03007d4c R06=0820f0f7 R10=00000001 R14=080413ed 
R03=020241e4 R07=00000002 R11=00000000 R15=0803fb4a 
CPSR=0000003f (......T Mode: 1f) 
0803fb48 e038 b $0803fbbc

This looks better. Go to the Disassmbler in normal VBA, goto $0803fb48 and scroll up

0803fb46 8008 strh r0, [r1, #0x0]

Okay, so your new HP is in r0 - we need to find out how this is calculated. You'll see that r0 is calculated by adding r0 and r1, both of which are derived from the memory near $03007d4c (the value in r2 at the moment).

A quick peek in the memory editor shows that these values are constantly changing, so we can't really break on these. What we're going to use is a conditional breakpoint, which SDL doesn't have but no$gba does.

I won't be going over how to use No$GBA, as it is pretty self explanatory (if you can follow this tutorial, you can surely work it out yourself), especially if you've used No$GBC. Make sure you make the modification to the ROM address 08044496 to 2000, which is what the DMA disabler does (remember that the memory viewer is in 8-bit mode - you have to reverse the bytes).

Also, savestates aren't compatible with VBA, so you'll have to make a separate one (this is why I don't use No$GBA often).

Now, get into battle and goto the items screen. Make a savestate. Now to set the breakpoint. In the debugging window press + . We want to set the breakpoint on 03007d4c to break when the values is equal to your HP after you've used the potion - I'm on 4 HP, 2+20=22=$16, so I would type in

[03007d4c] = 16

Back in the game, use the potion. The game breaks a couple of times before you select the pokemon (to continue, Run -> Run), then breaks at $080413C4. Okay, we're done with No$GBA - back to VBA, reload your save in SDL, stick a BT on $080413C4, and use the potion. The game breaks at

Breakpoint 0 reached 
R00=00000016 R04=00000019 R08=020241e4 R12=00000008 
R01=00000014 R05=00000000 R09=00000000 R13=03007d4c 
R02=00000000 R06=0820f0f7 R10=00000001 R14=080413c1 
R03=00000039 R07=00000002 R11=00000000 R15=080413c6 
CPSR=0000003f (......T Mode: 1f) 
080413c4 9000 str r0, [sp, #0x0]

Your new HP is currently in r0, and it gets stored at an address pointed to by the Stack Pointer (r13).

So, how was r0 calculated? In normal VBA, open up the Disassembly view, goto the address and scroll up and you'll see

080413c0 9900 ldr r1, [sp, #0x0] 
080413c2 1840 add r0, r0, r1

So it seems the 'potion value' is loaded from the SP, and added to your old HP in r0.

We're going to have to go back to No$GBA to find out when the 'potion value' (which is $14, i.e. 20, btw) was written.

Reload your No$GBA savestate, clear your Breakpoints and add a new one: [03007d4c] = 14

Only do this when you get to the item screen or else it will break repeatedly before then.

Use the potion and the game breaks at $08041348 (ignore the breaks before you select the pokemon to use the potion on).

Back to normal VBA, in Disassembly go to the addrss and scroll up. The opcode that triggered the break is at 08041346 (str r1, [sp, #0x0]) The previous instruction loads the value - 08041344 7809 ldrb r1, [r1, #0x0]. So we need to find out what r1 was. In SDL, reload your save and stick a bt on 08041342.

Use the potion and the game will break. n one instruction so we can see what the r1 is

R00=00000007 R04=0820f0f4 R08=020241e4 R12=00000008 
R01=0820f0fa R05=00000001 R09=00000000 R13=03007d4c 
R02=00000000 R06=0820f0f7 R10=00000001 R14=0804132b 
R03=00000039 R07=00000002 R11=00000000 R15=08041346 
CPSR=0000003f (......T Mode: 1f) 
08041344 7809 ldrb r1, [r1, #0x0]

So, the value that determines how much HP a potion restores is at $0820f0fa! Verify this with the memory editor, and you'll see that the value there is $14, i.e. 20!

Now, the real test. Change it to a different value, any will do (I set it to 4).

Use a potion now. w00t!!! It works - my Squirtle recovered a measly 4 HP.

Analysis on what we've found
I'm guessing that what we've eventually got is the 'HP Recover Item' routine - this is probably used for all items that let you recover HP. So, you can leave the BT on and try using other items, and see what the r1 value is. For example, H. Potion (usu. 200HP) is stored at $0820f12d. Therefore it's pretty safe to assume that most of the item data would be stored around this area.

As you can see from todays lesson, Code hacking can be applied to ROM hacking, the information we have found today can be used (or as a starting point) for creating custom items!