PDA

View Full Version : I'm Fixin' It: Emerald's Broken PRNG


HackMew
May 1st, 2010, 06:35 AM
Brief Intro
As probably most of you are aware of already, Emerald has a faulty PRNG implementation. The game does not take care of reseeding during the startup, leading to the fact it can be easily abused to get perfect IVs and similar.

Description
While it can be useful, it's indeed a major glitch. Since the whole game randomness is affected, it definitely needs to be fixed. Taking a look at Ruby's code, I found out that the initial reseeding happens as soon as the game starts (i.e. when the boot screen shows up). R/S use their internal clook to generate a 16-bit seed. In Emerald, of course, this part is totally missing. So I decided to emulate the R/S approach by porting their reseeding routine to Emerald. Here's the outcome:

[css-div="font-family:consolas, courier new,monospace"].text
.align 2
.thumb
.thumb_func
.global EmeraldPrngFix

main:
push {lr}
ldr r1, .GET_CLOCK
bl bx_r1
lsr r1, r0, #0x10
lsl r0, r0, #0x10
lsr r0, r0, #0x10
eor r0, r1
ldr r1, .UPDATE_SEED
bl bx_r1
ldr r0, .UNK_RAM1
mov r4, #0x0
strb r4, [r0, #0x0]
pop {pc}

bx_r1:
bx r1

.align 2
.UNK_RAM1:
.word 0x03002700
.GET_CLOCK:
.word 0x0802F664|1
.UPDATE_SEED:
.word 0x0806F5F8|1[/css-div]

In order to apply the fix, assemble the routine and insert it somewhere where there's enough free space (if you never done it before, you better check my ASM tutorials). Take note of the address you used, and then replace 02 24 04 70 with FE 46 00 47, and 00 27 00 03 with XX XX XX XX, where XX XX XX XX represents the pointer to the routine's address + 1. For the respective offsets, see below.

The Offsets



Emerald US v1.0

[css-div="font-family:consolas,courier new,monospace"]0x402
0x478[/css-div]



This research document is Copyright © 2010 by HackMew.
You are not allowed to copy, modify or distribute it without permission.

ArmoredGuns
December 19th, 2011, 11:35 PM
Can someone please make an IPS patch of this fix? It seems pretty important, and it seems it requires more than just hex editing... I would love to have this fix but I'm no programmer :P

Lost Heart
December 21st, 2011, 07:38 PM
Can someone please make an IPS patch of this fix? It seems pretty important, and it seems it requires more than just hex editing... I would love to have this fix but I'm no programmer :P

Okay, here you go... However, I really recommend you learn to apply simple hacks like this.
Download (http://www.mediafire.com/download.php?3dbj0obxb964309).
*Note: Routine inserted at 0x9C0D00*

Bond697
December 23rd, 2011, 12:19 AM
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:



ROM:08000560 @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560 @ void __fastcall seedRNG__()
ROM:08000560 seedRNG__:
ROM:08000560 10 B5 PUSH {R4,LR} @ this function never runs
ROM:08000562 06 48 LDR R0, =0x4000104 @ Timer1Data
ROM:08000564 04 88 LDRH R4, [R0]
ROM:08000566 20 1C MOVS R0, R4 @ Timer1Data to r0
ROM:08000568 6F F0 46 F8 BL setRNG__ @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49 LDR R1, =0x4000106 @ T1CNT
ROM:0800056E 00 20 MOVS R0, #0
ROM:08000570 08 80 STRH R0, [R1] @ turn off timer1
ROM:08000572 04 48 LDR R0, =0x2020000
ROM:08000574 04 80 STRH R4, [R0] @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC POP {R4}
ROM:08000578 01 BC POP {R0}
ROM:0800057A 00 47 BX R0
ROM:0800057A @ End of function seedRNG__
ROM:0800057A
ROM:0800057A @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C: .long 0x4000104 @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580: .long 0x4000106 @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584: .long 0x2020000 @ DATA XREF: seedRNG__+12r


ROM:0806F5F8 @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8 @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8 setRNG__: @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04 LSLS R0, R0, #0x10 @ dumb typecasting
ROM:0806F5FA 00 0C LSRS R0, R0, #0x10
ROM:0806F5FC 02 49 LDR R1, =0x3005D80 @ rng buffer
ROM:0806F5FE 08 60 STR R0, [R1] @ set rng to T1Dat
ROM:0806F600 02 49 LDR R1, =0x20249BC @ rng frame counter
ROM:0806F602 00 20 MOVS R0, #0 @ set counter to 0 to signify starting seed
ROM:0806F604 08 70 STRB R0, [R1]
ROM:0806F606 70 47 BX LR
ROM:0806F606 @ End of function setRNG__

ArmoredGuns
December 23rd, 2011, 01:42 AM
Okay, here you go... However, I really recommend you learn to apply simple hacks like this.

*Note: Routine inserted at 0x9C0D00*

Thank you very much!!! I greatly appreciate it :)

just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:



ROM:08000560 @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560 @ void __fastcall seedRNG__()
ROM:08000560 seedRNG__:
ROM:08000560 10 B5 PUSH {R4,LR} @ this function never runs
ROM:08000562 06 48 LDR R0, =0x4000104 @ Timer1Data
ROM:08000564 04 88 LDRH R4, [R0]
ROM:08000566 20 1C MOVS R0, R4 @ Timer1Data to r0
ROM:08000568 6F F0 46 F8 BL setRNG__ @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49 LDR R1, =0x4000106 @ T1CNT
ROM:0800056E 00 20 MOVS R0, #0
ROM:08000570 08 80 STRH R0, [R1] @ turn off timer1
ROM:08000572 04 48 LDR R0, =0x2020000
ROM:08000574 04 80 STRH R4, [R0] @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC POP {R4}
ROM:08000578 01 BC POP {R0}
ROM:0800057A 00 47 BX R0
ROM:0800057A @ End of function seedRNG__
ROM:0800057A
ROM:0800057A @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C: .long 0x4000104 @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580: .long 0x4000106 @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584: .long 0x2020000 @ DATA XREF: seedRNG__+12r


ROM:0806F5F8 @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8 @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8 setRNG__: @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04 LSLS R0, R0, #0x10 @ dumb typecasting
ROM:0806F5FA 00 0C LSRS R0, R0, #0x10
ROM:0806F5FC 02 49 LDR R1, =0x3005D80 @ rng buffer
ROM:0806F5FE 08 60 STR R0, [R1] @ set rng to T1Dat
ROM:0806F600 02 49 LDR R1, =0x20249BC @ rng frame counter
ROM:0806F602 00 20 MOVS R0, #0 @ set counter to 0 to signify starting seed
ROM:0806F604 08 70 STRB R0, [R1]
ROM:0806F606 70 47 BX LR
ROM:0806F606 @ End of function setRNG__


Hmm I wonder if FRLG's PRNG seeding routine is better than Ruby/sapphire's...

Kaphotics
January 28th, 2012, 08:52 AM
Hmm I wonder if FRLG's PRNG seeding routine is better than Ruby/sapphire's...

It's not, R/S was better due to the more variant initial starting seeds (hence more random).

FRLG had 0x0000 - 0xFFFF starting seeds, whereas R/S was 0x0 - 0x7FFFFFFF.

Both are definitely more random than Emerald, but R/S did it better. In later games (DPPt and BW) you have a mix of datetime and hardware timers (delay).

AlphaDrache
September 2nd, 2012, 07:23 AM
Are the addresses the same for the german emerald ROM?

Darthatron
September 2nd, 2012, 07:50 AM
Are the addresses the same for the german emerald ROM?

Probably, but to check just see if the bytes at the given offsets are the ones described in the tutorial.

Bond697
September 3rd, 2012, 12:52 PM
It's not, R/S was better due to the more variant initial starting seeds (hence more random).

FRLG had 0x0000 - 0xFFFF starting seeds, whereas R/S was 0x0 - 0x7FFFFFFF.

Both are definitely more random than Emerald, but R/S did it better. In later games (DPPt and BW) you have a mix of datetime and hardware timers (delay).

this is wrong. r/s seeds only go 0-0xffff also even though they use a more complex formula. the seeding is 16-bit either way, so no there's not more seeds.


ROM:080003E4 ; =============== S U B R O U T I N E =======================================
ROM:080003E4
ROM:080003E4
ROM:080003E4 seedRNG ; CODE XREF: main+30p
ROM:080003E4 PUSH {LR}
ROM:080003E6 BL buildSeed
ROM:080003EA MOVS R2, R0 ; s32 seed to r2
ROM:080003EC LSRS R0, R2, #0x10 ; r0 = seed >> 16
ROM:080003EE LDR R1, =0xFFFF
ROM:080003F0 ANDS R1, R2 ; r1 = seed & 0xFFFF (get lower 16 bits of seed)
ROM:080003F2 EORS R0, R1 ; upperSeed ^ lowerSeed
ROM:080003F4 BL setRNG
ROM:080003F8 POP {R0}
ROM:080003FA BX R0
ROM:080003FA ; End of function seedRNG
ROM:080003FA
ROM:080003FA ; ---------------------------------------------------------------------------
ROM:080003FC dword_80003FC DCD 0xFFFF ; DATA XREF: seedRNG+Ar


(sapphire)

aroenai
October 24th, 2012, 10:35 PM
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:



ROM:08000560 @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560 @ void __fastcall seedRNG__()
ROM:08000560 seedRNG__:
ROM:08000560 10 B5 PUSH {R4,LR} @ this function never runs
ROM:08000562 06 48 LDR R0, =0x4000104 @ Timer1Data
ROM:08000564 04 88 LDRH R4, [R0]
ROM:08000566 20 1C MOVS R0, R4 @ Timer1Data to r0
ROM:08000568 6F F0 46 F8 BL setRNG__ @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49 LDR R1, =0x4000106 @ T1CNT
ROM:0800056E 00 20 MOVS R0, #0
ROM:08000570 08 80 STRH R0, [R1] @ turn off timer1
ROM:08000572 04 48 LDR R0, =0x2020000
ROM:08000574 04 80 STRH R4, [R0] @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC POP {R4}
ROM:08000578 01 BC POP {R0}
ROM:0800057A 00 47 BX R0
ROM:0800057A @ End of function seedRNG__
ROM:0800057A
ROM:0800057A @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C: .long 0x4000104 @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580: .long 0x4000106 @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584: .long 0x2020000 @ DATA XREF: seedRNG__+12r


ROM:0806F5F8 @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8 @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8 setRNG__: @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04 LSLS R0, R0, #0x10 @ dumb typecasting
ROM:0806F5FA 00 0C LSRS R0, R0, #0x10
ROM:0806F5FC 02 49 LDR R1, =0x3005D80 @ rng buffer
ROM:0806F5FE 08 60 STR R0, [R1] @ set rng to T1Dat
ROM:0806F600 02 49 LDR R1, =0x20249BC @ rng frame counter
ROM:0806F602 00 20 MOVS R0, #0 @ set counter to 0 to signify starting seed
ROM:0806F604 08 70 STRB R0, [R1]
ROM:0806F606 70 47 BX LR
ROM:0806F606 @ End of function setRNG__


Can someone post an .ips patch that uses the built in code for Emerald, and possibly port it to R/S? The reason I ask is the batteries finally died in my copies of R/S/E so I wanted to start using my EZ Flash 3in1 and EZ Flash IV which both lack a RTC (gbata patched).

Edit: Oh wait, would that just be 61 05 00 08 at 0x478 for Emerald?
Edit 2: Nope white screen

ThomasWinwood
April 7th, 2014, 10:34 PM
Can someone post an .ips patch that uses the built in code for Emerald, and possibly port it to R/S?
This isn't an IPS patch (though making one is trivial) but I think that you can use the existing RNG seeding routine by making the following changes. (I would really appreciate someone checking that this does in fact seed the PRNG correctly - I'm on Linux, so the only debugging tools I have available to me are "does the ROM work" and "do I get anything odd, like a trainer ID of 00000".)


At 0x402 change 00 24 04 70 to FE 46 00 47.
At 0x478 change 00 27 00 03 to 61 05 00 08.
At 0x578 change 01 BC 00 47 to 00 BD 08 47.