mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-04-04 18:32:08 +02:00
141 lines
6.1 KiB
Markdown
141 lines
6.1 KiB
Markdown
# Embedded Systems Reverse Engineering
|
|
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
|
|
|
## 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.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)
|
|
|
|
#### 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:**
|
|
|
|
```powershell
|
|
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:**
|
|
|
|
```powershell
|
|
arm-none-eabi-gdb build\0x001a_operators.elf
|
|
```
|
|
|
|
**Connect to target:**
|
|
|
|
```gdb
|
|
(gdb) target remote :3333
|
|
(gdb) monitor reset halt
|
|
```
|
|
|
|
##### Step 2: Disassemble Main to Find printf Calls
|
|
|
|
```gdb
|
|
(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
|
|
(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
|
|
(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
|
|
|
|
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin`
|
|
2. For each string, press **Ctrl+G** and enter the file offset
|
|
3. Verify you can read the ASCII text in the right panel
|
|
4. 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 `printf` calls 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`-`0x7E` range
|
|
- The `\r\n` at the end of format strings shows up as bytes `0x0D 0x0A`
|
|
- Use HxD's **Search** → **Find** (Ctrl+F) with "Text string" mode to search for known text like "arithmetic"
|
|
- Strings in `.rodata` are 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
|