# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)

## Week 4
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics

### Exercise 4: Patch GPIO Binary to Change LED Pin

#### Objective
Patch the `0x0008_uninitialized-variables.bin` binary to change which LED blinks, modify the printed value, and change the blink timing, then verify all changes work correctly on hardware.

#### Prerequisites
- Completed Exercise 3 (GPIO binary analyzed in Ghidra)
- Understanding of how GPIO pin numbers are encoded
- Knowledge of hexadecimal-to-decimal conversion
- Pico 2 with ability to test multiple GPIO pins

#### Task Description
You will locate all instances where GPIO 16 is used, patch them to GPIO 17 (changing from red LED to green LED), modify the printed value from 0 to 66, and adjust the blink timing from 500ms to 100ms for faster blinking.

#### Step-by-Step Instructions

##### Step 1: Plan Your Patches

Before we start patching, let's identify what needs to change:

| Current Value | New Value | Description           | Hex Conversion      |
| ------------- | --------- | --------------------- | ------------------- |
| GPIO 16       | GPIO 17   | Change LED pin        | 0x10 → 0x11         |
| age = 0       | age = 66  | Change printed value  | 0x00 → 0x42         |
| 500ms         | 100ms     | Change blink timing   | 0x1f4 → 0x64        |

**Verify the hex conversions:**
- 17 decimal = 0x11 hex ✓
- 66 decimal = 0x42 hex ✓
- 100 decimal = 0x64 hex ✓

##### Step 2: Open the GPIO Project in Ghidra

1. Launch Ghidra and open `week04-ex03-gpio-analysis`
2. Double-click the binary to open the CodeBrowser
3. Navigate to the `main` function

**Review the decompiled code:**
```c
int main(void)
{
    stdio_init_all();
    gpio_init(0x10);
    gpio_set_dir(0x10, 1);
    
    while (true) {
        printf("age: %d\r\n", 0);
        gpio_put(0x10, 1);
        sleep_ms(0x1f4);
        gpio_put(0x10, 0);
        sleep_ms(0x1f4);
    }
}
```

##### Step 3: Find and Patch gpio_init Parameter

Look at the **Listing** window (assembly view) for the main function.

**Find the gpio_init call:**
```assembly
1000023a    10 20    movs    r0, #0x10
1000023c    xx xx    bl      gpio_init
```

**Patch instruction:**
1. Right-click on `movs r0, #0x10`
2. Select **Patch Instruction**
3. Change `#0x10` to `#0x11`
4. Press **Enter**

**Result:**
```assembly
1000023a    11 20    movs    r0, #0x11
```

The instruction bytes change from `10 20` to `11 20`.

##### Step 4: Find and Patch gpio_set_dir Parameter

Continue down the assembly listing:

```assembly
10000240    10 23    movs    r3, #0x10
10000242    01 22    movs    r2, #1
10000244    xx xx    bl      gpio_set_dir
```

**Patch the r3 load:**
1. Right-click on `movs r3, #0x10`
2. Select **Patch Instruction**
3. Change to `#0x11`
4. Press **Enter**

**Why r3 instead of r0?** The SDK might pass GPIO pin as the first parameter differently, or this could be due to register allocation. Trust the analysis!

##### Step 5: Find All gpio_put Calls

Inside the while loop, there are two `gpio_put` calls:

**First gpio_put (LED ON):**
```assembly
10000252    10 24    movs    r4, #0x10
10000254    01 25    movs    r5, #1
10000256    xx xx    bl      gpio_put
```

**Patch:**
1. Right-click on `movs r4, #0x10`
2. Change to `#0x11`

**Second gpio_put (LED OFF):**
```assembly
1000025e    10 24    movs    r4, #0x10
10000260    00 25    movs    r5, #0
10000262    xx xx    bl      gpio_put
```

**Patch:**
1. Right-click on `movs r4, #0x10`
2. Change to `#0x11`

**Note:** The exact addresses will vary, but the pattern is consistent.

##### Step 6: Patch the Printed Value

Find the printf call in the loop:

```assembly
1000024a    00 21    movs    r1, #0x0
1000024c    xx xx    ldr     r0, [pc, #offset]
1000024e    xx xx    bl      printf
```

**Patch the value:**
1. Right-click on `movs r1, #0x0`
2. Select **Patch Instruction**
3. Change to `#0x42` (66 in decimal)
4. Press **Enter**

**Result:**
```assembly
1000024a    42 21    movs    r1, #0x42
```

##### Step 7: Patch the Sleep Timing (First)

Find the first `sleep_ms(0x1f4)` call:

```assembly
10000258    f4 21    movs    r1, #0xf4
1000025a    01 20    movs    r0, #1
1000025c    00 04    lsls    r0, r0, #16
1000025e    08 44    add     r0, r1
10000260    xx xx    bl      sleep_ms
```

**Wait, this looks complex!** The value 0x1f4 (500) is being constructed:
- Load 1 into r0
- Shift left 16 bits: 1 << 16 = 0x10000
- Load 0xf4 into r1  
- Add them: 0x10000 + 0xf4 = 0x1f4

**Alternative pattern (simpler):**
```assembly
10000xxx    f4 20    movs    r0, #0xf4
10000xxx    01 20    movs    r1, #0x01
10000xxx    ...
```

**For 100ms (0x64):**
Simply find where 0x1f4 is loaded and change it to 0x64.

**If the instruction is:**
```assembly
movs    r0, #0x1f4
```

**Change to:**
```assembly
movs    r0, #0x64
```

**Note:** The exact encoding depends on the instruction. For immediate values > 255, Thumb-2 uses different encodings.

##### Step 8: Handle Large Immediate Values

If `sleep_ms(500)` uses a multi-instruction sequence to load 0x1f4, you have two options:

**Option A: Patch both instructions**
If it's loading 0x1f4 as (0x100 + 0xf4):
1. Find where 0xf4 is loaded
2. Change it to 0x64
3. Find where 0x1 is loaded for the high byte
4. Change it to 0x0

**Option B: Simplify to single instruction**
Since 0x64 (100) fits in an 8-bit immediate, you can replace the multi-instruction sequence with:
```assembly
movs    r0, #0x64
nop
nop
```

##### Step 9: Verify All Patches

Check the **Decompile** window to confirm changes:

```c
int main(void)
{
    stdio_init_all();
    gpio_init(0x11);        // Changed from 0x10!
    gpio_set_dir(0x11, 1);
    
    while (true) {
        printf("age: %d\r\n", 0x42);  // Changed from 0!
        gpio_put(0x11, 1);            // Changed from 0x10!
        sleep_ms(0x64);               // Changed from 0x1f4!
        gpio_put(0x11, 0);            // Changed from 0x10!
        sleep_ms(0x64);               // Changed from 0x1f4!
    }
}
```

Perfect! All changes are reflected.

##### Step 10: Export the Patched Binary

1. Click **File** → **Export Program**
2. Set Format: **Binary**
3. Navigate to: `Embedded-Hacking\0x0008_uninitialized-variables\build\`
4. Filename: `0x0008_uninitialized-variables-h.bin`
5. Click **OK**

##### Step 11: Convert to UF2

Open PowerShell and navigate to the project:

```powershell
cd C:\path\to\Embedded-Hacking\0x0008_uninitialized-variables
```

**Run conversion:**
```powershell
python ..\uf2conv.py build\0x0008_uninitialized-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
```

**Expected output:**
```
Converting to uf2, output size: 61952, start address: 0x10000000
Wrote 61952 bytes to build\hacked.uf2
```

##### Step 12: Flash and Test

**Enter bootloader:**
1. Hold **BOOTSEL** button
2. Plug in USB
3. Release BOOTSEL

**Flash:**
1. Drag `build\hacked.uf2` to RPI-RP2 drive
2. Pico reboots automatically

**Test with serial monitor:**
```
age: 66
age: 66
age: 66
...
```

**Hardware verification:**
- ✅ GREEN LED (GPIO 17) should be blinking
- ✅ RED LED (GPIO 16) should be off
- ✅ Blink rate should be much faster (10 Hz instead of 1 Hz)
- ✅ Serial output shows 66 instead of 0

🎉 **Triple success!** You've patched three different aspects of the program!

#### Expected Output

After completing this exercise, you should:
- See `age: 66` printing continuously
- Observe the green LED (GPIO 17) blinking rapidly
- Understand how to find and patch all instances of a value
- Know how to handle different immediate value encoding schemes

#### Questions for Reflection

###### Question 1: Why did we need to patch GPIO 16 in multiple places (gpio_init, gpio_set_dir, gpio_put)?

###### Question 2: What would happen if you forgot to patch one of the gpio_put calls?

###### Question 3: How does the instruction encoding differ for immediate values less than 256 vs. greater than 255?

###### Question 4: If you wanted to make the LED blink at exactly 5 Hz, what sleep_ms value would you use?

#### Tips and Hints
- Use Ghidra's **Search** → **For Scalars** to find all instances of a hex value
- Right-click in Listing → **Highlight** → **Highlight Instruction** helps track your patches
- Make notes of addresses you've patched to avoid confusion
- Test incrementally - patch one thing at a time if you're unsure
- Keep the original UF2 to revert if needed

#### Next Steps
- Try patching to use GPIO 18 (blue LED) instead
- Change the printf format string to display in hexadecimal
- Experiment with different timing patterns (e.g., 200ms on, 800ms off)

#### Additional Challenge

**Advanced Multi-LED Pattern:**

Patch the binary to create an alternating pattern:
- GPIO 16 (red) blinks for 100ms
- GPIO 17 (green) blinks for 100ms  
- GPIO 18 (blue) blinks for 100ms
- Repeat

This requires:
1. Adding new gpio_init and gpio_set_dir calls for GPIO 18
2. Restructuring the while loop to have three gpio_put sequences
3. Finding space in the binary or replacing existing code

**Hint:** You might need to NOP out some instructions and carefully insert new ones. This is advanced patching!

#### Verification Checklist

Before moving on, confirm:
- [ ] GPIO 17 LED blinks (not GPIO 16)
- [ ] Blink rate is approximately 10 Hz (100ms on/off)
- [ ] Serial output shows "age: 66"
- [ ] You can explain each patch you made
- [ ] You understand why each patch was necessary
- [ ] You successfully converted and flashed the UF2

**Congratulations!** You've completed all Week 4 exercises and mastered variable analysis, binary patching, and GPIO manipulation!
