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.

Arbitrary Code Execution Discussion

Full Control: Real-time RAM writing with 8F - Page 1

Full Control: Real-time RAM writing with 8F

Posted by: Cryo
Date: 2016-12-20 22:58:25
Whew, it definitely took a few days, and the code may not look all that great, but I've finally come up with a method of using the GameBoy's joypad to write arbitrary bytes to RAM in as little time as possible with as few buttons as possible.

HOW IT WORKS:
When 8F is used, the screen and sound will function as normal, but the controls will lock up and you will now be in INPUT mode. During this mode, any button you press will add that button's value to the specified byte in memory, with two exceptions: If you press the same button twice in a row, it will move on to the next byte; and if you hold (or press) the START and SELECT buttons together at the same time, the program will jump to the specified offset and start executing your code.

This allows for a 1-to-1 mapping of buttons to values for optimal speed while still providing all necessary functionality.

NOTE: Due to space limitations, you must press A once before you enter anything on the joypad. When you press A to select the USE option on 8F, the game registers that as the initial value to be executed. Pressing A before you enter your own code skips this junk byte, and it's also why HL is initially set to $D3FE instead of $D400 in the code below.

ITEM LIST:
[tt]Item            Quantity
========================
8F              x1
[Any Item]      xAny
X Accuracy      x254
Escape Rope    x84
Potion          x213
HP Up          x205
TM50            x63
Soda Pop        x240
TM48            x254
Burn Heal      x200
TM40            x178
Guard Spec.    x183
Rare Candy      x241
X Speed        x185
X Defense      x40
TM35            x79
X Attack        x134
Ether          x119
X Special      x24
TM28            xAny[/tt]

ASM:

Start:
    ld l,$FE            ; Destination = $D3FE
    dec e              ; Zero out E
    ld d,h              ; DE = $D300
    inc d              ; DE = $D400 (Code Start)
    push de            ; Push onto the stack for later RET

Next_Byte:
    inc hl              ; Go to the next byte

Check_Input:
    call $3FFA          ; Joypad polling subroutine
    dec a              ; - Padding -
    ldh a,($F8)        ; Get the current held button
    cp $0C              ; START + SELECT = exit
    ret z              ; Jump to arbitrary code ($D400)

Check_Released:
    ldh a,($B2)        ; Get the most recently released button
    scf                ; - Padding -
    or a                ; Check whether a button was released
    jr z,Check_Input    ; If not, keep looping until one is

Check_Previous:
    ld b,e              ; - Padding -
    cp c                ; Check if the button was pressed twice
    ld b,d              ; - Padding -
    jr z,Next_Byte      ; Move to the next byte if so

Modify_Byte:
    ld c,a              ; Backup the previous button
    ld b,c              ; - Padding -
    add a,(hl)          ; Add button value to current value
    ld d,b              ; - Padding -
    ld (hl),a          ; Save new value in memory
    ld b,h              ; - Padding -
    jr Check_Input      ; Loop until manually RET
End:



EXAMPLE:
One of the things that I use this method for the most has to do with cartridge swapping capabilities. The setup below simply puts P14 to low and enters STOP mode, followed by a RET instruction to continue normal execution. This means that you can enter STOP mode, swap cartridges, then press any button on the D-Pad to return execution.

ASM:

ld a,$EF
ldh ($00),a
stop
ret


To execute the code above, simply use the 8F item, then press the buttons below in sequence. Each line represents a byte written to memory, with the first line skipping the junk byte and the last line jumping to the written program.

BUTTON INPUT:
[tt]A
LEFT RIGHT START SELECT B B
DOWN UP LEFT START SELECT B A A
DOWN UP LEFT LEFT
LEFT
RIGHT RIGHT
A A
DOWN UP START A A
START + SELECT[/tt]

NOTE: If you pop the cartridge out, put the same cartridge back in, then exit STOP mode, then the game will continue executing as normally. However, the values written to RAM remain there, so in order to re-run the stop routine above, the only buttons you'd have to press are [tt]START + SELECT[/tt].

Putting in the same combination twice without resetting will effectively double the existing program's bytes in RAM, since this is an additive approach. One pretty rad workaround is the polymorphic aspect of the setupyou can alter the items in your bag (to remove padding, etc.) and save the game with your new RAM writing bulldozer. ;D


PS: This method was successfully tested on Pokemon Red and Pokemon Blue hardware; I'm not sure about Pokemon Yellow yet, but it should work just fine.

Re: Full Control: Real-time RAM writing with 8F

Posted by: Krys3000
Date: 2016-12-22 07:58:43
Very Nice, I need to test this!

Re: Full Control: Real-time RAM writing with 8F

Posted by: Cryo
Date: 2016-12-22 08:42:54
I did have a usage example previously, but it had a few bugs in it and I removed it. I've modified the post with a new example, but an even easier and faster test would be to write the STOP function to RAM, which would just require these button inputs:

[tt]A
RIGHT RIGHT
START + SELECT[/tt]

Of course, the only thing you can do is reset the system after that, but it's a quick and dirty approach if I just want to test how clean a cartridge is when cartridge swapping. Since the system will reset if the game is inserted at the wrong angle or is too dirty, staying in STOP mode after insertion means that the game is (relatively) clean and that it was inserted at the right angle. ;)

Re: Full Control: Real-time RAM writing with 8F

Posted by: libjet
Date: 2019-06-08 22:56:54
Hello! This is my first post, so I'm sorry if i'm necroposting and I really can't be bothered to make a new thread :P

Anyway, onto the point of my post, there's a flaw in this RAM writer that I find pretty major. It's to do with the fact that once you've entered a program and saved the game, there is no apparent
way to delete it or overwrite without a memory editor and that is pretty bad news for a save file on a cartridge.
And so, I present you my "enhanced" version of this program. This is my first try at modifying ASM to do something cool, so the code is pretty messy, but it werks.

ITEM LIST:
[tt]Item            Quantity
========================
8F              x1
[Any Item]      xAny
X Accuracy      x254
Escape Rope      x84
Potion          x213
HP Up            x115
TM13            x205
TM50            x63
TM09            x240
TM48            x254
Burn Heal        x200
TM40            x178
Poke Ball        x183
Guard Spec.      x40
TM39            x185
Rare Candy      x234
PP Up            x134
X Attack        x119
X Speed          x24
TM29            xAny

[tt]2E FE 1D 54 14 D5 23 73 D5 CD FA 3F D1 F0 F8 FE 0C C8 F0 B2 04 B7 37 28 EF B9 28 EA 4F 86 41 77 43 18 E5 01[/tt]
[tt]2EFE1D5414D52373D5CDFA3FD1F0F8FE0CC8F0B204B73728EFB928EA4F8641774318E501[/tt]

Start:
    ld l,$FE            ; Destination = $D3FE
    dec e              ; Zero out E
    ld d,h              ; DE = $D300
    inc d              ; DE = $D400 (Code Start)
    push de            ; Push onto the stack for later RET

Next_Byte:
    inc hl              ; Go to the next byte
    ld (hl),e          ; Clear the byte

Check_Input:
    push de            ; 'e'=$00 here, but after calling $3FFA,'e'=$01. Not good!
    call $3FFA          ; Joypad polling subroutine
    pop de              ; 'e' now equals $00 again
    ldh a,($F8)        ; Get the current held button
    cp $0C              ; START + SELECT = exit
    ret z              ; Jump to arbitrary code ($D400)

Check_Released:
    ldh a,($B2)        ; Get the most recently released button
    inc b              ; - Padding -
    or a                ; Check whether a button was released
    scf                ; - Padding -
    jr z,Check_Input    ; If not, keep looping until one is

Check_Previous:
    cp c                ; Check if the button was pressed twice
    jr z,Next_Byte      ; Move to the next byte if so

Modify_Byte:
    ld c,a              ; Backup the previous button
    add a,(hl)          ; Add button value to current value
    ld b,c              ; - Padding -
    ld (hl),a          ; Save new value in memory
    ld b,e              ; - Padding -
    jr Check_Input      ; Loop until manually RET
End:
;This took way too long to do


What my modification does is set the (HL) to 0, prior to writing to it. This means that you can write a new program over an old one, whereas the older version
of "Full Control" added the input on top of the value already present. In other words, the older version didn't care what byte was in there before, it just added over it instead of
overwriting it. My version doesn't remove the (arguably) best feature of this either, which is the fact that the program persists in SaveRAM, and you can still press start+select
to run the program as many times as you want.
Feel free to point out any errors. (God I hope there are none)

Re: Full Control: Real-time RAM writing with 8F

Posted by: Sherkel
Date: 2019-06-10 01:15:26
Nobody's said anything? They must have just been busy over the weekend. This is one heck of an introduction, to say the least, and of course it's great to see a new spin on a program like this one. In case you plan on sticking around, the general rule is that if it could be a new thread, it's not an unnecessary bump, so you're fine there.