# 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 By the end of this tutorial, you will be able to: - Understand all six types of C operators (arithmetic, increment, relational, logical, bitwise, assignment) - Know how the DHT11 temperature and humidity sensor communicates with the Pico 2 - Understand how post-increment operators affect variable values - Navigate to the Reset_Handler and main function in stripped binaries - Identify function arguments by analyzing register values in Ghidra - Understand IEEE-754 floating-point representation - Hack floating-point constants to manipulate sensor readings --- ## πŸ“š Part 1: Understanding C Operators ### What Are Operators? **Operators** are symbols that tell the compiler to perform specific mathematical, logical, or data manipulation operations. Think of them as the "verbs" of programming - they describe actions to perform on data. ### The Six Types of Operators | Type | Example | What It Does | | -------------- | -------------------- | ----------------------------------- | | **Arithmetic** | `x * y` | Math operations (+, -, *, /, %) | | **Increment** | `x++` or `++x` | Increase/decrease by 1 | | **Relational** | `x > y` | Compare values (returns true/false) | | **Logical** | `(x > y) && (y > x)` | Combine conditions (AND, OR, NOT) | | **Bitwise** | `x << 1` | Manipulate individual bits | | **Assignment** | `x += 5` | Assign and modify values | --- ## πŸ“š Part 2: Arithmetic Operators ### Basic Math in C Arithmetic operators perform mathematical calculations: ```c int x = 5; int y = 10; 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) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“š Part 3: Increment and Decrement Operators ### Pre-Increment vs Post-Increment This is where many beginners get confused! There are TWO ways to increment: ```c int x = 5; int a = x++; // Post-increment: a = 5, then x becomes 6 int b = ++x; // Pre-increment: x becomes 7, then b = 7 ``` **The Key Difference:** | 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++) β”‚ β”‚ β”‚ β”‚ 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 ### Comparing Values Relational operators compare two values and return `true` (1) or `false` (0): ```c int x = 6; int y = 10; 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 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“š Part 5: Logical Operators ### Combining Conditions Logical operators combine multiple conditions: ```c int x = 6; int y = 10; 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 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“š Part 6: Bitwise Operators ### Manipulating Individual Bits Bitwise operators work on the binary representation of numbers: ```c int x = 6; // Binary: 0b00000110 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) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Common Bitwise Operators:** | Operator | Name | Example | Result | | -------- | ----------- | -------- | ------------------ | | `<<` | Left shift | `6 << 1` | 12 (multiply by 2) | | `>>` | Right shift | `6 >> 1` | 3 (divide by 2) | | `&` | AND | `6 & 3` | 2 (bits in common) | | `\|` | OR | `6 \| 3` | 7 (all set bits) | | `^` | XOR | `6 ^ 3` | 5 (different bits) | | `~` | NOT | `~6` | Inverts all bits | --- ## πŸ“š Part 7: Assignment Operators ### Shorthand for Math + Assign Assignment operators combine math with assignment: ```c int x = 6; 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 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“š 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 Specifications | Parameter | Range | Accuracy | | --------------- | ------------ | -------- | | **Humidity** | 20% - 90% RH | Β±5% RH | | **Temperature** | 0Β°C - 50Β°C | Β±2Β°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 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) ### The & Operator (Address-Of) When you see `&variable`, it means "the memory address of variable": ```c 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); } ``` ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 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 ### Prerequisites Before we start, make sure you have: 1. A Raspberry Pi Pico 2 board 2. A Raspberry Pi Pico Debug Probe 3. Ghidra installed (for static analysis) 4. Python installed (for UF2 conversion) 5. A serial monitor (PuTTY, minicom, or screen) 6. A DHT11 temperature and humidity sensor 7. The sample project: `0x001a_operators` ### Hardware Setup Connect your DHT11 like this: | DHT11 Pin | Pico 2 Pin | | --------- | ---------- | | VCC | 3.3V | | DATA | GPIO 4 | | 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. β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Project Structure ``` Embedded-Hacking/ β”œβ”€β”€ 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 ### Step 1: Review the Source Code Let's examine the operators code: **File: `0x001a_operators.c`** ```c #include #include "pico/stdlib.h" #include "dht11.h" int main(void) { stdio_init_all(); dht11_init(4); int x = 5; int y = 10; int arithmetic_operator = (x * y); int increment_operator = x++; bool relational_operator = (x > y); bool logical_operator = (x > y) && (y > x); int bitwise_operator = (x<<1); // x is now 6 because of x++ or 0b00000110 and (x<<1) is 0b00001100 or 12 int assignment_operator = (x += 5); while (true) { printf("arithmetic_operator: %d\r\n", arithmetic_operator); printf("increment_operator: %d\r\n", increment_operator); printf("relational_operator: %d\r\n", relational_operator); printf("logical_operator: %d\r\n", logical_operator); printf("bitwise_operator: %d\r\n", bitwise_operator); printf("assignment_operator: %d\r\n", assignment_operator); float hum, temp; if (dht11_read(&hum, &temp)) { printf("Humidity: %.1f%%, Temperature: %.1fΒ°C\r\n", hum, temp); } else { printf("DHT11 read failed\r\n"); } sleep_ms(2000); } } ``` ### Step 2: Understand the Variable Flow 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++ β”‚ 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 1. Hold the BOOTSEL button on your Pico 2 2. Plug in the USB cable (while holding BOOTSEL) 3. Release BOOTSEL - a drive called "RPI-RP2" appears 4. Drag and drop `0x001a_operators.uf2` onto the drive 5. The Pico will reboot and start running! ### Step 4: Verify It's Working Open your serial monitor (PuTTY at 115200 baud) and you should see: ``` arithmetic_operator: 50 increment_operator: 5 relational_operator: 0 logical_operator: 0 bitwise_operator: 12 assignment_operator: 11 Humidity: 51.0%, Temperature: 23.8Β°C ``` **Understanding the Output:** | Variable | Value | Explanation | | ------------------- | ------ | --------------------------------------------- | | 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 | --- ## πŸ”¬ Part 12: Debugging with GDB ### Step 5: Start OpenOCD (Terminal 1) Open a terminal and 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" ``` You should see output indicating OpenOCD connected successfully to your Pico 2 via the Debug Probe. ### Step 6: Start GDB (Terminal 2) Open a **new terminal** and launch GDB with the binary: ```powershell arm-none-eabi-gdb build\0x001a_operators.elf ``` ### Step 7: Connect to the Remote Target Inside GDB, type: ``` target remote :3333 ``` This connects GDB to OpenOCD. ### Step 8: Halt the Running Binary ``` monitor reset halt ``` This stops the Pico 2 so we can examine its state. ### Step 9: Examine Main Function Let's examine the main function. Disassemble from the entry point: ``` x/60i 0x10000234 ``` You should see the operator calculations and function calls: ``` 0x10000234: push {r4, r5, r6, r7, lr} 0x10000236: sub sp, #20 0x10000238: bl 0x10003014 ; stdio_init_all 0x1000023c: movs r0, #4 ; GPIO 4 for DHT11 0x1000023e: bl 0x100003b4 ; dht11_init ... ``` ### Step 10: Set a Breakpoint at Main ``` b *0x10000234 c ``` GDB responds: ``` Breakpoint 1 at 0x10000234 Continuing. Breakpoint 1, 0x10000234 in ?? () ``` ### Step 11: Find the Operator Calculations The compiler likely optimized many of these calculations at compile time. Look for immediate values: ``` x/30i 0x10000240 ``` You may see values like: - `#0x32` (50) for arithmetic_operator - `#0x5` (5) for increment_operator - `#0x0` (0) for relational and logical operators - `#0xc` (12) for bitwise_operator - `#0xb` (11) for assignment_operator ### Step 12: Examine Printf Arguments Set a breakpoint before the first printf and examine registers: ``` b *0x10000262 c i r r0 r1 ``` You should see: - `r0` = address of format string - `r1` = value to print (50 for arithmetic_operator) ### Step 13: Examine the Format Strings ``` x/s 0x10003xxx ``` Find the format strings like: ``` "arithmetic_operator: %d\r\n" "increment_operator: %d\r\n" ... ``` ### Step 14: Examine DHT11 Function Call Find where dht11_read is called: ``` x/10i 0x100002a0 ``` You'll see stack addresses being passed as arguments: ``` add r0, sp, #0x8 ; Address of hum variable add r1, sp, #0xc ; Address of temp variable bl dht11_read ``` ### Step 15: Watch the Float Values After dht11_read returns, examine the float values on the stack: ``` x/2fw $sp+8 ``` This shows the humidity and temperature as floats. ### Step 16: Step Through the Loop Continue execution and watch the values: ``` c ``` The program will loop, printing values to serial. --- ## πŸ”¬ Part 13: Setting Up Ghidra for Analysis ### Step 17: Start Ghidra Open a terminal and type: ```powershell ghidraRun ``` ### Step 18: Create a New Project 1. Click **File** β†’ **New Project** 2. Select **Non-Shared Project** 3. Click **Next** 4. Enter Project Name: `0x001a_operators` 5. Click **Finish** ### Step 19: Import the Binary 1. Open your file explorer 2. Navigate to the `0x001a_operators/build/` folder 3. **Drag and drop** the `.bin` file into Ghidra's project window ### Step 20: Configure the Binary Format **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:** 1. Change **Block Name** to `.text` 2. Change **Base Address** to `10000000` 3. Click **OK** ### Step 21: Analyze the Binary 1. Double-click on the file in the project window 2. A dialog asks "Analyze now?" - Click **Yes** 3. Use default analysis options and click **Analyze** Wait for analysis to complete. --- ## πŸ”¬ 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 β”‚ β”‚ ... β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Step 23: Read the Reset_Handler Address 1. Press `G` (Go to address) and type `10000004` 2. You'll see bytes like `5d 01 00 10` (your exact bytes may vary) **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 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Step 24: Navigate to Reset_Handler 1. Press `G` and type `1000015c` (or your calculated address) 2. You might see undefined data - that's OK! ### Step 25: Create the Reset_Handler Function 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** 4. Change the name to `Reset_Handler` 5. Click **OK** ### Step 26: Find Main from Reset_Handler 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! β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` Look at the end of Reset_Handler for three function calls. The middle one is `main`! ### Step 27: Navigate to Main 1. Double-click on the middle function call (should be around `0x10000234`) 2. Right-click β†’ **Edit Function Signature** 3. Change to: `int main(void)` 4. Click **OK** --- ## πŸ”¬ Part 15: Resolving Functions in Ghidra ### Step 28: Resolve stdio_init_all 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** 4. Change to: `bool stdio_init_all(void)` 5. Click **OK** ### Step 29: Resolve dht11_init Look for a function call where `r0` is loaded with `0x4`: ```assembly movs r0, #0x4 ; GPIO pin 4 bl FUN_xxxxx ; dht11_init ``` **How do we know it's dht11_init?** - The argument `4` is the GPIO pin number - We physically connected the DHT11 to GPIO 4! 1. Right-click β†’ **Edit Function Signature** 2. Change to: `void dht11_init(uint pin)` 3. Click **OK** ### Step 30: Resolve printf Look for repeated function calls with string addresses: 1. Find a call like the one at `0x10000262` 2. Right-click β†’ **Edit Function Signature** 3. Change to: `int printf(char *format, ...)` 4. Check the **Varargs** checkbox 5. Click **OK** ### Step 31: Resolve sleep_ms Look for a function call where `r0` is loaded with `0x7d0` (2000 in decimal): ```assembly ldr r0, =0x7d0 ; 2000 milliseconds bl FUN_xxxxx ; sleep_ms ``` 1. Right-click β†’ **Edit Function Signature** 2. Change to: `void sleep_ms(uint ms)` 3. Click **OK** ### Step 32: Resolve dht11_read This is trickier! Look for a function call with TWO address arguments: ```assembly add r0, sp, #0x8 ; Address of hum on stack add r1, sp, #0xc ; Address of temp on stack bl FUN_xxxxx ; dht11_read ``` **Understanding the stack offsets:** - `sp + 0x8` = address of `hum` variable - `sp + 0xc` = address of `temp` variable - These are `float` pointers passed to the function 1. Right-click β†’ **Edit Function Signature** 2. Change to: `bool dht11_read(float *humidity, float *temperature)` 3. Click **OK** ### Step 33: Resolve puts Look for a function call after the `if` statement that takes a single string argument: ```assembly ldr r0, ="DHT11 read failed" bl FUN_xxxxx ; puts ``` 1. Right-click β†’ **Edit Function Signature** 2. Change to: `int puts(char *s)` 3. Click **OK** --- ## πŸ”¬ 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) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Example: Decoding 0x3dcccccc (0.1f) Let's decode the bytes `cc cc cc 3d`: 1. **Reverse for little-endian:** `0x3dcccccc` 2. **Convert to binary:** `00111101 11001100 11001100 11001100` 3. **Extract fields:** - Sign (bit 31): `0` (positive) - Exponent (bits 30-23): `01111011` = 123 - Mantissa (bits 22-0): `10011001100110011001100` 4. **Calculate value:** - Actual exponent: 123 - 127 = -4 - Mantissa value: 1.6 (approximately) - Final value: 1.6 Γ— 2^(-4) β‰ˆ 0.1 ### Example: Encoding -1.0f as 0xbf800000 For the number -1.0: 1. **Sign:** 1 (negative) 2. **Exponent:** 127 (for 2^0 = 1) 3. **Mantissa:** 0 (because value is exactly 1.0) Binary: `1 01111111 00000000000000000000000` Hex: `0xbf800000` Little-endian: `00 00 80 bf` ### Python for Float Conversion ```python import struct # Decode bytes to float bytes_data = bytes.fromhex('cdcccc3d') value = struct.unpack('>, &, \|, ^) | | **DHT11** | Digital humidity and temperature sensor | | **Exponent** | Power of 2 in IEEE-754 float representation | | **IEEE-754** | Standard for floating-point number representation | | **Increment Op** | Operators that add/subtract 1 (++, --) | | **Little-Endian** | Byte order where least significant byte comes first | | **Logical Op** | Operators combining conditions (&&, \|\|, !) | | **Mantissa** | Fractional part of IEEE-754 float | | **Post-Increment** | `x++` - returns value, then increments | | **Pre-Increment** | `++x` - increments, then returns value | | **Relational Op** | Operators comparing values (<, >, ==, !=) | | **Reset_Handler** | First function executed after CPU reset | | **Thumb Bit** | Lowest bit of ARM address indicating Thumb mode | | **Vector Table** | Table of exception/interrupt handler addresses | | **vfma.f32** | ARM floating-point fused multiply-add instruction | | **vadd.f32** | ARM floating-point add instruction | --- ## πŸ”— Additional Resources ### IEEE-754 Float Quick Reference | Value | Hex Encoding | Bytes (LE) | | ----- | ------------ | ----------- | | 0.1 | 0x3dcccccd | cd cc cc 3d | | 1.0 | 0x3f800000 | 00 00 80 3f | | -1.0 | 0xbf800000 | 00 00 80 bf | | 2.0 | 0x40000000 | 00 00 00 40 | | -2.0 | 0xc0000000 | 00 00 00 c0 | | 5.0 | 0x40a00000 | 00 00 a0 40 | | 10.0 | 0x41200000 | 00 00 20 41 | ### ARM Floating-Point Instructions | Instruction | Description | | --------------------- | ---------------------------------------- | | `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 | | `vldr.f32 Sd, [addr]` | Load float from memory | | `vstr.f32 Sd, [addr]` | Store float to memory | --- ## 🚨 Real-World Implications ### Why This Matters Imagine a scenario where temperature sensors control critical systems: - **Industrial processes** - Chemical reactions that must stay within temperature ranges - **Medical equipment** - Refrigerators storing vaccines or organs - **Nuclear facilities** - Cooling systems for reactors - **HVAC systems** - Climate control in sensitive environments By manipulating sensor readings, an attacker could: - Cause equipment to overheat while displaying normal temperatures - Trigger false alarms - Bypass safety interlocks - Cause physical damage or safety hazards ### Defensive Measures 1. **Redundant sensors** - Multiple sensors with consistency checks 2. **Physical security** - Prevent access to programming interfaces 3. **Anomaly detection** - Alert on sudden reading changes --- **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! πŸ”§