Glitch City Laboratories Archives

Glitch City Laboratories closed on 1 September 2020 (announcement). This is an archived copy of a thread from Glitch City Laboratories Forums.

You can join Glitch City Research Institute to ask questions or discuss current developments.

You may also download the archive of this forum in .tar.gz, .sql.gz, or .sqlite.gz formats.

Generation II Glitch Discussion

Initiating ACE during game startup in Pokemon Crystal - Page 1

Initiating ACE during game startup in Pokemon Crystal

Posted by: Npo
Date: 2018-05-16 14:06:13
So now that I have lots of free time for the summer I decided to look into setting up a save file that has ACE running all the time, and will continue to run even after a reset. The way I intend to do this is by editing the player name to contain the char $15 00, this will cause the game to jump to $cd52 which holds data corresponding to map tiles. The first time the player name is read after a reset is after the player selects 'Continue' from the start menu. If I can get the byte $c9 to be written to that part of memory then the program counter will return to after the address where the $15 00 char in the player name and will execute the rest of the player name as asm. Then from their I can write a jump to somewhere else in ram that had been previously set up to run whatever I want.

Editing the player name to have the char 50 00 in it can be done using a different ACE method, and by writing directly to SRAM instead of wram we won't have to worry about trying to save the game afterword, as doing so would cause the game to read the player name and thus cause the game to start running code from ram.

The first problem is trying to get the byte $c9 written to $cd52 before the game reads the $15 00 sequence. My solution to this is to make the player's name so long that as the game reads the name it will overwrite that part of memory with the char $c9. When the game starts reading the player name it stores the location of where to print the name in memory in hl which at the start of the name hl=$c574, we need to get hl up to $cd52. I found while looking into the unused mobile char functions, that the char sequence

$15 04 – – xx 50      where '–' is just any char, and 'xx' is some byte.

will cause the game to 'skip' xx spaces in it's output, effectively adding 'xx' to hl. However, I want to keep the player name short enough to fit in the 10 char limit so that the entire name is loaded when the game resets. To do this i will use char that refence other 'names' in the game.

The game actually has memory stored for Mom's name, Red's name and Green's name. It seems that the developers once intented the player to be able to change these NPC's names, but since that was never implemented the names stored in RAM are never refrenced in normal play. This means if we edit those names in ram, we can refrence them in the player name using the chars $49, $39, $38 for Mom's, Green's and Red's names respectivly.

Finaly we have what we need to set up the exploit. Here are the names we need for each character for the exploit to work.
Mom's name:    15 04 00 00 ff 50 50 (skip 255 char)
Red's  name:    15 04 00 00 f2 50 50 (skip 242 char)
Green's name:  49 49 49 38 50 ( skip 255 + 255 + 255 +242 = 1007 char)
Your name:      39 39 c9 15 00 c3 0e da 50  (skip 1,007*2=2,014 char then write c9…)

the player name when read will then cause the game to jump to $da0e which then should contain code to fix the player name so that once it is read again it will be as normal, and also initiate an HRAM hook allowing for pretty much anything.

It's important to note that the game actually reads the player name once before it actually prints it anywhere on screen after picking continue, this means that (assuming the code at $da0e will fix the player name) the game should appear to run normaly.

I will attach a link to a save file / save-state for bgb which is set up to run a "Rainbow Pallet" payload where the players pallet is randomly changed every frame as an example of how this would work.
https://drive.google.com/drive/folders/13Lwo0_5bhnaZCFnNf_B12oGJA26XHF3-?usp=sharing

———————
That was a pretty dense look at what I have been doing, but basically I made a way to have ACE on startup, my next goal is to write a method that will run with the HRAM hook and will detect when the player saves to fix the player name in SRAM so that when the game resets after a save the exploit will still work. If I can get that to work then this would open up the possibility of a functional "mod" to the gen 2 pokemon games. I will update this post in the future with the asm code for fixing the player name and implementing the HRAM hook.





Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: ISSOtm
Date: 2018-05-17 08:13:30
To detect if the player saved, you can check if the "SAVE" option in the menu has been selected (I think this could be detected by checking the cursor tile). I'm interested in this as well, I could lend you a hand if you want.
However, which version of Crystal are you using? (MD5/SHA1 if possible, please)
I'd prefer to use the US versions if possible, due to the SYM file provided by the disassembly.

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: Npo
Date: 2018-05-17 10:46:04
I am using :
Pokemon - Crystal Version (UE) (V1.1)
MD5: 54858AA278A0576B545FDC35CDBD1CF8

Although Since i'm pretty early in the project I am totally willing to use a different version if that would be helpful. For the Save detection, I think we would need to test more then just if the player has selected the save option since it's possible to save the game other ways as well, initiating a trade, going to the hall of fame, switching Pokemon boxes and such. Looking at the save procedure it seems that every time the game is saved the method PauseGameLogic is called and sets a byte in ram. I'm pretty sure this is the only time in normal play this happens so I think checking for that byte might be the best way of doing that. Later today I will post the asm code needed to fix the player's name and set up the hram hook.

EDIT:
So here is the asm code for the exploit starting at DA0E
This is probably not the best way to implement an hram hook but it's what I was able to figure out…
I had some problems where somethimes part of wram would be 'missing' and not contain the payload, so to fix this I check to see
if the last opcode of the exploite hasn't been changed to make sure it's safe to execute the payload..



DA0E:
di /might not be nesicary just easier to check for mistakes
push hl
push bc
push de /this is so we can return to romal code without any prblm
ld de,ffed /where the hram hook needs to go
ld hl,da65 /where it is stored
ld bc,000c /length of hram hook
call 3026 /copy data function
ld a,64
ld (ff00+88),a /cause the hram loop to jr to ffed
ld de,d47d /player name in wram
ld hl,da5b /backup of our player name
ld c,0a /size of player name
call 3026 /coby bytes
pop de
pop bc
pop hl /get ready to return to normal play
scf /Important! game wont stop printing char of player name otherwise
reti    /Note this byte is also checked by the hram hook to ensure it is 'safe' to execute the payload

Hram hook stored at DA65:
dec a 3d
jr nz,ffed 20 fd
ld a,(da31) fa 31 da /check byte for reti opcode to make sure it's safe to execute payload...
cp a,d9 fe d9
jp z,da32 ca 32 da
ret c9

example payload (rainbow pallet) stored at DA32
ld a,(ff00+e2)
ld (d4dc),a
ret

I'm not too happy with this asm code and will probably come back to this but it works as a proof of concept.

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: ISSOtm
Date: 2018-05-17 13:14:17
I actually re-did all your work on my own side, in order to have a RGBDS setup that patches in any save file. It's currently working! If you want, I can publish this to a GitHub repo and work from there.

I'm currently using the US Crystal 1.0 version built from pokecrystal (MD5: 9f2922b235a5eeb78d65594e82ef5dde), on which your exploit seemed to work out of the box.
Btw, US Crystal 1.1 (as built from pokecrystal, again) has a MD5 of 301899b8087289a6436b0a241fbbb474.


Checking if saving has occurred is actually trivial. Switch to SRA1, check if the player's name is still out exploit's name (checking for the first byte is enough, since the "Green's name" control char shouldn't be obtainable by the player). If that's the case, patch in the existing save, and call `Checksum`, and finally write it back. (This might be actually a bit dangerous if the code triggers while in the normal `Checksum` function, but there's a chance it doesn't occur)


As for the HRAM hook, here's how I do it:
OAMHook: ; Ends up at FF80
    call $C002
    ld [$ff00+c], a

DMALoader: ; Ends up at $C000
    ; Code here...

    ; Set up regs for DMA to go on smoothly
    ld c, $46 ; LOW(rDMA)
    ld a, $C4 ; HIGH(wVirtualOAM)
    ret
DMALoaderEnd:

NewPlayerName:
    db "GCL@"

InitialPayload:
    di
    push bc
    push de
    push hl
    ; Hook OAM DMA
    ld hl, OAMHook
    ld bc, 4 << 8 | $80
.copyOAMHook
    ld a, [hli]
    ld [$ff00+c], a
    inc c
    dec b
    jr nz, .copyOAMHook
    ; Copy loader to WRAM
    ld hl, DMALoader
    ld de, $C000 ; Stack space, of which a lot is usually available
    ld bc, DMALoaderEnd - DMALoader
    call CopyBytes
    ld de, NewPlayerName
    ld hl, wPlayerName
    call CopyName2
    pop hl
    pop de
    pop bc
    scf
    reti

(In my source, it's a bit different, due to requiring some artifacts to get RGBDS to output code with the proper, WRAM, addresses)

A side note regarding the use of C000+ as storage: this works fine, except with Withdraw Smash ACE. Should be OK, I guess.

Another side note as to how to restore the player's name: instead of copying a default name, we can probably fetch it from the save backup instead!
[EDIT] Sadly, the backup is overwritten before our name is evaluated, thus, we can't restore the name from the backup. My other idea is to instead store the player's name in another region of SRAM, and copy back from there. (Side note, I'm aiming at something like MrCheeze's virus, which can be applied to basically any save file, thus we could copy the player's name to an unused SRAM section before patching takes place)

And finally, another quirk: the game uses the Mom's name to store the player's during the Dude's catching tutorial. We'd have to patch that as well with the exploit's string.

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: Npo
Date: 2018-05-17 14:16:39
Wow! That's Great!

I like the idea of checking the SRAM to see if the name has changed, I'm not entirely familiar with the GB hardware but would there be a problem with unlocking / locking SRAM every frame? Or would you just be checking to see if it has changed when sram is already unlocked ie. when the game is saving?

As for the Mom's name being over written during the dude tutorial, I had no idea that happens. So I came up with a new set of names that only uses Red's and Green's names for the exploit to work, that way we won't have to worry about fixing / checking for Mom's name being overwritten.
Here are the new names:

RED:      15 04 00 00 FF 50 50
GREEN:  15 04 00 00 E5 50 38 38 38 38 50
YOUR's:  39 38 38 38 C9 15 00 C3 0E DA 50

If you replace these names with the ones I currently use then it should load the payload just fine.

And I love the idea of recreating MrCheeze's virus in gen 2. (That was part of the reason I started working on this…)

Also a GitHub repo would be great!

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: ISSOtm
Date: 2018-05-17 14:17:53
Alright, I'll try with the new names, and when I get something working, I'll publish a repo :)

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: ISSOtm
Date: 2018-05-17 14:50:50
I think this is enough to warrant a double-post, but… the new names worked perfectly, BGB keeps breaking due to accessing disabled SRAM (intended, lel), but it's working!

[EDIT]
The GitHub repository is live!

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: Torchickens
Date: 2018-05-17 16:34:09
Wow. :O This sounds amazing!

ISSOtm, can you upload a save file please, and I can mirror it?

Thanks.

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: ISSOtm
Date: 2018-05-17 16:57:30
I'm doubtful to upload a save file as long as I haven't made sure that saving is at least 99% fail-proof. Currently hard-resetting wile the game is saving may permanently "uninstall" the exploit. (The save patching currently only takes place when SRAM has been re-locked, which seems to happen very late into the process)

I'll also be providing a patching program (probably Python) later on, when I get around to meta-program it from the RGBDS output \o/

Re: Initiating ACE during game startup in Pokemon Crystal

Posted by: Torchickens
Date: 2018-05-17 17:05:26

I'm doubtful to upload a save file as long as I haven't made sure that saving is at least 99% fail-proof. Currently hard-resetting wile the game is saving may permanently "uninstall" the exploit. (The save patching currently only takes place when SRAM has been re-locked, which seems to happen very late into the process)

I'll also be providing a patching program (probably Python) later on, when I get around to meta-program it from the RGBDS output \o/


I see. That's OK.

Good luck in further developing it. :)