Updated WEEK04

This commit is contained in:
Kevin Thomas
2026-05-09 11:42:33 -04:00
parent 005fd08646
commit ee664b6733
165 changed files with 3952 additions and 13308 deletions
-66
View File
@@ -1,66 +0,0 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## 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
```powershell
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.
-141
View File
@@ -1,141 +0,0 @@
# 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 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:**
```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: Find the sleep_ms Call
Disassemble main and look for the `sleep_ms` call:
```gdb
(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
(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 **File****Save As**`0x001a_operators-h.bin`
```powershell
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
-66
View File
@@ -1,66 +0,0 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 9
Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Basics
### Non-Credit Practice Exercise 2 Solution: Invert the Temperature Reading
#### Answers
##### IEEE-754 Sign Bit Flip
| Value | IEEE-754 Hex | Little-Endian Bytes | Sign Bit |
|---------|--------------|--------------------|---------|
| +0.1f | 0x3DCCCCCD | CD CC CC 3D | 0 |
| -0.1f | 0xBDCCCCCD | CD CC CC BD | 1 |
Only the **last byte** changes in little-endian: `3D``BD`. This flips bit 31 (the IEEE-754 sign bit) from 0 to 1, negating the value.
##### Patch at File Offset 0x42C
```
Offset 0x42C:
Before: CD CC CC 3D (+0.1f)
After: CD CC CC BD (-0.1f)
```
Only 1 byte changes: offset `0x42F` from `0x3D` to `0xBD`.
##### How the Temperature Changes
The DHT11 returns raw integer and decimal parts (e.g., integer=24, decimal=0). The firmware computes:
```
temperature = integer_part + (decimal_part × 0.1f)
```
With `vfma.f32 s15, s13, s11`: result = s15 + (s13 × s11) = integer + (decimal × 0.1f)
After patching to -0.1f: result = integer + (decimal × -0.1f)
For a reading of 24.5°C: original = 24 + (5 × 0.1) = 24.5°C, patched = 24 + (5 × -0.1) = 23.5°C
For a reading of 24.0°C: integer=24, decimal=0, so 24 + (0 × -0.1) = 24.0°C (unchanged when decimal is 0).
##### Serial Output After Patch
```
Humidity: 51.0%, Temperature: 23.5°C
```
(Temperature decimal contribution is inverted; effect depends on the decimal component.)
#### Reflection Answers
1. **Why does changing the byte from 0x3D to 0xBD negate the float? What specific bit is being flipped?**
In IEEE-754 single-precision format, bit 31 is the **sign bit**: 0 = positive, 1 = negative. The byte `0x3D` in binary is `0011 1101` and `0xBD` is `1011 1101` — only bit 7 of that byte differs, which corresponds to bit 31 of the 32-bit float (since it's the MSB of the last byte in little-endian storage). The exponent and mantissa bits remain identical, so the magnitude stays exactly `0.1` — only the sign changes.
2. **Why does patching one constant affect both humidity AND temperature? They use different vfma instructions (at 0x410 and 0x414) — so why are both affected?**
Both `vfma` instructions at `0x410` (humidity) and `0x414` (temperature) load the scaling constant from the **same literal pool entry** at offset `0x42C`. The compiler recognized that both computations use the same `0.1f` value and stored it only once to save space. Both `vldr s11, [pc, #offset]` instructions resolve to address `0x1000042C`. So patching that single 4-byte value changes the scaling factor for both humidity and temperature simultaneously.
3. **What is the IEEE-754 encoding of 0.5f? If the raw sensor decimal reading was 8, what would the computed value be with 0.5f instead of 0.1f?**
0.5f in IEEE-754: sign=0, exponent=126 (`0x7E`), mantissa=0. Hex = `0x3F000000`. Little-endian bytes: `00 00 00 3F`. With a raw decimal reading of 8: `8 × 0.5 = 4.0`. So if the integer part was 24, the result would be `24 + 4.0 = 28.0°C` instead of `24 + 0.8 = 24.8°C`.
4. **Could you achieve the same inversion by patching the vfma instruction instead of the constant? What instruction change would work?**
Yes. You could change `vfma.f32` (fused multiply-add: d = d + a×b) to `vfms.f32` (fused multiply-subtract: d = d - a×b). This would compute `temperature = integer - (decimal × 0.1f)` instead of `integer + (decimal × 0.1f)`, achieving the same sign inversion on the decimal contribution. The instruction encoding difference between `vfma` and `vfms` is typically a single bit in the opcode. However, this approach is more complex than simply flipping the sign bit of the constant.
-136
View File
@@ -1,136 +0,0 @@
# 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 2: Invert the Temperature Reading
#### Objective
Using GDB to locate the IEEE-754 scaling constant `0.1f` at file offset `0x42C`, patch it to `-0.1f` using a hex editor, and verify on hardware that the serial output now displays negative temperature values.
#### Prerequisites
- Completed Week 9 tutorial (GDB, Ghidra, 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 DHT11 driver uses a scaling constant of `0.1f` stored at address `0x1000042C` (file offset `0x42C`) to convert raw sensor data into human-readable values. By changing this constant to `-0.1f`, you will invert the decimal component of the temperature calculation, causing the reported temperature to drop. This exercise teaches IEEE-754 float encoding and how a single 4-byte patch can dramatically change sensor behavior.
#### 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: Verify the Current Scaling Constant
Examine the float constant at the known address:
```gdb
(gdb) x/wx 0x1000042c
```
Output:
```
0x1000042c: 0x3dcccccd
```
This is `0.1f` in IEEE-754 encoding (approximately — the repeating binary fraction makes it `0x3dcccccd`).
##### Step 3: Understand the IEEE-754 Encoding
**Current value (0.1f):**
| Field | Bits | Value |
| -------- | ---------- | ----- |
| Sign | `0` | Positive |
| Exponent | `01111011` | 123 (biased) |
| Mantissa | `10011001100110011001101` | ~1.6 |
**New value (-0.1f):**
- Flip only the sign bit (bit 31) from `0` to `1`
- `0x3dcccccd``0xbdcccccd`
| Value | Hex | Little-Endian Bytes |
| ------ | ------------ | ------------------- |
| 0.1f | `0x3dcccccd` | `cd cc cc 3d` |
| -0.1f | `0xbdcccccd` | `cd cc cc bd` |
> 💡 **Key insight:** To negate an IEEE-754 float, you only need to flip the most significant bit. In little-endian, this is the **last** byte — change `3d` to `bd`.
##### Step 4: 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 offset: `42C`
3. You should see: `cd cc cc 3d` (or `cc cc cc 3d`)
4. Replace with: `cd cc cc bd` (or `cc cc cc bd`)
> ⚠️ **Note:** The exact bytes may be `cc cc cc 3d` or `cd cc cc 3d` depending on compiler rounding. Just change the last byte from `3d` to `bd`.
##### Step 5: Save and Convert
1. Click **File****Save As**`0x001a_operators-h.bin`
```powershell
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 6: 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:**
- All operator values remain unchanged (50, 5, 0, 0, 12, 11)
- Temperature should now display with an inverted decimal component
- Humidity will also be affected (same constant is shared)
#### Expected Output
After completing this exercise, you should be able to:
- Decode and encode IEEE-754 floating-point values
- Understand that flipping one bit (sign bit) negates a float
- Patch floating-point constants in compiled binaries
- Predict how a constant change propagates through calculations
#### Questions for Reflection
###### Question 1: Why does changing one byte (`3d` → `bd`) negate the entire float value? What does the sign bit (bit 31) control in IEEE-754?
###### Question 2: The scaling constant `0.1f` is used by BOTH the humidity and temperature `vfma.f32` instructions. Why does patching this single constant affect both readings?
###### Question 3: If you wanted to change the constant to `0.5f` (`0x3f000000`, little-endian `00 00 00 3f`) instead of `-0.1f`, how would the temperature reading change? If the raw decimal part is 8, what would the new output be?
###### Question 4: Could you achieve negative temperature by patching the `vfma.f32` instruction itself instead of the constant? What instruction might you replace it with?
#### Tips and Hints
- IEEE-754 sign bit is the MSB (bit 31) — `0` = positive, `1` = negative
- In little-endian, the sign bit is in the **last** (highest address) byte
- Use an online IEEE-754 converter to verify your understanding
- If the output looks completely wrong (NaN, inf), you may have changed the wrong byte — start over with a fresh copy of the `.bin` file
-74
View File
@@ -1,74 +0,0 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 9
Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Basics
### Non-Credit Practice Exercise 3 Solution: Add a Fixed Temperature Offset
#### Answers
##### Two Patches Required
This exercise requires **two** simultaneous patches to add a fixed +10°C offset to every temperature reading.
##### Patch 1: Instruction at Offset 0x414
Change `vfma.f32` to `vadd.f32`:
| Item | Original | Patched |
|------------|------------------------------|------------------------------|
| Instruction | vfma.f32 s15, s13, s11 | vadd.f32 s15, s15, s11 |
| Encoding | e6 ee a5 7a | b4 ee a5 7a |
| Operation | s15 = s15 + (s13 × s11) | s15 = s15 + s11 |
```
Offset 0x414:
Before: E6 EE A5 7A (vfma.f32)
After: B4 EE A5 7A (vadd.f32)
```
Only the first two bytes change: `E6 EE``B4 EE`.
##### Patch 2: Constant at Offset 0x42C
Change the constant from 0.1f to 10.0f:
| Value | IEEE-754 Hex | Little-Endian Bytes |
|--------|--------------|--------------------|
| 0.1f | 0x3DCCCCCD | CD CC CC 3D |
| 10.0f | 0x41200000 | 00 00 20 41 |
```
Offset 0x42C:
Before: CD CC CC 3D (0.1f)
After: 00 00 20 41 (10.0f)
```
##### Why Both Patches Are Needed
- **Original:** `vfma.f32` computes `temp = integer + (decimal × 0.1f)` — fractional scaling
- **After both patches:** `vadd.f32` computes `temp = integer + 10.0f` — fixed offset addition
- **If only constant changed:** `vfma.f32` would compute `temp = integer + (decimal × 10.0f)` — amplified decimal, not a fixed offset
##### Serial Output After Patch
```
Humidity: 51.0%, Temperature: 34.0°C
```
(Original 24.0°C + 10.0°C offset = 34.0°C)
#### Reflection Answers
1. **Why are both patches needed? What would happen if you only changed the constant to 10.0f but left vfma unchanged?**
If you only changed `0.1f` to `10.0f` but left `vfma.f32`, the computation would be `temp = integer + (decimal × 10.0f)`. For a reading of 24.5°C (integer=24, decimal=5): result = 24 + (5 × 10.0) = 74.0°C — wildly incorrect. The `vfma` instruction multiplies two operands and adds, so the constant serves as a multiplier for the decimal part. By changing to `vadd.f32`, we eliminate the multiplication entirely and just add the constant directly to the integer, giving `24 + 10.0 = 34.0°C`.
2. **The humidity vfma instruction at 0x410 was NOT changed. Both vfma instructions (0x410 and 0x414) load the same 0.1f constant from 0x42C. With the constant now 10.0f, what happens to the humidity computation?**
The humidity `vfma` at `0x410` now computes `hum = integer + (decimal × 10.0f)`. If the humidity decimal part is 0 (e.g., raw humidity = 51.0%), then `51 + (0 × 10.0) = 51.0%` — unchanged. But if the decimal part is non-zero (e.g., raw = 51.3%, decimal=3), the result would be `51 + (3 × 10.0) = 81.0%` — grossly incorrect. The DHT11 sensor's humidity decimal is often 0, so you might not notice the bug immediately, but it's a latent defect.
3. **If you wanted to add a 10°C offset to temperature WITHOUT affecting humidity, what additional patch(es) would you need?**
You would need to ensure humidity still uses the original `0.1f` scaling. Options: (1) Also change the humidity `vfma` at `0x410` to `vadd.f32` and create a separate literal pool entry with `0.1f` for it — but this requires finding free space. (2) More practically, place a second copy of `0.1f` (`CD CC CC 3D`) in unused space in the binary, and redirect the humidity `vldr` instruction's PC-relative offset to point to that new location instead of `0x42C`. (3) Alternatively, NOP out the humidity `vfma` entirely if the decimal contribution is negligible.
4. **Why do only the first 2 bytes differ between vfma and vadd? What do the last 2 bytes encode?**
In the ARM VFPv4 encoding, the first two bytes (`E6 EE` vs `B4 EE`) contain the **opcode** that distinguishes the operation type (fused multiply-add vs addition). The last two bytes (`A5 7A`) encode the **operand registers**: the source and destination VFP registers (s15, s13, s11). Since both instructions operate on the same registers, the operand encoding is identical. Only the operation code changes — this is a characteristic of the ARM instruction set where opcode and operand fields are cleanly separated.
-152
View File
@@ -1,152 +0,0 @@
# 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 3: Add a Fixed Temperature Offset
#### Objective
Patch both the `vfma.f32` instruction at file offset `0x414` and the scaling constant at `0x42C` to replace the multiply-add with a simple add of `10.0f`, causing every temperature reading to be increased by exactly 10°C, and verify on hardware.
#### Prerequisites
- Completed Week 9 tutorial and Exercise 2
- `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 temperature calculation uses `vfma.f32 s15, s13, s11` which computes `s15 = s15 + (s13 × s11)` where `s11 = 0.1f`. You will make TWO patches: (1) change the `vfma.f32` instruction to `vadd.f32` so it performs addition instead of multiply-add, and (2) change the constant from `0.1f` to `10.0f`. The result: every temperature reading will have 10°C added to it. This exercise teaches ARM floating-point instruction encoding and multi-site patching.
#### 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: Verify the Current Instructions
Examine the floating-point instructions near the temperature calculation:
```gdb
(gdb) x/4bx 0x10000414
```
Output:
```
0x10000414: 0xe6 0xee 0xa5 0x7a
```
This is `vfma.f32 s15, s13, s11` — the temperature fused multiply-add.
##### Step 3: Verify the Current Constant
```gdb
(gdb) x/wx 0x1000042c
```
Output:
```
0x1000042c: 0x3dcccccd
```
This is `0.1f`.
##### Step 4: Understand the Two Patches
**Patch 1 — Instruction at offset `0x414`:**
| Original | Bytes (LE) | New | Bytes (LE) |
| --------------------------- | --------------- | --------------------------- | --------------- |
| `vfma.f32 s15, s13, s11` | `e6 ee a5 7a` | `vadd.f32 s15, s15, s11` | `b4 ee a5 7a` |
> 🔍 Only the first two bytes change: `e6 ee` → `b4 ee`. The operand bytes `a5 7a` stay the same.
**Patch 2 — Constant at offset `0x42C`:**
| Original | Hex | LE Bytes | New | Hex | LE Bytes |
| -------- | ------------ | --------------- | ----- | ------------ | --------------- |
| 0.1f | `0x3dcccccd` | `cd cc cc 3d` | 10.0f | `0x41200000` | `00 00 20 41` |
##### Step 5: Patch the Instruction 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 offset: `414`
3. You should see: `e6 ee a5 7a`
4. Change the first two bytes: `e6 ee``b4 ee`
5. Result should be: `b4 ee a5 7a`
##### Step 6: Patch the Constant with HxD
1. Press **Ctrl+G** and enter offset: `42C`
2. You should see: `cd cc cc 3d` (or `cc cc cc 3d`)
3. Replace all 4 bytes with: `00 00 20 41`
##### Step 7: Save and Convert
1. Click **File****Save As**`0x001a_operators-h.bin`
```powershell
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:**
- All operator values remain unchanged (50, 5, 0, 0, 12, 11)
- Temperature should now read approximately **10°C higher** than the real temperature
- Humidity will also be affected (the constant is shared)
> ⚠️ **Note:** Since the constant at `0x42C` is shared between the humidity `vfma.f32` at `0x410` and the temperature one at `0x414`, changing it to `10.0f` will also affect humidity. The humidity instruction still uses `vfma` (multiply-add), so it will compute `humidity_int + (decimal × 10.0)` — producing very large humidity values.
#### Expected Output
After completing this exercise, you should be able to:
- Distinguish between `vfma.f32` (multiply-add) and `vadd.f32` (add) encodings
- Perform multi-site patches in a single binary
- Understand how shared constants affect multiple code paths
- Predict the side effects of patching shared data
#### Questions for Reflection
###### Question 1: Why did we need to change BOTH the instruction AND the constant? What would happen if you only changed the constant to `10.0f` but left the `vfma.f32` instruction unchanged?
###### Question 2: The humidity `vfma.f32` at offset `0x410` was NOT changed to `vadd`. With the constant now set to `10.0f`, what formula does the humidity instruction compute? If the raw humidity integer is 51 and decimal is 0, what value would it display?
###### Question 3: If you wanted to add 10°C to temperature WITHOUT affecting humidity, you would need to change both instructions. What bytes would you write at offset `0x410` to change the humidity `vfma` to `vadd` as well, and what constant would preserve the original humidity calculation?
###### Question 4: The `vadd.f32 s15, s15, s11` encoding is `b4 ee a5 7a`. In the original `vfma.f32 s15, s13, s11` (`e6 ee a5 7a`), why do only the first two bytes differ? What do those bytes encode?
#### Tips and Hints
- Make BOTH patches before saving — if you only patch one, the results will be wrong
- The `vfma``vadd` change only affects the first two bytes of the 4-byte instruction
- `10.0f` in IEEE-754 is `0x41200000` — memorize this common value
- Always start with a fresh copy of the `.bin` file if you need to redo the exercise
- Compare the original and hacked serial output side by side to verify only temperature changed as expected
-72
View File
@@ -1,72 +0,0 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## 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
(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.
-140
View File
@@ -1,140 +0,0 @@
# 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
+295 -318
View File
@@ -1,6 +1,6 @@
# Week 9: Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics.
?# Week 9: Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics.
## 🎯 What You'll Learn This Week
## ? What You'll Learn This Week
By the end of this tutorial, you will be able to:
- Understand all six types of C operators (arithmetic, increment, relational, logical, bitwise, assignment)
@@ -13,7 +13,7 @@ By the end of this tutorial, you will be able to:
---
## 📚 Part 1: Understanding C Operators
## Part 1: Understanding C Operators
### What Are Operators?
@@ -32,7 +32,7 @@ By the end of this tutorial, you will be able to:
---
## 📚 Part 2: Arithmetic Operators
## Part 2: Arithmetic Operators
### Basic Math in C
@@ -45,23 +45,23 @@ int result = x * y; // result = 50
```
```
┌─────────────────────────────────────────────────────────────────┐
Arithmetic Operators
│ │
Operator Example Result Description
│ ───────────────────────────────────────────────────────────── │
+ 5 + 10 15 Addition
- 10 - 5 5 Subtraction
* 5 * 10 50 Multiplication
/ 10 / 5 2 Division
% 10 % 3 1 Modulus (remainder)
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Arithmetic Operators |
| |
| Operator Example Result Description |
| ------------------------------------------------------------- |
| + 5 + 10 15 Addition |
| - 10 - 5 5 Subtraction |
| * 5 * 10 50 Multiplication |
| / 10 / 5 2 Division |
| % 10 % 3 1 Modulus (remainder) |
| |
+-----------------------------------------------------------------+
```
---
## 📚 Part 3: Increment and Decrement Operators
## Part 3: Increment and Decrement Operators
### Pre-Increment vs Post-Increment
@@ -77,29 +77,29 @@ int b = ++x; // Pre-increment: x becomes 7, then b = 7
| Type | Syntax | When Value Changes | Example Result |
| ------------------ | ------ | --------------------- | -------------------- |
| **Post-increment** | `x++` | AFTER the expression | `a = x++` a=5, x=6 |
| **Pre-increment** | `++x` | BEFORE the expression | `b = ++x` x=7, b=7 |
| **Post-increment** | `x++` | AFTER the expression | `a = x++` -> a=5, x=6 |
| **Pre-increment** | `++x` | BEFORE the expression | `b = ++x` -> x=7, b=7 |
```
┌─────────────────────────────────────────────────────────────────┐
Post-Increment (x++)
│ │
int x = 5;
int result = x++;
│ │
Step 1: result = x (result gets 5)
Step 2: x = x + 1 (x becomes 6)
│ │
Final: result = 5, x = 6
│ │
Think of it as: "Use first, THEN increment"
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Post-Increment (x++) |
| |
| int x = 5; |
| int result = x++; |
| |
| Step 1: result = x (result gets 5) |
| Step 2: x = x + 1 (x becomes 6) |
| |
| Final: result = 5, x = 6 |
| |
| Think of it as: "Use first, THEN increment" |
| |
+-----------------------------------------------------------------+
```
---
## 📚 Part 4: Relational Operators
## Part 4: Relational Operators
### Comparing Values
@@ -112,24 +112,24 @@ bool result = (x > y); // false, because 6 is NOT greater than 10
```
```
┌─────────────────────────────────────────────────────────────────┐
Relational Operators
│ │
Operator Example Result Description
│ ───────────────────────────────────────────────────────────── │
> 6 > 10 false Greater than
< 6 < 10 true Less than
>= 6 >= 6 true Greater than or equal
<= 6 <= 10 true Less than or equal
== 6 == 10 false Equal to
!= 6 != 10 true Not equal to
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Relational Operators |
| |
| Operator Example Result Description |
| ------------------------------------------------------------- |
| > 6 > 10 false Greater than |
| < 6 < 10 true Less than |
| >= 6 >= 6 true Greater than or equal |
| <= 6 <= 10 true Less than or equal |
| == 6 == 10 false Equal to |
| != 6 != 10 true Not equal to |
| |
+-----------------------------------------------------------------+
```
---
## 📚 Part 5: Logical Operators
## Part 5: Logical Operators
### Combining Conditions
@@ -142,33 +142,33 @@ bool result = (x > y) && (y > x); // false AND true = false
```
```
┌─────────────────────────────────────────────────────────────────┐
Logical Operators
│ │
Operator Name Example Result
│ ───────────────────────────────────────────────────────────── │
&& AND true && true true
&& AND true && false false
|| OR true || false true
|| OR false || false false
! NOT !true false
│ │
Truth Table for AND (&&):
│ ┌───────┬───────┬────────┐ │
A B A && B
│ ├───────┼───────┼────────┤ │
false false false
false true false
true false false
true true true
│ └───────┴───────┴────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Logical Operators |
| |
| Operator Name Example Result |
| ------------------------------------------------------------- |
| && AND true && true true |
| && AND true && false false |
| || OR true || false true |
| || OR false || false false |
| ! NOT !true false |
| |
| Truth Table for AND (&&): |
| +-------+-------+--------+ |
| | A | B | A && B | |
| +-------+-------+--------+ |
| | false | false | false | |
| | false | true | false | |
| | true | false | false | |
| | true | true | true | |
| +-------+-------+--------+ |
| |
+-----------------------------------------------------------------+
```
---
## 📚 Part 6: Bitwise Operators
## Part 6: Bitwise Operators
### Manipulating Individual Bits
@@ -180,21 +180,21 @@ int result = x << 1; // Shift left by 1: 0b00001100 = 12
```
```
┌─────────────────────────────────────────────────────────────────┐
Bitwise Left Shift (<<)
│ │
x = 6 = 0b00000110
│ │
x << 1 means "shift all bits LEFT by 1 position"
│ │
Before: 0 0 0 0 0 1 1 0 (6)
│ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ │
After: 0 0 0 0 1 1 0 0 (12)
│ │
Each left shift DOUBLES the value!
6 << 1 = 12 (same as 6 * 2)
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Bitwise Left Shift (<<) |
| |
| x = 6 = 0b00000110 |
| |
| x << 1 means "shift all bits LEFT by 1 position" |
| |
| Before: 0 0 0 0 0 1 1 0 (6) |
| ? ? ? ? ? ? ? ? |
| After: 0 0 0 0 1 1 0 0 (12) |
| |
| Each left shift DOUBLES the value! |
| 6 << 1 = 12 (same as 6 * 2) |
| |
+-----------------------------------------------------------------+
```
**Common Bitwise Operators:**
@@ -210,7 +210,7 @@ int result = x << 1; // Shift left by 1: 0b00001100 = 12
---
## 📚 Part 7: Assignment Operators
## Part 7: Assignment Operators
### Shorthand for Math + Assign
@@ -222,69 +222,69 @@ x += 5; // Same as: x = x + 5; Result: x = 11
```
```
┌─────────────────────────────────────────────────────────────────┐
Compound Assignment Operators
│ │
Operator Example Equivalent To Result (if x=6)
│ ───────────────────────────────────────────────────────────── │
+= x += 5 x = x + 5 x = 11
-= x -= 2 x = x - 2 x = 4
*= x *= 3 x = x * 3 x = 18
/= x /= 2 x = x / 2 x = 3
%= x %= 4 x = x % 4 x = 2
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Compound Assignment Operators |
| |
| Operator Example Equivalent To Result (if x=6) |
| ------------------------------------------------------------- |
| += x += 5 x = x + 5 x = 11 |
| -= x -= 2 x = x - 2 x = 4 |
| *= x *= 3 x = x * 3 x = 18 |
| /= x /= 2 x = x / 2 x = 3 |
| %= x %= 4 x = x % 4 x = 2 |
| |
+-----------------------------------------------------------------+
```
---
## 📚 Part 8: Understanding the DHT11 Sensor
## Part 8: Understanding the DHT11 Sensor
### What is the DHT11?
The **DHT11** is a low-cost digital temperature and humidity sensor. It uses a single wire for communication (plus power and ground).
```
┌─────────────────────────────────────────────────────────────────┐
DHT11 Pinout
│ │
│ ┌─────────────┐ │
DHT11
│ │ ┌─────┐ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ └─────┘ │ │
1 2 3 4
│ └──┬──┬──┬──┬─┘ │
│ │ │ │ │ │
VCC DATA NC GND
│ │
Pin 1: VCC (3.3V or 5V)
Pin 2: DATA (connect to GPIO)
Pin 3: Not Connected
Pin 4: GND (Ground)
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| DHT11 Pinout |
| |
| +-------------+ |
| | DHT11 | |
| | +-----+ | |
| | | | | |
| | | | | |
| | +-----+ | |
| | 1 2 3 4 | |
| +--+--+--+--+-+ |
| | | | | |
| VCC DATA NC GND |
| |
| Pin 1: VCC (3.3V or 5V) |
| Pin 2: DATA (connect to GPIO) |
| Pin 3: Not Connected |
| Pin 4: GND (Ground) |
| |
+-----------------------------------------------------------------+
```
### DHT11 Specifications
| Parameter | Range | Accuracy |
| --------------- | ------------ | -------- |
| **Humidity** | 20% - 90% RH | ±5% RH |
| **Temperature** | 0°C - 50°C | ±2°C |
| **Humidity** | 20% - 90% RH | ?5% RH |
| **Temperature** | 0 deg C - 50 deg C | ?2 deg C |
### How DHT11 Communication Works
The DHT11 uses a custom one-wire protocol:
1. **Host sends start signal** - Pull data line LOW for 18ms
2. **DHT11 responds** - Pulls line LOW for 80µs, then HIGH for 80µs
2. **DHT11 responds** - Pulls line LOW for 80 us, then HIGH for 80 us
3. **Data transmission** - 40 bits sent (8 humidity int, 8 humidity decimal, 8 temp int, 8 temp decimal, 8 checksum)
---
## 📚 Part 9: Understanding Pointers (Quick Review)
## Part 9: Understanding Pointers (Quick Review)
### The & Operator (Address-Of)
@@ -295,32 +295,32 @@ float hum, temp;
// Pass ADDRESSES to the function so it can modify our variables
if (dht11_read(&hum, &temp)) {
printf("Humidity: %.1f%%, Temperature: %.1f°C\n", hum, temp);
printf("Humidity: %.1f%%, Temperature: %.1f?C\n", hum, temp);
}
```
```
┌─────────────────────────────────────────────────────────────────┐
Passing by Reference
│ │
Stack Memory
│ ┌────────────────────────────┐ │
Address 0x20000008: hum │◄─── &hum (passed to function)
Value: 51.0
│ ├────────────────────────────┤ │
Address 0x2000000C: temp │◄─── &temp (passed to function)
Value: 23.8
│ └────────────────────────────┘ │
│ │
dht11_read() receives the ADDRESSES, so it can write
new values directly into hum and temp!
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Passing by Reference |
| |
| Stack Memory |
| +----------------------------+ |
| | Address 0x20000008: hum |?--- &hum (passed to function) |
| | Value: 51.0 | |
| +----------------------------+ |
| | Address 0x2000000C: temp |?--- &temp (passed to function) |
| | Value: 23.8 | |
| +----------------------------+ |
| |
| dht11_read() receives the ADDRESSES, so it can write |
| new values directly into hum and temp! |
| |
+-----------------------------------------------------------------+
```
---
## 📚 Part 10: Setting Up Your Environment
## Part 10: Setting Up Your Environment
### Prerequisites
@@ -344,43 +344,43 @@ Connect your DHT11 like this:
| GND | GND |
```
┌─────────────────────────────────────────────────────────────────┐
DHT11 Wiring
│ │
Pico 2 DHT11 Sensor
│ ┌──────────┐ ┌──────────┐ │
│ │ │ │ │ │
GPIO 4 │────────── DATA ──────►│ DATA
│ │ │ │ │ │
3.3V │────────── VCC ───────►│ VCC
│ │ │ │ │ │
GND │────────── GND ───────►│ GND
│ │ │ │ │ │
│ └──────────┘ └──────────┘ │
│ │
Note: Some DHT11 modules have a built-in pull-up resistor.
If yours doesn't, add a 10K resistor between DATA and VCC.
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| DHT11 Wiring |
| |
| Pico 2 DHT11 Sensor |
| +----------+ +----------+ |
| | | | | |
| | GPIO 4 |---------- DATA ------?| DATA | |
| | | | | |
| | 3.3V |---------- VCC -------?| VCC | |
| | | | | |
| | GND |---------- GND -------?| GND | |
| | | | | |
| +----------+ +----------+ |
| |
| Note: Some DHT11 modules have a built-in pull-up resistor. |
| If yours doesn't, add a 10K resistor between DATA and VCC. |
| |
+-----------------------------------------------------------------+
```
### Project Structure
```
Embedded-Hacking/
├── 0x001a_operators/
├── build/
├── 0x001a_operators.uf2
└── 0x001a_operators.bin
├── main/
└── 0x001a_operators.c
└── dht11.h
└── uf2conv.py
+-- 0x001a_operators/
| +-- build/
| | +-- 0x001a_operators.uf2
| | +-- 0x001a_operators.bin
| +-- main/
| | +-- 0x001a_operators.c
| +-- dht11.h
+-- uf2conv.py
```
---
## 🔬 Part 11: Hands-On Tutorial - The Operators Code
## ? Part 11: Hands-On Tutorial - The Operators Code
### Step 1: Review the Source Code
@@ -417,7 +417,7 @@ int main(void) {
float hum, temp;
if (dht11_read(&hum, &temp)) {
printf("Humidity: %.1f%%, Temperature: %.1f°C\r\n", hum, temp);
printf("Humidity: %.1f%%, Temperature: %.1f?C\r\n", hum, temp);
} else {
printf("DHT11 read failed\r\n");
}
@@ -432,20 +432,20 @@ int main(void) {
Let's trace through what happens to `x`:
```
┌─────────────────────────────────────────────────────────────────┐
Variable x Through the Program
│ │
Line x value Result
│ ──────────────────┼─────────┼───────────────────────────────── │
int x = 5; 5 x initialized to 5
x * y 5 arithmetic = 5 * 10 = 50
x++ 56 increment = 5 (then x becomes 6)
x > y 6 relational = (6 > 10) = false
(x>y) && (y>x) 6 logical = false && true = false
x << 1 6 bitwise = 6 << 1 = 12
x += 5 611 assignment = 6 + 5 = 11
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Variable x Through the Program |
| |
| Line | x value | Result |
| ------------------+---------+--------------------------------- |
| int x = 5; | 5 | x initialized to 5 |
| x * y | 5 | arithmetic = 5 * 10 = 50 |
| x++ | 5->6 | increment = 5 (then x becomes 6) |
| x > y | 6 | relational = (6 > 10) = false |
| (x>y) && (y>x) | 6 | logical = false && true = false |
| x << 1 | 6 | bitwise = 6 << 1 = 12 |
| x += 5 | 6->11 | assignment = 6 + 5 = 11 |
| |
+-----------------------------------------------------------------+
```
### Step 3: Flash the Binary to Your Pico 2
@@ -467,25 +467,25 @@ relational_operator: 0
logical_operator: 0
bitwise_operator: 12
assignment_operator: 11
Humidity: 51.0%, Temperature: 23.8°C
Humidity: 51.0%, Temperature: 23.8 deg C
```
**Understanding the Output:**
| Variable | Value | Explanation |
| ------------------- | ------ | --------------------------------------------- |
| arithmetic_operator | 50 | 5 × 10 = 50 |
| arithmetic_operator | 50 | 5 * 10 = 50 |
| increment_operator | 5 | Post-increment returns value BEFORE increment |
| relational_operator | 0 | 6 > 10 is false (0) |
| logical_operator | 0 | false AND true = false (0) |
| bitwise_operator | 12 | 6 (0b0110) << 1 = 12 (0b1100) |
| assignment_operator | 11 | 6 + 5 = 11 |
| Humidity | 51.0% | Real reading from DHT11 |
| Temperature | 23.8°C | Real reading from DHT11 |
| Temperature | 23.8 deg C | Real reading from DHT11 |
---
## 🔬 Part 12: Debugging with GDB
## ? Part 12: Debugging with GDB
### Step 5: Start OpenOCD (Terminal 1)
@@ -493,7 +493,7 @@ Open a terminal and start OpenOCD:
```powershell
openocd ^
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
-f interface/cmsis-dap.cfg ^
-f target/rp2350.cfg ^
-c "adapter speed 5000"
@@ -640,7 +640,7 @@ The program will loop, printing values to serial.
---
## 🔬 Part 13: Setting Up Ghidra for Analysis
## ? Part 13: Setting Up Ghidra for Analysis
### Step 17: Start Ghidra
@@ -652,7 +652,7 @@ ghidraRun
### Step 18: Create a New Project
1. Click **File** **New Project**
1. Click **File** -> **New Project**
2. Select **Non-Shared Project**
3. Click **Next**
4. Enter Project Name: `0x001a_operators`
@@ -666,12 +666,12 @@ ghidraRun
### Step 20: Configure the Binary Format
**Click the three dots () next to "Language" and:**
**Click the three dots (...) next to "Language" and:**
1. Search for "Cortex"
2. Select **ARM Cortex 32 little endian default**
3. Click **OK**
**Click the "Options" button and:**
**Click the "Options..." button and:**
1. Change **Block Name** to `.text`
2. Change **Base Address** to `10000000`
3. Click **OK**
@@ -686,25 +686,25 @@ Wait for analysis to complete.
---
## 🔬 Part 14: Finding the Reset_Handler
## ? Part 14: Finding the Reset_Handler
### Step 22: Understand the Vector Table
In ARM Cortex-M, the **vector table** is at the base of flash (0x10000000). The second entry (offset 4) contains the Reset_Handler address.
```
┌─────────────────────────────────────────────────────────────────┐
ARM Vector Table at 0x10000000
│ │
Offset Contents Description
│ ───────────────────────────────────────────────────────────── │
0x00 Initial SP value Stack pointer at reset
0x04 Reset_Handler addr First code to execute
0x08 NMI_Handler addr Non-maskable interrupt
0x0C HardFault_Handler Hard fault handler
...
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| ARM Vector Table at 0x10000000 |
| |
| Offset Contents Description |
| ------------------------------------------------------------- |
| 0x00 Initial SP value Stack pointer at reset |
| 0x04 Reset_Handler addr First code to execute |
| 0x08 NMI_Handler addr Non-maskable interrupt |
| 0x0C HardFault_Handler Hard fault handler |
| ... |
| |
+-----------------------------------------------------------------+
```
### Step 23: Read the Reset_Handler Address
@@ -715,18 +715,18 @@ In ARM Cortex-M, the **vector table** is at the base of flash (0x10000000). The
**Important:** This is **little-endian**, so we need to reverse the byte order!
```
┌─────────────────────────────────────────────────────────────────┐
Little-Endian Byte Order
│ │
In memory: 5d 01 00 10
Reversed: 10 00 01 5d
As hex: 0x1000015d
│ │
But wait! ARM uses the THUMB bit!
The lowest bit indicates Thumb mode (always set for Cortex-M)
Real address: 0x1000015d - 1 = 0x1000015c
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Little-Endian Byte Order |
| |
| In memory: 5d 01 00 10 |
| Reversed: 10 00 01 5d |
| As hex: 0x1000015d |
| |
| But wait! ARM uses the THUMB bit! |
| The lowest bit indicates Thumb mode (always set for Cortex-M) |
| Real address: 0x1000015d - 1 = 0x1000015c |
| |
+-----------------------------------------------------------------+
```
### Step 24: Navigate to Reset_Handler
@@ -740,7 +740,7 @@ If Ghidra didn't automatically recognize this as a function:
1. Click on the address `0x1000015c`
2. Right-click and press `F` to create a function
3. Right-click **Edit Function Signature**
3. Right-click -> **Edit Function Signature**
4. Change the name to `Reset_Handler`
5. Click **OK**
@@ -749,17 +749,17 @@ If Ghidra didn't automatically recognize this as a function:
The Reset_Handler typically calls three functions:
```
┌─────────────────────────────────────────────────────────────────┐
Reset_Handler Flow (crt0.S)
│ │
Reset_Handler:
1. Call some_init() ◄── Initialize hardware
2. Call main() ◄── THIS IS WHAT WE WANT!
3. Call exit() ◄── Never returns
│ │
The MIDDLE function is main!
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Reset_Handler Flow (crt0.S) |
| |
| Reset_Handler: |
| 1. Call some_init() ?-- Initialize hardware |
| 2. Call main() ?-- THIS IS WHAT WE WANT! |
| 3. Call exit() ?-- Never returns |
| |
| The MIDDLE function is main! |
| |
+-----------------------------------------------------------------+
```
Look at the end of Reset_Handler for three function calls. The middle one is `main`!
@@ -767,13 +767,13 @@ Look at the end of Reset_Handler for three function calls. The middle one is `ma
### Step 27: Navigate to Main
1. Double-click on the middle function call (should be around `0x10000234`)
2. Right-click **Edit Function Signature**
2. Right-click -> **Edit Function Signature**
3. Change to: `int main(void)`
4. Click **OK**
---
## 🔬 Part 15: Resolving Functions in Ghidra
## ? Part 15: Resolving Functions in Ghidra
### Step 28: Resolve stdio_init_all
@@ -781,7 +781,7 @@ The first function call in main is `stdio_init_all`:
1. Find the call at approximately `0x10000238`
2. Double-click to navigate to the function
3. Right-click **Edit Function Signature**
3. Right-click -> **Edit Function Signature**
4. Change to: `bool stdio_init_all(void)`
5. Click **OK**
@@ -798,7 +798,7 @@ bl FUN_xxxxx ; dht11_init
- The argument `4` is the GPIO pin number
- We physically connected the DHT11 to GPIO 4!
1. Right-click **Edit Function Signature**
1. Right-click -> **Edit Function Signature**
2. Change to: `void dht11_init(uint pin)`
3. Click **OK**
@@ -807,7 +807,7 @@ bl FUN_xxxxx ; dht11_init
Look for repeated function calls with string addresses:
1. Find a call like the one at `0x10000262`
2. Right-click **Edit Function Signature**
2. Right-click -> **Edit Function Signature**
3. Change to: `int printf(char *format, ...)`
4. Check the **Varargs** checkbox
5. Click **OK**
@@ -821,7 +821,7 @@ ldr r0, =0x7d0 ; 2000 milliseconds
bl FUN_xxxxx ; sleep_ms
```
1. Right-click **Edit Function Signature**
1. Right-click -> **Edit Function Signature**
2. Change to: `void sleep_ms(uint ms)`
3. Click **OK**
@@ -840,7 +840,7 @@ bl FUN_xxxxx ; dht11_read
- `sp + 0xc` = address of `temp` variable
- These are `float` pointers passed to the function
1. Right-click **Edit Function Signature**
1. Right-click -> **Edit Function Signature**
2. Change to: `bool dht11_read(float *humidity, float *temperature)`
3. Click **OK**
@@ -853,32 +853,32 @@ ldr r0, ="DHT11 read failed"
bl FUN_xxxxx ; puts
```
1. Right-click **Edit Function Signature**
1. Right-click -> **Edit Function Signature**
2. Change to: `int puts(char *s)`
3. Click **OK**
---
## 🔬 Part 16: Understanding IEEE-754 Floating-Point
## ? Part 16: Understanding IEEE-754 Floating-Point
### What is IEEE-754?
IEEE-754 is the standard for representing decimal numbers in binary. A 32-bit float is divided into three parts:
```
┌─────────────────────────────────────────────────────────────────┐
IEEE-754 Single Precision (32-bit) Float
│ │
│ ┌─────┬─────────────┬───────────────────────────────────────┐ │
S Exponent Mantissa (Fraction)
1 8 bits 23 bits
│ └─────┴─────────────┴───────────────────────────────────────┘ │
bit bits bits
31 30-23 22-0
│ │
Value = (-1)^S × (1 + Mantissa) × 2^(Exponent - 127)
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| IEEE-754 Single Precision (32-bit) Float |
| |
| +-----+-------------+---------------------------------------+ |
| | S | Exponent | Mantissa (Fraction) | |
| | 1 | 8 bits | 23 bits | |
| +-----+-------------+---------------------------------------+ |
| bit bits bits |
| 31 30-23 22-0 |
| |
| Value = (-1)^S * (1 + Mantissa) * 2^(Exponent - 127) |
| |
+-----------------------------------------------------------------+
```
### Example: Decoding 0x3dcccccc (0.1f)
@@ -895,7 +895,7 @@ Let's decode the bytes `cc cc cc 3d`:
4. **Calculate value:**
- Actual exponent: 123 - 127 = -4
- Mantissa value: 1.6 (approximately)
- Final value: 1.6 × 2^(-4) 0.1
- Final value: 1.6 * 2^(-4) ? 0.1
### Example: Encoding -1.0f as 0xbf800000
@@ -927,7 +927,7 @@ print(f"Bytes: {encoded.hex()}") # 0000 80bf
---
## 🔬 Part 17: Finding the Temperature Hack Point
## ? Part 17: Finding the Temperature Hack Point
### Step 34: Locate the dht11_read Function
@@ -945,19 +945,19 @@ vfma.f32 s15, s13, s11 ; Fused multiply-add for temperature
The constant `0.1` (at address `0x1000042c`) is loaded into register `s11` and used to scale the raw sensor readings.
```
┌─────────────────────────────────────────────────────────────────┐
DHT11 Scaling Calculation
│ │
Raw sensor data: integer + decimal parts
Example: 238 (integer=23, decimal=8)
│ │
Formula: result = integer + (decimal × 0.1)
23.8 = 23 + (8 × 0.1)
│ │
The vfma.f32 instruction does: s15 = s13 + (s11 × something)
Where s11 = 0.1f (our target!)
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| DHT11 Scaling Calculation |
| |
| Raw sensor data: integer + decimal parts |
| Example: 238 (integer=23, decimal=8) |
| |
| Formula: result = integer + (decimal * 0.1) |
| 23.8 = 23 + (8 * 0.1) |
| |
| The vfma.f32 instruction does: s15 = s13 + (s11 * something) |
| Where s11 = 0.1f (our target!) |
| |
+-----------------------------------------------------------------+
```
### Step 36: Identify Key Offsets
@@ -972,11 +972,11 @@ Make note of these offsets in the binary file:
---
## 🔬 Part 18: Manual Hacking in Ghidra
## ? Part 18: Manual Hacking in Ghidra
### Step 37: Open the Bytes Editor
1. Click **Window** **Bytes**
1. Click **Window** -> **Bytes**
2. A new panel appears showing raw hex bytes
### Step 38: Enable Editing
@@ -1011,11 +1011,11 @@ print(f"New: {new}") # 5.0
---
## 🔬 Part 19: Exporting and Testing
## ? Part 19: Exporting and Testing
### Step 41: Export the Patched Binary
1. Click **File** **Export Program**
1. Click **File** -> **Export Program**
2. Set **Format** to **Binary**
3. Navigate to your build directory
4. Name the file `0x001a_operators-h.bin`
@@ -1026,7 +1026,7 @@ print(f"New: {new}") # 5.0
Open a terminal and run:
```powershell
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators
cd C:\Users\assem.KEVINTHOMAS\OneDrive\Documents\Embedded-Hacking\0x001a_operators
python ..\uf2conv.py build\0x001a_operators-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
```
@@ -1040,7 +1040,7 @@ You should see dramatically increased temperature readings!
---
## 📊 Part 20: Summary and Review
## ? Part 20: Summary and Review
### What We Accomplished
@@ -1055,18 +1055,18 @@ You should see dramatically increased temperature readings!
### The Hacking Workflow
```
┌─────────────────────────────────────────────────────────────────┐
Binary Hacking Workflow
│ │
1. Analyze the binary in Ghidra
2. Identify target values/instructions
3. Calculate file offsets from memory addresses
4. Determine replacement bytes
5. Patch the binary (manual in hex editor)
6. Export and convert to UF2
7. Flash and test
│ │
└─────────────────────────────────────────────────────────────────┘
+-----------------------------------------------------------------+
| Binary Hacking Workflow |
| |
| 1. Analyze the binary in Ghidra |
| 2. Identify target values/instructions |
| 3. Calculate file offsets from memory addresses |
| 4. Determine replacement bytes |
| 5. Patch the binary (manual in hex editor) |
| 6. Export and convert to UF2 |
| 7. Flash and test |
| |
+-----------------------------------------------------------------+
```
### Key Memory Addresses
@@ -1082,34 +1082,9 @@ You should see dramatically increased temperature readings!
---
## ✅ Practice Exercises
### Exercise 1: Change the Sleep Duration
Find the `sleep_ms(2000)` call and change it to 5000ms (5 seconds).
**Hint:** Look for `0x7d0` (2000) being loaded into r0.
### Exercise 2: Invert Temperature Reading
Using HxD, change the scaling constant at offset `0x42C` to make temperature readings negative.
**Hint:** Encode -0.1f as IEEE-754 and write those bytes.
### Exercise 3: Add a Fixed Offset
Using HxD, patch the instruction at offset `0x414` and the constant at `0x42C` to add exactly 10°C to every reading.
**Hint:** Change vfma to vadd and set the pool constant to 10.0f (`00 00 20 41`).
### Exercise 4: Find All printf Strings
Search the binary for all format strings like "%d" and "%.1f".
**Hint:** Use GDB's `x/s` command to search flash memory, or scan in HxD's ASCII panel.
### Exercise 5: Trace the Variable Flow
In Ghidra, trace how x changes through each operator. Match your findings to the output values.
---
## 🎓 Key Takeaways
## ? Key Takeaways
1. **Post-increment returns the OLD value** - `x++` gives you x, THEN adds 1
@@ -1121,7 +1096,7 @@ In Ghidra, trace how x changes through each operator. Match your findings to the
5. **IEEE-754 is how floats are stored** - Sign, exponent, mantissa
6. **File offset = Memory address - Base** - 0x10000410 offset 0x410
6. **File offset = Memory address - Base** - 0x10000410 -> offset 0x410
7. **Little-endian reverses byte order** - 0x3dcccccc stored as cc cc cc 3d
@@ -1131,7 +1106,7 @@ In Ghidra, trace how x changes through each operator. Match your findings to the
---
## 📖 Glossary
## ? Glossary
| Term | Definition |
| ------------------ | --------------------------------------------------- |
@@ -1156,7 +1131,7 @@ In Ghidra, trace how x changes through each operator. Match your findings to the
---
## 🔗 Additional Resources
## ? Additional Resources
### IEEE-754 Float Quick Reference
@@ -1174,16 +1149,16 @@ In Ghidra, trace how x changes through each operator. Match your findings to the
| Instruction | Description |
| --------------------- | ---------------------------------------- |
| `vfma.f32 Sd, Sn, Sm` | Sd = Sd + (Sn × Sm) (fused multiply-add) |
| `vfma.f32 Sd, Sn, Sm` | Sd = Sd + (Sn * Sm) (fused multiply-add) |
| `vadd.f32 Sd, Sn, Sm` | Sd = Sn + Sm |
| `vsub.f32 Sd, Sn, Sm` | Sd = Sn - Sm |
| `vmul.f32 Sd, Sn, Sm` | Sd = Sn × Sm |
| `vmul.f32 Sd, Sn, Sm` | Sd = Sn * Sm |
| `vldr.f32 Sd, [addr]` | Load float from memory |
| `vstr.f32 Sd, [addr]` | Store float to memory |
---
## 🚨 Real-World Implications
## ? Real-World Implications
### Why This Matters
@@ -1210,4 +1185,6 @@ By manipulating sensor readings, an attacker could:
**Remember:** The techniques you learned today can be used for good (security research, debugging) or bad (sabotage, fraud). Always use your skills ethically and legally. Understanding how attacks work helps us build more secure systems!
Happy hacking! 🔧
Happy hacking! ?