mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-04-01 17:10:20 +02:00
157 lines
5.9 KiB
Markdown
157 lines
5.9 KiB
Markdown
# 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 <struct_base_address>
|
|
```
|
|
|
|
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
|