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

3.6 KiB
Raw Permalink Blame History

Embedded Systems Reverse Engineering

Repository

Week 9

Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Basics

Non-Credit Practice Exercise 1 Solution: Change the Sleep Duration

Answers

Sleep Duration Values
Parameter Original Patched
Duration (ms) 2000 5000
Hex 0x000007D0 0x00001388
Little-endian D0 07 00 00 88 13 00 00
Why a Literal Pool Is Needed

The value 2000 exceeds the 8-bit immediate range of movs (0255) and the 16-bit range is also impractical for a single-instruction load. The compiler stores 0x000007D0 in a literal pool near the function code and loads it with a ldr r0, [pc, #offset] instruction that reads the 32-bit word from the pool into r0 before the bl sleep_ms call.

Patch Procedure
  1. Find the literal pool entry containing D0 07 00 00 in HxD
  2. Replace with 88 13 00 00
Before: D0 07 00 00  (2000)
After:  88 13 00 00  (5000)
Conversion and Flash
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
Serial Output After Patch
arithmetic_operator: 50
increment_operator: 5
relational_operator: 0
logical_operator: 0
bitwise_operator: 12
assignment_operator: 11
Humidity: 51.0%, Temperature: 24.0°C

Output repeats every 5 seconds instead of 2 seconds.

Reflection Answers

  1. Why can't 2000 be encoded as a movs immediate? What is the maximum value movs can hold? The movs Rd, #imm8 instruction is a 16-bit Thumb encoding that has only 8 bits for the immediate value, giving a range of 0255. The value 2000 (0x7D0) is far beyond this range. Even the 32-bit Thumb-2 movw instruction can only encode 065535, which could handle 2000, but the compiler chose a literal pool approach. The literal pool is a general-purpose solution that works for any 32-bit value, including addresses and large constants.

  2. If you wanted to change the sleep to exactly 1 second (1000ms), what 4 bytes would you write in little-endian? Show your work. 1000 decimal = 0x000003E8 hex. In little-endian byte order (LSB first): E8 03 00 00. Breakdown: byte 0 = 0xE8 (LSB), byte 1 = 0x03, byte 2 = 0x00, byte 3 = 0x00 (MSB).

  3. Could other code in the program reference the same literal pool entry containing 0x7D0? What would happen if it did? Yes, the compiler may share literal pool entries to save space. If another instruction also loads 0x7D0 from the same pool address (using its own ldr rN, [pc, #offset]), then patching that pool entry would change the value for ALL instructions that reference it. This is a risk with literal pool patching — you might unintentionally modify other parts of the program. To check, search for all ldr instructions whose PC-relative offset resolves to the same pool address.

  4. What would happen if you set sleep_ms to 0? Would the program crash or just run extremely fast? The program would not crash — sleep_ms(0) is a valid call that returns immediately. The loop would run as fast as the processor can execute it, printing operator values and reading the DHT11 sensor with no delay between iterations. The serial output would flood extremely quickly. However, the DHT11 sensor has a minimum sampling interval of about 1 second; reading it more frequently may return stale data or read errors ("DHT11 read failed"), but the program itself would continue running.