Evie (ChickasaurusGL) 🌺 | Sound bank arbitrary code execution (0A:58EA's stack corruption) - Save file modification (Red/Blue) @ChickasaurusGL | Uploaded September 2021 | Updated October 2024, 15 hours ago.
Notes: Documenting another arbitrary code execution method in Red/Blue. ^^ I think someone (luckytyphlosion?) talked about sound bank ACE a long time ago, but unsure if anyone ever made a method to do it.
Steps:
You'll need:
0. You may want to do this where a 0x50 sub-tile is early on screen (e.g. the spot on Route 1 in this video) to avoid lag item names.
1. At least the bag expanded inventory; see https://glitchcity.wiki/Dry_underflow_glitch and https://glitchcity.wiki/Expanded_bag_item_documentation_(Generation_I))
2. A routine to run in PC item 17 (Water Stone x211 takes you to bag item 3).
3. Following that pointer, additional code (e.g. at item 3) taking into account the stack pointer (and its pointers within) will be corrupted to there, so you'll need to avoid a freeze e.g. by using it to modify the save file instead and resetting.
Steps:
1. Save the game
2. Place Moon Stone into item 32
3. Use the Bicycle
4. Dismount
5. You've now run your code (save modification script in this video)
Explanation:
02, 08 and 1F are the normal sound banks. In addition to these are glitch sound banks, it seems all run (bank):58EA ; as due to the conditionals in the code, the game moves to as if they are bank 1F (1F:58EA is a valid routine) but gets the bank wrong (02 meanwhile is 02:5103, 08 is 08:5879). As Pokémon Red is 1048576 bytes and a ROM + MBC3 + RAM + Battery cart, there are 0x3F (dec:63) ROM banks to try (so effectively 63 different glitch sound banks; not sure about the bankless region which is like bank 1 anyway), outside of possible hardware accurate invalid bank details some emulators fail to manage accurately.
Bank 0A has arbitrary code execution potential. In short, the stack pointer will be corrupted to F557 (Echo RAM for D557) as 1D3D, after 1D42 was called there (1D3A: CD 42 1D); so probably the next operation in the program counter. F559 will also become 9AC0, but is not executed. The stack will also progress to F55B, which is unchanged.
Hence since D55B is PC item 17, you can add your own routine there. I added 22 D3 (Water Stone x211); to move it to item 3. At item 3 I moved it again to box Pokémon with jp DA80. Lastly, since the stack pointer is corrupted, I decided to just modify the SRAM, resave the game directly without the message (I assume this fixes the checksum) and reset it with interrupts disabled.
I was then able to modify my save with sound bank ACE to turn my first Pokémon into Mew, and reset the sound bank. You should be able to modify your save file in any other way that's loaded by continue though (e.g. items, Pokémon, the current map scripts (and by modifying the current map script you can set up arbitrary code execution again, and do anything you can code/fit in RAM)).
This is my proof of concept code at DA80, but it's not optimal at all. Someone could possibly shorten it and rewrite it as reasonable inventory items (even though D36E-F is arguably better for this purpose).
3E0AEA00003E01EA0060EA00402198A5018B0F3E15EA2DAFEA34AF3E02EA07A6EA08A6EA5BD3EA5CD3F3061C218C77CDD635C3541F0
ld a,0A
ld (0000),a
ld a,01
ld (6000),a
ld (4000),a ; enable SRAM in bank 1
ld hl, A598
ld bc,0F8B ; I copied this over from an actual routine in the game, I don't know if it's needed now.
ld a,15
ld (af2d),a
ld (af34),a ; Pokémon in party slot 1 is Mew (both bytes match, so stable)
ld a,02
ld (a607),a ; reset to SE 02
ld (a608),a ; reset to sound bank 02 ('outside overworld music')
ld (d35b),a
ld (d35c),a ; as this was overwritten for some reason, I had to change the RAM as well, which is also written back to A607 and A608.
di ; I disabled interrupts, so the game wouldn't freeze (probably could have gone at the top?)
ld b,1c
ld hl,778c
call 35d6 (run 1C:778C; SaveSAVtoSRAM0 in the disassembly)
jp 1F54 ; reset the game before everything freezes
Notes: Documenting another arbitrary code execution method in Red/Blue. ^^ I think someone (luckytyphlosion?) talked about sound bank ACE a long time ago, but unsure if anyone ever made a method to do it.
Steps:
You'll need:
0. You may want to do this where a 0x50 sub-tile is early on screen (e.g. the spot on Route 1 in this video) to avoid lag item names.
1. At least the bag expanded inventory; see https://glitchcity.wiki/Dry_underflow_glitch and https://glitchcity.wiki/Expanded_bag_item_documentation_(Generation_I))
2. A routine to run in PC item 17 (Water Stone x211 takes you to bag item 3).
3. Following that pointer, additional code (e.g. at item 3) taking into account the stack pointer (and its pointers within) will be corrupted to there, so you'll need to avoid a freeze e.g. by using it to modify the save file instead and resetting.
Steps:
1. Save the game
2. Place Moon Stone into item 32
3. Use the Bicycle
4. Dismount
5. You've now run your code (save modification script in this video)
Explanation:
02, 08 and 1F are the normal sound banks. In addition to these are glitch sound banks, it seems all run (bank):58EA ; as due to the conditionals in the code, the game moves to as if they are bank 1F (1F:58EA is a valid routine) but gets the bank wrong (02 meanwhile is 02:5103, 08 is 08:5879). As Pokémon Red is 1048576 bytes and a ROM + MBC3 + RAM + Battery cart, there are 0x3F (dec:63) ROM banks to try (so effectively 63 different glitch sound banks; not sure about the bankless region which is like bank 1 anyway), outside of possible hardware accurate invalid bank details some emulators fail to manage accurately.
Bank 0A has arbitrary code execution potential. In short, the stack pointer will be corrupted to F557 (Echo RAM for D557) as 1D3D, after 1D42 was called there (1D3A: CD 42 1D); so probably the next operation in the program counter. F559 will also become 9AC0, but is not executed. The stack will also progress to F55B, which is unchanged.
Hence since D55B is PC item 17, you can add your own routine there. I added 22 D3 (Water Stone x211); to move it to item 3. At item 3 I moved it again to box Pokémon with jp DA80. Lastly, since the stack pointer is corrupted, I decided to just modify the SRAM, resave the game directly without the message (I assume this fixes the checksum) and reset it with interrupts disabled.
I was then able to modify my save with sound bank ACE to turn my first Pokémon into Mew, and reset the sound bank. You should be able to modify your save file in any other way that's loaded by continue though (e.g. items, Pokémon, the current map scripts (and by modifying the current map script you can set up arbitrary code execution again, and do anything you can code/fit in RAM)).
This is my proof of concept code at DA80, but it's not optimal at all. Someone could possibly shorten it and rewrite it as reasonable inventory items (even though D36E-F is arguably better for this purpose).
3E0AEA00003E01EA0060EA00402198A5018B0F3E15EA2DAFEA34AF3E02EA07A6EA08A6EA5BD3EA5CD3F3061C218C77CDD635C3541F0
ld a,0A
ld (0000),a
ld a,01
ld (6000),a
ld (4000),a ; enable SRAM in bank 1
ld hl, A598
ld bc,0F8B ; I copied this over from an actual routine in the game, I don't know if it's needed now.
ld a,15
ld (af2d),a
ld (af34),a ; Pokémon in party slot 1 is Mew (both bytes match, so stable)
ld a,02
ld (a607),a ; reset to SE 02
ld (a608),a ; reset to sound bank 02 ('outside overworld music')
ld (d35b),a
ld (d35c),a ; as this was overwritten for some reason, I had to change the RAM as well, which is also written back to A607 and A608.
di ; I disabled interrupts, so the game wouldn't freeze (probably could have gone at the top?)
ld b,1c
ld hl,778c
call 35d6 (run 1C:778C; SaveSAVtoSRAM0 in the disassembly)
jp 1F54 ; reset the game before everything freezes