Files
Embedded-Hacking/WEEK09/WEEK09-01.md
2026-03-19 15:01:07 -04:00

4.9 KiB

Embedded Systems Reverse Engineering

Repository

Week 9

Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics

Non-Credit Practice Exercise 1: Change the Sleep Duration

Objective

Find the sleep_ms(2000) call in the 0x001a_operators binary using GDB, identify the immediate value 0x7d0 (2000) being loaded into r0, calculate the file offset, patch it to 0x1388 (5000) using a hex editor, and verify on hardware that the serial output now prints every 5 seconds instead of every 2 seconds.

Prerequisites

  • Completed Week 9 tutorial (GDB and hex editor sections)
  • 0x001a_operators.elf and 0x001a_operators.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 DHT11 sensor connected

Task Description

The program calls sleep_ms(2000) at the end of its main loop, causing a 2-second delay between each set of serial output. The value 2000 (0x7D0) is loaded into register r0 before the bl sleep_ms call. You will locate this value in the disassembly, find the corresponding bytes in the .bin file, and patch them to 5000 (0x1388) so the loop runs every 5 seconds instead.

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\0x001a_operators.elf

Connect to target:

(gdb) target remote :3333
(gdb) monitor reset halt
Step 2: Find the sleep_ms Call

Disassemble main and look for the sleep_ms call:

(gdb) x/60i 0x10000234

Look for an instruction pattern like:

ldr  r0, =0x7d0     ; 2000 milliseconds
bl   sleep_ms

The value 0x7d0 will be loaded from the literal pool.

Step 3: Examine the Literal Pool Value

Once you find the ldr r0, [pc, #offset] instruction, examine the literal pool entry it references:

(gdb) x/wx <literal_pool_address>

You should see 0x000007d0 (2000 in hex).

Step 4: Calculate the File Offset
file_offset = literal_pool_address - 0x10000000

Note the file offset of the 4-byte word containing 0x7d0.

Step 5: Encode the New Value

The new value 5000 in hex is 0x1388. In little-endian byte order:

Value Hex Little-Endian Bytes
2000 0x000007D0 D0 07 00 00
5000 0x00001388 88 13 00 00
Step 6: Patch with HxD
  1. In HxD, open C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin
  2. Press Ctrl+G and enter the file offset you calculated
  3. You should see: D0 07 00 00
  4. Replace with: 88 13 00 00
Step 7: Save and Convert
  1. Click FileSave As0x001a_operators-h.bin
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators
python ..\uf2conv.py build\0x001a_operators-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 serial monitor:

  • Output should now appear every 5 seconds instead of every 2 seconds
  • All operator values should remain unchanged (50, 5, 0, 0, 12, 11)

Expected Output

After completing this exercise, you should be able to:

  • Locate literal pool values referenced by ldr instructions
  • Understand little-endian byte ordering for 32-bit values
  • Patch timing constants in embedded firmware
  • Calculate file offsets from memory addresses

Questions for Reflection

Question 1: The value 2000 is stored in the literal pool as a 32-bit word, not as an immediate in the instruction. Why can't 2000 be encoded as an immediate in a single movs instruction?
Question 2: If you wanted to change the delay to exactly 1 second (1000ms = 0x3E8), what bytes would you write in little-endian order?
Question 3: The literal pool value is shared — could other code in the binary also reference this same 0x7D0 value? How would you check?
Question 4: What would happen if you changed the sleep value to 0 (00 00 00 00)? Would the program crash or just run extremely fast?

Tips and Hints

  • movs can only encode immediates 0-255; values larger than 255 must be loaded from the literal pool via ldr
  • Always verify the bytes BEFORE patching — make sure you see D0 07 00 00 at your calculated offset
  • The literal pool is typically right after the function's b.n (loop branch) instruction
  • Use a stopwatch or count "one-one-thousand" to verify the timing change