Difference between revisions of "Secret of Evermore:Alchemy RAM manipulation"

From Data Crystal
Jump to: navigation, search
m
 
(2 intermediate revisions by the same user not shown)
Line 675: Line 675:
 
==Routing the Exploit==
 
==Routing the Exploit==
 
===Setup===
 
===Setup===
TODO
+
 
 +
* 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
 
|}
 
|}
  
TODO
+
'''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====
Line 925: Line 943:
 
00885f stp                    A:00f0 X:00f0 Y:0089 S:1fe6 D:0000 DB:7e NvmxdIzc V:254 H:293 F:29
 
00885f stp                    A:00f0 X:00f0 Y:0089 S:1fe6 D:0000 DB:7e NvmxdIzc V:254 H:293 F:29
 
</pre>
 
</pre>
 +
 +
===Verminator Skip===
 +
TODO
 +
 +
===Entity===
 +
TODO
 +
 +
==FAQ==
 +
{| class="wikitable"
 +
|-
 +
! Q
 +
! A
 +
|-
 +
| Is the run deterministic on real hardware?
 +
| Unknown, but the game does not play music in between screen transitions, which is a good sign!
 +
|-
 +
| How late in the run is the crash?
 +
| The current setup is on frame $4218
 +
|-
 +
| Does a replay/movie exist?
 +
| Not yet
 +
|-
 +
| Is this strategy RTA viable?
 +
| No, because the current variations can't be performed with just 2 controllers
 +
|}
  
 
==TL;DR==
 
==TL;DR==

Latest revision as of 15:37, 14 January 2020

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:
  • x can be manipulated
  •  ? is pseudo random (Current script)
$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
  • Can be used:
    • $8C (Boy)
    • $98 (Dog)
    • $C2 (Call Beads - Choose spell)
  • Can't be used:
    • $AC (Buy ingredients)
    • $B0 (Call Beads - Choose person)
    • $9C (Buy consumables)
    • $A4 (Sell consumables)
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

Verminator Skip

TODO

Entity

TODO

FAQ

Q A
Is the run deterministic on real hardware? Unknown, but the game does not play music in between screen transitions, which is a good sign!
How late in the run is the crash? The current setup is on frame $4218
Does a replay/movie exist? Not yet
Is this strategy RTA viable? No, because the current variations can't be performed with just 2 controllers

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