Files
Embedded-Hacking/WEEK11/WEEK11-03.md
2026-03-19 15:01:07 -04:00

5.9 KiB

Embedded Systems Reverse Engineering

Repository

Week 11

Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics

Non-Credit Practice Exercise 3: Swap All Three LEDs

Objective

Find the struct initialization instructions where led1_pin = 0x10 (GPIO 16, Red), led2_pin = 0x11 (GPIO 17, Green), and led3_pin = 0x12 (GPIO 18, Yellow) are written in the 0x0026_functions binary using GDB, calculate the file offsets, and rotate the GPIO values so that button 1→Green (0x11), button 2→Yellow (0x12), and button 3→Red (0x10), then verify on hardware that the LED mapping has shifted.

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

Task Description

The struct initialization sets led1_pin = 16 (0x10), led2_pin = 17 (0x11), led3_pin = 18 (0x12) using movs instructions that store each value into the struct. By patching the immediate values in these three movs instructions, you can rotate the LED assignment: led1_pin = 17 (Green), led2_pin = 18 (Yellow), led3_pin = 16 (Red). This means button 1 will light the Green LED, button 2 the Yellow LED, and button 3 the Red LED.

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\0x0026_functions.elf

Connect to target:

(gdb) target remote :3333
(gdb) monitor reset halt
Step 2: Find the Three movs Instructions

Disassemble main and find the struct pin initialization:

(gdb) disassemble 0x10000234,+300

Look for three consecutive movs/strb pairs:

movs r0, #0x10      ; led1_pin = 16 (Red)
strb r0, [r4, #0]
movs r0, #0x11      ; led2_pin = 17 (Green)
strb r0, [r4, #1]
movs r0, #0x12      ; led3_pin = 18 (Yellow)
strb r0, [r4, #2]

Note the address of each movs instruction.

Step 3: Examine the Instruction Bytes

Check the raw encoding of each movs:

(gdb) x/2bx <address_of_movs_0x10>
(gdb) x/2bx <address_of_movs_0x11>
(gdb) x/2bx <address_of_movs_0x12>

Each will have the GPIO pin number as the immediate byte.

Step 4: Calculate the File Offsets
file_offset = address - 0x10000000

Note the offset of the immediate byte in each of the three movs instructions.

Step 5: Plan the Rotation
Struct Member Original New Effect
led1_pin 10 (GPIO 16 Red) 11 (GPIO 17 Green) Button 1 → Green
led2_pin 11 (GPIO 17 Green) 12 (GPIO 18 Yellow) Button 2 → Yellow
led3_pin 12 (GPIO 18 Yellow) 10 (GPIO 16 Red) Button 3 → Red
Step 6: Patch with HxD
  1. In HxD, open C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin
  2. Go to the first movs immediate offset and change 10 to 11
  3. Go to the second movs immediate offset and change 11 to 12
  4. Go to the third movs immediate offset and change 12 to 10
Question 1: All three patches are single-byte changes in movs immediates. Why is this simpler than patching literal pool entries?
Step 7: Save and Convert
  1. Click FileSave As0x0026_functions-h.bin
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 8: 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:

  • Press button 1 → Green LED blinks (was Red)
  • Press button 2 → Yellow LED blinks (was Green)
  • Press button 3 → Red LED blinks (was Yellow)
  • Terminal still says "LED 1 activated on GPIO 16" — but the actual LED is Green (GPIO 17)

Expected Output

After completing this exercise, you should be able to:

  • Locate struct initialization patterns in ARM Thumb assembly
  • Patch multiple movs immediates to rotate data values
  • Understand the disconnect between logged values and actual hardware behavior
  • Recognize log desynchronization as a security concern

Questions for Reflection

Question 1: The terminal log still says "LED 1 activated on GPIO 16" even though GPIO 17 (Green) is actually blinking. Why don't the logs update automatically?
Question 2: If the struct initialization used ldr from a literal pool instead of movs immediates, how would the patching approach differ?
Question 3: Could you achieve the same LED rotation by patching the gpio_init and gpio_put calls instead of the struct? Which approach is cleaner and why?
Question 4: In a real attack scenario, why is log desynchronization (logs say one thing, hardware does another) particularly dangerous for forensic analysis?

Tips and Hints

  • The three movs instructions are likely within 10-20 bytes of each other — use x/20i to see them all at once
  • The movs rN, #imm8 immediate is in the lower byte of the 2-byte Thumb instruction
  • Make sure you patch the movs for the struct initialization, not any other movs #0x10/0x11/0x12 that may exist elsewhere
  • Verify by examining the struct in memory after initialization: x/6bx <struct_address> should show 11 12 10 for the pin bytes