# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 10 Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics ### Non-Credit Practice Exercise 2: Add a Third Command #### Objective Find the comparison instruction `cmp r4, #0x32` ('2') in the `0x0020_dynamic-conditionals` binary using GDB, locate the branch target for case '2', and modify existing code so that pressing '3' (0x33) moves the servo to the center position (90°) by patching one of the existing comparisons and its corresponding angle value to `0x42b40000` (90.0f). #### Prerequisites - Completed Week 10 tutorial (GDB and hex editor sections) - `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` 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 with SG90 servo motor connected on GPIO 6 #### Task Description The program has two active commands: '1' (0x31) moves the servo 0°→180° and '2' (0x32) moves it 180°→0°. Adding a completely new code path would require rewriting branch offsets throughout the binary. Instead, you will repurpose the '2' command by changing its comparison value from `0x32` ('2') to `0x33` ('3') and patching both of its angle values to `0x42b40000` (90.0f), so pressing '3' moves the servo to center and holds it there. #### 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\0x0020_dynamic-conditionals.elf ``` **Connect to target:** ```gdb (gdb) target remote :3333 (gdb) monitor reset halt ``` ##### Step 2: Find the Comparison Instructions Disassemble main and locate both `cmp` instructions: ```gdb (gdb) disassemble 0x10000234,+250 ``` Look for: ``` cmp r4, #0x31 ; compare with '1' beq cmp r4, #0x32 ; compare with '2' beq ``` Note the address of the `cmp r4, #0x32` instruction. ##### Step 3: Examine the Comparison Byte The `cmp r4, #0x32` instruction encodes `0x32` as an immediate. Examine the instruction bytes: ```gdb (gdb) x/2bx ``` You should see a byte containing `0x32`. ##### Step 4: Find the Angle Values for Case '2' Follow the `beq` target for case '2' and look for the literal pool loads: ```gdb (gdb) x/wx (gdb) x/wx ``` Case '2' loads `0x43340000` (180.0f) first, then `0x00000000` (0.0f). ##### Step 5: Calculate the File Offsets ``` file_offset = address - 0x10000000 ``` Note offsets for: 1. The `0x32` byte in the `cmp` instruction 2. Both angle literal pool entries for case '2' ##### Step 6: Encode the New Values | Patch Target | Original | New | Purpose | | ---------------- | ---------------- | ---------------- | ------------------------- | | Compare byte | `32` | `33` | Match '3' instead of '2' | | Angle 1 (180.0f) | `00 00 34 43` | `00 00 b4 42` | 90.0f center position | | Angle 2 (0.0f) | `00 00 00 00` | `00 00 b4 42` | 90.0f center position | ##### Step 7: Patch with HxD 1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin` 2. Press **Ctrl+G** and go to the compare byte offset 3. Change `32` to `33` 4. Go to the first angle offset for case '2' and replace `00 00 34 43` with `00 00 b4 42` 5. Go to the second angle offset for case '2' and replace `00 00 00 00` with `00 00 b4 42` ###### Question 1: Why do we set both angle values to 90.0f instead of just one? ##### Step 8: Save and Convert 1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin` ```powershell cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 ``` ##### Step 9: Flash and Verify 1. Hold BOOTSEL and plug in your Pico 2 2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive **Check the behavior:** - Press '1' → servo sweeps 0° to 180° (unchanged) - Press '3' → servo moves to **90° center** and stays - Press '2' → now falls through to default "??" (no longer mapped) #### Expected Output After completing this exercise, you should be able to: - Locate and patch comparison immediate values in ARM Thumb instructions - Repurpose existing code paths instead of adding new ones - Understand how `cmp` immediates are encoded in the instruction stream - Combine multiple patches (comparison + data) for a single behavior change #### Questions for Reflection ###### Question 1: Why is it easier to repurpose an existing command than to add a truly new third code path in the binary? ###### Question 2: The `cmp` instruction uses an 8-bit immediate field. What range of ASCII characters could you use as command keys? ###### Question 3: After your patch, pressing '2' now triggers the default "??" branch. Could you keep both '2' AND '3' working? What would that require? ###### Question 4: What would happen if you changed the comparison to `0x00`? Could a user ever trigger that command via `getchar()`? #### Tips and Hints - The `cmp rN, #imm8` instruction in Thumb has the immediate in the lower byte of the instruction word - IEEE-754 for 90.0f: `0x42b40000` → little-endian `00 00 b4 42` - Be careful not to confuse literal pool entries between case '1' and case '2' — trace the branch targets carefully - The `getchar()` function reads one byte from UART, so any byte value 0x00-0xFF is theoretically possible