mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-09 10:55:46 +02:00
184 lines
6.2 KiB
Markdown
184 lines
6.2 KiB
Markdown
# Embedded Systems Reverse Engineering
|
|
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
|
|
|
## Week 6
|
|
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
|
|
|
|
### Non-Credit Practice Exercise 3: Make the Overflow Happen Faster
|
|
|
|
#### Objective
|
|
Patch the `adds r3, #0x1` instruction — which increments `static_fav_num` by 1 each loop iteration — to `adds r3, #0xa` so the variable increments by 10 instead. Use GDB to locate the instruction, calculate the hex editor file offset, patch the binary, and verify on hardware that the `uint8_t` overflow occurs roughly 10 times sooner.
|
|
|
|
#### Prerequisites
|
|
- Completed Week 6 tutorial (GDB and hex editor sections)
|
|
- `0x0014_static-variables.bin` binary 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 connected via USB
|
|
- Serial monitor software (PuTTY, minicom, or screen)
|
|
|
|
#### Task Description
|
|
The static variable `static_fav_num` is a `uint8_t` that counts from 42 to 255 before wrapping to 0. Currently it increments by 1 each iteration, so it takes 214 steps to overflow. You will change the increment value from 1 to 10 so that it overflows after only ~22 steps. This exercise teaches you how Thumb immediate encoding works for small arithmetic instructions and demonstrates the real-world impact of patching arithmetic operations.
|
|
|
|
#### 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\0x0014_static-variables.elf
|
|
```
|
|
|
|
**Connect to target:**
|
|
|
|
```gdb
|
|
(gdb) target remote :3333
|
|
(gdb) monitor reset halt
|
|
```
|
|
|
|
##### Step 2: Locate the Increment Instruction
|
|
|
|
From the tutorial, we know the static variable operations are in the loop body starting at `0x10000274`. Disassemble the loop body:
|
|
|
|
```gdb
|
|
(gdb) x/20i 0x10000274
|
|
```
|
|
|
|
Look for this sequence:
|
|
|
|
```
|
|
0x10000278: ldrb r3, [r4, #0] ; Load static_fav_num from RAM
|
|
0x1000027a: movs r2, #16 ; LED GPIO pin number
|
|
0x1000027c: adds r3, #1 ; Increment by 1 ? THIS IS OUR TARGET
|
|
0x1000027e: strb r3, [r4, #0] ; Store back to RAM
|
|
```
|
|
|
|
The `adds r3, #1` instruction is at address `0x1000027c`.
|
|
|
|
##### Step 3: Examine the Instruction Encoding
|
|
|
|
Look at the raw bytes of the instruction:
|
|
|
|
```gdb
|
|
(gdb) x/2bx 0x1000027c
|
|
```
|
|
|
|
You should see:
|
|
|
|
```
|
|
01 33
|
|
```
|
|
|
|
**Thumb encoding breakdown:**
|
|
- `01` = the immediate value `0x01` (decimal 1)
|
|
- `33` = the opcode for `adds r3, #imm8`
|
|
|
|
##### Step 4: Test the Change in GDB First
|
|
|
|
Before making a permanent patch, test the change in RAM:
|
|
|
|
```gdb
|
|
(gdb) b *0x1000027c
|
|
(gdb) c
|
|
```
|
|
|
|
When the breakpoint hits:
|
|
|
|
```gdb
|
|
(gdb) x/1db 0x200005a8
|
|
```
|
|
|
|
Note the current value of `static_fav_num`. Now continue a few iterations and check how it increments.
|
|
|
|
##### Step 5: Calculate the File Offset
|
|
|
|
```
|
|
file_offset = address - 0x10000000
|
|
```
|
|
|
|
For the `adds r3, #0x1` instruction at its address, calculate the offset.
|
|
|
|
##### Step 6: Patch with the Hex Editor
|
|
|
|
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables\build\0x0014_static-variables.bin`
|
|
2. Press **Ctrl+G** (Go to offset) and enter the calculated offset
|
|
3. You should see the byte `01` followed by `33`
|
|
4. Change `01` to `0A` (10 in decimal)
|
|
5. Verify: the bytes should now read `0A 33` — encoding `adds r3, #0xa`
|
|
6. Click **File** ? **Save As** ? `0x0014_static-variables-h.bin` (in the same `build` directory)
|
|
|
|
> ?? **Why this works:** In Thumb `adds rD, #imm8` encoding, the immediate value is stored in the first byte. The `#imm8` field accepts values 0-255, so changing 1 to 10 is safe.
|
|
|
|
##### Step 7: Convert to UF2 and Flash
|
|
|
|
```powershell
|
|
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables
|
|
python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
|
```
|
|
|
|
1. Hold BOOTSEL and plug in your Pico 2
|
|
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
|
3. Open your serial monitor
|
|
|
|
##### Step 8: Verify the Hack
|
|
|
|
**Expected serial output:**
|
|
```
|
|
regular_fav_num: 42
|
|
static_fav_num: 42
|
|
regular_fav_num: 42
|
|
static_fav_num: 52 ? Jumped by 10!
|
|
regular_fav_num: 42
|
|
static_fav_num: 62
|
|
...
|
|
regular_fav_num: 42
|
|
static_fav_num: 242
|
|
regular_fav_num: 42
|
|
static_fav_num: 252
|
|
regular_fav_num: 42
|
|
static_fav_num: 6 ? Overflow! 252 + 10 = 262, but uint8_t wraps: 262 - 256 = 6
|
|
```
|
|
|
|
Notice the overflow now happens much sooner, and the wrap value is no longer 0 — it's 6 because `252 + 10 = 262` which wraps to `262 mod 256 = 6`.
|
|
|
|
#### Expected Output
|
|
|
|
After completing this exercise, you should be able to:
|
|
- Locate arithmetic instructions in disassembled code
|
|
- Understand Thumb `adds rD, #imm8` encoding
|
|
- Patch an immediate operand in a hex editor
|
|
- Predict the effects of changing an increment value on overflow behavior
|
|
|
|
#### Questions for Reflection
|
|
|
|
###### Question 1: The overflow now wraps to 6 instead of 0. Explain why, using the modular arithmetic of a `uint8_t` (range 0-255).
|
|
|
|
###### Question 2: What is the maximum value you could change the increment to while still using `adds r3, #imm8`? What would happen if you needed an increment larger than 255?
|
|
|
|
###### Question 3: If you changed the increment to 128 (`0x80`), how many iterations would it take to wrap, and what value would it wrap to?
|
|
|
|
###### Question 4: Could you achieve the same speedup by changing the `strb` (store byte) to `strh` (store halfword)? Why or why not?
|
|
|
|
#### Tips and Hints
|
|
- In Thumb encoding, `adds rD, #imm8` has the immediate in the first byte and opcode in the second
|
|
- The `imm8` field is 8 bits, so valid ranges are `0x00` to `0xFF` (0-255)
|
|
- Overflow for `uint8_t` is $(value) \bmod 256$
|
|
- Use GDB to verify: `set *(unsigned char*)0x200005a8 = 250` then continue to watch the wrap quickly
|
|
|
|
#### Next Steps
|
|
- Proceed to Exercise 4 to learn about inverting button logic with XOR
|
|
- Try changing the increment to other values (2, 5, 50, 128) and predict the wrap behavior before flashing
|
|
- Consider: what would happen if you changed `adds` to `subs` (subtract)?
|