The current URL is datacrystal.tcrf.net.
Secret of Evermore/Alchemy RAM manipulation: Difference between revisions
No edit summary |
No edit summary |
||
Line 675: | Line 675: | ||
==Routing the Exploit== | ==Routing the Exploit== | ||
===Setup=== | ===Setup=== | ||
* Secret of Evermore | |||
** US | |||
* lsnes | |||
** Arbitrary 64 bit inputs | |||
** LUA scripts (Which are required for the) | |||
===Examples for Executing Code=== | ===Examples for Executing Code=== | ||
Line 686: | Line 691: | ||
! Comment | ! Comment | ||
|- | |- | ||
| EA EA EA EA EA CB 80 F8 | |||
| Do nothing (Also synchronizes the ACE) | |||
|- | |||
| A9 XX XX EA EA CB 80 F8 | |||
| Store value in accumulator | |||
|- | |||
| 8F XX XX XX EA CB 80 F8 | |||
| Store accumulator in memory | |||
|- | |||
| 60 60 60 60 60 60 60 60 | |||
| Exit ACE | |||
|} | |} | ||
'''Caveat:''' | |||
* $CB waits till the next interrupt (Which might not be long enough) | |||
* The last 3 bytes cannot be changed, because it'd desync the process | |||
====Frame Counter==== | ====Frame Counter==== |
Revision as of 20:16, 14 January 2020
This is a sub-page of Secret of Evermore.
Affects of the Alchemy Crash to a Player
Details
Usually there are only up to 2-3 spells active, because the game limits how many can be cast:
- The boy has an internal cooldown on opening the ring menu after using alchemy
- Bosses have some kind of internal cooldown
- Only 8 alchemy spells per type can be active at any given moment
- Particle type alchemy (like Flash and Fireball)
- Animation type alchemy (like Crush and Acid Rain)
But there are known ways to circumvent these limitations:
- Opening the boys ring menu as the dog can be done once per frame (Also known as 8cast, because the same spell can be cast up to 8 times)
- Bosses cast their spells regardless of the limit (See Enemies Casting Spells)
- Magmar casts at a certain damage threshold Heat Wave, which is an animation spell
- Aquagoth randomly casts Lightning Storm and other spells, which are animation spells
- Verminator randomly casts Acid Rain and other spells, which is are animation spells
Additional facts:
- The 2x8 alchemy slots aren't cleared once the spell has been resolved, they are just flagged as inactive (Leaving the game overrides most memory with zeros, though)
Crash
Once the game tries to put the 9th alchemy spell in a slot the game somewhat freezes:
- The game no longer progresses states
- User inputs are blocked
- Spell projectiles stop moving
- Enemies stop moving
- The music keeps playing the most recent loop (because it's not linked to the hardware)
In very rare cases the game does not crash and the following effects may occur based on what memory is being executed:
- Severe visual glitches
- Black screen
- Repeating patterns
- Corrupted HUD
- Corrupted background
- Side effects to the projectile
- Animation alchemy like healing is randomly applied (E.g. Healing)
- The projectile might fly in random directions (E.g. orbiting the boy, or flying outside the screen)
Reproducing the Crash
- Cast a projectile alchemy spell near the exit of a map
- Leave the screen instantly (before the projectile has been processed)
- Unfinished projectiles are being flagged as "currently active" and cannot be reused anymore
- This also circumvents the "only 8 per school" limitation, because it uses a separated stack
- Once the 9th projectile is being cast the game "freezes"
Manipulating Memory
Details on the Crash
Casting 6 Hard Balls in the transition leads to the game crashing on the next 3+cast, which in almost all cases looks the same:
9198f7 ldx $0014,y [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:226 F:48 9198fa beq $9907 [919907] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:236 F:48 9198fc lda $0028,y [7e338c] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:239 F:48 9198ff sta $4c [00004c] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:249 F:48 919901 jsl $919750 [919750] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:256 F:48 919750 lda $910000,x [91d22c] A:4e89 X:d22c Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 72 H:270 F:48 919754 tax A:800a X:d22c Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:279 F:48 919755 jsr ($8000,x) [91000a] A:800a X:800a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:282 F:48 00885f stp A:800a X:800a Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 72 H:312 F:48
Address/Value | Register/Usage | Comment |
---|---|---|
$7E3378 (16 bit) | X | Is the 14th and 15th byte of the first animation alchemy slot ($7E3364-$7E3563, 40 bytes per slot) |
$7E338c (16 bit) | A | Is the 28th and 29th byte of the first animation alchemy slot ($7E3364-$7E3563, 40 bytes per slot) |
$910000 | Base jump address for both X values | Bank $91 mirrors bank $11 ($0000-$1FFF refer to LowRAM) |
$8000 | Final jump offset | - |
Which means that the jump address can be altered, by altering the first animation alchemy slot.
- Store 2 bytes from $7E3378 in X_alchemy
- $7E3378 happens to be the 14th and 15th byte of the first animation alchemy slot
- MSB: $7E3379 (Seems to be some kind of timer which advances after $7E3378 overflows)
- LSB: $7E3378 (Seems to be some kind of timer which advances after each partial animation)
- Read 2 bytes from $910000+X_alchemy
- X_alchemy=$0000-$1FFF happens to be LowRAM
- MSB: $910000+X_alchemy+1 refers to $7E000+X_alchemy+1
- LSB: $910000+X_alchemyrefers to $7E000+X_alchemy
- Store that new value in X_ram
- Jump to $918000+X_ram
This leads to the following formula: (Random value for X_alchemy)
[$7E3378] = $002B = X_alchemy Jump [$91002B] = $8080 = X_ram (Has an offset of $8000) Jump with offset [$910080] = $FFFE Jump Execute code
Or shorter:
[7E_3378]=0x002B -> [91_002B]=0x8080 -8k-> [91_0080]=0xFFFE -> [91_FFFE]=??? (Execute code)
Therefore the code can be manipulated by altering the indirect, indirect (with offset) jump.
Manipulating X_alchemy
To this point it's not known if X_alchemy can be overwritten at the right moment. Therefore it has to be routed with RNG first.
Examples:
Seed=$D22C:
[7E_3378]=0xD22C -> [91_D22C]=0x800A -8k-> [91_000A]="???" (In LowRAM)
9198f7 ldx $0014,y [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:226 F:48 9198fa beq $9907 [919907] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:236 F:48 9198fc lda $0028,y [7e338c] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:239 F:48 9198ff sta $4c [00004c] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:249 F:48 919901 jsl $919750 [919750] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:256 F:48 919750 lda $910000,x [91d22c] A:4e89 X:d22c Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 72 H:270 F:48 919754 tax A:800a X:d22c Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:279 F:48 919755 jsr ($8000,x) [91000a] A:800a X:800a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:282 F:48 00885f stp A:800a X:800a Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 72 H:312 F:48
Seed=$0003:
[7E_3378]=0x0003 -> [91_0003]=0xC900 -8k-> [91_5900]="???" (In Unused)
9198f7 ldx $0014,y [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:176 F:31 9198fa beq $9907 [919907] A:000a X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:186 F:31 9198fc lda $0028,y [7e338c] A:000a X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:189 F:31 9198ff sta $4c [00004c] A:4e89 X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:199 F:31 919901 jsl $919750 [919750] A:4e89 X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:206 F:31 919750 lda $910000,x [910003] A:4e89 X:0003 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 45 H:220 F:31 919754 tax A:c900 X:0003 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 45 H:230 F:31 919755 jsr ($8000,x) [914900] A:c900 X:c900 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 45 H:233 F:31 918080 iny A:c900 X:c900 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 45 H:246 F:31 918081 sta $a841,y [7edba6] A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e nvmxdizC V: 45 H:249 F:31 918084 stx $a7 [0000a7] A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e nvmxdizC V: 45 H:259 F:31 918086 ora ($ab),y [7edaf8] A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e nvmxdizC V: 45 H:266 F:31 918088 rti A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e NvmxdizC V: 45 H:278 F:31 00885f stp A:c900 X:0000 Y:0065 S:1fec D:0000 DB:7e nVmXdIZC V: 45 H:307 F:31
With RNG
Based on yet unknown factors seemingly random values between $0000 and $FFFF are being used. That leads to different jumps for every X_alchemy value, unless the RNG has been locked.
Observed patterns:
- $7E3379 seems to be either $00 or $FF, most of the time
- $00-$1F are LowRAM ($01-1F contain relevant values)
- $7E3378
- Seems to be rather random
This leads to mostly to two specific memory blocks:
Memory | Values | Comment |
---|---|---|
$9100xx | 00 00 ?? 00 ?? ?? ?? ?0 0? 00 00 00 ?? ?? 0? 00 64 35 ?? 01 ?? 51 e8 00 c9 00 3? 00 ?? ?? 00 00 00 00 f? ?? ?? 00 ?? ?? c? 8e ?? 80 ?? 00 ?? 0? e2 00 00 00 60 01 a7 80 a7 00 00 c3 7f 00 12 00 0d 00 00 00 10 00 27 00 03 00 74 02 ?? 4? ?? 0? 1? 00 0? 00 ?? 00 xx_xx 7f xx_xx xx_xx ?? ?? c7 00 00 00 00 00 00 ?? ?? 10 ?? 0? 10 50 36 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ff xx 00 00 00 00 00 00 00 01 00 80 a7 09 04 00 00 02 0c c4 34 08 xx 99 8e ff 00 00 00 85 14 00 00 8a 00 00 00 00 e4 81 a7 4f 93 a7 2e 13 7f 00 00 a7 00 00 00 00 00 00 00 00 00 00 00 00 70 02 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 40 96 0? 00 ?? 00 ?? 0? ?? 00 ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
LowRAM contains a lot of volatile values:
|
$9101xx | xx_xx_xx_xx xx_xx 0f 00 00 00 00 00 04 00 b8 02 17 01 2d 02 df 00 00 00 ff ff 00 00 ff 00 ff 00 ff 00 00 00 00 8b 85 80 00 00 80 8b 85 80 00 00 00 00 00 93 50 46 91 fe 92 23 1b 78 00 78 00 80 64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80 ... |
Slightly out of range for $9100xx |
$91ffxx | 00 01 00 c0 00 00 00 00 00 00 00 80 00 00 07 00 1f 00 01 00 c0 00 00 00 00 00 00 00 80 80 00 e0 00 80 00 00 00 00 00 03 00 00 00 00 00 00 80 00 e0 00 80 00 00 00 00 00 03 00 00 00 00 e0 00 80 00 00 00 00 00 07 00 00 00 00 00 00 00 00 e0 00 80 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 e0 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 00 f0 00 00 00 00 00 00 3f 03 00 00 00 00 00 00 00 03 00 1f 00 01 00 00 00 00 03 00 00 00 00 00 00 00 03 00 1f 00 01 00 00 80 00 00 00 00 00 00 00 c0 00 f0 00 c0 00 00 00 00 80 00 00 00 00 00 00 00 c0 00 f0 00 c0 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 00 70 00 00 00 08 |
ROM |
Bytes that can be manipulated:
Address | Values | Comment |
---|---|---|
$0056-$0057 | ? | Unknown purpuse, but any moving entity changes this value deterministically (Therefore hard to manipulate)
Coordinates over $0FFF don't exist! |
$0059-$005A | $0000-$0620 (Utopia map) | Copy of the camera offset X (Can be pause buffered)
Coordinates over $0FFF don't exist! |
$005B-$005C | $0000-$0440 (Utopia map) | Y (See $0059-$005A) |
$0082 | $00-$FF? | Lower half of the pointer to the most recent script ($83 and $84 get cleared) |
$0095 |
|
Most recent ring menu ($93 and $94 get cleared)
Other menus can't be closed without entering the boys or dogs ring menu |
Slightly outside $9100FF | ||
$0100-$0103 | $00000000-$FFFFFFFF | Frame counter |
$0104-$0105 | ? | Controller inputs (Player 1) |
X_alchemy values that load specific values as X_ram:
X_alchemy | X_ram | Comment |
---|---|---|
$0081 | $xxFF | See $0082 |
$0082 | $00xx | $82 can be manipulated by triggering scripts |
$0094 | $(8C,98,C2)00 | See $0095 |
$0095 | $00(8C,98,C2) | $95 can be manipulated by closing ring menus |
? | $8100 | Frame counter ($0100) |
$0002, $0018, $001C, $0054, $00DB, $00E1, etc. | $xx00 | Wildcards (Very hard to manipulate) |
Example: Enforce $0100 with the table
Possible X_alchemy values: $910089, $91ff00, $91ff11, $91ff89, $91ff9A
Seed=$FF89:
[7E_3378]=0xFF89 -> [91_FF89]=0x0100 -8k-> [91_8100]="???" (In ??)
; missing ldx line 9198fa beq $9907 [919907] A:000a X:ff89 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H: 26 F:48 9198fc lda $0028,y [7e338c] A:000a X:ff89 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H: 29 F:48 9198ff sta $4c [00004c] A:4e89 X:ff89 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H: 39 F:48 919901 jsl $919750 [919750] A:4e89 X:ff89 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H: 46 F:48 919750 lda $910000,x [91ff89] A:4e89 X:ff89 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H: 60 F:48 919754 tax A:0100 X:ff89 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H: 69 F:48 919755 jsr ($8000,x) [918100] A:0100 X:0100 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H: 72 F:48 918416 bit $00,x [000100] A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdizC V: 60 H: 85 F:48 918418 eor ($00) [7e0000] A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdiZC V: 60 H: 93 F:48 91841a bpl $841c [91841c] A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdizC V: 60 H:104 F:48 91841c cop #$00 A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdizC V: 60 H:109 F:48 00885e stp A:0100 X:0100 Y:3364 S:1fe8 D:0000 DB:7e nvmxdIzC V: 60 H:124 F:48
With Alchemy
Usually X can be altered by casting animation based alchemy, but not during the crash.
There is no proof yet, but the memory behind X_alchemy can also be set by casting an animation. Items are also included in this list, because they are treated as animation spell.
This is done by casting them and waiting for the sub animation of interest to set the memory value:
Alchemy | Possible X_alchemy Values | Comment |
---|---|---|
Acid Rain | $86F0, $86F2, $86F8, $8716, $871C, $871E, $8722, $8726 | - |
Atlas | $8B2A, $8B2C, $8B32, $8B44, $8B48, $8B4A, $8B50, $8B52 | - |
Barrier | $944C, $944E, $9452, $9462, $9466, $9474 | - |
Cure | $85D8, $85DA, $85DC, $85E2, $85F2, $86C6, $86CC, $86CE, $86D2, $86E2 | - |
Crush | $8A9C, $8A9E, $8AA4, $8AAE, $8ABA, $8B04, $8B0C | - |
Corrosion | $8F20, $8F22, $8F2C, $8F42, $8F48, $8F4A, $8F54, $8F5A, $8F5C, $8F46, $8F6A, $8F78, $8F7E, $8F80, $8F8A | - |
Defend | $872A, $872C, $8732, $8740, $8744 | - |
Double Drain | $9362, $9364, $9376, $937E, $9380, $9382, $938E, $9390, $9446 | - |
Drain | $89B4, $89B6, $89C8, $89D0, $89D2, $89D4, $89E0, $89E2 | - |
Energize | $9610, $9612, $9616, $961C | - |
Escape | $8E22, $8E24, $8E2C | - |
Explosion | $90D2, $90D4, $90DA, $90EA, $90FE, $91BE, $91C0, $91C4, $91CA | - |
Fireball | - | - |
Fire Power | $8F8E, $8F90, $8F92, $8F9A, $8FA6, $8FA8, $8FAA $9068, $9070 | - |
Flash | - | - |
Force Field | $962A, $962C, $9630, $9636 | - |
Heal | $886C, $886E, $8872, $8880 $894E, $895E, $8960, $8964, $8968 | - |
Lance | $8E36, $8E38, $8E3A, $8E40, $8E4E $8F14, $8F1E | - |
Levitate | $896E, $8970, $8974, $897E, $8982, $8984 | Can only be cast once per rock |
Lightning Storm | $91CC, $91CE, $91D4, $91Da, $91E4 | - |
Miracle Cure | $920C, $920E, $9212, $9226, $9230, $9240, $9242, $9246, $9254, $925A, $925C, $9268 | - |
Nitro | $94F6, $94F8, $94FE, $9508, $9522, $95D8 | - |
One Up | $9072, $9074, $907A, $9080, $909E, $90A0, $90A4 | - |
Reflect | $95DC, $95DE, $95E4, $95EA | - |
Regrowth | $90AE, $90B0, $90B4, $90C2 | - |
Reveal | ? | Can only be cast in act 2 |
Revive | $8B60, $8B62, $8B66, $8C34, $8C4A | Requires the dog to be dead |
Slow Burn | $91E6, $91E8, $91F2, $9202 | - |
Speed | $8988, $898A, $898E, $899C, $89A4 | - |
Sting | $8B10, $8B12, $8B18, $8B1E, $8B26 | - |
Stop | $94D6, $94D8, $94DE, $94E8 | - |
Super Heal | $947E, $9480, $9484, $9492, $9494, $949E, $94A8, $94BE, $94C8, $94CA, $94CE | - |
Storm | $81C0, $81C2, $81C8, $81CE, $81D8 | - |
Life Spark | $81DA, $81DC, $81E2, $81EE, $81F0, $81F8 | - |
Flare | - | - |
Heat Wave | $8164, $8166, $816C, $817E, $818A, $818C, $8198, $819A, $81A4, $81AA, $81AC, $81B6, $81CB | - |
Time Warp | $8200, $8202, $8208, $823E, $8244, $8246, $825C | - |
First Aid | $8270, $8272, $8278, $8284, $828A, $8294, $829E, $82B4, $82BE, $82C0, $82C4, $82CA | - |
Confound | $82CE, $82D0, $82D6, $82E0, $82F4, $82FE, $8300, $8304 | - |
Plague | $8416, $8418, $8420, $842A, $8440, $8432, $845C, $8474, $847E, $8480, $8484, $849C, $84A2, $84A4 | - |
Hypnotize | $84AC, $84AE, $84B4, $84E8, $84EA, $8500 | - |
Shock Wave | $8374, $8376, $837C, $8390, $8392, $839C, $839E, $83A8, $83AA, $83B4, $83B6, $83C0, $83C2, $83CC, $83CE, $83D8, $83DA, $83E4, $83E6, $83F0, $83F2, $83F6 | - |
Electra-Bolt | $85B0, $85B2, $85B8, $85C6, $85D0, $85D2, $85D8 | - |
Disrupt | $8512, $8514, $851A, $8524, $8538, $8542, $8544, $8548, $854E | - |
Dog Biscuit | $96D8, $96DA, $96DE, $9718, $972E | Requires the dog to be dead |
Essence | $9644, $9646, $964A, $965C, $9674, $967A, $967C, $9680 | - |
Honey | $9690, $9692, $9696, $96A4, $96B8, $96C8, $96CA, $96CE, $96D2 | - |
Nectar | (See Honey) | - |
Petal | (See Honey) | - |
Pixie Dust | $830E, $8310, $8314, $8324, $8328, $8336, $8344 | - |
Wings | $8E22, $8E24, $8E2C | - |
Desired Values for X_ram
X_alchemy just has to find a good X_ram value. (It's hard to make a list of #FFFF values, which are partially dynamic)
The offset of $918000 leads to the following jumps for X_ram:
X_ram Value | Bank | Addresses | Comment |
---|---|---|---|
$0000-$7FFF | $11 | $8000-$FFFF | HiROM section (program memory) |
$8000-$9FFF | $12 | $0000-$1FFF | LowRAM, shadowed from bank $7E |
$A000-$A0FF | $12 | $2000–$20FF | Unused |
$A100–$A1FF | $12 | $2100–$21FF | PPU1, APU, hardware registers |
$A200–$AFFF | $12 | $2200–$2FFF | Unused |
$B000–$BFFF | $12 | $3000–$3FFF | DSP, SuperFX, hardware registers |
$C000–$C0FF | $12 | $4000–$40FF | Old Style Joypad Registers |
$C100–$C1FF | $12 | $4100–$41FF | Unused |
$C200–$C4FF | $12 | $4200–$44FF | DMA, PPU2, hardware registers |
$C500–$DFFF | $12 | $4500–$5FFF | Unused |
$E000–$FFFF | $12 | $6000–$7FFF | RESERVED |
LowRAM is the easiest memory to manipulate and contains promising values:
X_ram Value | LowRAM Address | Comment |
---|---|---|
$8A3F-$8A40 | $0A3F-$0A40 | Boy - Attack (Roughly $0000-$00FF and $FF00-$FFFF) |
$8A41-$8A42 | $0A41-$0A42 | Boy - Defense (Roughly $0000-$00FF and $FF00-$FFFF) |
$8AC6-$8AC8 | $0AC6-$0AC8 | Money - Talons |
$8AC9-$8ACB | $0AC9-$0ACB | Money - Jewels |
$8ACC-$8ACE | $0ACC-$0ACE | Money - Gold Coins |
$8ACF-$8AD1 | $0ACF-$0AD1 | Money - Credits |
$B218-? | $4218-? | Controller inputs |
Routing the Exploit
Setup
- Secret of Evermore
- US
- lsnes
- Arbitrary 64 bit inputs
- LUA scripts (Which are required for the)
Examples for Executing Code
Arbitrary example of code that shall be executed:
Instruction | Comment |
---|---|
EA EA EA EA EA CB 80 F8 | Do nothing (Also synchronizes the ACE) |
A9 XX XX EA EA CB 80 F8 | Store value in accumulator |
8F XX XX XX EA CB 80 F8 | Store accumulator in memory |
60 60 60 60 60 60 60 60 | Exit ACE |
Caveat:
- $CB waits till the next interrupt (Which might not be long enough)
- The last 3 bytes cannot be changed, because it'd desync the process
Frame Counter
The by far easiest address to reach address, that can still be manipulated, is the 4 Byte frame counter:
7E0059 to 7E005A = Copy of camera x offset (Mask: 0FFF) 7E005B to 7E005C = Copy of camera y offset (Mask: 0FFF) 7E0100 to 7E0103 = Frame counter
It can be accessed in various ways...
Directly: ("$01xx" is a rare crash to get)
[7E_3378]=$0100 -> [91_0100]=$B218 -8k-> [91_4218]="arbitrary code" (Controller inputs)
By manipulating the camera offset:
[7E_3378]=$005A -> [91_005A]=$8100 -8k-> [91_0100]=$4218 -> [91_4218]="arbitrary code" (Frame counter Byte 0-2) [7E_3378]=$005A -> [91_005A]=$8101 -8k-> [91_0101]=$4218 -> [91_4218]="arbitrary code" (Frame counter Byte 1-3)
Address | Alias | Value | Comment |
---|---|---|---|
$7E3378 | $AnimationAlchemySlot0Byte14 | $SemiRandomNumber | Somewhat based on the animation of the 9th particle |
$7E005A | $CameraXY | (XX) 01 81 (XX) | Camera offset X=$01XX and Y=$XX81 pixels: (Can be pause buffered)
$FrameCounter with an offset of $8000 |
$7E0101 | $FrameCounter | (XX) 18 42 (XX) | 4,331,520 Frames: (Roughly 20 hours, but valid for $FF frames)
Jump to controller inputs ($4218) |
$914218 | $ControllerInputs | $ArbitraryCode | Can be altered by pressing buttons and is usually used for Arbitrary Code Execution |
Seed=$005A (No RAM manipulation, random frame count)
[7E_3378]=0x005A -> [91_005A]=0x8101 -8k-> [91_0101]=0x0AEA -> [91_0AEA]="random code"
; x_alchemy=$SemiRandomNumber ([AnimationAlchemySlot0Byte14]) ; missing ldx ("read $7E3378=$5A" triggers the break point) 9198fa beq $9907 [919907] A:000a X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:275 F:57 9198fc lda $0028,y [7e338c] A:000a X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:278 F:57 9198ff sta $4c [00004c] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:288 F:57 919901 jsl $919750 [919750] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:295 F:57 ; A=$FrameCounter ([$CameraXY], including an 8k offset) 919750 lda $910000,x [91005a] A:4e89 X:005a Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 37 H:308 F:57 ; x_ram=A 919754 tax A:8101 X:005a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 37 H:318 F:57 ; jump to $RandomFrameCount ($CameraXY) 919755 jsr ($8000,x) [910101] A:8101 X:8101 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 37 H:321 F:57 ; frame count = $00000AEA00xx ([$RandomFrameCount] Contains no useful code, but can be easily manipulated) 910aea ora ($00,x) [7e0a9c] A:8101 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 37 H:334 F:57 910aec ora ($00,x) [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 8 F:57 910aee ora ($00,x) [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 21 F:57 910af0 ora ($00,x) [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 35 F:57 910af2 ora ($00,x) [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 48 F:57 910af4 ora ($00,x) [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 62 F:57 910af6 ora ($00,x) [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 75 F:57 910af8 brk #$00 A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 89 F:57 00885f stp A:8501 X:8101 Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 38 H:105 F:57
Seed=$005A (Injected frame count)
[7E_3378]=0x005A -> [91_005A]=0x8101 -8k-> [91_0101]=0x4218 -> [91_4218]="arbitrary code"
; missing ldx ("read $7E3378=$5A" triggers the break point) ; missing beq ; missing lda 9198ff sta $4c [00004c] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 65 H:287 F:35 919901 jsl $919750 [919750] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 65 H:294 F:35 919750 lda $910000,x [91005a] A:4e89 X:005a Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 65 H:307 F:35 919754 tax A:8101 X:005a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 65 H:317 F:35 919755 jsr ($8000,x) [910101] A:8101 X:8101 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 65 H:320 F:35 914218 brk #$00 A:8101 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 65 H:333 F:35 00885f stp A:8101 X:8101 Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 66 H: 8 F:35
Currencies
The currencies contain 12 Bytes, which can be manipulated by killing enemies and buying items:
7E0AC6 to 7E0AC8 = Money - Talons 7E0AC9 to 7E0ACB = Money - Jewels 7E0ACC to 7E0ACE = Money - Gold Coins 7E0ACF to 7E0AD1 = Money - Credits
Address | Alias | Value | Comment |
---|---|---|---|
$7E3378 | $AnimationAlchemySlot0Byte14 | $SemiRandomNumber | Somewhat based on the animation of the 9th particle |
$7E0AC6 | $Talon | C9 8A (XX) | 35,529 Talons:
$Jewels with an offset of $8000 |
$7E0AC9 | $Jewels | CC 0A (XX) | 2,764 Jewels:
$GoldCoins |
$7E0ACC | $GoldCoins | 5C 18 42 | 4,331,612 Gold Coins:
Arbitrary code 1: Long jump ($5C) to controller inputs ($4218) |
$7E0ACF | $Credits | 00 (XX XX) | 0 Credits:
Arbitrary code 2: The chosen example requires a 4th Byte |
$004218 | $ControllerInputs | $ArbitraryCode | Can be altered by pressing buttons and is usually used for Arbitrary Code Execution |
Seed=$0AC6: (Manually injected)
[7E_FF89]=0x0AC6 -> [91_0AC6]=0x8AC9 -8k-> [91_0AC9]= 0x0ACC -> [91_0ACC]="JML 004218" (Long jump to $004218)
; x_alchemy=$SemiRandomNumber ([AnimationAlchemySlot0Byte14]) 9198f7 ldx $0014,y [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H:167 F: 9 ; x_alchemy=$Talon (Injected $Talon, for testing) 9198fa beq $9907 [919907] A:000a X:ffb8 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H:177 F: 9 9198fc lda $0028,y [7e338c] A:000a X:0ac6 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H:180 F: 9 9198ff sta $4c [00004c] A:4e89 X:0ac6 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H:190 F: 9 919901 jsl $919750 [919750] A:4e89 X:0ac6 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H:197 F: 9 ; A=$Jewels ([$Talon], including an 8k offset) 919750 lda $910000,x [910ac6] A:4e89 X:0ac6 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H:210 F: 9 ; x_ram=A 919754 tax A:8ac9 X:0ac6 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 60 H:220 F: 9 ; jump to $GoldCoins ([$Jewels]) 919755 jsr ($8000,x) [910ac9] A:8ac9 X:8ac9 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 60 H:223 F: 9 ; jump to $ControllerInputs ([$GoldCoins]) 910acc jml $004218 [004218] A:8ac9 X:8ac9 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 60 H:237 F: 9 004218 brk #$00 A:8ac9 X:8ac9 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 60 H:245 F: 9 00885f stp A:8ac9 X:8ac9 Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 60 H:260 F: 9
Similar Crashes
Enemies Casting Spells
Reproducing the Crash:
- Damage Magmar if neccessary (Heat Wave is triggered by a damage threshold)
- Cast 8 animation spells via 8cast (E.g. Storm from Fire Eyes Call Beads)
- Magmar will cast Heat Wave in response to the damage
- The game tries to adds a 9th animation spell in a slot (Sometimes refereed to as 9cast)
- The game "freezes"
Executed code:
8cd01f ldy $2f28,x [7e2f2c] A:b912 X:0004 Y:0002 S:1ff1 D:0000 DB:7e nvmxdizc V: 0 H:311 F: 7 8cd022 bne $d011 [8cd011] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V: 0 H:321 F: 7 8cd011 stx $80 [000080] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V: 0 H:325 F: 7 8cd013 sty $7e [00007e] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V: 0 H:332 F: 7 8cd015 ldx $0003,y [7e29ec] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V: 0 H:339 F: 7 8cd018 jsr ($d029,x) [8cd02b] A:b912 X:0002 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V: 1 H: 9 F: 7 8cd09c lda $0000,y [7e29e9] A:b912 X:0002 Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V: 1 H: 22 F: 7 8cd09f sta $82 [000082] A:f404 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V: 1 H: 32 F: 7 8cd0a1 lda $0001,y [7e29ea] A:f404 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V: 1 H: 39 F: 7 8cd0a4 sta $83 [000083] A:95f4 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V: 1 H: 49 F: 7 8cd0a6 lda [$82] [95f404] A:95f4 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V: 1 H: 56 F: 7 8cd0a8 inc $82 [000082] A:f4d6 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V: 1 H: 68 F: 7 8cd0aa and #$00ff A:f4d6 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V: 1 H: 80 F: 7 8cd0ad asl a A:00d6 X:0002 Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V: 1 H: 85 F: 7 8cd0ae tax A:01ac X:0002 Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V: 1 H: 88 F: 7 8cd0af jsr ($e8bd,x) [8cea69] A:01ac X:01ac Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V: 1 H: 91 F: 7 8c0285 bpl $0287 [8c0287] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V: 1 H:104 F: 7 8c0287 bra $0307 [8c0307] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V: 1 H:109 F: 7 8c0307 bra $037d [8c037d] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V: 1 H:115 F: 7 8c037d ora $00,s [001fed] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V: 1 H:120 F: 7 8c037f ora ($00,x) [7e4043] A:b1ad X:01ac Y:29e9 S:1fed D:0000 DB:7e Nvmxdizc V: 1 H:130 F: 7 8c0381 brk #$00 A:b1ad X:01ac Y:29e9 S:1fed D:0000 DB:7e Nvmxdizc V: 1 H:153 F: 7 00885f stp A:b1ad X:01ac Y:29e9 S:1fe9 D:0000 DB:7e NvmxdIzc V: 1 H:169 F: 7
8cea4f lda [$82] [94b92a] A:0001 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:216 F:29 8cea51 inc $82 [000082] A:0078 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:227 F:29 8cea53 bne $ea57 [8cea57] A:0078 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:235 F:29 8cea57 asl a A:0078 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:240 F:29 8cea58 rol $8a [00008a] A:00f0 X:0062 Y:0089 S:1fea D:0000 DB:7e NvMXdizc V:254 H:243 F:29 8cea5a tax A:00f0 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdiZc V:254 H:251 F:29 8cea5b rep #$30 A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e NvMXdizc V:254 H:254 F:29 8cea5d jmp ($f041,x) [8cf131] A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e Nvmxdizc V:254 H:259 F:29 8cf03a sta $99a8,y [7e9a31] A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e Nvmxdizc V:254 H:268 F:29 8cf03d brk #$00 A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e Nvmxdizc V:254 H:278 F:29 00885f stp A:00f0 X:00f0 Y:0089 S:1fe6 D:0000 DB:7e NvmxdIzc V:254 H:293 F:29
TL;DR
It's possible to flag all 8 available particle alchemy slots as "being currently used" by casting them into a screen transition. The 9th cast overflows that logic and is being written into the first animation alchemy slot, which has an incompatible structure.
This wouldn't be harmful as is, but progressing the animations seems to execute code for each animation in every frame. So based on the properties of the projectile various memory addresses can be manipulated. If the crash is being executed in the very right moment it leads to executing RAM values, like the currencies, as code.
Example:
This can be exploited by having a very specific crash and having some specific amounts of each currency:
- 35,529 Talons
- 2,764 Jewels
- 4,331,612 Gold Coins
- 0 Credits
The amount of Gold Coins is an instruction to execute controller inputs as code.
This example has flaws, though:
- It's hard to control the semi random number (That's why it has been injected in this example and a setup has to be found first, that leads to the specific X_alchemy value)
- The game is still crashing, unless the arbitrary code fixes the 9cast bug and jump back to regular code