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

5.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 4 Solution: Find All printf Format Strings

Answers

Complete String Catalog
# String Type Used By
1 "arithmetic_operator: %d\r\n" Format string printf #1
2 "increment_operator: %d\r\n" Format string printf #2
3 "relational_operator: %d\r\n" Format string printf #3
4 "logical_operator: %d\r\n" Format string printf #4
5 "bitwise_operator: %d\r\n" Format string printf #5
6 "assignment_operator: %d\r\n" Format string printf #6
7 "Humidity: %.1f%%, Temperature: %.1f°C\r\n" Format string printf #7
8 "DHT11 read failed\r\n" Plain string puts
Format Specifier Analysis
Specifier Meaning Used In
%d Signed decimal integer Strings 16
%.1f Float with 1 decimal place String 7
%% Literal percent sign (escaped) String 7
\r\n Carriage return + line feed (0x0D 0x0A) All strings
°C UTF-8 degree symbol + C (0xC2 0xB0 0x43) String 7
Expected Operator Output Values
Operator Expression Value Explanation
arithmetic_operator 5 × 10 50 Multiplication
increment_operator x++ (x=5) 5 Post-increment returns old value
relational_operator 6 > 10 0 False
logical_operator (6>10) && (10>6) 0 Short-circuit: first operand false
bitwise_operator 6 << 1 12 Left shift = multiply by 2
assignment_operator 6 + 5 11 Addition assignment
GDB Search Commands
(gdb) x/20s 0x10003e00
(gdb) x/50s 0x10003d00
Special Byte Sequences in Strings
Sequence Bytes Meaning
\r\n 0x0D 0x0A CRLF line ending
%% 0x25 0x25 Literal % character
° 0xC2 0xB0 UTF-8 degree symbol

Reflection Answers

  1. The humidity/temperature format string contains %%. What would happen if you patched one of the % characters to a different character (e.g., changed %% to %,)? The %% escape produces a literal % in the output. If you change it to %, (bytes 25 2C), printf would interpret %, as the start of a format specifier where , is the conversion character. Since , is not a valid printf conversion specifier, the behavior is undefined — most implementations would either print garbage, skip it, or consume the next argument from the stack incorrectly. This could corrupt the remaining output or even crash if printf tries to read a non-existent argument.

  2. If you changed "arithmetic_operator" to "hacked_operator__" (same length) in the binary, what would the serial output look like? Would the computed value change? The serial output would show hacked_operator__: 50 instead of arithmetic_operator: 50. The computed value (50) would not change — it's determined by the actual multiplication instruction in the code, not by the format string. The format string is just a label for display purposes. The %d specifier still reads the same r1 register value (50) passed as the second argument to printf.

  3. What happens if you make a format string 1 byte longer (e.g., add a character)? Where would the extra byte be stored? The extra byte would overwrite the null terminator (0x00) of the current string, and the byte after that is the first byte of the next consecutive string in .rodata. This effectively merges the two strings: printf would continue reading past the intended end into the next string's data until it finds another 0x00. The output would include garbage characters from the adjacent string. If the adjacent data happens to contain % followed by a valid specifier, printf might try to read additional arguments from the stack, potentially causing a crash or information leak.

  4. The "DHT11 read failed" message uses puts instead of printf. Why would the compiler choose puts over printf for this particular string? The compiler (with optimizations enabled) recognizes that printf("DHT11 read failed\r\n") has no format specifiers — it's a plain string with no %d, %s, %f, etc. Since no formatting is needed, the compiler optimizes it to puts("DHT11 read failed") (which automatically appends a newline). This is a common GCC optimization (-fprintf-return-value) because puts is simpler and faster than printf — it doesn't need to parse the format string looking for specifiers. The \r\n may be handled slightly differently depending on the implementation, but the key insight is that the compiler automatically selects the more efficient function.