Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Dragon Warrior III Dream Ruby glitch (aka numbness glitch, item glitch)
- =======================================================================
- By forming a party consisting of only dead characters, you can confuse
- the game into modifying your party's status in useful ways, such as
- changing weak armor into strong weapons and getting access to endgame
- towns through the Return spell.
- Cause of the glitch
- -------------------
- Each time you take a step, the game checks the square each character
- just stepped onto and applies damage if it's a swamp or barrier square.
- The game is smart enough not to try and damage characters who are dead,
- but it assumes there's always at least one living character in the party
- -- which the game normally ensures by preventing you from removing your
- last living character at Luisa's Place, but if that character is numb,
- the game lets you leave that character behind anyway, giving you a party
- of only dead characters. You can also end up with a party of 1 dead
- character (the hero) by going to the fortuneteller in Assaram with the
- hero dead and all other living characters numb, typically accomplished
- by using the Dream Ruby on the other characters (hence the name of the
- glitch).
- Once you do get an all-dead party, the damage check gets confused and
- tries to check a whopping 256 characters for damage. Depending on what
- data happens to be in memory, some of those "characters" will take
- "damage" by subtracting 2 from the memory location that would have the
- current HP of that character. If the right "character" triggers damage,
- the memory location will be where the party's items are stored, causing
- an item to change to the item 2 steps before it in the item list, or
- where the Return destination list is stored, giving access to towns you
- haven't yet visited.
- Technical details
- -----------------
- When moving to a new tile, $D389 does a far call to $B16A in bank 14.
- This routine has two purposes: auto-cure any numb characters (1/16
- chance per character per step) and check each non-dead character for
- field damage. The routine first initializes variables for the damage
- check by calling $B1BD, then performs the check itself at $B1EE.
- The main purpose of $B1BD is to count the number of living characters in
- the party. This count is stored to $66, and a list of party indices of
- the living characters is stored starting at $68. Zero is stored in $67
- to initialize the counter for $B1EE.
- $B1EE performs the field damage check as follows:
- 1) Load the current counter value ($67) into register Y.
- 2) Load the index of the tile under party member Y from $93+Y.
- 3) If the map type ($9A) is zero (the overworld) and the tile index
- is $07, apply swamp damage and go to step 6. (This is effectively
- dead code since the tile type for overworld tile index $07 is $05,
- so swamp damage would be applied anyway.)
- 4) Load the tile type for the tile index from $6DE0 (indexed by the
- low 5 bits of the tile byte; the high 3 bits are the layer number
- in towns and dungeons).
- 5) If the tile type is $05, apply swamp damage; if the tile type is
- $06, apply barrier damage.
- 6) Increment the counter.
- 7) If the counter is not equal to the number of live party members
- ($66), repeat from step 1.
- Note that the counter is not checked against the limit until the end of
- the loop, and it is tested for equality, so if there are no living party
- members, the loop will iterate 256 times before the counter overflows
- from 255 to 0 and the stop condition becomes true.
- Damage is applied by loading a byte from the array at $68 (indexed by
- the current counter value) and calling the damage routine, which
- subtracts the damage from the character's current HP (HP is stored as 4
- 16-bit values at $071C).
- In order for the bug to occur, at least one tile type on the map must be
- $05 (swamp) or $06 (barrier). This is true, for example, in the second
- floor of Luisa's Place (map $44, tile type index $01). Using that map
- as an example, any zero-page byte whose low 5 bits are 00001 will cause
- 2 to be subtracted from an even address in the range $071C...$081A (due
- to NES memory mapping, $0800...$081A are mapped to zero-page addresses
- $00...$1A). For a byte at zero-page address A which triggers damage,
- the party index will be loaded from zero-page address A minus $2B (the
- difference between $93 and $68); if the value of the byte at that
- address is B, 2 (swamp) or 15 (barrier) will be subtracted from the byte
- at address $071C + ((B & 127) * 2).
- Potentially useful addresses to modify are:
- - $0746, $074C: High byte of experience for characters 1 and 3, which
- can be underflowed to level the character up to 99 in the next
- battle. Requires a party index byte of $15 or $18, respectively,
- and requires the next character's experience to not be a multiple
- of 256.
- - $0752, $0758: 3rd byte of Return list for characters 1 and 3 (if
- zero, swamp damage will change it to $FE, allowing access to
- endgame towns -- note that the borrow clears the Aliahan bit for
- the next character). Requires a party index byte of $1B or $1E,
- respectively.
- - $077C...$079A: Party inventory. The 1st, 3rd, 5th, and 7th items
- in each character's inventory can be changed; underflowing will
- also change the following item (as long as that item is not ID 0,
- an unequipped Cypress Stick). Requires a party index byte of
- $30...$3F.
- - $079C...$07BA: Party spells. The 3rd page of battle spells can be
- underflowed if the field spell byte is nonzero (as is the case for
- a level-1 Pilgrim, for example). Requires a party index byte of
- $41...$4F (odd values).
- - $07BE: High byte of party gold. Gold will not be capped at 99999
- when buying items (though the number displayed in the gold window
- is capped at 99999). On underflow, this marks the first slot in
- the stored character list (normally occupied by the hero) as empty;
- creating a new character at Luisa's Place 2F would then overwrite
- the hero's data in the save file. Requires a party index byte of
- $51.
- - $07C2: Stored-character index (in the adventurer list) for the 2nd
- party member. This could be underflowed to a large value, though I
- haven't investigated whether this would produce any useful effects.
- Underflowing would also decrement the index of the third party
- slot, which could potentially allow having two copies of the same
- character in the party. Requires a party index byte of $53, and
- requires the hero to not be in the third party slot.
- In all cases, the party index byte is shifted left to address the HP
- value, so the high bit of the byte can be either 0 or 1.
- Note that some bytes which seem like they might be useful to underflow
- (maximum HP, for example) can't be underflowed because the next byte is
- zero; the damage routine treats the two bytes as a 16-bit integer, and
- will not attempt to reduce it below zero.
- Also note that if you underflow the third spell page for a Pilgrim, Heal
- will be removed from the field spell list. If you also subtract 2 from
- the first spell page, the character will (if at level 1 or 2) learn Heal
- at the next level-up.
- The following addresses can trigger damage on Luisa 2F:
- - The random number seed ($1C and $1D) will trigger damage if it has
- the proper value.
- - $2F will be $01 in towns, which triggers damage if $01 is a swamp
- tile (as on Luisa's Place 2F)
- - The lead character position ($30 and $31) can trigger damage; for
- example, on Luisa 2F, tile index $01 is a swamp tile, so X or Y
- coordinate 1 (the top or left edge of the map) will trigger
- damage.
- - $83 appears to be used as a temporary in message processing, and
- it can take on values which trigger damage.
- - The map number ($8B) and map type ($9A) could potentially trigger
- damage. Maps with type $01 are: $00 (Aliahan), $06, $07, $0A
- (Portoga), $0D (undefined map), $12, $50 (Isis), $96 (Isis oasis).
- - $9D receives the low 2 bits of a random value every 64 frames on
- the overworld if no party members are standing on a town. There
- are no swamp or barrier overworld tiles in the $00-$03 range, but
- since the value does not change while in a town, it could be set
- on the overworld and then used in a town to trigger damage.
- - $A4 is a counter which increments with each random number
- returned; it could be manipulated to trigger damage.
- - The music data pointers at $D6...$DD could trigger damage.
- - The sound timers at $E2...$E9 and envelope offsets at $F7, $F9,
- $FB, and $FD could trigger damage, though timing would be tight.
- Additional values which can trigger damage on Luisa 2F:
- - Consistent: $34, $45, $71, $73, $8D, $99, $B5, $C8, $CF, $DD.
- - Inconsistent (conditions not yet known): $0A, $0E, $12, $75, $77,
- $79, $7B.
- Additional values which can trigger damage on the overworld:
- - The byte at $01 is consistently $07, which triggers damage.
- The associated character index byte is at $D6, the low byte of the
- first music channel data pointer.
- - $6C is consistently $E7 (low byte of the end of the overworld
- entrance list at 6/$B387) at entry to $B1EE, which would trigger
- damage, but it's cleared by other code if any preceding byte (such
- as $01) triggers damage.
- The bug is also present in the initial release of the Japanese version
- of the game (Dragon Quest III), though it was reportedly fixed in a
- later rerelease. Since DQ3 limits names to four letters (kana) long,
- all data at $077C and later in DW3 is shifted 16 bytes toward $0700; for
- example, inventory data is located at $076C rather than $077C.
- Stick Slime glitch
- ==================
- The Stick Slime is a dummy item which can be obtained via the Dream Ruby
- glitch by glitching an empty inventory slot. The game has 125 different
- items, but the format of the inventory data allows for 128 different
- item types, so setting an inventory slot to one of those 3 unused types
- causes the game to read parts of the program code as item data.
- When you try to use an item, the game checks a table that tells it
- whether the item can actually be used and what to do when you use it.
- For the Stick Slime, the game reads part of the program code that makes
- it think the item can be used, but the data that says what to do with it
- points into the middle of nowhere, so the results are random: sometimes
- you can get several item messages at once, sometimes the game will
- crash or do other strange things, sometimes nothing will happen.
- Technical details
- -----------------
- $AE12 in bank 0 is called when using an item on the field. This routine
- first looks up the item's data in the table at $922B; bit 7 of the value
- indicates whether the item can be used at all. If so, or if (as applies
- here) the item number is at least $77, the routine then looks up a jump
- pointer for the item effect subroutine, which is stored in a 3-byte-per-
- entry table (the first byte appears to be a flag byte) at $B0C5, which
- only has entries for field-usable items. The Stick Slime is item $7D;
- as $7D is the first invalid item number, the effect routine pointer is
- read from the first 3 bytes after the end of the $B0C5 table, which gives
- the pointer $2948.
- $2948 is within the PPU register region, pointing to (a mirror of)
- PPUCTRL. The CPU attempts to read an opcode from this address and gets
- open bus, which will be $29 (the high byte of the address read for the
- indirect jump). $29 is AND #imm, so the CPU reads an operand byte from
- $2949 (PPUMASK); this is also write-only, so the CPU gets $29 from open
- bus again.
- The next instruction is found at $294A; this is PPUSTAT, which will
- return $00 (BRK) at the time this particular code is executed. Dragon
- Warrior III implements BRK as a sort of far call instruction, with two
- operand bytes which indirectly select the function to be called (via
- table lookup). The first byte will be at $294B (OAMADDR), which is
- write-only so the CPU gets $29 from open bus (the high byte of the
- indirect address used for the load). The second byte, however, will be
- at $294C, or OAMDATA; since this code will execute while the PPU is
- rendering the screen, the byte loaded will be depend on the precise
- timing of the read. The BRK handler uses table lookup rather than
- directly taking the address from the operand bytes, so this won't
- necessarily lead to a crash, but the particular behavior is effectively
- random.
- Incidentally, the subroutine pointer for item $7E (Black Raven) is $D385
- ($85 $D3 = sta $D3), which is also used for item $7F (Sword Horned)
- since that item's flag byte doesn't have bit 7 set and the table offset
- consequently isn't incremented for that item. This address happens to
- lie right before the normal call to the field damage subroutine, which
- is what got all this started in the first place. Coincidence or
- insanely clever inside joke? You decide.
- The names of the invalid items come from overrunning the name tables;
- for example, "Stick" is the second line of the name of the first item
- (Cypress Stick), and "Slime" is the first line of the name of the first
- enemy (Slime). The garbage character at the end of "Slime" is a code
- used in enemy names to indicate how the name is pluralized.
- Is arbitrary code execution possible?
- -------------------------------------
- I really, really want to say "yes", just because it would be so much
- fun. But unfortunately, it doesn't seem to be possible, at least not
- reliably.
- The most likely exploitable path would be to read a value of $xF from
- OAMDATA with $4 <= x <= $E; this causes the BRK handler to select bank
- $1x at $8000, treat $8000 as a table of addresses, and jump to the
- address at the entry in that table selected by the first BRK operand
- byte -- here $29, so the jump target is read from $8052. Potentially
- exploitable values for the second operand byte include (note that on
- entry, A is the party index of the character who has the Stick Slime, X
- is $16, and Y is $29 from open bus):
- - $5F => $691D; this is the second byte of the 10th character's spell
- list in the third save file.
- - $6F => $68A8; this is the fifth inventory slot of the 7th character
- in the third save file.
- - $AF => $0F00; this mirrors to $0700 and is the beginning of the
- active party data.
- - $BF => $C915; this jumps into the middle of another subroutine with
- PLA instructions following, so stack manipulation might be
- possible.
- However, the possibilities for finding one of these bytes in OAM are
- limited. Sprites in DW3 are positioned with an offset (0,4) from
- multiple-of-8 coordinates, so byte 0 of a sprite entry will always be
- $x3 or $xB and byte 3 will always be $x0 or $x8. Bits $1C of byte 2
- are always zero, so that leaves finding a sprite that uses one of the
- values above in its tile set and triggering the OAMDATA read at the
- exact instant (one of 2 cycles) the PPU is copying that byte to the
- secondary OAM during sprite evaluation.
- If the Stick Slime could be used in battle, data past the end of the
- battle effect routine list ($BE3A, 53 entries) gives some interesting
- pointers, like $0558 (found at offset $72; this is the battle command
- data list, so you could write e.g. $20 $65 $65 by using Clothes,
- Medical Herb, Medical Herb with the first 3 characters, use the Stick
- Slime with the 4th character, and jump into the second save file's
- inventory data). Unfortunately, the item flags for battle are located
- right before the field flags, so the overflow items overlap with the
- first three items in the field list, which are weapons and thus not
- field-usable. Even if they were, the corresponding effect byte past the
- end of 4/$B270 is $00, which is handled properly by the code (it would
- be treated like the Blaze spell). This applies to the other invalid
- items as well.
- On the Japanese version (Dragon Quest III), the Stick Slime routine
- pointer is $8100, in the middle of a separate routine, and the Black
- Raven pointer is $6600, in the second save file's spell list. The
- latter is promising, but unfortunately, when the game tries to write any
- of the glitched item names to the text window, it crashes due to
- overflowing a temporary buffer for copying the name. (DQ3 uses a
- different method to store names, with a length byte following the name
- of the item. The name copy loop has a similar bug to the Dream Ruby
- glitch in that a length of zero results in copying 256 bytes. The
- buffer is located at $0634, so copying 256 bytes will overwrite all the
- state information stored at the end of the $06xx page, such as the
- current $8000 bank index which is stored at $06D5.)
Add Comment
Please, Sign In to add comment