SearchForCheats.de.vu » Tutorials » Advanced User Tutorial #1 - How To Create A Shiny Encounter


Advanced User Tutorial #1 - How To Create A Shiny Encounter

Uh, it“s nice to meet you here. This “secret“ part of my laboratory can only be found by the very skilled coders. *just joking*
But, uhm... be sure, you won“t be able to understand the procedures we will “hack“ here, if you just have finished Hacking Lesson 4 or something like that.
So... let“s get hacking (cracking?)! We are trying to make a shiny encounter for a US-Version of pokemon Fire Red. Let“s say we want back our old-fashioned shiny gyarados. Your previous knowledge should be something like this:

  • standart-operations with a hexeditor (something like copy & paste :-P )
  • how to re-point events in Advance Map / Elite Map
  • the gba-addressing (pointer => offset and reverse)
  • you“d know the gba-generation“s standart-pokescript-commands
  • and... yeah... some knowledge about ASM would help... (you won“t need it for the tutorial but if you are interested in understanding the script-hooks, it would be nice)

What we“ll need:

  • a hexviewer (uh... you didn“t expect that, did you?)
  • the ROM (don“t ask me where to get it!)
  • an emulator to test the result
  • your brain <= Important!!1oneone

And what are we going to do with the stuff?
Well. The main idea should be something like this:

  • finding the shiny-routine
  • deviding it into two parts - a patched routine and a conventional - depending on a flag located in the RAM
  • writing a ASM-Script that sets or unsets the flag
  • writing the pokescript-part with the two ASM-calls

Maybe there are already questions/doubts. What“s the reason use such a complicated solution? Why not just calling a routine which patches the needed bytes?
Well. The answer is... That way, we create a proper flag, accessible from all pokescripts. And besides that - it“s not a really clean solution to let the ROM overwrite itself, is it?

Do some standart search for the 32-Bit PokemonID in the RAM. The chance whether a pokemon is a shiny or not is based on the PokemonID. (Also known as Rnd#) It“s also the location of the gender, the nature, the unown shape, and all that stuff. But we are just interested in the shinyness. The shinyness is calculated from the upper 16-Bit XOR the lower 16-bit of the so-called XKey. The XKey is the result of XORing the PID with the TrainerIDs.
@_@ That sounds very complicated. I think, I have to explain it to you more clearly. Let me use an example. Let“s say your Trainer ID (which will be passed to an encountering pokemon) is 56432. Your “secret“ Trainer ID (SID) is... err... 026025. Convert it to hex, so you get 0xDC70 for OTID and 0x65A9 for OTSID. Put it together like this:

(OTSID << 0x10) OR (OTID)

You get the second word (called the OTrainerIDs) 0x65A9DC70. The first value is the PID/Rnd#. It is calculated randomly. Let“s say, the PID for the currently encountering pokemon is 0x57ADF001.
Based on the knowledge of these two values, we (or the game?) calculate the Xkey. (Yeah. That sounds cool, doesn“t it?) The XKey, as I said before, is the result of XORing the PID with the OTrainerIDs. So we get (in our case):

    0x57ADF001
XOR 0x65A9DC70
--------------
    0x32042C71

The shiny data is stored in the ratio of the upper halfword to the lower halfword. If the result of a XOR operation of these two values is lower than eight, the pokemon is a shiny. Okay. Let“s check that:

(Xkey >> 0x10) XOR (XKey AND 0xFFFF)

(Xkey >> 0x10)    ==     0x3204
(XKey AND 0xFFFF) == XOR 0x2C71
                     ----------
                         0x1E75

The result 0x1E75 is much greater than 8. The pokemon isn“t a shiny. :-( But we are here, because we are going to change that. My idea is the following:
(Xkey >> 0x10) and (XKey AND 0xFFFF) may not differ more than 8. If we could manage that (Xkey >> 0x10) is always equal to (XKey AND 0xFFFF), the XOR operation would return zero. And 0 < 8. So we had our shiny.
So, every halfword, which is just doubled to a word would be a valid integer. That“s the one part.
But the Xkey is just another result of a XOR calculation. How do we manage to force it to our wanted integer? The following method is the easiest and the one, I like the best.
Let“s take 0x00000000 as our XKey. It is a “valid“ shiny integer and is easy to calculate from a XOR operator. I think, you know, how we will go on. Setting the PID equal to the OTrainerIDs would return in the XOR calculation 0x00000000 what“s exactly that, what we“re wanting at the moment. For all of you, don“t understanding anything anything other than a equation:

((PID XOR OTrainerIDs) >> 0x10) XOR ((PID XOR OTrainerIDs) AND 0xFFFF) < 0x8

That“s it. And if we use the OTrainerIDs for the PID we get the following:

((OTrainerIDs XOR OTrainerIDs) >> 0x10) XOR ((OTrainerIDs XOR OTrainerIDs) AND 0xFFFF) < 8
(0x0 >> 0x10) XOR (0x0 AND 0xFFFF) < 0x8
0 XOR 0 < 0x8
0 < 8

Yeah. We solved the problem. Cool, isn“t it?
Search the RAM for the wild pokemon data. I propose to start with a equal to 0 search (ONLY BEFORE THE FIRST ENCOUNTER OF A POKEMON AFTER LOADING THE SAVE!!) and to continue with a 32-bit search for the OTrainerIDs. (You can calculate it with the formula a bit more at the top.)
You“ll find it around 0x02024030. Maybe exactly there, at the moment I“m to lazy to check for a DMA-Protection. Okay. Open your ROM in your prefered debugger (I choose VBA-SDL-H). All following steps are for the debugger I use, otherwise do the needed steps on yourself.
We try to figure out, when or where the OTrainerIDs“ 32-bit-value gets written into the RAM. So I first enter

mb 02024010

into the console and check the data-position. It hasn“t moved yet, in my case, the second word of the data is still remaining on 0x02024030. (The pdata itself starts at 0x0202402C with the PID, u know?)
Now I stick a 32-bit (4-byte) breakpoint on write to the position of the data.

bpw 02024030 4

Type c into the window and continue the execution. When could be the point reached, where the OTrainerIDs get new calculated? Maybe when encountering a wild pokemon?
Let“s give it a try and walk in some grass. Yes! The game breaks! You see:

Breakpoint (on write) address 02024030 old:00 new:00
R00=02024030 R04=0202402c R08=00000001 R12=00000001
R01=00000004 R05=02024220 R09=00000000 R13=03007d64
R02=0202402c R06=00000017 R10=00000000 R14=0803d99f
R03=00000000 R07=083c8d50 R11=00000000 R15=0803d98a
CPSR=0000003f (......T Mode: 1f)
0803d988 3101 add r1, #0x1

Shit. The current operation just wrote the byte 0x00 to 0x02024030. We aren“t interested in patching a silly nop-procedure, so I type c to continue. The game breaks again.

Breakpoint (on write) address 02024031 old:00 new:00
R00=02024031 R04=0202402c R08=00000001 R12=00000001
R01=00000005 R05=02024220 R09=00000000 R13=03007d64
R02=0202402c R06=00000017 R10=00000000 R14=0803d99f
R03=00000000 R07=083c8d50 R11=00000000 R15=0803d98a
CPSR=0000003f (......T Mode: 1f)
0803d988 3101 add r1, #0x1

Same ROM location. Just two changed (lower) registers. A 4 has become a 5 and the adress in r0, maybe (in fact, SURE) the one holding the write location has increased by one. We are currently inside of a loop which kills the old pokedata. So we can expect, that there are going to follow a couple of breaks again before the one we are looking for. Type c and break again. You can study the changes or even just ignore them by typing c.
There are some breaks later at a other ROM location but they are still nop-functions. Continue typing c.

Breakpoint (on write) address 02024030 old:00000000 new:65a9dc70
R00=bc000000 R04=03007cf8 R08=00000000 R12=00000008
R01=65a9dc70 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406dc
CPSR=8000003f (N.....T Mode: 1f)
080406da e1fe b $08040ada

YAY! That“s our routine! The word @ 02024030 has just got overwritten with 0x65a9dc70, my OTrainerIDs. Now I have a look on that procedure. Disassemble it with

d 080406c2

Why? It“s just an estimation of the procedure“s length. Something narrow 080406da, that told me the debugger. Likely the displayed numbers and letters don“t make any sense to you. For this reason I“m going to spell everything out. The subroutine is the operands between the two codes starting with “b $“. “b $location“ stands for a jump (=branch) operation. This is the sub:

080406c4  7821 ldrb r1, [r4, #0x0]   // load the byte @ r4 (=03007cf8) to r1
080406c6  7860 ldrb r0, [r4, #0x1]   // load the byte @ r4+1 (=03007cf9) to r0
080406c8  0200 lsl r0, r0, #0x08   // the byte in r0 is shifted left by 1 byte (=8bit)
080406ca  1809 add r1, r1, r0   // r1 and r0 are added. we get a halfword r0+r1
080406cc  78a0 ldrb r0, [r4, #0x2]   // load the byte @ r4+2 (=03007cfa) to r0
080406ce  0400 lsl r0, r0, #0x10   // r0 is left-shifted by 2-bytes again
080406d0  1809 add r1, r1, r0   // r0 is added to r1
080406d2  78e0 ldrb r0, [r4, #0x3]   // load the byte @ r4+3 (=03007cfb) to r0
080406d4  0600 lsl r0, r0, #0x18   // r0 is left-shifted by 3-bytes
080406d6  1809 add r1, r1, r0   // and added to r1. that“s the algorithm which shifts together the ID and the SID
080406d8  6079 str r1, [r7, #0x4]   // and finally the OTrainerIDs are stored at r7+4 (=0202402c) (the operation which triggered our breakpoint)
080406da  e1fe b $08040ada   // exit routine and jump to some other location

Let“s test our theory. If we could manage to change the

080406d6  1809 add r1, r1, r0   // add r1 to r0

to something like this

080406d6  xxxx str r1, [r7, #0x0]   // overwrite the PID with the OTrainerIDs

the PID would always be equal to the OTrainerIDs.
The thumb-operand for str r1, [r7, #0x0] is 0x6039, don“t ask how to calculate it. It“s enough for now, if you know what it does. (Well... If you are really interested, search Martin Korth“s gba-tech-dok and look for the “store word“ instruction set)
Let“s patch our ROM “on the fly“ by entering in your debugger the following:

eh 080406d6 6039

Then, delete the annoying breakpoint on write.

bpwc

Type c and let the encounter go on. But... it isn“t a shiny! Oh DAMN! What happened to our solution???
The answer is: nothing.
The pokemon isn“t a shiny, because the CPU had already passed the key-location when we patched it.
How to fix that?
Easy. Encounter another pokemon. You got your shiny. :-P
With knowing the Offset to patch and the value too, we can create an shiny encounter code quickly. The AR V3 syntax is this:

00000000 18XXXXXX
0000YYYY 00000000

uhm... XXXXXX stands for ((address AND 0x3FFFFF) >> 1) and YYYY is just the value to patch with. 0x18 tells the AR to use the first rom-patching-slot (z0C).

00000000 1802036B
00006039 00000000

Encrypt it with ARCrypt and your own (working) always-shiny-code is finished:

A74320F4 175B5B22
18452A7D DDE55BCC

End of Part I
If you are just interested in coding a always shiny code, you don“t have to read on. You“ve already reached your goal.
But if you are someone interested in integrating the patch above into a so-called hack-ROM, you still have the exiting part before you. Now, we“ll add good old shiny gyarados. Ready? Go!


We start (continue?) with extracting the... well... though it“s not a good description, I call it the “shiny routine“. Why extracting? Because if we want to insert a flag-compare to it, the subroutine grows. Therefore, all following bytes would be shifted down, all the jump-advices would get invalid. As you can see, we have no choice. Let“s extract it. What we want is the following:

080406c4  b402 push {r1} // save the value in r1 by pushing it on the stack
080406c6  4902 ldr r1, [$080406d0] (=$0871b701) // load the target-adress of the new routine
080406c8  f000 bl $080406cc // jump with bl to save the return adress in lr (needs 2*16bit)
080406ca  f800 blh $0000 // belongs to bl
080406cc  470f bx r1 // branch exchange. Switches the values of pc and r1
080406ce  0000 // not passed by the cpu
080406d0  b701 // data1 (needed in 0x080406c6)
080406d2  0871 // data2
080406d4  0000 lsl r0, r0, #0x0 // nop, unneeded space
080406d6  0000 lsl r0, r0, #0x0 // nop, unneeded space
080406d8  0000 lsl r0, r0, #0x0 // nop, unneeded space
080406da  e1fe b $08040ada // continue normal programflow

Open the ROM in a hexviewer. Jump to 0x406C0. There you“ll find the “shiny routine“, we are going to patch.

000406c0h: 39 60 0A E2 21 78 60 78 00 02 09 18 A0 78 00 04 ; 9`.ā!x`x.... x..
000406d0h: 09 18 E0 78 00 06 09 18 79 60 FE E1 00 22 3B 1C ; ..ąx....y`žį.";.

Overwrite it with our new routine. (the one from the disassembly view above)

000406c0h: 39 60 0A E2 02 B4 02 49 00 F0 00 F8 0F 47 00 00 ; 9`.ā.“.I.š.ų.G.. 000406d0h: 01 B7 71 08 00 00 00 00 00 00 FE E1 00 22 3B 1C ; .·q.......žį.";.

That way, the CPU always skips before an encounter to the unallocated ROM. You can test this by walking into the grass and finding the encounter completely messed up. ;-)

Let“s insert the modified “shiny routine“ at 0871b700. Why 0x00 instead of 0x01?
Well. The last bit of a branch-operation declares whether the following routine is written in ARM or THUMB mode. 0 is ARM and 1 stands for a thumb-routine. We use a thumb-routine, so the address ends with 1, even if it starts @ 0871b700.

0871b700  bc02 pop {r1} // get the saved value
0871b702  b500 push {lr} // put the return address onto the stack
0871b704  bc02 pop {r1} // reload it to r1
0871b706  3108 add r1, #4 // adjust the return adress by 8. (for skipping the target-adress“ data)
0871b708  b402 push {r1} // save return address again
0871b70a  490e ldr r1, [$0871b744] (=$02022000) // aww... and here it gets overwritten... pretty useless, i know ^^
0871b70c  6809 ldr r1, [r1, #0x0] // load the value @ 02022000 to r1
0871b70e  2901 cmp r1, #0x1
0871b710  d00b beq $0871b72a
0871b712  7821 ldrb r1, [r4, #0x0]   // load the byte @ r4 (=03007cf8) to r1
0871b714  7860 ldrb r0, [r4, #0x1]   // load the byte @ r4+1 (=03007cf9) to r0
0871b716  0200 lsl r0, r0, #0x08   // the byte in r0 is shifted left by 1 byte (=8bit)
0871b718  1809 add r1, r1, r0   // r1 and r0 are added. we get a halfword r0+r1
0871b71a  78a0 ldrb r0, [r4, #0x2]   // load the byte @ r4+2 (=03007cfa) to r0
0871b71c  0400 lsl r0, r0, #0x10   // r0 is left-shifted by 2 bytes again
0871b71e  1809 add r1, r1, r0   // r0 is added to r1
0871b720  78e0 ldrb r0, [r4, #0x3]   // load the byte @ r4+3 (=03007cfb) to r0
0871b722  0600 lsl r0, r0, #0x18   // r0 is left-shifted by 3 bytes
0871b724  1809 add r1, r1, r0   // and added to r1
0871b726  6079 str r1, [r7, #0x4]   // and finally the OTrainerIDs are stored at r7+4 (=0202402c) 0871b728  e00b b $0871b742 // skip the following lines. they“re used for shinys
0871b72a  7821 ldrb r1, [r4, #0x0]   // load the byte @ r4 (=03007cf8) to r1
0871b72c  7860 ldrb r0, [r4, #0x1]   // load the byte @ r4+1 (=03007cf9) to r0
0871b72e  0200 lsl r0, r0, #0x08   // the byte in r0 is shifted left by 1 byte (=8bit)
0871b730  1809 add r1, r1, r0   // r1 and r0 are added. we get a halfword r0+r1
0871b732  78a0 ldrb r0, [r4, #0x2]   // load the byte @ r4+2 (=03007cfa) to r0
0871b734  0400 lsl r0, r0, #0x10   // r0 is left-shifted by 2 bytes again
0871b736  1809 add r1, r1, r0   // r0 is added to r1
0871b738  78e0 ldrb r0, [r4, #0x3]   // load the byte @ r4+3 (=03007cfb) to r0
0871b73a  0600 lsl r0, r0, #0x18   // r0 is left-shifted by 3 bytes
0871b73c  1809 add r1, r1, r0   // and added to r1
0871b73e  6079 str r1, [r7, #0x4]   // and finally the OTrainerIDs are stored at r7+4 (=0202402c)
0871b740  6039 str r1, [r7, #0x0]   // and here“s our patch. the PID is overwritten with the OTrainerIDs
0871b742  bd00 pop {pc} // return & exit sub
0871b744  0020 //data1
0871b746  0202 //data2

Nice. Maybe you noticed, that I didn“t replace the commands as before for the ar Code.
Why? That“s just because overwriting the operator @0871b73c will affect the first byte of the OTrainerIDs. Using an action replay we“re content to have the shiny-effect and don“t care further about the OTrainerIDs. (So, cheaters, your hacked shinys could always be traced by reason the OTrainerIDs don“t match!)
Writing directly to the ROM (which is what we“re going to do) gives us the opportunity of fixing that bug. There is no need to kill an operator, so we just add a line.
How to get all the calculated values instead of operators? Well. There are two solutions. I, for myself, wrote the function directly in ASM, but you even can use a compiler. (like devkit pro“s arm-eabi) So, we open the ROM in the hexviewer and jump to our desired loaction: 0x71b700. Insert your operators, the ROM should look like this:

0071b700h: 02 BC 00 B5 02 BC 08 31 02 B4 0E 49 09 68 01 29 ; .¼.µ.¼.1.“.I.h.)
0071b710h: 0B D0 21 78 60 78 00 02 09 18 A0 78 00 04 09 18 ; .Š!x`x.... x....
0071b720h: E0 78 00 06 09 18 79 60 0B E0 21 78 60 78 00 02 ; ąx....y`.ą!x`x..
0071b730h: 09 18 A0 78 00 04 09 18 E0 78 00 06 09 18 79 60 ; .. x....ąx....y`
0071b740h: 39 60 00 BD 00 20 02 02 FF FF FF FF FF FF FF FF ; 9`.½. ..’’’’’’’’

That was a huge mass of coding. Let“s test the result!
Boot the ROM in VBA, open the memviewer and go to 02022000. You should find the value zero. Head for a pokemon. It will be a “normal“ monster. Now, change the “flag“ to 0x01. Encounter a pokemon. Shiny. Great success!
Good. Now we need a possibility to change the flag within a pokescript. Therefor we“ll use the command 0x23. It stands for an ASM call. The routine called has to set the flag or to unset it. So, what we construct, is the following:

0871b760  b507 push {r0, r1, r2, lr} // save return adress
0871b762  4803 ldr r0, [$0871b770] (=$02022000) // get the flag“s position
0871b764  6801 ldr r1, [r0, #0x0] // get the flag-value
0871b766  2201 mov r2, #0x1
0871b768  4051 eor r1, r2 // switch the flag“s value
0871b76a  6001 str r1, [r0, #0x0] // store back the new value
0871b76c  bd07 pop {r0, r1, r2, pc} // get saved values, return
0871b76e  0000 // not passed
0871b770  0020 //data1
0871b772  0202 //data2

Well. Everytime we call that function, it sets or unsets the “shinyflag“. Insert it into the ROM.

0071b770h: 07 B5 03 48 01 68 01 22 51 40 01 60 07 BD 00 00 ; .µ.H.h."Q@.`.½..
0071b780h: 00 20 02 02 FF FF FF FF FF FF FF FF FF FF FF FF ; . ..’’’’’’’’’’’’

Yay! Now, we“ve finished the ASM part. The final part might by the easiest one. We just have to write a pokescript in which we call the shiny-flag-set-function, the encounter and again the shiny-flag-set-function. The script is the following:

[23]        //asm call
[XXXXXXXX]  //pointer to thumb-sub+1
[00]        //filler
[B6]        //define wild pokemon
[XXXX]      //pokemon-id (INGAME)
[XX]        //level
[XXXX]      //held Item
[00]
[25]        //special-event
[3801]      //wild pokemon battle!
[28]        //wait
[0101]      //a second
[23]        //asm call
[XXXXXXXX]  //pointer to thumb-sub+1
[02]        //end

Puttin“ alltogether, we get (for a shiny gyarados, lvl 30) the following script:

0071b7a0h: 23 71 B7 71 08 00 B6 82 00 1E 00 00 00 25 38 01 ; #q·q..¶‚.....%8.
0071b7b0h: 28 01 01 23 71 B7 71 08 02 FF FF FF FF FF FF FF ; (..#q·q..’’’’’’’

And that“s it. Choose an event and repoint it to $71b7a0 or insert the pokecript above into an other pokescript, just as you like it. ;-)



"Pokémon" ist ein eingetragenes Warenzeichen der Firma Nintendo
"Action Replay" ist ein eingetragenes Warenzeichen von Datel Interact.
© www.SearchForCheats.de.vu by Mastermind_X
© 2006 - 2008