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 I Glitch Discussion

PokéWTrainer freeze - Page 1

PokéWTrainer freeze

Posted by: Stackout
Date: 2014-03-28 15:35:14
So, I decided to break out bgb and investigate why certain glitch pokemon freeze the game on encounter.

And first on my list was pokewtrainer..

Turns out the cause for the freeze is.. buffer overflow.

I don't know the entire specifics, but as part of sprite loading the game calls AlignSpriteDataCentered (at $16C2).

It copies data between two sprite buffers.

Now, the sprite buffers are located at the start of SRAM; there are three of them, each 392 bytes in size (7*7 tiles, where a tile is 8 bytes long). (And for those who don't know, SRAM is located at the start of RAM.)

Of course, the sprite data is abnormal. The sprite width of PokéWTrainer's front sprite just happens to be 00.

And this byte is equal to the number of loops taken. So the function loops 256 times and ends up trying to copy $179E0 bytes (or over 94KB) from $A188 to $A0F0. This obviously means both these pointers wrap around, and we end up overwriting nearly the entirety of RAM (and attempting to overwrite ROM, something that will never succeed except maybe in some lame flashcarts). Go figure.

We freeze thanks to the vblank interrupt handler. Therefore I doubt this will ever be exploitable to run arbitrary code (although I'm not TheZZAZZGlitch so…).

And yes, I know what you're thinking. Here, take a screenshot. This is what could happen to your save file.

[img]http://goput.it/a8c6.png[/img]

Re: PokéWTrainer freeze

Posted by: pokechu22
Date: 2014-03-28 17:03:04
First question: Where does the pattern "0039" come from?  I see it a lot when the game crashes.

Second question:  If the sprite width comes from an address, could the address be a variable?  It would explain how " ." corrupts the sound when it appears sometimes, but other times doesn't.  Although I don't know why " ." doesn't corrupt the save data then…  Hm. 

Also, a correction:
(7*7 tiles, where a tile is 8 bytes long).

Tiles are 16 bytes long.  Two bytes per row of pixels.  As an example, this:

01010101
00001111

Would produce this:



Though you probably already know that. 

Also, I never knew that sprite data was compressed.  Is that a common thing on Gameboy games?

Re: PokéWTrainer freeze

Posted by: Stackout
Date: 2014-03-28 17:22:27

First question: Where does the pattern "0039" come from?  I see it a lot when the game crashes.


No idea.

Second question:  If the sprite width comes from an address, could the address be a variable?  It would explain how " ." corrupts the sound when it appears sometimes, but other times doesn't.  Although I don't know why " ." doesn't corrupt the save data then…  Hm. 


Possibly. Depends on what is being pointed to.

Also, a correction:
(7*7 tiles, where a tile is 8 bytes long).

Tiles are 16 bytes long.  Two bytes per row of pixels.  As an example, this:

01010101
00001111

Would produce this:



Though you probably already know that. 

Also, I never knew that sprite data was compressed.  Is that a common thing on Gameboy games?


The "tile is 8 bytes long" thing is going by IIMarckus' disasm.

Regarding sprite data being compressed, I didn't know this either until I saw the relevant parts of the disasm. I assume some games would have compressed sprites to keep the rom size down.

Re: PokéWTrainer freeze

Posted by: pokechu22
Date: 2014-03-28 18:17:06

Also, a correction:
(7*7 tiles, where a tile is 8 bytes long).

Tiles are 16 bytes long.  Two bytes per row of pixels.  As an example, this:

01010101
00001111

Would produce this:



Though you probably already know that. 

Also, I never knew that sprite data was compressed.  Is that a common thing on Gameboy games?


The "tile is 8 bytes long" thing is going by IIMarkus' disasm.

Regarding sprite data being compressed, I didn't know this either until I saw the relevant parts of the disasm. I assume some games would have compressed sprites to keep the rom size down.


Hm.  I never knew there was a disassembly.  Found a link to it though; it is here

I have used a tool to create Gameboy sprites, and it said they could be exported to a "GB-COMPRESS"ed format, but I had no idea on the details.  These sprites are definitely compressed though.  Interesting.

Re: PokéWTrainer freeze

Posted by: TheZZAZZGlitch
Date: 2014-03-29 09:23:02
Where does the pattern "0039" come from?  I see it a lot when the game crashes.


When the game starts executing code from where it shouldn't, it will most commonly encounter an 'rst 38' instruction, and it's essentially the same as 'call $0038'. It will push the return address ($0039) onto the stack, and jump to address $0038.
At $0038, we have again:
[tt]0038: FF    rst 38[/tt]
So this is an infinite loop. It will keep writing $0039 to stack forever. Eventually, when the stack space runs out, it will start writing to other memory areas. Hence the vertical bars (corrupting VRAM) and erased save files (corrupting SRAM).

If the sprite width comes from an address, could the address be a variable?  It would explain how " ." corrupts the sound when it appears sometimes, but other times doesn't.  Although I don't know why " ." doesn't corrupt the save data then…


a) Sprite width cannot come from a variable address - it is always read from the base stats table. The sprite data itself may vary though.

b) Normally, viewing invalid Pokemon sprites or corrupting the whole address space in some other way won't corrupt the save file completely. It will corrupt the first 0x2000 bytes, but it won't affect the save. It's because SRAM has switchable banks, just like ROM. The save file is in bank 1, but the save corruption happens in bank 0.
But if the memory corruption somehow causes the bank to switch (for example, by writing $01 to $0000), the save will get erased.

Re: PokéWTrainer freeze

Posted by: Stackout
Date: 2014-03-29 09:36:20

Normally, viewing invalid Pokemon sprites or corrupting the whole address space in some other way won't corrupt the save file completely. It will corrupt the first 0x2000 bytes, but it won't affect the save. It's because SRAM has switchable banks, just like ROM. The save file is in bank 1, but the save corruption happens in bank 0.
But if the memory corruption somehow causes the bank to switch (for example, by writing $01 to $0000), the save will get erased.


OK. I figured SRAM had switchable banks, but I couldn't find any information about that at all.

Re: PokéWTrainer freeze

Posted by: Nerator
Date: 2014-04-09 08:48:56
Hey, Wack0! Just wanted to stop by and report something i noticed. May be it's not new, but i didn't see it, mainly because i'm new to glitching/memory hacking thing.
Anyway, i was inspired by MissingNoXpert LGPY series on YouTube, and i was kinda interested by pokemon "4 4" (hex BF), cause it was only one pokemon in range of 190-199 (which MissingNoXpert showed) to crash game every time. I got BGB emulator and dived in.
I didn't use Mew trick to encounter "4 4" (mainly because i'm too lazy of beating the game :P), so i just modified RAM at address $D058 to BF. After doing some seemingly random stuff with debugger i eventually, through some tries found some code that seemed to repeat many times. After comparing lines with IIMarckus's disasm (i understood, that adresses could vary in Yellow), i realised, that it was very same AlignSpriteDataCentered function/subroutine (don't know, how this things called exactly in asm), in Yellow it starts at address $149F. So i remembered your topic and wondered, if "4 4" crashed game exactly like PokeWTrainer, cause of sprite width. So here's piece of code from disasm:
AlignSpriteDataCentered: ; 16c2 (0:16c2)
ld a, [H_SPRITEOFFSET]
ld b, $0
ld c, a
add hl, bc
ld a, [H_SPRITEWIDTH] ; $FF00+$8b
.columnLoop
push af
push hl
ld a, [H_SPRITEHEIGHT] ; $FF00+$8c
ld c, a

So there game loads sprite offset, width and heigth from addresses $FF8D, $FF8B and $FF8C respectively. I think they're loaded there sometime earlier in the runtime from ROM. So i checked these addresses for "4 4" and yep, offset was 18h, but width and height were both 00.
Then i thought, may be i can encounter him normally if i change width and height manually? I checked values for Pidgey (were 05h and 28h) and encountered "4 4" again, but rigth as the game got to code at $149F i changed values at $FF8B and $FF8C and it worked like magic! I'll attach screenshots.
His sprite in your party and back sprite seems normal and don't crash your game, but it's hard to see because of this damn black glitchbox.
Sorry in advance if knew about it before, it was just my first sort of discovery in glitching, so i wanted to share! Also english is not my native language, so sorry for any mistakes.

Re: PokéWTrainer freeze

Posted by: pokechu22
Date: 2014-04-09 11:09:17

Hey, Wack0! Just wanted to stop by and report something i noticed. May be it's not new, but i didn't see it, mainly because i'm new to glitching/memory hacking thing.
Anyway, i was inspired by MissingNoXpert LGPY series on YouTube, and i was kinda interested by pokemon "4 4" (hex BF), cause it was only one pokemon in range of 190-199 (which MissingNoXpert showed) to crash game every time. I got BGB emulator and dived in.
I didn't use Mew trick to encounter "4 4" (mainly because i'm too lazy of beating the game :P), so i just modified RAM at address $D058 to BF. After doing some seemingly random stuff with debugger i eventually, through some tries found some code that seemed to repeat many times. After comparing lines with IIMarckus's disasm (i understood, that adresses could vary in Yellow), i realised, that it was very same AlignSpriteDataCentered function/subroutine (don't know, how this things called exactly in asm), in Yellow it starts at address $149F. So i remembered your topic and wondered, if "4 4" crashed game exactly like PokeWTrainer, cause of sprite width. So here's piece of code from disasm:
AlignSpriteDataCentered: ; 16c2 (0:16c2)
ld a, [H_SPRITEOFFSET]
ld b, $0
ld c, a
add hl, bc
ld a, [H_SPRITEWIDTH] ; $FF00+$8b
.columnLoop
push af
push hl
ld a, [H_SPRITEHEIGHT] ; $FF00+$8c
ld c, a

So there game loads sprite offset, width and heigth from addresses $FF8D, $FF8B and $FF8C respectively. I think they're loaded there sometime earlier in the runtime from ROM. So i checked these addresses for "4 4" and yep, offset was 18h, but width and height were both 00.
Then i thought, may be i can encounter him normally if i change width and height manually? I checked values for Pidgey (were 05h and 28h) and encountered "4 4" again, but rigth as the game got to code at $149F i changed values at $FF8B and $FF8C and it worked like magic! I'll attach screenshots.
His sprite in your party and back sprite seems normal and don't crash your game, but it's hard to see because of this damn black glitchbox.
Sorry in advance if knew about it before, it was just my first sort of discovery in glitching, so i wanted to share! Also english is not my native language, so sorry for any mistakes.


First off, your English was easily readable, although there were a few typos.  Also, do you think it would be possible to do this effect with a game genie code?  (there's a tool to make them here).

One final thing: you may be able to get a better sprite by using Super Gameboy mode or regular Gameboy mode.  Also, you might be interested in this effect TheZZAZZGlitch once got.

Re: PokéWTrainer freeze

Posted by: Spoink
Date: 2016-02-03 08:22:05
(and attempting to overwrite ROM, something that will never succeed except maybe in some lame flashcarts)


I know this topic is old, but I've seen pokemon gold overwrite the rom, on visualboyadvance. It had a bunch of 00s and 60s in the first few bites (most likely $0-100)

Re: PokéWTrainer freeze

Posted by: ISSOtm
Date: 2016-11-14 20:57:47

Where does the pattern "0039" come from?  I see it a lot when the game crashes.


When the game starts executing code from where it shouldn't, it will most commonly encounter an 'rst 38' instruction, and it's essentially the same as 'call $0038'. It will push the return address ($0039) onto the stack, and jump to address $0038.
At $0038, we have again:
[tt]0038: FF    rst 38[/tt]
So this is an infinite loop. It will keep writing $0039 to stack forever. Eventually, when the stack space runs out, it will start writing to other memory areas. Hence the vertical bars (corrupting VRAM) and erased save files (corrupting SRAM).

Hello, £e Nécrobumper here.

Actually, all rst vectors in RBY have a FF instruction, which means any rst instruction is basically an entry point towards that infinite loop… heh.

Also, save files should not be corrupted, since SRAM only unlocks when a $0A is sent. Unless you're using a crappy emulator… why, hello VBA ! Long time no see !
Furthermore, no function that opens SRAM has the potential to crash (maybe VBlank could ? That'd explain)

Re: PokéWTrainer freeze

Posted by: Ketsuban
Date: 2016-11-18 11:16:08
I wonder why they did that.

Re: PokéWTrainer freeze

Posted by: Torchickens
Date: 2016-11-18 14:54:38

I wonder why they did that.


Wack0 and I were talking about this and he wondered whether rst $38 was a good idea for debugging, because if the memory is filled with 00 39 you know a rst $38 is very likely to be the cause.

Re: PokéWTrainer freeze

Posted by: Yeniaul
Date: 2016-11-18 15:30:47
Wait… if my understanding of the GBz80 and ROM structure is correct, theoretically, couldn't you just replace the chain of "rst $38" at the beginning of the ROM to code that jumps back to the RST address + 1? So, in Python2-esque format, something like

LastPC = F572 #whatever
PC = F573 #or something, really doesn't matter
if instruction == FF: #whatever, works for example
>>jump(0038) #standard "rst $38" behavior
LastPC = F573 #works for example
PC = 0038 #due to jump
#and, at $0038, lies:
jump(LastPC + 1) #so we jump OVER the FF, not back TO it


So… anyone see this in gbz80 ASM?

Re: PokéWTrainer freeze

Posted by: ISSOtm
Date: 2016-11-18 18:32:12

I wonder why they did that.

The rst $38 instruction is actually one byte long. Guess which byte ? Why, it's a $FF ! So I guess they just put some FF bytes because it made sense (when you put a filler value, you usually put $00 or $FF ; however $00 is more "blank"… so they put $FF as fillers anyways.)



I wonder why they did that.


Wack0 and I were talking about this and he wondered whether rst $38 was a good idea for debugging, because if the memory is filled with 00 39 you know a rst $38 is very likely to be the cause.

To debug, something better would have been a jump to a function that prints stuff like stack info, instead of just… crashing.


Wait… if my understanding of the GBz80 and ROM structure is correct, theoretically, couldn't you just replace the chain of "rst $38" at the beginning of the ROM to code that jumps back to the RST address + 1? So, in Python2-esque format, something like

LastPC = F572 #whatever
PC = F573 #or something, really doesn't matter
if instruction == FF: #whatever, works for example
>>jump(0038) #standard "rst $38" behavior
LastPC = F573 #works for example
PC = 0038 #due to jump
#and, at $0038, lies:
jump(LastPC + 1) #so we jump OVER the FF, not back TO it


So… anyone see this in gbz80 ASM?

Or just :

ret

which is

C9


Actually, rst $38 is equivalent to call $0038, with two exceptions :
1. Only one byte long.
2. Because it is two bytes smaller than call $0038, it is also 8 M1 cycles faster (8 processor cycles, to simplify).

It has one downside, though : you can't do conditionals with rst's.


Yeniaul, actually that'd be a ROM hack. TheZZAZZGlitch's Debug Yellow actually has code for the rst vectors that allows them to be "fixed" (either they can act like NOPs, or double-return, or manipulate the stack).

Also, that it not a chain of rst 38's. It's just that there is this :
ROM0:0038  rst 38          FF
Basically, the instruction at $0038 is a call to 0038. So here is what happens :

1. Read a $FF byte (form the code, or from any other rst vector)
2. Push the low byte of PC+1 on the stack
3. Push the high byte of PC+1 on the stack
4. Set PC (program counter) to $0038
5. Read a $FF byte at $0038
6. Push the low byte of PC+1 (= low($0038 + 1) = low($0039) = $39) on the stack
7. Push the high byte of PC+1 (= high($0038 + 1) = low($0039) = $00) on the stack
8. Set PC (program counter) to $0038
9. Goto step 5

Low bytes are first because we have a little-endian processor here ;)

So, what will happen first  is that the stack, usually located between $DF00 and $DFFF, will first overflow into Box Pokémon data when it reaches DEE1 ; then it will corrupt your play time (although in less than a frame it won't matter anymore :P), then the opposing Pokémon data, right before it also gives you some level 57 ($39) 'Ms… but right after that grass encounters will be removed :(
Then objets such as collectible items will despawn and respawn on their maps, then you'll get 3900 Casino Chips (which is… cool, I guess ?). Immediately after, you'll get your PC crammed with Max Repels x0 :D… but you will have 0 items there >.>
Then the stack will proceed to corrupt tile metadata, map metadata (including setting the script pointer to $3900, lol), player ID, badges and options, rival name (like BG tileXX ERROR but not terminated anymore :P), then it will make your purse contain exactly 3900 pokédollars (even though Red won't experience a single frame of having this money, derp), then the pack will fill with 20 stacks of hex:00 glitch items… and OMG THE ITEM PACK CONTAINS 57 ITEMS NOW !!! ITEM UNDERFLOW CONFIRMED !!!!!!1
Then the Pokédex will freak out just a lil'bit (maybe giving us Pokémon #152 in the process, too lazy to figure dat out), then it will turn your beloved Pokémon into some Mankeys and other Pokémon you already know about (the sixth will make you cry !), then give ya the same name as your rival. Then battle-related memories will be screwed up badly.

Now that people aren't right, the world will begin to screw up heavily.
First, menu data will be severely affected. Then all of the game's working data will be overwritten with that obnoxious 0039 pattern. Then tile buffers will be also screwed up (the game won't even have the time to use them anyways), then sprites and NPC will distort in horrible, painful ways. Then sounds will distort.

Then the stack pointer reaches save RAM. If it was open, then behavior differs between loaded banks. Bank 0 will just have your Hall of Fame corrupted (seriously, who cares). Bank 1 will have your main save data corrupted. Bank 2 and 3 will have boxes corrupted.
So, really, other than bank 0, that'll be… "your save file was destroyed !".

Then comes VRAM. Maybe it will be open ; maybe not. But if it is open, first all the screen will be covered with alternating patterns of $00 and $39 tiles. But you won't be able to see it for any more than a single frame if VRAM locks up at this exact moment. Otherwise tiles will be corrupted all with vertical lines of $0039 (little-endian, huh !).

Then comes ROM.
First, the MBC1 banking mode will be set alternatively to 0 and 1 (wow, that doesn't damage the cartridge ? Phew.), then ROM banks 1 and 9 will be alternated between. Then SRAM will be locked again (due to writing non-$0A values). Ironically, during that time, the rst 38 instruction will be overwritten with a $39 (add hl, sp). Because ROM is write-only, nothing happens. Otherwise pretty whacky stuff would go on from then on :D

But $0000 is an end. But after the end is more ; SP is just a 16-bit register.
SP can underflow.
And thus $FFFF (interrupt enable) gets zeroed, and HRAM is zerg-rushed by hordes of $00s paired up with $39s.
Then all sorts of GB registers are overwritten, which should have nice effects. (info here)
Then the stack pointer eliminates the last resistance : OAM. Echo RAM had already submitted itself in the same time as Echo RAM.

Be aware that while all of this is going on, IFF1 is disabled, meaning that interrupts are inhibited. So, all that is going on when the game seems to have crahsed is that is is permanently writing these $0039's to memory. The CPU doesn't crash or freeze. It's just stuck writing these $0039's because it keeps calling the same address.

Now, all writable memory is conquered. And read-only memory has been reduced to silence, since the 0039s have infinite powers and have the CPU all for themselves.
They are almighty.
They rule the GB.
The whole GB.
In less than a frame.

And then the player resets the console, the end.

What a touching story.



[EDIT] I realized I swapped 00s with 39s. I'm too lazy to rewrite all, so imagine it yourself, I'm going to bed.


___________________________________________




Useless trivia :
- Actually, the z80 has several "interrupt" modes that were removed from the gbz80 ; interestingly, mode 0 was triggered by grounding one of the CPU's pins, which made the CPU execute whichever byte was on its data lines. rst's were likely to be created for just that.
- Mode 1 periodically triggered some rst $38's
- Mode 2 periodically triggered a read from an address table, the reading index being given by the data lines at the time on the interrupt. I guess that's how the gbz80 is locked to be.

Re: PokéWTrainer freeze

Posted by: Yeniaul
Date: 2016-11-19 18:57:28

Also, that it not a chain of rst 38's. It's just that there is this :
ROM0:0038  rst 38          FF

ROM0:0000 FF              rst  38
ROM0:0001 00              nop 
ROM0:0002 00              nop 
ROM0:0003 00              nop 
ROM0:0004 00              nop 
ROM0:0005 00              nop 
ROM0:0006 00              nop 
ROM0:0007 00              nop 
ROM0:0008 FF              rst  38
ROM0:0009 00              nop 
ROM0:000A 00              nop 
ROM0:000B 00              nop 
ROM0:000C 00              nop 
ROM0:000D 00              nop 
ROM0:000E 00              nop 
ROM0:000F 00              nop 
ROM0:0010 FF              rst  38
ROM0:0011 00              nop 
ROM0:0012 00              nop 
ROM0:0013 00              nop 
ROM0:0014 00              nop 
ROM0:0015 00              nop 
ROM0:0016 00              nop 
ROM0:0017 00              nop 
ROM0:0018 FF              rst  38
ROM0:0019 00              nop 
ROM0:001A 00              nop 
ROM0:001B 00              nop 
ROM0:001C 00              nop 
ROM0:001D 00              nop 
ROM0:001E 00              nop 
ROM0:001F 00              nop 
ROM0:0020 FF              rst  38
ROM0:0021 00              nop 
ROM0:0022 00              nop 
ROM0:0023 00              nop 
ROM0:0024 00              nop 
ROM0:0025 00              nop 
ROM0:0026 00              nop 
ROM0:0027 00              nop 
ROM0:0028 FF              rst  38
ROM0:0029 00              nop 
ROM0:002A 00              nop 
ROM0:002B 00              nop 
ROM0:002C 00              nop 
ROM0:002D 00              nop 
ROM0:002E 00              nop 
ROM0:002F 00              nop 
ROM0:0030 FF              rst  38
ROM0:0031 00              nop 
ROM0:0032 00              nop 
ROM0:0033 00              nop 
ROM0:0034 00              nop 
ROM0:0035 00              nop 
ROM0:0036 00              nop 
ROM0:0037 00              nop 
ROM0:0038 FF              rst  38
ROM0:0039 00              nop 
ROM0:003A 00              nop 
ROM0:003B 00              nop 
ROM0:003C 00              nop 
ROM0:003D 00              nop 
ROM0:003E 00              nop 
ROM0:003F 00              nop 

Not that any of the others MATTER, it's just I like to be accurate :P

Also, just a C9 doesn't do jack, as, like you said,
Now, all writable memory is conquered. And read-only memory has been reduced to silence, since the 0039s have infinite powers and have the CPU all for themselves.