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

Sending input via joypad using 8F - Page 1

Sending input via joypad using 8F

Posted by: ISSOtm
Date: 2016-08-18 21:13:52
Although I've seen many ACE TASes sending data via joypad, I've never seen this unassisted (although https://youtu.be/hB6eY73sLV0 is kinda it).
I was wondering if a 8F setup coud get the job done.


WARNING : this post is composed of huge chunks of text WITHOUT ANY TL;DR.
If feeling bored, get medical advice && GTFO. Thanks.

I wrote some code that should get the job done. I didn't test it, so I have totally zero proof that it works fine.
I guess having an empty active box before running this is better.

ld hl, $DA80 ; start of current box data
ld b, 1
  mainloop:
; VBlank interrupt calls ReadJoypad for us, yay !
call Joypad ; located early in ROM0, so no bank switch, yay !
ld a, ($FF00 + $B3) ; hJoyPressed

rla ; Down
jr nc, $+2
srl b ; halves B

rla ; Up
jr nc, $+3
sla b ; doubles B since C = 0

rla ; Left
jr nc, $+1
dec b

rla ; Right
jr nc, $+1
inc b

rla ; Start
jp c, $DA80 ; jump to written code

rla ; Select
jr nc, $+2
ld (hl), b
inc hl

rla ; B
ret c ; quit if then

; there's room for code for B and A.

jr mainloop



User manual :
How to operate
1. Set up the thing
Optional : empty your current PC box / switch to one you don't care about. The box open as 8F is ran will be heavily damaged :)
2. Run 8F ; the value will be set to 1
3. Write values :
* Press Right to increment the value
* Press Left to decrement the value
* Press Up to halve the value
* Press Down to double the value
* Press Select to place the value and advance forwards
* Press Start to run the values as code
* Press B to abort
4. ???
5. Profit.

Size limit
You should avoid writing too many bytes, otherwise expect crashes. $452 (1152) bytes is a reasonable limit.


Explanation of joypad routines :
ReadJoypad reads joypad input and transfers it into a more "readable" format to hJoyInput
Joypad updates three variables containing the state of the joypad keys basing itself on hJoyInput ; hJoyPressed contains the keys that were pressed since last time (1 = just pressed)
Format :
Bit 7 - Down
Bit 6 - Up
Bit 5 - Left
Bit 4 - Right
Bit 3 - Start
Bit 2 - Select
Bit 1 - B
Bit 0 - A


Compiled, that'd give

06 01
21 80 DA

CD ?? ??
F0 B3

17
30 02
CB 38

17
30 03
CB 20

17
30 01
04

17
30 01
05

17
DA 80 DA

17
30 02
70
23

17
D0

18 DD

This is 43 bytes large as-is. There is a chance that could fit in one inventory item list.
Another option would be to have one part of the code set to be in the item pack, and the rest sitting in the PC.
The final jr mainloop would then become a jp mainloop, though.

Also, the code could be written to SRAM bank 0, in the sprite decompression data zone.
That'd require to enable SRAM R/W plus switching to bank 0 (I recall some actions cause this bank to be loaded ? I can't remember which, though)

Other ideas for storing :
-> Pokémans (party is prohibited due to 8F setup)
Could store to Daycare or current box.
Opening SRAM also allows using other boxes.

Pokémon data :
[table]
[tr]
[td]Data[/td][td]Usability[/td][td]Comments[/td]
[/tr]
[tr]
[td]Pokémon ID[/td][td]Good[/td][td]Unless using hybrids, linked to ID list.[/td]
[/tr]
[tr]
[td]HP[/td][td]Good[/td][td]High HP usually requires high levels.[/td]
[/tr]
[tr]
[td]Level[/td][td]Good[/td][td]> 100 is tedious[/td]
[/tr]
[tr]
[td]Status[/td][td]Low[/td][td]Only a few values are possible.[/td]
[/tr]
[tr]
[td]Types[/td][td]Medium[/td][td]linked to ID[/td]
[/tr]
[tr]
[td]Held item (???)[/td][td]???[/td][td]Is this set in Gen 1 ? Catch rate maybe ?[/td]
[/tr]
[tr]
[td]Moves[/td][td]Medium[/td][td]Restricted to a specific learnset, I guess. Plus, 00 can't be created nor moved around, except with Metamorph (maybe Mew). Dammit.[/td]
[/tr]
[tr]
[td]Trainer ID[/td][td]Super low[/td][td]… duh.[/td][/tr]
[tr]
[td]Experience[/td][td]Low[/td][td]No one likes manipulating EXP. Except Metarkrai, I guess.[/td]
[/tr]
[tr]
[td]EVs[/td][td]Low[/td][td]Same as above, i guess.[/td]
[/tr]
[tr]
[td]IVs[/td][td]Super low[/td][td]Even Metarkrai doesn't manipulate IVs.[/td]
[/tr]
[tr][td]PP[/td][td]Medium[/td][td]Depend on the mon's moves.[/td]
[/tr]
[tr]
[td]Trainer name[/td][td]Super low[/td][td]Restricted values set, repeating pattern… nope.[/td]
[/tr]
[tr][td]Mon's name[/td][td]Low[/td][td]Same value restrictions, but patterns are different. Careful of the $50, though.[/td][/tr][/table]
So, at best, using one Pokémon's PP and the following's ID, HP and level, that'd give us 8 bytes per Pokémon.

-> Using parts of the game as "gadgets".
I don't think that's going to work. But maybe…
We're already using the game's joypad routines ; the rest of the code is, to me, too specific to be gadget-able.

-> Names
Most letters perform arithmetics… but it looks like lowercase x pops bc, y is jp nz, and z is jp.
Other than that, it seems pretty useless. The other guess would be using glitch mon names ?

-> Stack
Immediately following the mon nicks is the stack… yet :
1. the stack is in RAM, but I don't think this RAM is zero'ed when booting (=> quitting the nicks won't nicely NOP slide to the stack
2. jumping to the stack would imply manipulaing it… but that requires code : dismissed.
3. ROP (Return-Oriented Programming) seems like an option, but I don't think this game has the right gadgets for our purposes, as stated above.



[EDIT]
Aldrasio suggested not to disable VBlank, so I edited the code accordingly. Saves 4 bytes.

[EDIT 2]
Aldrasio suggested using sla b instead of ccf/rl b. Saves 1 byte.

Re: Sending input via joypad using 8F

Posted by: Aldrasio
Date: 2016-08-19 00:03:56
Disabling vblank might not be a great idea for this. The game would just appear frozen while you inputted the program and you'd have no feedback when you entered commands. It also might not be necessary either, but I'd have to dig more into the vblank routine to check.

Re: Sending input via joypad using 8F

Posted by: Spoink
Date: 2016-08-19 03:29:54

[table][tr][td]Moves[/td][td]Medium[/td][td]Retricted to a specific learnset, I guess. Plus, 00 can't be created nor moved around. Dammit.[/td][/tr][/table]


Not entirely true, as you can use glitch Pokémon or transform, but the latter is only for Ditto (and $90, the move ID for transform, isn't really that useful) and the former seems to be not liked very well)

Edit: Although Mew can learn transform and so can certain glitch Pokémon, so I guess it's not that limited.

Re: Sending input via joypad using 8F

Posted by: ISSOtm
Date: 2016-08-19 06:13:59

Disabling vblank might not be a great idea for this. The game would just appear frozen while you inputted the program and you'd have no feedback when you entered commands. It also might not be necessary either, but I'd have to dig more into the vblank routine to check.

Yep, you're right, the VBlank only calls ReadJoypad (if hDisableJoypadPolling is zero)
https://github.com/pret/pokered/blob/bfaabd08be0a790dff961276d76af3e1af4e6e24/home/vblank.asm#L77
That removes 4 bytes of code, so I've edited the first post.

Do you think of a compact way to give feedback ? Enabling VBlank means we can't directly edit VRAM, we have to use something else…

Re: Sending input via joypad using 8F

Posted by: Yeniaul
Date: 2016-08-19 08:24:40

[table][tr][td]Moves[/td][td]Medium[/td][td]Retricted to a specific learnset, I guess. Plus, 00 can't be created nor moved around. Dammit.[/td][/tr][/table]


Um… 00 is a NOP on execution, so it'd just slide to the next byte. That means it's not necessary as it'd just make your code that much longer.

Re: Sending input via joypad using 8F

Posted by: ISSOtm
Date: 2016-08-19 10:42:58
I mean, if you want ld bc, $100 you would need 01 00 01. This series of bytes cannot be done only with moves, for example.

Re: Sending input via joypad using 8F

Posted by: Yeniaul
Date: 2016-08-19 13:32:32

I mean, if you want ld bc, $100 you would need 01 00 01. This series of bytes cannot be done only with moves, for example.

Oh shit, that's right! Derp… I incorrectly remembered that the gbz80 only had single-byte ops. :P

Re: Sending input via joypad using 8F

Posted by: Aldrasio
Date: 2016-08-19 16:42:45


Disabling vblank might not be a great idea for this. The game would just appear frozen while you inputted the program and you'd have no feedback when you entered commands. It also might not be necessary either, but I'd have to dig more into the vblank routine to check.

Yep, you're right, the VBlank only calls ReadJoypad (if hDisableJoypadPolling is zero)
https://github.com/pret/pokered/blob/bfaabd08be0a790dff961276d76af3e1af4e6e24/home/vblank.asm#L77
That removes 4 bytes of code, so I've edited the first post.

Do you think of a compact way to give feedback ? Enabling VBlank means we can't directly edit VRAM, we have to use something else…


The first thing that comes to mind is calling PlaySound ($23b1), which would require 4 or 5 bytes (1-2 for loading a value into A, 3 for calling PlaySound). Also we don't need to update VRAM directly, because there's a tilemap buffer in C380-C507 that gets copied to VRAM during VBlank. Calling ClearScreen ($190f) empties the tilemap buffer (it doesn't do anything to tiles), and you can edit the buffer as a blank slate from there.

Re: Sending input via joypad using 8F

Posted by: Yeniaul
Date: 2016-08-19 20:20:03
I know minimal ASM (just enough to know what the hell was going on if I read ASM source) but couldn't you just have it wait for a 'pad press until every time one could be accepted (twice a frame, if I recall correctly, during VSync and VBlank) and if the interrupt was 0, have it wait for the next VBlank/Sync?

So the logic expressed in Python 2 format would be:

#whatever
def JoyRead():
    if(Interrupt = 00000010): #JoyInt is bit 7, right?
        RAM.write(ButtonID)
        #whatever
    elif(Interrupt != 00000010): #elif is an else{if{}} but wrapped so it doesn't make a pyramid.
        waitForVBlank()
        JoyRead()

Re: Sending input via joypad using 8F

Posted by: ISSOtm
Date: 2016-08-20 09:47:08
Aldrasio : some thing we could do is, right before the final loop :

ld a, b
ld ($C380), a

Still requires 4 bytes :/

Yeniaul :
Due to switch bounce, JoyInt fires multiple times per button press (except on GBA SP).
I prefer to rely on the game's joypad routines.

Re: Sending input via joypad using 8F

Posted by: Aldrasio
Date: 2016-08-20 12:11:40
So I thought of another way to shorten it. First, you don't need to use ccf/rl b to shift b left; instead, you can use sla b. So that's 1 byte. Also, you really only need to increment and shift left in order to get any value you need, so 2 of the button checks can go. For A3 (10100011), you'd do the following:

00000000
inc
00000001
sla
00000010
sla
00000100
inc
00000101
sla
00001010
sla
00010100
sla
00101000
sla
01010000
inc
01010001
sla
10100010
inc
10100011

This way you'd only need to check for 2 button presses instead of 4, which would save another 7 bytes.

Re: Sending input via joypad using 8F

Posted by: ISSOtm
Date: 2016-08-20 17:11:08
The problem with sla b is that it doesn't modify bit 7.

Suppressing two buttons still means we have to rla them (or we put the START commande on the RIGHT button… doesn't make sense to me.
Plus, less user-friendly / intuitive, but it's a good idea anyways, considering how non-user-friendly this is right now.

Re: Sending input via joypad using 8F

Posted by: Yeniaul
Date: 2016-08-20 18:30:36

Yeniaul :
Due to switch bounce, JoyInt fires multiple times per button press (except on GBA SP).
I prefer to rely on the game's joypad routines.

I keep forgetting all this crap that the GB/C/A does.

Re: Sending input via joypad using 8F

Posted by: Aldrasio
Date: 2016-08-20 20:51:38

The problem with sla b is that it doesn't modify bit 7.


I'm pretty sure that's not right. I've never read it anywhere.


Suppressing two buttons still means we have to rla them (or we put the START commande on the RIGHT button… doesn't make sense to me.
Plus, less user-friendly / intuitive, but it's a good idea anyways, considering how non-user-friendly this is right now.


I mean, yeah, you still have to rla them, but you just don't do anything with the carry result and roll it to the next one. Plus, if you make a mistake, you can always just shift 8 times and start over. I didn't think user-friendliness was as much of a priority as minimum necessary functionality, given the size restriction.

Re: Sending input via joypad using 8F

Posted by: ISSOtm
Date: 2016-08-21 07:21:23


The problem with sla b is that it doesn't modify bit 7.


I'm pretty sure that's not right. I've never read it anywhere.


Suppressing two buttons still means we have to rla them (or we put the START commande on the RIGHT button… doesn't make sense to me.
Plus, less user-friendly / intuitive, but it's a good idea anyways, considering how non-user-friendly this is right now.


I mean, yeah, you still have to rla them, but you just don't do anything with the carry result and roll it to the next one. Plus, if you make a mistake, you can always just shift 8 times and start over. I didn't think user-friendliness was as much of a priority as minimum necessary functionality, given the size restriction.

Welp, sla modifies bit 7. It's sra that preserves it. My bad :P
Edited the first post.

I agree that user-friendliness isn't much of a priority, but I felt only having shift / dec was unintuitive.
Actually, the method you posted is quite intuitive ; to put it in a more universal manner, assuming LEFT is "sla" and UP is "inc" :
* Press LEFT 8 times
* For each bit of the value you want to write :
** Press LEFT
** If the bit is 1, press UP
** Repeat
* Press SELECT to place the value
* Repeat everything

What do you think ?