# 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.)