6.1 KiB
Embedded Systems Reverse Engineering
Week 9
Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics
Non-Credit Practice Exercise 4: Find All printf Format Strings
Objective
Systematically search through the 0x001a_operators binary using GDB and a hex editor to locate every printf format string, catalog their addresses, file offsets, contents, and purposes, and gain experience identifying data structures in compiled binaries.
Prerequisites
- Completed Week 9 tutorial (GDB section)
0x001a_operators.elfand0x001a_operators.binavailable in your build directory- GDB (
arm-none-eabi-gdb) and OpenOCD installed - A hex editor (HxD, ImHex, or similar)
Task Description
The 0x001a_operators program contains multiple printf calls, each with a format string like "arithmetic_operator: %d\r\n". These strings are stored in the .rodata section of flash memory. You will use GDB to trace each printf call to its format string argument, then verify the strings in HxD. You will also search for strings that are NOT directly referenced by printf (like the "DHT11 read failed" error message). This exercise builds your ability to map out all human-readable data in a binary.
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: Disassemble Main to Find printf Calls
(gdb) x/60i 0x10000234
Look for repeated patterns of:
ldr r0, [pc, #offset] ; Load format string address
movs r1, #value ; Load the value to print
bl printf ; Call printf
Each ldr r0 before a bl printf loads the format string address from the literal pool.
Step 3: Examine the Literal Pool
Find the literal pool after the loop branch (typically after the b.n instruction). Examine the word values:
(gdb) x/10wx <literal_pool_start>
Each word that falls in the 0x10003xxx range is likely a pointer to a string in .rodata.
Step 4: Read Each Format String
For each address found in the literal pool, use x/s to read the string:
(gdb) x/s <address_from_literal_pool>
Document each one. You should find at least these format strings:
"arithmetic_operator: %d\r\n""increment_operator: %d\r\n""relational_operator: %d\r\n""logical_operator: %d\r\n""bitwise_operator: %d\r\n""assignment_operator: %d\r\n""Humidity: %.1f%%, Temperature: %.1f°C\r\n""DHT11 read failed"
Step 5: Build a String Catalog
Fill in a table like this (addresses will vary — use the ones you find):
| Address | File Offset | String Content | Used By |
|---|---|---|---|
0x10003xxx |
0x3xxx |
"arithmetic_operator: %d\r\n" |
printf #1 |
0x10003xxx |
0x3xxx |
"increment_operator: %d\r\n" |
printf #2 |
0x10003xxx |
0x3xxx |
"relational_operator: %d\r\n" |
printf #3 |
0x10003xxx |
0x3xxx |
"logical_operator: %d\r\n" |
printf #4 |
0x10003xxx |
0x3xxx |
"bitwise_operator: %d\r\n" |
printf #5 |
0x10003xxx |
0x3xxx |
"assignment_operator: %d\r\n" |
printf #6 |
0x10003xxx |
0x3xxx |
"Humidity: %.1f%%, Temperature: %.1f°C\r\n" |
printf #7 |
0x10003xxx |
0x3xxx |
"DHT11 read failed" |
puts |
Step 6: Verify in HxD
- In HxD, open
C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin - For each string, press Ctrl+G and enter the file offset
- Verify you can read the ASCII text in the right panel
- Note how the strings are stored consecutively in memory, each terminated by
0x00
Step 7: Search for Hidden Strings
Scroll through the .rodata region in HxD (typically starting around offset 0x3000+) and look for any ASCII text in the right panel that you didn't find via printf calls. Library functions may have their own strings.
Expected Output
After completing this exercise, you should be able to:
- Trace
printfcalls to their format string arguments using GDB - Read string addresses from literal pools
- Build a complete catalog of strings in a binary
- Navigate to specific offsets in a hex editor to verify string data
Questions for Reflection
Question 1: The format string "Humidity: %.1f%%, Temperature: %.1f°C\r\n" uses %% to print a literal percent sign. What would happen if you patched one of the % characters to a space (0x20)?
Question 2: If you patched the string "arithmetic_operator: %d\r\n" to "HACKED_OPERATOR!: %d\r\n" (same length, 27 characters + null), what would the serial output show? Would the actual computed value change?
Question 3: The strings are stored consecutively in .rodata. If you made "arithmetic_operator: %d\r\n" one byte longer, which string would be corrupted and how?
Question 4: Why does the compiler use puts instead of printf for "DHT11 read failed"? What's the difference between the two functions for strings with no format specifiers?
Tips and Hints
- Format strings always start with a printable ASCII character — look for bytes in the
0x20-0x7Erange - The
\r\nat the end of format strings shows up as bytes0x0D 0x0A - Use HxD's Search → Find (Ctrl+F) with "Text string" mode to search for known text like "arithmetic"
- Strings in
.rodataare typically 4-byte aligned, so there may be padding bytes (0x00) between them - The
°character in "°C" is a multi-byte UTF-8 sequence (0xC2 0xB0), not a single byte