mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-06-07 23:03:59 +02:00
Updated WEEK04
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 11
|
||||
Functions in Embedded Systems: Debugging and Hacking Functions w/ IR Remote and Multi-LED Control
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Add a Fourth LED
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Struct Layout (simple_led_ctrl_t)
|
||||
|
||||
| Offset | Field | Size | Original Value | Hex |
|
||||
|--------|------------|--------|----------------|------|
|
||||
| 0 | led1_pin | 1 byte | GPIO 16 | 0x10 |
|
||||
| 1 | led2_pin | 1 byte | GPIO 17 | 0x11 |
|
||||
| 2 | led3_pin | 1 byte | GPIO 18 | 0x12 |
|
||||
| 3 | led1_state | 1 byte | false (0) | 0x00 |
|
||||
| 4 | led2_state | 1 byte | false (0) | 0x00 |
|
||||
| 5 | led3_state | 1 byte | false (0) | 0x00 |
|
||||
|
||||
Total struct size: **6 bytes** (3 pin bytes + 3 state bytes).
|
||||
|
||||
##### Assembly Initialization Pattern
|
||||
|
||||
```asm
|
||||
movs r0, #0x10 ; led1_pin = 16
|
||||
strb r0, [r4, #0] ; struct offset 0
|
||||
movs r0, #0x11 ; led2_pin = 17
|
||||
strb r0, [r4, #1] ; struct offset 1
|
||||
movs r0, #0x12 ; led3_pin = 18
|
||||
strb r0, [r4, #2] ; struct offset 2
|
||||
```
|
||||
|
||||
##### Patch: Add GPIO 19 at Struct Offset 3
|
||||
|
||||
Writing `0x13` to offset 3 **overwrites led1_state**:
|
||||
|
||||
| Offset | Before | After | Impact |
|
||||
|--------|-------------|-------------|----------------------|
|
||||
| 3 | 0x00 (led1_state = false) | 0x13 (led4_pin = GPIO 19) | led1_state corrupted |
|
||||
|
||||
##### GDB Verification
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x10000280
|
||||
(gdb) c
|
||||
(gdb) x/8bx <struct_address>
|
||||
```
|
||||
|
||||
Before patch: `10 11 12 00 00 00`
|
||||
After patch: `10 11 12 13 00 00`
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
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?**
|
||||
The byte `0x13` (decimal 19) is written to offset 3, which the program reads as `led1_state`. Since `bool` in C treats any non-zero value as `true`, `led1_state` would be interpreted as `true` (on) immediately after the struct is initialized. LED 1 would appear to be in the "on" state from the start, regardless of whether the user pressed button 1. The `leds_all_off` function may reset it to 0, but every time the struct is re-initialized on the stack (each loop iteration), the corrupted state returns. The fourth LED at GPIO 19 would need additional `gpio_init` and `gpio_set_dir` calls to actually function — just writing the pin number into the struct doesn't configure the GPIO hardware.
|
||||
|
||||
2. **How would you verify the exact struct layout and offsets using GDB's memory examination commands?**
|
||||
Set a breakpoint after struct initialization (`b *0x10000280`), then `x/6bx <struct_base>` to see all 6 bytes. Verify: offsets 0–2 should show `10 11 12` (pin values), offsets 3–5 should show `00 00 00` (state values). Use `x/1bx <struct_base+N>` for individual fields. To find the struct base, examine `r4` at the breakpoint since the `strb r0, [r4, #N]` instructions use r4 as the base. You can also use `p/x $r4` to get the base address, then `x/6bx $r4` for the complete layout.
|
||||
|
||||
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?**
|
||||
You would need to find the comparison instruction in `get_led_pin` (at approximately `0x100002a0`) — likely a `cmp rN, #3` followed by a conditional branch. Patch the immediate from `#3` to `#4` so the bounds check allows led_num = 4. For example, if the check is `cmp r1, #3; bhi default`, change `03` to `04` in the `cmp` instruction's immediate byte. Without this patch, passing led_num=4 would fail the bounds check and return 0 (no pin), so the fourth LED would never be addressed.
|
||||
|
||||
4. **Could you extend the struct without overwriting existing fields by finding free space elsewhere in the binary? What challenges would that introduce?**
|
||||
You could find unused space (padding, NOP sleds, or unused data) and place the extended struct there. However, this introduces major challenges: (1) Every instruction that references the original struct address via `r4` would need to be redirected to the new location. (2) All `strb`/`ldrb` offsets would need updating. (3) Stack-allocated structs are recreated each loop iteration — you'd need to change the stack frame size (`sub sp, sp, #N`). (4) Functions that receive the struct pointer as an argument would need their call sites updated. In practice, relocating a struct in a compiled binary is extremely complex and error-prone — overwriting adjacent fields is the pragmatic (if destructive) approach.
|
||||
@@ -1,156 +0,0 @@
|
||||
# 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
|
||||
@@ -1,62 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 11
|
||||
Functions in Embedded Systems: Debugging and Hacking Functions w/ IR Remote and Multi-LED Control
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Change Blink Count
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Blink Count Parameter
|
||||
|
||||
| Parameter | Original | Patched |
|
||||
|-------------|---------|---------|
|
||||
| Blink count | 3 | 5 |
|
||||
| Hex | 0x03 | 0x05 |
|
||||
| Register | r1 | r1 |
|
||||
| Instruction | movs r1, #3 | movs r1, #5 |
|
||||
|
||||
##### Assembly Context (blink_led Call)
|
||||
|
||||
```asm
|
||||
movs r0, <pin> ; r0 = GPIO pin number
|
||||
movs r1, #3 ; r1 = blink count ← PATCH THIS
|
||||
movs r2, #0x32 ; r2 = delay (50ms)
|
||||
bl blink_led ; blink_led(pin, 3, 50)
|
||||
```
|
||||
|
||||
##### Patch
|
||||
|
||||
The immediate byte in `movs r1, #3` is the first byte of the 2-byte Thumb instruction:
|
||||
|
||||
```
|
||||
Before: 03 21 (movs r1, #3)
|
||||
After: 05 21 (movs r1, #5)
|
||||
```
|
||||
|
||||
File offset = instruction address - 0x10000000.
|
||||
|
||||
##### Behavior After Patch
|
||||
|
||||
| Button | LED | Original | Patched |
|
||||
|--------|--------|-------------------|---------------------|
|
||||
| 1 | Red | Blinks 3×, stays on | Blinks 5×, stays on |
|
||||
| 2 | Green | Blinks 3×, stays on | Blinks 5×, stays on |
|
||||
| 3 | Yellow | Blinks 3×, stays on | Blinks 5×, stays on |
|
||||
|
||||
Total blink time at 50ms delay: 5 × (50 + 50) = **500ms** (was 300ms).
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **movs rN, #imm8 can encode values 0–255. What is the maximum blink count with a single byte patch?**
|
||||
The maximum is **255** (`0xFF`). The `movs Rd, #imm8` Thumb instruction uses a full 8-bit immediate field, giving an unsigned range of 0–255. Setting the blink count to 255 would make each LED blink 255 times per button press — at 50ms on + 50ms off per blink, that's 255 × 100ms = **25.5 seconds** of blinking before the LED stays on. A count of 0 would skip the blink loop entirely (LED turns on immediately with no blinking).
|
||||
|
||||
2. **Why is blink count in r1 and not r0? What does r0 hold at this point?**
|
||||
The ARM calling convention (AAPCS) passes the first four function arguments in registers `r0`, `r1`, `r2`, `r3` in order. The `blink_led` function signature is `blink_led(uint8_t pin, uint8_t count, uint32_t delay_ms)`. So `r0` = pin (the GPIO number of the LED to blink), `r1` = count (how many times to blink), and `r2` = delay_ms (the delay in milliseconds between on/off transitions). The blink count is the second parameter, hence `r1`.
|
||||
|
||||
3. **If you wanted a blink count larger than 255 (e.g., 1000), what instruction sequence would the compiler generate instead of movs?**
|
||||
For values exceeding 255, the compiler would use a 32-bit Thumb-2 `movw r1, #imm16` instruction, which can encode 0–65535. For example, `movw r1, #1000` would be 4 bytes: `40 F2 E8 31` (encoding `movw r1, #0x3E8`). For values exceeding 65535, the compiler would add `movt r1, #imm16` to set the upper 16 bits, or use a literal pool load (`ldr r1, [pc, #offset]`). The function parameter type (`uint8_t`) would still truncate to 0–255, so a count of 1000 would wrap to 232 (1000 mod 256) unless the function uses a wider type internally.
|
||||
|
||||
4. **Is there one shared movs r1, #3 instruction for all three LEDs, or does each blink_led call have its own? How can you tell?**
|
||||
Each `blink_led` call likely has its **own** `movs r1, #3` instruction. The compiler generates separate parameter setup sequences for each `bl blink_led` call site — the `movs r0, <pin>` instruction before each call loads a different GPIO pin. You can verify by disassembling the full range (`disassemble 0x10000234,+300`) and counting how many `movs r1, #3` instructions appear before `bl blink_led` calls. If there are three separate call sites with three separate `movs r1, #3` instructions, you need to **patch all three** to change the blink count for every LED. If only one is patched, only that LED's blink count changes.
|
||||
@@ -1,144 +0,0 @@
|
||||
# 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
|
||||
@@ -1,70 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 11
|
||||
Functions in Embedded Systems: Debugging and Hacking Functions w/ IR Remote and Multi-LED Control
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Swap All Three LEDs
|
||||
|
||||
#### Answers
|
||||
|
||||
##### GPIO Rotation Patch
|
||||
|
||||
| Struct Member | Original | Patched | Effect |
|
||||
|--------------|-----------------|-----------------|---------------------|
|
||||
| led1_pin | 0x10 (GPIO 16 Red) | 0x11 (GPIO 17 Green) | Button 1 → Green |
|
||||
| led2_pin | 0x11 (GPIO 17 Green) | 0x12 (GPIO 18 Yellow) | Button 2 → Yellow |
|
||||
| led3_pin | 0x12 (GPIO 18 Yellow) | 0x10 (GPIO 16 Red) | Button 3 → Red |
|
||||
|
||||
##### Assembly Patches
|
||||
|
||||
Three single-byte patches in `movs` immediate fields:
|
||||
|
||||
```
|
||||
Patch 1 (led1_pin): 10 → 11
|
||||
Before: 10 20 (movs r0, #0x10)
|
||||
After: 11 20 (movs r0, #0x11)
|
||||
|
||||
Patch 2 (led2_pin): 11 → 12
|
||||
Before: 11 20 (movs r0, #0x11)
|
||||
After: 12 20 (movs r0, #0x12)
|
||||
|
||||
Patch 3 (led3_pin): 12 → 10
|
||||
Before: 12 20 (movs r0, #0x12)
|
||||
After: 10 20 (movs r0, #0x10)
|
||||
```
|
||||
|
||||
##### GDB Verification
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x10000280
|
||||
(gdb) c
|
||||
(gdb) x/6bx <struct_address>
|
||||
```
|
||||
|
||||
Before patch: `10 11 12 00 00 00`
|
||||
After patch: `11 12 10 00 00 00`
|
||||
|
||||
##### Behavior After Patch
|
||||
|
||||
| Button (IR) | NEC Code | Terminal Log | Actual LED |
|
||||
|------------|----------|---------------------------|-----------|
|
||||
| Button 1 | 0x0C | "LED 1 activated on GPIO 16" | Green (GPIO 17) |
|
||||
| Button 2 | 0x18 | "LED 2 activated on GPIO 17" | Yellow (GPIO 18) |
|
||||
| Button 3 | 0x5E | "LED 3 activated on GPIO 18" | Red (GPIO 16) |
|
||||
|
||||
The terminal logs are **desynchronized** from actual behavior.
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **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?**
|
||||
The `printf` format strings and their arguments are separate from the struct pin assignments. The log message "LED 1 activated on GPIO 16" is generated from hardcoded format strings or from reading the **original** pin value before our patch takes effect. The GPIO number in the log comes from a different code path — likely a format string like `"LED %d activated on GPIO %d\r\n"` where the GPIO value was loaded from the struct at a different point or is computed independently. Since we only patched the `movs` instructions that store pin values into the struct, the logging code still uses whatever values it computes independently.
|
||||
|
||||
2. **If the struct initialization used ldr from a literal pool instead of movs immediates, how would the patching differ?**
|
||||
With literal pool loads, the pin values would be stored as 32-bit words in a data area near the function code. You would need to: (1) find the `ldr r0, [pc, #offset]` instruction, (2) calculate the PC-relative offset to locate the literal pool entry, (3) navigate to the pool address in the hex editor, and (4) modify the 4-byte value there. For example, GPIO 16 would be `10 00 00 00` (little-endian) in the pool. This is more work than patching a 1-byte `movs` immediate, and you'd need to verify no other code shares the same pool entry. The `movs` approach is simpler because the value is encoded directly in the instruction.
|
||||
|
||||
3. **Could you achieve the same LED rotation by patching gpio_init/gpio_put calls instead of the struct initialization? Which approach is cleaner?**
|
||||
Patching `gpio_init` and `gpio_put` calls would require finding every call site that references each GPIO pin and modifying the pin argument. This is scattered throughout multiple functions (`process_ir_led_command`, `blink_led`, `leds_all_off`). The struct initialization approach is **far cleaner** — three adjacent `movs` instructions in one location control the entire mapping. By patching the struct data at its source, every function that reads from the struct automatically gets the new values. This demonstrates the power of data-driven design: changing the data at one point affects all code that uses it.
|
||||
|
||||
4. **In a real attack, why is log desynchronization (display says one thing, hardware does another) dangerous for forensic analysis?**
|
||||
Log desynchronization is dangerous because forensic investigators rely on logs to reconstruct what happened. If logs show "LED 1 on GPIO 16" but the hardware actually activated GPIO 17, investigators would draw incorrect conclusions about which physical device was controlled. In industrial systems, this could mask sabotage — operators see "normal" readings while equipment is being misused. In security systems, tampered firmware could log "door locked" while actually unlocking it. The logs become actively misleading, not just incomplete. This is a form of **anti-forensics** that makes post-incident analysis unreliable and can delay or prevent discovery of the actual attack.
|
||||
@@ -1,150 +0,0 @@
|
||||
# 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
|
||||
@@ -1,60 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 11
|
||||
Functions in Embedded Systems: Debugging and Hacking Functions w/ IR Remote and Multi-LED Control
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Change Blink Speed
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Delay Parameter
|
||||
|
||||
| Parameter | Original | Patched |
|
||||
|----------|-------------|--------------|
|
||||
| Delay | 50ms | 25ms |
|
||||
| Hex | 0x32 | 0x19 |
|
||||
| Register | r2 | r2 |
|
||||
| Instruction | movs r2, #0x32 | movs r2, #0x19 |
|
||||
|
||||
##### Assembly Context
|
||||
|
||||
```asm
|
||||
movs r0, <pin> ; r0 = GPIO pin
|
||||
movs r1, #3 ; r1 = blink count
|
||||
movs r2, #0x32 ; r2 = delay 50ms ← PATCH THIS
|
||||
bl blink_led ; blink_led(pin, 3, 50)
|
||||
```
|
||||
|
||||
##### Patch
|
||||
|
||||
```
|
||||
Before: 32 22 (movs r2, #0x32 = 50ms)
|
||||
After: 19 22 (movs r2, #0x19 = 25ms)
|
||||
```
|
||||
|
||||
**Warning:** The byte `0x32` is also ASCII '2'. Verify you're patching the correct `movs r2` instruction by checking surrounding bytes — `movs r1, #3` (`03 21`) should appear immediately before, and `bl blink_led` immediately after.
|
||||
|
||||
##### Timing Comparison
|
||||
|
||||
| Metric | Original (50ms) | Patched (25ms) |
|
||||
|-------------------|-----------------|----------------|
|
||||
| On-time per blink | 50ms | 25ms |
|
||||
| Off-time per blink| 50ms | 25ms |
|
||||
| One blink cycle | 100ms | 50ms |
|
||||
| 3 blinks total | 300ms | 150ms |
|
||||
| Perceived speed | Normal | 2× faster |
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **If delay = 1ms (0x01), would you still see the LED blink, or would it appear constantly on?**
|
||||
At 1ms on/off (2ms per cycle, 500Hz flicker), the LED would appear **constantly on** to the human eye. Human flicker fusion threshold is approximately 60Hz — anything above that appears as a steady light. At 500Hz, the LED is switching far too fast for the eye to perceive individual blinks. The LED would look like it's at roughly 50% brightness (since it's on half the time) compared to being fully on. The 3 blinks would complete in just 6ms total, appearing as a brief flash rather than distinct blinks.
|
||||
|
||||
2. **0x32 appears as both the delay value (50ms) and potentially ASCII '2'. How would you systematically find ALL occurrences of 0x32 and determine which to patch?**
|
||||
Search the binary for all `0x32` bytes, then examine the **context** of each occurrence: (1) Check the byte following `0x32` — if it's `0x22`, this is `movs r2, #0x32` (the delay parameter). If it's `0x2C`, it's `cmp r4, #0x32` (comparing against ASCII '2'). (2) Examine surrounding instructions: the delay `0x32` will be preceded by `movs r1, #3` (blink count) and followed by `bl blink_led`. A comparison `0x32` will be near `beq`/`bne` branches. (3) Use GDB to disassemble the region (`x/10i <addr-4>`) and read the instruction mnemonic. (4) Cross-reference with the function structure — delay patches are in `blink_led` call setup, comparisons are in `ir_to_led_number` or similar dispatcher functions.
|
||||
|
||||
3. **For a delay of 500ms (0x1F4), the value won't fit in a movs immediate (max 255). How would the compiler handle it?**
|
||||
For 500 (`0x1F4`), the compiler would use either: (1) A 32-bit `movw r2, #0x1F4` Thumb-2 instruction (4 bytes), which can encode any 16-bit immediate (0–65535). (2) A literal pool load: `ldr r2, [pc, #offset]` that reads `0x000001F4` from a nearby data word. The `movw` approach is preferred for values 256–65535 because it's a single instruction with no data dependency. For values exceeding 65535, a literal pool or `movw`+`movt` pair would be necessary.
|
||||
|
||||
4. **The blink function uses the delay for both on-time and off-time (symmetrical blink). Could you make the LED stay on longer than off by patching only one instruction?**
|
||||
Not with a single patch to the `movs r2` instruction, because `blink_led` uses the same delay parameter for both the on-phase and off-phase `sleep_ms` calls internally. To create asymmetric blink timing, you would need to patch **inside** the `blink_led` function itself — find the two `sleep_ms` calls within the blink loop and modify their delay arguments independently. For example, find the `ldr`/`movs` that sets up `r0` before each `bl sleep_ms` inside `blink_led`, and patch one to a different value. This would require disassembling `blink_led` to locate both `sleep_ms` call sites.
|
||||
@@ -1,146 +0,0 @@
|
||||
# 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 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
|
||||
+359
-384
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user