# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 11 Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics ### Non-Credit Practice Exercise 1: Add a Fourth LED #### Objective Find the struct initialization pattern in the `0x0026_functions` binary using GDB where `led1_pin` (0x10), `led2_pin` (0x11), and `led3_pin` (0x12) are stored, locate an unused byte in the struct memory region, and patch it to include a fourth LED on GPIO 19 (0x13) by extending the struct data and modifying the `ir_to_led_number` function to handle a fourth button mapping. #### Prerequisites - Completed Week 11 tutorial (GDB and hex editor sections) - `0x0026_functions.elf` and `0x0026_functions.bin` 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 IR remote and LEDs on GPIO 16, 17, 18 (and GPIO 19 wired for the new LED) #### Task Description The `simple_led_ctrl_t` struct stores three LED pin numbers: `led1_pin` (16/0x10), `led2_pin` (17/0x11), `led3_pin` (18/0x12). These are stored as consecutive bytes in the struct initialization. You will find where the struct is initialized in the binary, locate the `movs` instructions that set the pin values, and add `led4_pin` = 19 (0x13) by patching a nearby unused or default byte. You will also need to find where `ir_to_led_number` returns values 1, 2, or 3 and adjust the NEC command comparison to map a fourth button to LED 4. #### 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\0x0026_functions.elf ``` **Connect to target:** ```gdb (gdb) target remote :3333 (gdb) monitor reset halt ``` ##### Step 2: Find the Struct Initialization Disassemble main and look for the struct pin assignments: ```gdb (gdb) disassemble 0x10000234,+300 ``` Look for consecutive `movs` instructions: ``` movs r0, #0x10 ; led1_pin = 16 strb r0, [r4, #0] ; store to struct offset 0 movs r0, #0x11 ; led2_pin = 17 strb r0, [r4, #1] ; store to struct offset 1 movs r0, #0x12 ; led3_pin = 18 strb r0, [r4, #2] ; store to struct offset 2 ``` ##### Step 3: Examine the Struct in Memory Set a breakpoint after initialization and examine the struct: ```gdb (gdb) break *0x10000280 (gdb) monitor reset halt (gdb) continue (gdb) x/8bx ``` You should see: `10 11 12 00 00 00` — the three pin values followed by the state booleans (all false/0x00). ##### Step 4: Find the `get_led_pin` Function Look for the function that reads from the struct based on LED number: ```gdb (gdb) disassemble 0x100002a0,+50 ``` This function takes a struct pointer and LED number and returns the GPIO pin by reading from a struct offset. ##### Step 5: Calculate File Offsets ``` file_offset = address - 0x10000000 ``` Note offsets for: 1. The `movs r0, #0x12` instruction (last pin assignment) 2. The byte after `led3_pin` in the struct (where `led4_pin` would go) ##### Step 6: Plan the Patches | Patch Target | Original | New | Purpose | | --------------------- | -------- | ------ | ------------------------- | | Struct byte after 0x12 | `00` | `13` | Add led4_pin = GPIO 19 | ###### Question 1: The struct layout has `led3_pin` at offset 2 and `led1_state` at offset 3. If you write `0x13` to offset 3, what happens to `led1_state`? ##### Step 7: Patch with HxD 1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin` 2. Navigate to the struct initialization area 3. Apply the patches identified in Step 6 ##### Step 8: Save and Convert 1. Click **File** → **Save As** → `0x0026_functions-h.bin` ```powershell cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 ``` ##### Step 9: Flash and Verify 1. Hold BOOTSEL and plug in your Pico 2 2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive **Check the behavior:** - Existing buttons 1, 2, 3 should still control their LEDs - Verify with GDB that the struct now contains `10 11 12 13` at the pin offsets #### Expected Output After completing this exercise, you should be able to: - Understand struct memory layout and member offsets - Identify struct initialization patterns in ARM assembly - Patch struct data members in binary firmware - Reason about the consequences of overwriting adjacent struct fields #### Questions for Reflection ###### Question 1: The original struct has 6 members (3 pins + 3 states) in 6 bytes. If you add a fourth pin at offset 3, you overwrite `led1_state`. What is the practical impact on LED 1 behavior? ###### Question 2: How would you verify the exact struct layout and offsets using GDB's memory examination commands? ###### Question 3: If the `get_led_pin` function uses a bounds check (e.g., `if led_num > 3 return 0`), what additional patch would you need? ###### Question 4: Could you extend the struct without overwriting existing fields by finding free space elsewhere in the binary? What challenges would that introduce? #### Tips and Hints - GPIO 19 = `0x13` in hex - The struct is likely stack-allocated, so the initialization `movs`/`strb` sequence happens every loop iteration - Overwriting `led1_state` (offset 3) with `0x13` means LED 1 will appear as "on" (non-zero boolean) — this may cause LED 1 to be on at startup - The `get_led_pin` function likely uses the LED number as an index into the struct — trace how it calculates the offset