mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-07-06 20:47:55 +02:00
Overhall w/ slides
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
# 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
|
||||
|
||||
### 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
|
||||
@@ -0,0 +1,144 @@
|
||||
# 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
|
||||
|
||||
### Exercise 2: Change Blink Count
|
||||
|
||||
#### Objective
|
||||
Find the `blink_led(pin, 3, 50)` call in the `0x0026_functions` binary using GDB, identify the immediate value `#3` being loaded into `r1` (the blink count parameter), calculate the file offset, and patch it to `#5` so that each LED blinks 5 times instead of 3 when activated by the IR remote.
|
||||
|
||||
#### 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 `blink_led` function is called with three parameters: the GPIO pin number, a blink count of `3`, and a delay of `50`ms. The blink count is loaded as a small immediate value (`movs r1, #3`) directly in the instruction before the `bl blink_led` call. You will locate this instruction, find the byte encoding the `#3` immediate, and patch it to `#5` so the LEDs blink 5 times per button press.
|
||||
|
||||
#### 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 blink_led Call
|
||||
|
||||
Disassemble main and look for the function call sequence:
|
||||
|
||||
```gdb
|
||||
(gdb) disassemble 0x10000234,+300
|
||||
```
|
||||
|
||||
Look for the parameter setup before `bl blink_led`:
|
||||
|
||||
```
|
||||
movs r0, <pin> ; GPIO pin number (from get_led_pin)
|
||||
movs r1, #3 ; blink count = 3
|
||||
movs r2, #0x32 ; delay = 50ms
|
||||
bl blink_led
|
||||
```
|
||||
|
||||
Note the address of the `movs r1, #3` instruction.
|
||||
|
||||
##### Step 3: Examine the Instruction Encoding
|
||||
|
||||
Look at the raw bytes of the `movs r1, #3` instruction:
|
||||
|
||||
```gdb
|
||||
(gdb) x/2bx <address_of_movs_r1_3>
|
||||
```
|
||||
|
||||
In Thumb encoding, `movs r1, #imm8` has the immediate in the lower byte. You should see a byte containing `03`.
|
||||
|
||||
##### Step 4: Calculate the File Offset
|
||||
|
||||
```
|
||||
file_offset = address - 0x10000000
|
||||
```
|
||||
|
||||
Note the file offset of the byte containing `03`.
|
||||
|
||||
##### Step 5: Encode the New Value
|
||||
|
||||
| Parameter | Original | New | Encoding |
|
||||
| ---------- | -------- | ---- | -------------- |
|
||||
| Blink count | `03` | `05` | `movs r1, #5` |
|
||||
|
||||
##### Step 6: Patch with HxD
|
||||
|
||||
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin`
|
||||
2. Press **Ctrl+G** and enter the file offset
|
||||
3. You should see: `03`
|
||||
4. Replace with: `05`
|
||||
|
||||
###### Question 1: The `movs r1, #3` is a 2-byte Thumb instruction. Which byte contains the immediate — the first or the second?
|
||||
|
||||
##### 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 → Red LED blinks **5 times** (was 3), then stays on
|
||||
- Press button 2 → Green LED blinks **5 times** (was 3), then stays on
|
||||
- Press button 3 → Yellow LED blinks **5 times** (was 3), then stays on
|
||||
- Count carefully — you should see exactly 5 on/off cycles
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Locate small immediate values in Thumb `movs` instructions
|
||||
- Understand Thumb instruction encoding for immediate operands
|
||||
- Patch function parameters by modifying instruction immediates
|
||||
- Verify behavioral changes by counting observable events
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: The `movs rN, #imm8` instruction can encode values 0-255. What is the maximum blink count you could set with a single byte patch?
|
||||
|
||||
###### Question 2: Why is the blink count passed in `r1` and not `r0`? What does `r0` hold at this point in the calling convention?
|
||||
|
||||
###### Question 3: If you wanted to set the blink count to 256 or higher, the `movs` immediate would not be enough. What instruction sequence would the compiler need to generate instead?
|
||||
|
||||
###### Question 4: The same `blink_led` function is called for all three buttons. Does that mean there is only one `movs r1, #3` to patch, or could there be multiple call sites?
|
||||
|
||||
#### Tips and Hints
|
||||
- Small immediates (0-255) are encoded directly in the `movs` instruction — no literal pool needed
|
||||
- The ARM calling convention uses `r0`, `r1`, `r2`, `r3` for the first four function parameters in order
|
||||
- Look for `movs r1, #3` right before `bl blink_led` — there may be one shared call site or multiple per button
|
||||
- If there are multiple `movs r1, #3` instructions (one per case), you need to patch all of them for consistent behavior
|
||||
@@ -0,0 +1,150 @@
|
||||
# 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
|
||||
|
||||
### 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
|
||||
@@ -0,0 +1,146 @@
|
||||
# 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
|
||||
|
||||
### Exercise 4: Change Blink Speed
|
||||
|
||||
#### Objective
|
||||
Find the `blink_led(pin, 3, 50)` call in the `0x0026_functions` binary using GDB, identify the immediate value `0x32` (50) being loaded into `r2` (the delay parameter), calculate the file offset, and patch it to `0x19` (25) so that each LED blinks at double speed when activated by the IR remote.
|
||||
|
||||
#### 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 `blink_led` function takes a delay parameter of `50`ms (`0x32`) in register `r2`. This value controls how long each LED stays on and off during the blink cycle. By patching this to `25`ms (`0x19`), the LEDs will blink twice as fast, creating a noticeably quicker flashing pattern when any IR remote button is pressed.
|
||||
|
||||
#### 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 blink_led Call
|
||||
|
||||
Disassemble main and look for the parameter setup before `bl blink_led`:
|
||||
|
||||
```gdb
|
||||
(gdb) disassemble 0x10000234,+300
|
||||
```
|
||||
|
||||
Look for:
|
||||
|
||||
```
|
||||
movs r0, <pin> ; GPIO pin number
|
||||
movs r1, #3 ; blink count
|
||||
movs r2, #0x32 ; delay = 50ms
|
||||
bl blink_led
|
||||
```
|
||||
|
||||
Note the address of the `movs r2, #0x32` instruction.
|
||||
|
||||
##### Step 3: Examine the Instruction Encoding
|
||||
|
||||
Look at the raw bytes:
|
||||
|
||||
```gdb
|
||||
(gdb) x/2bx <address_of_movs_r2_0x32>
|
||||
```
|
||||
|
||||
The `movs r2, #0x32` instruction has `0x32` (50) as the immediate byte.
|
||||
|
||||
##### Step 4: Calculate the File Offset
|
||||
|
||||
```
|
||||
file_offset = address - 0x10000000
|
||||
```
|
||||
|
||||
Note the file offset of the byte containing `32`.
|
||||
|
||||
##### Step 5: Encode the New Value
|
||||
|
||||
| Parameter | Original | New | Effect |
|
||||
| --------- | --------------- | --------------- | --------------- |
|
||||
| Delay | `32` (50ms) | `19` (25ms) | 2x faster blink |
|
||||
|
||||
**Be careful:** `0x32` is also the ASCII code for '2'. Make sure you are patching the `movs r2` instruction and not a comparison value like `cmp r4, #0x32`.
|
||||
|
||||
##### Step 6: Patch with HxD
|
||||
|
||||
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin`
|
||||
2. Press **Ctrl+G** and enter the file offset
|
||||
3. You should see: `32`
|
||||
4. Replace with: `19`
|
||||
|
||||
###### Question 1: How can you confirm you are patching the delay parameter and not some other `0x32` byte in the binary?
|
||||
|
||||
##### 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 → Red LED blinks 3 times but **noticeably faster** (25ms on/off vs 50ms)
|
||||
- Press button 2 → Green LED blinks 3 times at **double speed**
|
||||
- Press button 3 → Yellow LED blinks 3 times at **double speed**
|
||||
- The total blink sequence should complete in roughly half the original time
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Locate function parameters in ARM Thumb `movs` instructions
|
||||
- Distinguish between identical byte values used in different contexts
|
||||
- Patch timing parameters to change observable hardware behavior
|
||||
- Understand the relationship between delay values and perceived blink speed
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: The `blink_led` function calls `sleep_ms` internally with the delay value. If you set the delay to `1`ms (0x01), would you still see the LED blink, or would it appear constantly on?
|
||||
|
||||
###### Question 2: The value `0x32` appears in this binary as both a delay parameter (50ms) and potentially as an ASCII comparison ('2'). How would you systematically find ALL occurrences of `0x32` and determine which one to patch?
|
||||
|
||||
###### Question 3: If you wanted a delay of 500ms (0x1F4), the value would not fit in a `movs` immediate. How would the compiler handle this larger delay value?
|
||||
|
||||
###### Question 4: The blink function uses the delay for both the on-time and the off-time. Could you make the LED stay on longer than it stays off? What kind of patch would that require?
|
||||
|
||||
#### Tips and Hints
|
||||
- `25` decimal = `0x19` hex — fits in one byte, so the `movs` encoding works directly
|
||||
- Verify location by checking the surrounding instructions: `movs r1, #3` should be right before and `bl blink_led` right after
|
||||
- The total blink time for 3 blinks at 50ms = 3 × (50 + 50) = 300ms; at 25ms = 3 × (25 + 25) = 150ms
|
||||
- If there are multiple call sites for `blink_led`, each may have its own `movs r2, #0x32` that needs patching
|
||||
Binary file not shown.
+1529
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user