mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-17 21:44:45 +02:00
151 lines
5.9 KiB
Markdown
151 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 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:**
|
|
|
|
```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 Three movs Instructions
|
|
|
|
Disassemble main and find the struct pin initialization:
|
|
|
|
```gdb
|
|
(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
|
|
(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 **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 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
|