5.7 KiB
Embedded Systems Reverse Engineering
Week 10
Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
Non-Credit Practice Exercise 1: Change Servo Angle Range
Objective
Find the IEEE-754 floating-point value 0x43340000 (180.0f) in the 0x0020_dynamic-conditionals binary using GDB, calculate the file offset, patch it to 0x43070000 (135.0f) using a hex editor, then find and patch the 0x00000000 (0.0f) value to 0x42340000 (45.0f), and verify on hardware that the servo now sweeps from 45° to 135° instead of 0° to 180°.
Prerequisites
- Completed Week 10 tutorial (GDB and hex editor sections)
0x0020_dynamic-conditionals.elfand0x0020_dynamic-conditionals.binavailable 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 uses servo_set_angle(0.0f) and servo_set_angle(180.0f) to sweep the servo across its full range. The float values 0.0 (0x00000000) and 180.0 (0x43340000) are loaded from the literal pool into registers before the bl servo_set_angle calls. You will locate these values in the disassembly, find the corresponding bytes in the .bin file, and patch them to 45.0 (0x42340000) and 135.0 (0x43070000) so the servo sweeps a narrower 90° range centered at 90°.
Step-by-Step Instructions
Step 1: Start the Debug Session
Terminal 1 - Start OpenOCD:
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:
arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
Connect to target:
(gdb) target remote :3333
(gdb) monitor reset halt
Step 2: Find the servo_set_angle Calls
Disassemble main and look for the servo_set_angle calls:
(gdb) disassemble 0x10000234,+250
Look for instruction patterns like:
ldr r0, [pc, #offset] ; load float from literal pool
bl servo_set_angle
There will be multiple pairs — one loading 0x00000000 (0.0f) and another loading 0x43340000 (180.0f).
Step 3: Examine the Literal Pool Values
Once you find the ldr r0, [pc, #offset] instructions, examine the literal pool entries they reference:
(gdb) x/wx <literal_pool_address_for_180>
You should see 0x43340000 (180.0f in IEEE-754).
(gdb) x/wx <literal_pool_address_for_0>
You should see 0x00000000 (0.0f in IEEE-754).
Step 4: Calculate the File Offsets
file_offset = literal_pool_address - 0x10000000
Note the file offsets for both 4-byte words.
Step 5: Encode the New Values
IEEE-754 Encoding:
| Angle | IEEE-754 Hex | Little-Endian Bytes |
|---|---|---|
| 0.0f | 0x00000000 |
00 00 00 00 |
| 45.0f | 0x42340000 |
00 00 34 42 |
| 135.0f | 0x43070000 |
00 00 07 43 |
| 180.0f | 0x43340000 |
00 00 34 43 |
Step 6: Patch with HxD
- In HxD, open
C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin - Press Ctrl+G and enter the file offset for the 180.0f value
- You should see:
00 00 34 43 - Replace with:
00 00 07 43(135.0f) - Press Ctrl+G and enter the file offset for the 0.0f value
- You should see:
00 00 00 00 - Replace with:
00 00 34 42(45.0f)
Question 1: How many literal pool entries reference 0x43340000? Do you need to patch all of them?
Step 7: Save and Convert
- Click File → Save As →
0x0020_dynamic-conditionals-h.bin
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
- Hold BOOTSEL and plug in your Pico 2
- Drag and drop
hacked.uf2onto the RPI-RP2 drive
Check the servo behavior:
- Press '1' → servo sweeps from 45° to 135° (was 0° to 180°)
- Press '2' → servo sweeps from 135° to 45° (was 180° to 0°)
- The total sweep range should be noticeably smaller
Expected Output
After completing this exercise, you should be able to:
- Locate IEEE-754 floating-point values in the literal pool
- Understand the IEEE-754 single-precision encoding format
- Patch floating-point angle constants in embedded firmware
- Calculate file offsets from memory addresses
Questions for Reflection
Question 1: The value 180.0f is encoded as 0x43340000 in IEEE-754. Break this down: what are the sign bit, exponent, and mantissa fields?
Question 2: Why is 0.0f stored as 0x00000000 and not some other pattern? What makes zero special in IEEE-754?
Question 3: If you wanted to set the servo to exactly 90° (center), what IEEE-754 hex value would you use? Show the calculation.
Question 4: Could the compiler optimize 0.0f differently — for example, using movs r0, #0 instead of a literal pool load? How would that affect your patching strategy?
Tips and Hints
- IEEE-754 for 90.0f: sign=0, exponent=127+6=133=0x85, mantissa=0x340000 →
0x42b40000 - There may be multiple references to
0x43340000in the literal pool — the case '1' and case '2' branches each load both angles - Be careful with
0x00000000— make sure you are patching a float literal pool entry and not zeroed data - Use
x/4wx <address>in GDB to view several literal pool words at once