mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-18 14:04:48 +02:00
145 lines
5.3 KiB
Markdown
145 lines
5.3 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 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
|