mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-19 22:38:05 +02:00
221 lines
6.5 KiB
Markdown
221 lines
6.5 KiB
Markdown
# 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 2: Patch Binary to Change Variable Value
|
|
|
|
#### Objective
|
|
Use Ghidra's patching capabilities to modify the compiled binary, changing the value printed by the program from 43 to a different value of your choice, then convert and flash the modified binary to the Pico 2.
|
|
|
|
#### Prerequisites
|
|
- Completed Exercise 1 (binary imported and analyzed in Ghidra)
|
|
- Python installed for UF2 conversion
|
|
- `uf2conv.py` script available in your project directory
|
|
- Raspberry Pi Pico 2 connected via USB
|
|
- Serial monitor software (PuTTY, minicom, or screen)
|
|
|
|
#### Task Description
|
|
You will locate the instruction that loads the value 43 into a register, patch it to use a different value (70 in this example), export the modified binary, convert it to UF2 format, and flash it to verify the change.
|
|
|
|
#### Step-by-Step Instructions
|
|
|
|
##### Step 1: Open Your Ghidra Project
|
|
|
|
If you closed Ghidra from Exercise 1:
|
|
1. Launch `ghidraRun`
|
|
2. Open the project: `week04-ex01-intro-to-variables`
|
|
3. Double-click the binary file to open it
|
|
|
|
##### Step 2: Navigate to the Value Load Instruction
|
|
|
|
In Exercise 1, we found that `main()` calls `printf("age: %d\r\n", 0x2b)`.
|
|
|
|
**Find the assembly instruction:**
|
|
1. Click on the `main` function in the Symbol Tree
|
|
2. Look at the **Listing** window (assembly view)
|
|
3. Find the line with `movs r1, #0x2b`
|
|
|
|
The instruction should look like:
|
|
```assembly
|
|
10000xxx 21 2b movs r1, #0x2b
|
|
```
|
|
|
|
**What this instruction means:**
|
|
- Opcode: `21 2b` (encoded instruction bytes)
|
|
- Mnemonic: `movs r1, #0x2b`
|
|
- Operation: Move the immediate value 0x2b into register r1
|
|
- Register r1 will be used as the argument to printf
|
|
|
|
##### Step 3: Choose Your New Value
|
|
|
|
Let's change the value from `43` (0x2b) to `70` (0x46).
|
|
|
|
**Convert 70 to hexadecimal:**
|
|
- 70 ÷ 16 = 4 remainder 6
|
|
- Therefore: 70 decimal = 0x46 hexadecimal
|
|
|
|
You can verify this in Python:
|
|
```python
|
|
>>> hex(70)
|
|
'0x46'
|
|
>>> 0x46
|
|
70
|
|
```
|
|
|
|
##### Step 4: Patch the Instruction
|
|
|
|
Now we'll modify the binary:
|
|
|
|
1. **Right-click** on the instruction `movs r1, #0x2b`
|
|
2. Select **Patch Instruction**
|
|
3. A dialog appears showing the current instruction
|
|
4. Change `#0x2b` to `#0x46`
|
|
5. Press **Enter** or click **OK**
|
|
|
|
The instruction now reads:
|
|
```assembly
|
|
10000xxx 21 46 movs r1, #0x46
|
|
```
|
|
|
|
**Visual confirmation:**
|
|
- The patched instruction should be highlighted (usually in red or orange)
|
|
- The bytes should change from `21 2b` to `21 46`
|
|
- The decompiled view should update to show `printf("age: %d\r\n", 0x46);`
|
|
|
|
##### Step 5: Verify the Patch in Decompile Window
|
|
|
|
Click on the `main` function again and check the **Decompile** window:
|
|
|
|
```c
|
|
int main(void)
|
|
{
|
|
stdio_init_all();
|
|
do {
|
|
printf("age: %d\r\n", 0x46); // Changed from 0x2b!
|
|
} while (true);
|
|
}
|
|
```
|
|
|
|
Perfect! The decompiler recognized our patch.
|
|
|
|
##### Step 6: Export the Patched Binary
|
|
|
|
Now we need to save the modified binary:
|
|
|
|
1. Click **File** → **Export Program**
|
|
2. Set **Format** to: **Binary**
|
|
3. Navigate to your build directory:
|
|
- `Embedded-Hacking/0x0005_intro-to-variables/build/`
|
|
4. Set **Filename** to: `0x0005_intro-to-variables-h.bin`
|
|
- The `-h` suffix means "hacked"
|
|
5. Click **OK**
|
|
|
|
**Important:** Make sure you're exporting to the correct location!
|
|
|
|
##### Step 7: Convert to UF2 Format
|
|
|
|
The Pico 2 requires UF2 format. Open a terminal and run:
|
|
|
|
**Navigate to the project directory:**
|
|
```powershell
|
|
cd C:\path\to\Embedded-Hacking\0x0005_intro-to-variables
|
|
```
|
|
|
|
**Run the conversion:**
|
|
```powershell
|
|
python ..\uf2conv.py build\0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
|
```
|
|
|
|
**Command breakdown:**
|
|
- `uf2conv.py` - The conversion script
|
|
- `--base 0x10000000` - XIP flash base address (where code runs from)
|
|
- `--family 0xe48bff59` - RP2350 family ID
|
|
- `--output build\hacked.uf2` - Output filename
|
|
|
|
**Expected output:**
|
|
```
|
|
Converting to uf2, output size: 57856, start address: 0x10000000
|
|
Wrote 57856 bytes to build\hacked.uf2
|
|
```
|
|
|
|
##### Step 8: Flash the Hacked Binary
|
|
|
|
**Enter bootloader mode:**
|
|
1. Disconnect your Pico 2 from USB
|
|
2. Hold down the **BOOTSEL** button
|
|
3. While holding BOOTSEL, plug in the USB cable
|
|
4. Release BOOTSEL
|
|
5. A drive called **RPI-RP2** appears
|
|
|
|
**Flash the binary:**
|
|
1. Open the RPI-RP2 drive
|
|
2. Drag and drop `build\hacked.uf2` onto the drive
|
|
3. The Pico will automatically reboot
|
|
|
|
##### Step 9: Verify the Changes
|
|
|
|
**Open your serial monitor:**
|
|
|
|
For PuTTY:
|
|
1. Select **Serial** connection type
|
|
2. Set the COM port (check Device Manager)
|
|
3. Set speed to **115200**
|
|
4. Click **Open**
|
|
|
|
For PowerShell:
|
|
```powershell
|
|
# Find the COM port
|
|
Get-PnpDevice -Class Ports | Where-Object {$_.FriendlyName -like "*USB Serial*"}
|
|
|
|
# Connect (replace COM3 with your port)
|
|
$port = new-Object System.IO.Ports.SerialPort COM3,115200,None,8,one
|
|
$port.Open()
|
|
while($true) { $port.ReadLine() }
|
|
```
|
|
|
|
**Expected output:**
|
|
```
|
|
age: 70
|
|
age: 70
|
|
age: 70
|
|
age: 70
|
|
...
|
|
```
|
|
|
|
🎉 **Success!** You've successfully patched a binary and changed its behavior!
|
|
|
|
#### Expected Output
|
|
|
|
After completing this exercise, you should:
|
|
- See `age: 70` printing instead of `age: 43`
|
|
- Have a patched binary file (`0x0005_intro-to-variables-h.bin`)
|
|
- Have a UF2 file (`hacked.uf2`)
|
|
- Understand the complete patching workflow
|
|
|
|
#### Questions for Reflection
|
|
|
|
###### Question 1: Why do we need to convert to UF2 format instead of flashing the raw .bin file?
|
|
|
|
###### Question 2: What is the significance of the base address 0x10000000 in the conversion command?
|
|
|
|
###### Question 3: What would happen if you patched the wrong instruction by mistake?
|
|
|
|
###### Question 4: How can you verify a patch was applied correctly before exporting?
|
|
|
|
#### Tips and Hints
|
|
- Always make a backup of the original binary before patching
|
|
- Use descriptive names like `-h` (hacked) or `-patch` for modified binaries
|
|
- Test your patches on hardware to ensure they work as expected
|
|
- If something goes wrong, you can always flash the original UF2 file
|
|
- Use `File → Export Program → Original File` to revert all patches
|
|
|
|
#### Next Steps
|
|
- Try patching to different values (100, 255, etc.)
|
|
- Proceed to Exercise 3 to learn about GPIO control
|
|
- Experiment with patching multiple values in the same binary
|
|
|
|
#### Additional Challenge
|
|
Instead of changing the value to 70, change it to 255 (0xFF) - the maximum value for a `uint8_t`. What do you observe? Now try changing it to 256 (0x100). What happens and why? (Hint: Think about the size limits of the instruction encoding.)
|