3.6 KiB
Embedded Systems Reverse Engineering
Week 4
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
Non-Credit Practice Exercise 2 Solution: Patch Binary to Change Variable Value
Answers
Patch Details
| Item | Original | Patched |
|---|---|---|
| Instruction | movs r1, #0x2b | movs r1, #0x46 |
| Hex bytes | 21 2b | 21 46 |
| Decimal value | 43 | 70 |
| Output | age: 43 | age: 70 |
Patching Steps
- Located
movs r1, #0x2bin Ghidra Listing view - Right-click → Patch Instruction → changed
#0x2bto#0x46 - Verified in Decompile window:
printf("age: %d\r\n", 0x46) - Exported: File → Export Program → Binary →
0x0005_intro-to-variables-h.bin - Converted to UF2:
python ..\uf2conv.py build\0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 - Flashed via BOOTSEL → RPI-RP2 drive
Serial Output
age: 70
age: 70
age: 70
...
Reflection Answers
-
Why do we need to convert to UF2 format instead of flashing the raw .bin file? The RP2350 bootloader (accessed via BOOTSEL) expects UF2 (USB Flashing Format) files. UF2 is a container format that includes metadata: the target flash address for each 256-byte block, a family ID (
0xe48bff59for RP2350), and checksums. A raw.binfile contains only code bytes with no addressing information—the bootloader wouldn't know where in flash to write the data. UF2 also supports partial updates and is self-describing, making it safer for USB mass storage flashing. -
What is the significance of the base address 0x10000000 in the conversion command?
0x10000000is the XIP (Execute In Place) flash base address on the RP2350. This tells the UF2 converter that byte 0 of the binary should be written to flash address0x10000000. The CPU fetches instructions directly from this address range via the XIP controller. If the base address were wrong (e.g.,0x20000000for RAM), the code would be written to the wrong location and the processor would fail to boot because the vector table wouldn't be found at the expected address. -
What would happen if you patched the wrong instruction by mistake? The consequences depend on what was changed: (a) Patching a different
movsmight corrupt an unrelated function parameter, causing incorrect behavior or a crash. (b) Patching opcode bytes (not just the immediate) could create an invalid instruction, triggering a HardFault or UsageFault. (c) Patching inside a multi-byte instruction could split it into two unintended instructions, corrupting the entire subsequent instruction stream. The program would likely crash, output garbage, or hang—requiring reflashing with the original UF2 to recover. -
How can you verify a patch was applied correctly before exporting? Multiple verification methods: (a) Check the Decompile window—it should reflect the new value (e.g.,
printf("age: %d\r\n", 0x46)). (b) Inspect the Listing window bytes—confirm the instruction bytes changed from21 2bto21 46. (c) Use right-click → Highlight → Highlight Difference to see patched bytes highlighted. (d) Compare the patched instruction against the ARM Thumb encoding reference to verify the encoding is valid. (e) Check surrounding instructions are unchanged—patches should not accidentally modify adjacent code.