Switch case using EA in ROP - Ep.2
An example ROP chain using the EA switch case technique
Notes: All addresses mentioned below is for verA
Let’s consider the following example where the keycodes to be checked are:
0401, 0402, 0404, 0201, 0204, 0101, 0102, 0104, 0208, 0210, 0108, 0110
And their corresponding jump addresses are:
D730, D740, D750, D760, D770, D780, D790, D7A0, D7B0, D7C0, D7D0, D7E0
The keycodes are placed first, followed by the jymp addresses. The last two bytes of the keycode table are 0000, and the jump address for no key press is D7F0. At address D800, the table is constructed as follows:
org 0xD800
hex 04 01 30 D7 04 02 40 D7 04 04 50 D7 02 01 60 D7
hex 02 04 70 D7 01 01 80 D7 01 02 90 D7 01 04 A0 D7
hex 02 08 B0 D7 02 10 C0 D7 01 08 D0 D7 01 10 E0 D7
hex 00 00 F0 D7
Program Logic
We will write the program at D700 (skipping the part where keycodes are read):
Setup Link Register (LR) and other registers:
Use
3:08D0(far_call_stub) to setLR. To setEAtoD800, we can usePOP XR12(2:0730) to set bothER12andER14toD800 - 0xA = D7F6setlr pop xr12 (D7F6 D7F6)Set
EAtoD800:Call
1:7CA6to assignEAat*[D800]. Next, add aPOP ER0and pad it with 2 bytes. To optimize the program, we have decided to directly store the keycode into the 2 bytes pad, and later pop them intoER0to save up someLcommands.
If you use2:F5EAto read the keycode and no key is pressed, the value will not be written, thus making thekeycode:still remains0000. (Explanation: Because this is a backup loop, the orginal default value will not be overwritten)setlr pop xr12 (D7F6 D7F6) call 17CA6 pop er0 keycode: hex 00 00Use
0:9C20Call0:9C20to obtain the address of the keycode that matchesER0. After running it, theEAwill perfectly points to the address value.setlr pop xr12 (D7F6 D7F6) call 17CA6 pop er0 keycode: hex 00 00 call 09C20Final Steps
Finally, call
1:C64Ato store the value intoER6, and2:1F74to copy the value inER6toSPsetlr pop xr12 (D7F6 D7F6) call 17CA6 pop er0 keycode: hex 00 00 call 09C20 call 1C64A call 21F74(Don’t forget to pad all your jump address by 2 since
2:1F74ends withPOP ER8)
P/s: Issues when using 2:F5EA key detection with EA switcher 0:9C20
Overview
2:F5EA detects key presses and writes the keycode to *[ER0]. It then continues execution without any delay. When you use it in a loop to detect key presses, the function will repeatedly execute while the key is being held down, leading to unexpected behaviours.
To address this issue, a dedicated entry is reserved in the table to store the last keycode and its corresponding jump address. This allows the program to compare the current keycode with the previously detected keycode.
Idea
- After each traversal, the keycode at the table header in the main program (eg at
E9E0) is updated with the newly pressed keycode. - During the next traversal, the copied table begins by checking whether the keycode mathces the already backup keycode in the table header. If they match, the program should immediately exits the traversal loop to prevent repeated execution of the same function.
Writing the keycode to the table header
To write the keycode to the table header
- First, load the keycode into
ER0(you could use thePOP ER0trick aforementioned) - Set
ER2to point to the table header location - Call
1:3B9E(er0 = [er2],r2 = 9,rt) to write the value inER0to*[ER2]
Additionally, you can use 1:0E78 to write the keycode to *[ER4]
- Before calling
1:0E78, load the table header address intoER4 1:0E78writes the value ofER0to[ER4]
1:0E78H 9141 ST R1, [ER4]
1:0E7AH E4FF ADD ER4, #-1H
1:0E7CH 9041 ST R0, [ER4]
1:0E7EH E4FF ADD ER4, #-1H
1:0E80H F18E POP EA
1:0E82H 16FF ADD R6, #-1H
1:0E84H C8F4 BNE .l_010
1:0E86H F42E POP XR4
1:0E88H F28E POP PC
1:0E78 is followed by the 1:0E80 (POP EA) which is mentioned in the last post, which assigns a value to EA. This makes 1:0E78 particularly useful for scenarios where both keycode writing and EA assignment need to occur in the sequence.
Very important note
If you are going to do this, your table’s structure should looks like this
hex FFFF ;reserved for last keycode
hex D700 ;address to return when the same key is pressed
hex [key] [value]
hex [key] [value]
hex [key] [value]
...
hex 0000 [default value]
However, when you are not pressing anything, the keycode stored in ER0 will be 00 00. Let’s modify the previous code by changing the hex 00 00 after keycode: into a different unique value. I advise you to use hex FF FF, since there shouldn’t be any key matches that value.