TTYD - Coin Address Hunting #2
Welcome to part 2! Last time, we looked for an address containing the number of coins that Mario had using cheat search. We found an address, but we could not increase our useful number of coins. We did find some interesting behavior, though - if you change the address while you are selling an item, you will see the value count down or up to the real value. This may come in handy later.

So what's the next step when memory search fails? Let us think about this a little. We know that this address seems to contain the number of coins that is displayed, but when we try to change it, either nothing happens, or this coin counting animation plays. Over time, the address will reset to the real number of coins. This means that something is overwriting this address with the real number of coins, and to do that, it has to load the real number of coins into memory. It is time to start looking into the instructions and the registers!

Let's see who is touching this address. Right click the address and toggle breakpoint. This will pause the emulator whenever an instruction reads or writes to this address. If you hit play and then go to the instructions tab...

You will see you are paused at some instruction. 'Play' will keep running the game until something else 'breaks' it. So if you hit play again, you will come to another instruction that is reading or writing our desired address. You'll notice that there are a ton of instructions, and we would really prefer not to look through all of this assembly! Luckily for us in this case, there is a solution.

Remember that we don't care about the ones that READ the address to display it. We want to know, who writes to it? Go back to your memory address with the break point, and click 'write only' instead on the bottom right where it says memory breakpoint options. Set 38 to some absurd number like ff again so we can trigger the coin counting animation while selling. Then click play.

We come here to this instruction, 80209db4. Write this down in your notepad, as we may we want to investigate it. It has this instruction: stw r0, 0x0004 (r31)

Let's take a look at the registers. Look at r0. it shows here 'ec' which is 236 in decimal. And r4 has ff, which is the number we set our coin display address to. Click play. Watch as the coin counter, which was at 255, drops to 236. This is promising!



And it keeps dropping to da... and if you press play again, it will update the counter, and r0 will have dropped to ca. This is enough - clearly this function is somehow comparing the display value of the coins to the actual coin and decrementing it by some value.

If you would like to know, it drops from ff to ec to da to ca to bc to to af to a4 to 9a to 91 to 89 to 81 to 7a to 74 to 6e to 69 to 65 to 61 to 5d to 5a to 57 to 54 to 52 to 50 to 4e to 4c to 4a to 48 and then decreases by 1 from there. So interesting behavior - the game starts by subtracting big numbers from the difference amount and as it reaches goal posts, it shrinks that number so that you have a pleasant but appropriately short coin change animation.
So what is this instruction we were taken to?
stw r0, 0x0004 (r31)
store what is in register r0 into the address at r31 + 0x0004. Well, if you take a look at the registers, you will see r31 is 80d1eba0. + 4 gives us our original address for storing the display coin value. So we know for sure that this subroutine is overwriting our attempts to game the system and get money. But how does it know where to look for the correct amount of money?
Press 'play' to return to the beginning of the subroutine that handles changing the display value. Go to 'registers'. Now click 'step' to move to the next instruction. Changed register values will be in red. We know at some point this thing has to compare the display value to the real value, so that means it needs to load the real value into a register at some point. Keep your eyes peeled for '38' when it appears. Just keep clicking...

Whoa! Did you see that? '38' got loaded into r3! (It took me something like 50 clicks to get here, by the way :) ). Don't go any further. Let us see who loaded 38 into that register.

OK, this is the instruction AFTER we got updated. it says 'blr', used to end a subroutine. We don't know if we jumped directly to this address or if the whole subroutine got called.

Click next to the address to place a little dot - that's a breakpoint.

I look back at the registers and see what values populate the registers BEFORE 38 loads, then go back to code to see what instruction I am in.
800d3e64: lwz r3, 0x1BE0 (r13)
800d3e68: lha r3, 0x0078 (r3)
800d3e6c: blr

The third instruction, blr, is just to end the subroutine. This leaves us with two instructions left. Let's look at the first one.
800d3e64: lwz r3, 0x1BE0 (r13)
Lwz (into this register), (from here)
So this instruction will load something into r3 from r13+1BE0.
8041cf20 + 1BE0 = 8041EB00. Nothing interesting at that address.

Let's look at r3, which should have the address. Apparently it equals 80b07b60? Huh.
Let's look at the next instruction.
800d3e68: lha r3, 0x0078 (r3)
The subroutine after this ends this instruction, so this has to be it. So what does this do?
Load Halfword Algebraic — load a signed 16-bit value from memory at r3 + 0x0078, sign-extend it to 32 bits, and store it back into r3.
Effective Address:
EA = r3 + 0x0078
= 0x80B07B60 + 0x78
= 0x80B07BD8
Memory Access: At memory address 0x80B07BD8, the CPU will read 2 bytes (a halfword), interpreted as a signed value.
Sign Extension: The 16-bit value at that memory location is sign-extended to 32 bits (i.e., the upper bits are filled with the sign bit — 0 for positive, 1 for negative).
Result: That sign-extended 32-bit value is written back into r3.
Effective address: 0x80B07B60 + 0x78 = 0x80B07BD8
Memory read: Load 2 bytes from 0x80B07BD8: 0x0038
Sign-extend: Since 0x0038 is positive, sign-extension just pads with zeros: 0x00000038
Result: r3 is updated to 0x00000038 (which is 56 in decimal)

So let's look at r3 + 78, which is 80B07BD8. And... there it is. This is the value that will be loaded into r3 to compare against :) Save that address in your text file! Now go back and remove the breakpoints so the game won't constantly pause when we try to play.

Let's get evil... will our plan work this time? We'll give ourself 100 (0x64) coins.

Yes! It even displays a counting animation up there, too! We did it!
Now, this may seem pretty simple and straightforward, but the first time I did this, it took me several days. I had to make my own list of PowerPC instructions that were used frequently and reference it constantly. I wasted a lot of time trying to look at what the reading subroutines were doing when I could have just used the 'write only' check. This is the prettified version after the blood, sweat, and tears of originally finding this. Even then, it is a little tedious. This sort of work usually is.
Here is a question - why isn't the real coin value appearing in our memory search when we search the game? Good question! And one, perhaps, best answered in a future article...