# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)

## Week 5
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis

### Exercise 4: Patch the Double Binary — Changing 42.52525 to 99.99

#### Objective
Calculate the IEEE 754 double-precision encoding of `99.99`, patch **both** register words in the double binary in Ghidra, export the patched binary, convert it to UF2 format, and flash it to the Pico 2 to verify the change.

#### Prerequisites
- Completed Exercise 3 (double binary imported and analyzed in Ghidra)
- Understanding of IEEE 754 double-precision encoding from Week 5 Parts 2.7 and 3.7
- Knowledge of integer-to-binary conversion and the multiply-by-2 method for fractions
- Python installed for UF2 conversion and verification
- Raspberry Pi Pico 2 connected via USB

#### Task Description
You will derive the IEEE 754 encoding of `99.99` step by step (integer part, fractional part, normalization, field extraction), patch both the low word and high word data constants in Ghidra, and verify on hardware that the serial output now prints `99.990000`. Unlike Exercise 2 where only one word changed, this exercise requires patching **both** registers.

#### Step-by-Step Instructions

##### Step 1: Convert the Integer Part (99) to Binary

Use repeated division by 2:

| Division | Quotient | Remainder |
|----------|----------|-----------|
| 99 ÷ 2   | 49       | **1**     |
| 49 ÷ 2   | 24       | **1**     |
| 24 ÷ 2   | 12       | **0**     |
| 12 ÷ 2   | 6        | **0**     |
| 6 ÷ 2    | 3        | **0**     |
| 3 ÷ 2    | 1        | **1**     |
| 1 ÷ 2    | 0        | **1**     |

Read remainders bottom-to-top: $99_{10} = 1100011_2$

##### Step 2: Convert the Fractional Part (.99) to Binary

Use the multiply-by-2 method:

| Multiply       | Result | Integer part | Remaining fraction |
|----------------|--------|--------------|-------------------|
| 0.99 × 2      | 1.98   | **1**        | 0.98              |
| 0.98 × 2      | 1.96   | **1**        | 0.96              |
| 0.96 × 2      | 1.92   | **1**        | 0.92              |
| 0.92 × 2      | 1.84   | **1**        | 0.84              |
| 0.84 × 2      | 1.68   | **1**        | 0.68              |
| 0.68 × 2      | 1.36   | **1**        | 0.36              |
| 0.36 × 2      | 0.72   | **0**        | 0.72              |
| 0.72 × 2      | 1.44   | **1**        | 0.44              |
| 0.44 × 2      | 0.88   | **0**        | 0.88              |
| 0.88 × 2      | 1.76   | **1**        | 0.76              |
| 0.76 × 2      | 1.52   | **1**        | 0.52              |
| 0.52 × 2      | 1.04   | **1**        | 0.04              |
| ...            | ...    | ...          | *(continues — repeating fraction)* |

Reading the integer parts top-to-bottom: $0.99_{10} \approx 0.111111010111..._2$

This is a **repeating fraction** — it never terminates in binary.

##### Step 3: Combine Integer and Fractional Parts

$$99.99_{10} = 1100011.111111010111..._2$$

##### Step 4: Normalize to IEEE 754 Form

Move the binary point so there is exactly one `1` before it:

$$1100011.111111010111..._2 = 1.100011111111010111..._2 \times 2^6$$

We shifted the binary point 6 places left, so the exponent is **6**.

##### Step 5: Extract the IEEE 754 Fields

1. **Sign:** `0` (positive)
2. **Exponent:** $6 + 1023 = 1029 = 10000000101_2$
3. **Mantissa:** `1000111111110101110000101000111101011100001010001111...` (52 bits after the `1.`)
4. **Full double:** `0x4058FF5C28F5C28F`

**Verify with Python:**
```python
>>> import struct
>>> struct.pack('>d', 99.99).hex()
'4058ff5c28f5c28f'
```

##### Step 6: Split into Register Words

| Register | Old Value    | New Value    | Changed? |
| -------- | ------------ | ------------ | -------- |
| `r2`     | `0x645A1CAC` | `0x28F5C28F` | **Yes**  |
| `r3`     | `0x4045433B` | `0x4058FF5C` | **Yes**  |

**Both registers change!** This is the key difference from Exercise 2 where only r3 changed.

##### Step 7: Locate the Data Constants in Ghidra

Open your Ghidra project from Exercise 3. In the Listing view, find the two data constants:

**Low word (loaded into r2):**
```
        DAT_10000254
10000254 ac  1c  5a  64    undefined4  645A1CACh
```

**High word (loaded into r3):**
```
        DAT_10000258
10000258 3b  43  45  40    undefined4  4045433Bh
```

##### Step 8: Patch the Low Word

1. Click on **Window** → **Bytes** to open the Bytes Editor
2. Click the **Pencil Icon** to enable editing
3. Navigate to address `10000254`
4. The bytes read: `AC 1C 5A 64` (little-endian for `0x645A1CAC`)
5. Change to: `8F C2 F5 28` (little-endian for `0x28F5C28F`)
6. Press **Enter**

##### Step 9: Patch the High Word

1. Navigate to address `10000258`
2. The bytes read: `3B 43 45 40` (little-endian for `0x4045433B`)
3. Change to: `5C FF 58 40` (little-endian for `0x4058FF5C`)
4. Press **Enter**

**Verify** in the Listing view:
- `DAT_10000254` should show `28F5C28Fh`
- `DAT_10000258` should show `4058FF5Ch`

Together: `0x4058FF5C28F5C28F` = `99.99` as a double ✓

##### Step 10: Export the Patched Binary

1. Click **File** → **Export Program**
2. Set **Format** to **Raw Bytes**
3. Navigate to your build directory
4. Name the file: `0x0011_double-floating-point-data-type-h.bin`
5. Click **OK**

##### Step 11: Convert to UF2 Format

Open a terminal:

```powershell
cd Embedded-Hacking-main\0x0011_double-floating-point-data-type
```

```powershell
python ..\uf2conv.py build\0x0011_double-floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
```

##### Step 12: Flash and Verify

1. Hold **BOOTSEL** and plug in your Pico 2
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
3. Open your serial monitor

**Expected output:**

```
fav_num: 99.990000
fav_num: 99.990000
fav_num: 99.990000
...
```

🎉 **Success!** The value changed from `42.52525` to `99.99`!

#### Expected Output

After completing this exercise, you should:
- See `fav_num: 99.990000` printing instead of `fav_num: 42.525250`
- Have a patched binary file (`0x0011_double-floating-point-data-type-h.bin`)
- Have a UF2 file (`hacked.uf2`)
- Understand that patching doubles with repeating fractions requires modifying **both** register words

#### Questions for Reflection

###### Question 1: Why did both r2 and r3 change when patching 42.52525 → 99.99, but only r3 changed when patching 42.5 → 99.0?

###### Question 2: The multiply-by-2 method for 0.99 produces a repeating pattern. What does this mean for the precision of the stored value?

###### Question 3: If you wanted to patch the double to `100.0` instead of `99.99`, how many data constants would need to change?

###### Question 4: Compare the Ghidra Listing for the float binary (Exercise 1) and the double binary (Exercise 3). How does the compiler load the double differently?

#### Tips and Hints
- Always verify your encoding with Python before patching
- Little-endian byte order: `0x28F5C28F` is stored as `8F C2 F5 28` in memory
- Use Ghidra's **Bytes** window (Window → Bytes) for precise hex editing
- If `r2` was zero before and needs to be non-zero after, you need to patch the data constant — not the `movs r4, #0x0` instruction
- The `ldrd` instruction loads r4 and r5 from two consecutive memory addresses — both must be correct

#### Next Steps
- Review the complete patching workflow diagram in Week 5 Part 3.95
- Try patching to `100.0` — since it has a zero low word, you'll need to change `r2` from non-zero to zero
- Attempt the practice exercises at the end of Week 5

#### Additional Challenge
Patch the double to `3.14159265358979` (pi). This requires extreme precision in all 52 mantissa bits. Use Python to get the exact encoding, then patch both words. Verify the output prints at least 6 correct decimal places. What happens to the precision if you only patch the high word and leave the low word as `0x645A1CAC`?

#### Verification Checklist

Before moving on, confirm:
- [ ] Serial output shows `fav_num: 99.990000`
- [ ] Both data constants were patched (low word and high word)
- [ ] You can derive the IEEE 754 encoding of `99.99` from scratch
- [ ] You understand why messy fractions require patching both register words
- [ ] You can explain the difference between the float and double patching workflows
- [ ] You successfully converted and flashed the UF2

**Congratulations!** You've completed all Week 5 exercises and mastered floating-point analysis, IEEE 754 decoding, and double-precision binary patching!
