# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 6 Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics ### Non-Credit Practice Exercise 4: Invert the Button Logic with XOR #### Objective Find the `eor.w r3, r3, #1` instruction that implements the ternary operator's button inversion, patch it to `eor.w r3, r3, #0` using a hex editor to reverse the LED behavior, and verify that the LED is now ON when the button is pressed and OFF when released — the opposite of the original behavior. #### Prerequisites - Completed Week 6 tutorial (all GDB and hex editor sections) - `0x0014_static-variables.bin` binary available in your build directory - GDB (`arm-none-eabi-gdb`) and OpenOCD installed - A hex editor (HxD, ImHex, or similar) - Python installed (for UF2 conversion) - Raspberry Pi Pico 2 with button on GP15 and LED on GP16 #### Task Description The original program uses `gpio_put(LED_GPIO, !gpio_get(BUTTON_GPIO))` which the compiler implements as an XOR (`eor.w r3, r3, #1`) to invert the button state. With the pull-up resistor, button released = HIGH, so `HIGH XOR 1 = 0` (LED off). You will patch the XOR operand from `#1` to `#0`, which effectively removes the inversion: `HIGH XOR 0 = 1` (LED on when released). This exercise demonstrates how a single-byte binary patch can completely reverse hardware behavior. #### Step-by-Step Instructions ##### Step 1: Start the Debug Session **Terminal 1 - Start OpenOCD:** ```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ -f target/rp2350.cfg ^ -c "adapter speed 5000" ``` **Terminal 2 - Start GDB:** ```powershell arm-none-eabi-gdb build\0x0014_static-variables.elf ``` **Connect to target:** ```gdb (gdb) target remote :3333 (gdb) monitor reset halt ``` ##### Step 2: Locate the GPIO Logic From the tutorial, the GPIO input/output logic is near address `0x10000274`. Disassemble: ```gdb (gdb) x/10i 0x10000274 ``` Look for this sequence: ``` 0x10000274: mov.w r1, #0xd0000000 ; SIO base address 0x10000280: ldr r3, [r1, #4] ; Read GPIO input register 0x10000282: ubfx r3, r3, #15, #1 ; Extract bit 15 (button state) 0x10000286: eor.w r3, r3, #1 ; XOR with 1 — INVERT ? OUR TARGET 0x1000028a: mcrr 0, 4, r2, r3, cr0 ; Write to GPIO output ``` The `eor.w r3, r3, #1` instruction is at address `0x10000286`. ##### Step 3: Understand the Current Logic Trace the logic with the pull-up resistor: | Button State | GPIO 15 Input | After UBFX | After EOR #1 | LED (GPIO 16) | | ------------ | ------------- | ---------- | ------------ | -------------- | | Released | 1 (HIGH) | 1 | 0 | OFF | | Pressed | 0 (LOW) | 0 | 1 | ON | The `eor.w #1` flips the bit, implementing the `!` (NOT) from the C code. ##### Step 4: Verify with GDB Set a breakpoint at the `eor.w` instruction: ```gdb (gdb) b *0x10000286 (gdb) c ``` When it hits, check what value is about to be XORed: ```gdb (gdb) info registers r3 ``` - If button is **released**: `r3 = 1` ? after EOR: `r3 = 0` - If button is **pressed**: `r3 = 0` ? after EOR: `r3 = 1` ##### Step 5: Test the Patch in GDB Modify the EOR operand in RAM to see the effect live: ```gdb (gdb) set $r3 = 0 (gdb) si (gdb) info registers r3 ``` Or skip the EOR entirely by advancing the PC past it, then observe the LED behavior. ##### Step 6: Examine the Instruction Encoding Look at the raw bytes: ```gdb (gdb) x/4bx 0x10000286 0x10000286 : 0x83 0xf0 0x01 0x03 ``` The `eor.w` instruction is a 32-bit Thumb-2 encoding. The 4 bytes break down as: - `0x83 0xF0` — opcode + source register (r3) - `0x01` — **the immediate value (`#1`)** ? this is what we change - `0x03` — destination register (r3) ##### Step 7: Patch with the Hex Editor 1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables\build\0x0014_static-variables.bin` 2. The instruction starts at file offset: `0x10000286 - 0x10000000 = 0x286` 3. The immediate byte is the 3rd byte: offset `0x286 + 2 = 0x288` 4. Press **Ctrl+G** and enter offset: `288` 5. You should see `01` — change it to `00` 6. Verify the surrounding bytes (`83 F0` before and `03` after) are unchanged 7. Click **File** ? **Save As** ? `0x0014_static-variables-h.bin` (in the same `build` directory) > ?? **Why offset `0x288`?** The 4-byte instruction starts at `0x286`, but the immediate value `#1` is in the **third byte** (index 2), so it's at `0x286 + 2 = 0x288`. ##### Step 8: Predict the New Behavior After patching, the logic changes: | Button State | GPIO 15 Input | After UBFX | After EOR #0 | LED (GPIO 16) | | ------------ | ------------- | ---------- | ------------ | -------------- | | Released | 1 (HIGH) | 1 | 1 | **ON** | | Pressed | 0 (LOW) | 0 | 0 | **OFF** | The LED behavior is now **inverted** from the original! ##### Step 9: Convert to UF2 and Flash ```powershell cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 ``` 1. Hold BOOTSEL and plug in your Pico 2 2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive ##### Step 10: Verify the Hack Test the button: - **Button NOT pressed**: LED should now be **ON** (was OFF before patching) - **Button PRESSED**: LED should now be **OFF** (was ON before patching) The LED behavior is completely reversed by changing a single byte! #### Expected Output After completing this exercise, you should be able to: - Locate XOR / EOR instructions in disassembled GPIO logic - Understand how XOR implements logical NOT for single-bit values - Patch a Thumb-2 encoded immediate operand - Predict hardware behavior changes from binary patches #### Questions for Reflection ###### Question 1: Why does XOR with 1 act as a NOT for single-bit values? Write out the truth table for `x XOR 1` and `x XOR 0` where x is 0 or 1. ###### Question 2: Instead of changing `eor.w r3, r3, #1` to `eor.w r3, r3, #0`, could you achieve the same result by NOPing (removing) the instruction entirely? What bytes encode a NOP in Thumb? ###### Question 3: The pull-up resistor means "pressed = LOW." If you removed the pull-up (changed `gpio_pull_up` to no pull), would the button still work? Why or why not? ###### Question 4: The `ubfx r3, r3, #0xf, #0x1` instruction extracts bit 15. If you changed `#0xf` to `#0x10` (bit 16), what GPIO pin would you be reading? What value would you get if nothing is connected to that pin? #### Tips and Hints - `eor.w r3, r3, #1` is a 32-bit Thumb-2 instruction (4 bytes), not a 16-bit Thumb instruction - A Thumb NOP is `00 bf` (2 bytes) — you would need two NOPs to replace a 4-byte instruction - Use GDB `x/1tw` to view a word in binary format, making bit manipulation easier to see - The SIO base address `0xd0000000` provides single-cycle access to GPIO — it's separate from the IO_BANK0 registers at `0x40028000` #### Next Steps - Review all four exercises and verify you can patch any part of the binary: data values, arithmetic operations, and logic operations - Try combining multiple hacks in a single binary: change the initial value, speed up the overflow, AND invert the button logic - Compare your patched binary with the original using `fc /b original.bin patched.bin` in the command prompt to see all changed bytes