Sorry but I can't explain how to defeat the encryption without explaining how to make the code.
Here you are :
I found that the zenny are stored at 0x215C39C - might be different for your game (can be found with the TT, or Renegade64 I guess).
Changing the value at 0x215C39C will nullify the zenny.
So you use no$gba, and you set a break on read at 0x0215C39C (or whatever address you found) (ie. you enter "[0215C39C]?", without the quotes in the break/watch window).
Then you press start to enter the menus. The game will break after 0x0202B836.
If you look at what's happening there, you'll see, amongst other things :
...
ldr r0,[r0,5Ch]
ldr r1,=215FCFCh
ldr r1,[r1]
eor r0,r1
...
The eor, ie. xor, is used a lot for encryption/decryption. Obviously, it'll be used to encrypt the zenny.
Now, we need need to find a cmp. It'll be a bit down :
ldr r1,[r1]
cmp r0,r1
beq 202B854h
mov r0,1h
pop r0-r7,r15
that means that if r0=r1 (which we guess should be true if the zenny are correctly encrypted/decrypted), the branch (beq) will be taken, and the mov r0,1h will not be executed.
So we have different ways to deal with it.
The cheap (usually what I choose) one would be to change the cmp r0,r1 with a cmp r0,r0, so the games always think the newly encrypted and the 'oldly' encrypted values match.
Highligh the 'cmp r0,r1', type in 'cmp r0,r0'.
See the numbers to the left of that instruction ?
0202B84E 4280
That means the asm instruction cmp r0,r0 is equal to 4280, and is stored at 0202B48E.
To convert that into a code, just replace the first 0 of the address with an 1 (because we are writing a 16-bits value), and then add 0000 before the instruction. Which gives :
1202B84E 00004280
Exemple :
999999 zenny
1202B84E 00004280
0215C39C 000F423F
But that is not enought. A little testing will show that this code will not work properly (the zenny will be reset to 0 upon loading the save if the code is disabled).
That should be because the 'encrypted zenny' value is wrong. To correct that, we'll change the ldr r1,[r1] instruction. Normaly, it loads the already encrypted zenny value (and then compare it with the newly encrypted). What we'll do is simple : instead of loading the old encrypted zenny value, we'll store the new one !
Which means changing ldr r1,[r1] to str r0,[r1].
Which will give :
0202B84C 6008 str r0, [r1]
Then, in ARDS code type :
1202B84C 00006008
You might notice that the 2 codes we made, 1202B84E 00004280 and 1202B84C 00006008, are 2 continous 16-bits code, and 'first' one (ie. the one that has the lowest address, 1202B84C) is 32-bits aligned.
So both codes can be merged in a 32-bits code :
0202B84C 42806008
So this code :
999999 zenny
0202B84C 42806008
0215C39C 000F423F
will actually work (the zenny will be set to 99999999, and will be saved/loaded correctly even if the code is turned off).
Now, we 'need' to know if the game uses pointers, ie. how it computes the r0 before the 'ldr r0,[r0,5Ch]' instruction.
See the 'bl' a bit up the ldr r0,[r0,5Ch] ? Follow it (right click on it, and click on 'follow').
You'll see 'ldr r1,=2165294h' then 'pop r15'.
Right click on an instruction, and click on 'undo follow'.
So we know r1,=2165294h, then we see :
mov r0,3Ch
ldr r0,[r1,r0]
pop r1
ldr r0,[r0,5Ch]
Which means the address where the zenny are stored is computed like that:
Add 0x3C to 0x2165294 and load the data that is there (ie. that is at 0x21652D0), then add 0x5C to it to get the zenny address.
That is a pointer code : 0x21652D0 points to an address, and at that address contents +0x5C we have the zenny.
We know that 0x2165294 and 0x3C are fixed (ie. they are 'written' in the program', they shouldn't change). So we can use 0x02165294+0x3C = 0x021652D0 directly in our code.
So we use the B code type :
621652D0 00000000 // checks if the data at 0x21652D0 is != 0
B21652D0 00000000 // if it is, load it into the offset
0000005C 000F423F // writes 000F423F to [offset+0x5C]
D2000000 00000000 // endif & clear offset
Maybe the data never moves. One would need to play though the whole game and check that. I won't, so by security I'll use the pointer code, in case the data moves (if it doesn't it'll just be 3 wasted lines of codes - not a big deal).
So, the code would be :
0202B84C 42806008
621652D0 00000000
B21652D0 00000000
0000005C 000F423F
D2000000 00000000
But... That's still not enought, the game has another protection : you see, when the code is active and you load a game, if the amount of zenny set by the code is different than the one set in the save, the game will think it's corrupted, and will delete the save right away!!!
So we can either remove that check, make sure that the zenny code is only activated in-game, or put a 'hard' key combo that will trigger the code to make sure the user won't use it during the game loading. The third choice is the easiest. If we set the key combo to B+Select, that means the user will have to press Select+Start+B on the main screen to corrupt his save, which is unlikely to happen. However we'll still add a note to avoid it :
Code:
Press B+Select to have 999999 zenny *
94000130 FFF90000
0202B84C 42806008
621652D0 00000000
B21652D0 00000000
0000005C 000F423F
D2000000 00000000
* : Do not use on the game's main screen !!!
That's it...!