Files
Embedded-Hacking/WEEK06/WEEK06-04.md
T
2026-03-01 12:45:26 -05:00

7.1 KiB

Embedded Systems Reverse Engineering

Repository

Week 6

Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics

Exercise 4: Invert the Button Logic with XOR

Objective

Find the eor r3, r3, #0x1 instruction that implements the ternary operator's button inversion, patch it to eor r3, r3, #0x0 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 r3, r3, #0x1) 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 #0x1 to #0x0, 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:

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:

arm-none-eabi-gdb build/0x0014_static-variables.elf

Connect to target:

(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) x/10i 0x10000274

Look for this sequence:

mov.w r1, #0xd0000000    ; SIO base address
ldr   r3, [r1, #offset]  ; Read GPIO input register
ubfx  r3, r3, #0xf, #0x1 ; Extract bit 15 (button state)
eor   r3, r3, #0x1       ; XOR with 1 — INVERT ← OUR TARGET
mcrr  p0, 0x4, r2, r3, cr0 ; Write to GPIO output

Note the exact address of the eor r3, r3, #0x1 instruction.

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 #0x1 flips the bit, implementing the ! (NOT) from the C code.

Step 4: Verify with GDB

Set a breakpoint at the eor instruction:

(gdb) b *<address_of_eor>
(gdb) c

When it hits, check what value is about to be XORed:

(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) 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) x/4bx <address_of_eor>

The eor instruction in Thumb-2 (32-bit encoding) will contain the immediate value 0x01. Study the bytes carefully — the immediate operand is encoded within the instruction word.

Step 7: Patch with the Hex Editor
  1. Open 0x0014_static-variables.bin in HxD
  2. Calculate the file offset: address - 0x10000000
  3. Press Ctrl+G and enter the offset
  4. Locate the byte that encodes the #0x1 immediate value
  5. Change 01 to 00
  6. Verify the surrounding bytes are unchanged
  7. Click FileSave As0x0014_static-variables-h.bin

🔍 Thumb-2 encoding note: The eor instruction is 4 bytes (32-bit Thumb-2). The immediate value may not be in the most obvious position — it is typically encoded in bit fields spread across the instruction. Look for the 01 byte within the 4-byte sequence.

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
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 r3, r3, #0x1 to eor r3, r3, #0x0, 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 r3, r3, #0x1 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