# 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 4: Speed Profile #### Objective Find both `sleep_ms(500)` calls in the `0x0020_dynamic-conditionals` binary using GDB, identify the literal pool values `0x1f4` (500) loaded into `r0` before each `bl sleep_ms`, calculate the file offsets, and patch case '1' to use `0x64` (100ms) for fast movement and case '2' to use `0x3e8` (1000ms) for slow movement, then verify on hardware that the two keys produce visibly different servo speeds. #### 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 Both case '1' and case '2' call `sleep_ms(500)` between their two `servo_set_angle` calls. The value `500` (`0x1F4`) is loaded from the literal pool into `r0` before each `bl sleep_ms`. You will find both `sleep_ms` literal pool entries — one in case '1' and one in case '2' — and patch them to different values: `100` (`0x64`) for fast snapping and `1000` (`0x3E8`) for slow sweeping, creating distinct speed profiles per key. #### 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 Both sleep_ms Calls Disassemble main and locate the `sleep_ms` calls: ```gdb (gdb) disassemble 0x10000234,+250 ``` Look for the pattern repeated in both cases: ``` ldr r0, [pc, #offset] ; load delay value bl sleep_ms ``` Each case has at least one `sleep_ms` call. Identify which belongs to case '1' and which to case '2' by tracing the branch targets. ##### Step 3: Examine the Literal Pool Entries For each `sleep_ms` call, examine the referenced literal pool entry: ```gdb (gdb) x/wx (gdb) x/wx ``` Both should show `0x000001f4` (500). ##### Step 4: Calculate the File Offsets ``` file_offset = literal_pool_address - 0x10000000 ``` Note the file offsets for both 4-byte sleep values. ##### Step 5: Encode the New Values | Case | Original | New | Speed | | ------ | ----------------- | ----------------- | -------- | | Case 1 | `F4 01 00 00` (500ms) | `64 00 00 00` (100ms) | Fast snap | | Case 2 | `F4 01 00 00` (500ms) | `E8 03 00 00` (1000ms) | Slow sweep | ###### Question 1: Each case calls `sleep_ms` twice (once between the first and second `servo_set_angle`). Do both share the same literal pool entry, or does each have its own? ##### Step 6: 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 case '1' sleep value offset 3. Replace `F4 01 00 00` with `64 00 00 00` (100ms) 4. Press **Ctrl+G** and go to the case '2' sleep value offset 5. Replace `F4 01 00 00` with `E8 03 00 00` (1000ms) ##### Step 7: 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 8: 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 snaps **fast** (100ms between angles) — almost instant jump - Press '2' → servo moves **slow** (1000ms between angles) — takes a full second at each position - The speed difference should be very obvious visually and audibly #### Expected Output After completing this exercise, you should be able to: - Distinguish between multiple literal pool entries for the same value - Trace which code path references which literal pool entry - Patch timing constants independently per branch - Understand how sleep duration affects perceived motor behavior #### Questions for Reflection ###### Question 1: Why does 100ms make the servo appear to "snap" while 1000ms makes it appear to "sweep"? Is the servo actually moving faster, or is it about the pause between commands? ###### Question 2: If the compiler uses a single shared literal pool entry for all `sleep_ms(500)` calls, what alternative patching strategy would you need to create different speeds per case? ###### Question 3: What is the minimum `sleep_ms` value that would still allow the servo to physically reach its target angle before the next command? How would you determine this experimentally? ###### Question 4: Could you set the sleep to `0` (`00 00 00 00`)? What would happen to the servo behavior? #### Tips and Hints - `100` decimal = `0x64`, fits in one byte: `64 00 00 00` in little-endian - `1000` decimal = `0x3E8`: `E8 03 00 00` in little-endian - If both `sleep_ms` calls share one literal pool word, you cannot give them different values by patching data alone — you would need to patch one `ldr` instruction to point to a different pool entry or use a `movs` immediate - The SG90 servo takes about 200-300ms to traverse its full range, so 100ms will cause it to not quite reach the endpoint before the next command fires