Wundereiland für Experten
Wundereiland ist eine Map, welche nach dem Daily-Random-Prinzip geladen wird. Es besteht eine (im schlechtesten Fall) Chance von 1:65535 pro Tag und Pokémon, dass die Insel "sichtbar" ist. Die Chance errechnet sich aus der Deckung zweier 16-Bit-Hexwerte. Faktor 1 sind die Pokémonwerte. Der Wundereilandwert ist ganz einfach für jedes Pokémon der erste 16-Bit-Value der PID. (Auch bekannt als RND). Da die PID für jedes Pokémon im Team gleich bleibt und ab dem Fangen fixiert ist, muss sich also der zweite Deckungsfaktor den Pokémon anpassen.
Der Wundereilandwert wird täglich neu generiert. Dabei wird ein Random-Command an zwei Bytes angewendet, woraus sich schlussfolgern lässt, dass sich (0 excluded) 65535 Möglichkeiten des Wertes ergeben. Der Wert ist in Rubin & Saphir noch ganz einfach an der RAM-Adresse 0x02026ABC zu finden. Den Vorgang für Smaragd erkläre ich hier genauer:
R01=0000012c R05=00000003 R09=00000000 R13=03007de0
R02=02024604 R06=0000d010 R10=00000000 R14=0806a673
R03=00000000 R07=030022c0 R11=00000000 R15=08137572
CPSR=0000003f (......T Mode: 1f)
08137570 4808 ldr r0, [$08137594] (=$020244ec)
Auch Gamefreak hat sich mit der DMA das Leben nicht leichter gemacht. Hier wird aus der ROM der Standartpointer für den Datenblock mit den Pokémondaten geladen.
R01=0000012c R05=00000003 R09=00000000 R13=03007de0
R02=02024604 R06=0000d010 R10=00000000 R14=0806a673
R03=00000000 R07=030022c0 R11=00000000 R15=08137574
CPSR=0000003f (......T Mode: 1f)
08137572 180c add r4, r1, r0
Der aktuelle Standpunkt der Daten in r1 wird dem Standartpointer hinzugefügt. Der Standpunkt der Pokémon-Daten ist somit klar.
R01=000013e4 R05=03000e40 R09=00000000 R13=03007dcc
R02=ffff939c R06=020375f0 R10=00000000 R14=0809d6bd
R03=03000e40 R07=030022c0 R11=00000000 R15=0809d6a2
CPSR=2000003f (..C...T Mode: 1f)
0809d6a0 6800 ldr r0, [r0, #0x0]
Der Standartpointer wird geladen für die Wundereilanddaten.
R01=000013e4 R05=03000e40 R09=00000000 R13=03007dcc
R02=ffff939c R06=020375f0 R10=00000000 R14=0809d6bd
R03=03000e40 R07=030022c0 R11=00000000 R15=0809d6a4
CPSR=2000003f (..C...T Mode: 1f)
0809d6a2 1840 add r0, r0, r1
Die aktuelle Datenposition wird errechnet.
R01=000013e4 R05=03000e40 R09=00000000 R13=03007dcc
R02=ffff939c R06=020375f0 R10=00000000 R14=0809d6bd
R03=03000e40 R07=030022c0 R11=00000000 R15=0809d6a6
CPSR=2000003f (......T Mode: 1f)
0809d6a4 bc02 pop
Die Data-Position wird wieder auf den Stapel gelegt.
R01=020244ec R05=00000000 R09=00000000 R13=03007db4
R02=0202453c R06=0202453c R10=00000000 R14=0806a673
R03=00000000 R07=00000000 R11=00000000 R15=0806a860
CPSR=0000003f (......T Mode: 1f)
0806a85e 680c ldr r4, [r1, #0x0]
Die Pokémondaten werden mittels des Pointers geladen.
R01=020244ec R05=00000000 R09=00000000 R13=03007db4
R02=0202453c R06=0202453c R10=00000000 R14=0806a673
R03=00000000 R07=00000000 R11=00000000 R15=0806a862
CPSR=0000003f (......T Mode: 1f)
0806a860 e216 b $0806ac90
R01=08137589 R05=00000000 R09=00000000 R13=03007de0
R02=0202453c R06=0000d010 R10=00000000 R14=0806a673
R03=00000000 R07=030022c0 R11=00000000 R15=0813758a
CPSR=0000003f (N.....T Mode: 1f)
08137588 4903 ldr r1, [$08137598] (=$0000ffff)
R01=0000ffff R05=00000000 R09=00000000 R13=03007de0
R02=0202453c R06=0000d010 R10=00000000 R14=0806a673
R03=00000000 R07=030022c0 R11=00000000 R15=0813758c
CPSR=0000003f (N.....T Mode: 1f)
0813758a 4001 and r1, r0
Dies ist die eigentliche Prozedur des Einlesens der PID. Aus der ROM wird ein 0xffff geladen und danach die Volle PID mit diesem 16-Bit-Wert geANDed. Dadurch bleiben nur noch die wichtigen ersten 16-Bit über. (Little Endian)
R01=00004654 R05=00000000 R09=00000000 R13=03007de0
R02=0202453c R06=0000d010 R10=00000000 R14=0806a673
R03=00000000 R07=030022c0 R11=00000000 R15=0813758e
CPSR=0000003f (......T Mode: 1f)
0813758c 42b1 cmp r1, r6
R01=00004654 R05=00000000 R09=00000000 R13=03007de0
R02=0202453c R06=0000d010 R10=00000000 R14=0806a673
R03=00000000 R07=030022c0 R11=00000000 R15=08137590
CPSR=0000003f (N.....T Mode: 1f)
0813758e d105 bne $0813759c
Hier werden PID und Wundereilandwert verglichen. Sind sie nicht gleich, fängt die Prozedur wieder von vorne an.
Angenommen, wir wollten die Routine cracken, haben wir mehrere Möglichkeiten:
- Den Branch if not equal zu einem NOP machen. Zum Beispiel mov r6, r6. Ganz nach Belieben
- Dafür sorgen, dass noch vor dem Vergleich die Daten immer gleich sind. Man könnte bei 0x0813758a den AND-Oparator durch ein mov r1, r6 ersetzen.
Welche Methode lieber gewählt wird, bleibt natürlich jedem selber überlassen ...

Zur