# 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 2: Patch the Float Binary — Changing 42.5 to 99.0

#### Objective
Calculate the IEEE 754 double-precision encoding of `99.0`, patch the float binary in Ghidra to change the printed value from `42.5` to `99.0`, export the patched binary, convert it to UF2 format, and flash it to the Pico 2 to verify the change.

#### Prerequisites
- Completed Exercise 1 (float binary imported and analyzed in Ghidra)
- Understanding of IEEE 754 double-precision encoding from Week 5 Part 2.7
- Python installed for UF2 conversion
- `uf2conv.py` script available in your project directory
- Raspberry Pi Pico 2 connected via USB
- Serial monitor software (PuTTY, minicom, or screen)

#### Task Description
You will convert `99.0` to its IEEE 754 double-precision encoding by hand (integer-to-binary conversion, normalization, field extraction), determine which register words need to change, patch the data constant in Ghidra, and verify on hardware that the serial output now prints `99.000000`.

#### Step-by-Step Instructions

##### Step 1: Convert 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: Handle the Fractional Part

The fractional part of `99.0` is `.0` — exactly zero. There are no fractional bits.

$$99.0_{10} = 1100011.0_2$$

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

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

$$1100011.0_2 = 1.100011_2 \times 2^6$$

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

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

1. **Sign:** `0` (positive)
2. **Exponent:** $6 + 1023 = 1029 = 10000000101_2$
3. **Mantissa:** `100011` followed by 46 zeros (everything after the `1.`, padded to 52 bits)
4. **Full double:** `0x4058C00000000000`

Split into register words:
- **r3 (high word):** `0x4058C000`
- **r2 (low word):** `0x00000000`

##### Step 5: Determine What to Patch

Compare old vs. new:

| Register | Old Value    | New Value    | Changed? |
| -------- | ------------ | ------------ | -------- |
| `r2`     | `0x00000000` | `0x00000000` | No       |
| `r3`     | `0x40454000` | `0x4058C000` | **Yes**  |

Since `r2` stays all zeros, we only need to patch the high word in `r3`.

##### Step 6: Locate the Data Constant in Ghidra

Open your Ghidra project from Exercise 1. In the Listing view, find the data constant that loads into `r3`:

```
        DAT_1000024c
10000248 00  40  45  40    undefined4  40454000h
```

This is the 32-bit constant `0x40454000` — the high word of the double `42.5`.

##### Step 7: Patch the Constant

1. Click on **Window** → **Bytes** to open the Bytes Editor
2. Click the **Pencil Icon** to enable editing
3. Navigate to the data at `DAT_1000024c`
4. The bytes in memory (little-endian) read: `00 40 45 40`
5. Change them to: `00 C0 58 40` (which is `0x4058C000` in little-endian)
6. Press **Enter**

**Verify** in the Listing view — the data should now show `4058C000h`.

##### Step 8: Verify the Patch in the Decompile Window

The decompiled code should now reference the new constant. The value loaded into `r3` should be `0x4058C000`.

##### Step 9: 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: `0x000e_floating-point-data-type-h.bin`
5. Click **OK**

##### Step 10: Convert to UF2 Format

Open a terminal and navigate to your project directory:

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

Run the conversion:

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

##### Step 11: 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.000000
fav_num: 99.000000
fav_num: 99.000000
...
```

🎉 **Success!** The value changed from `42.5` to `99.0`!

#### Expected Output

After completing this exercise, you should:
- See `fav_num: 99.000000` printing instead of `fav_num: 42.500000`
- Have a patched binary file (`0x000e_floating-point-data-type-h.bin`)
- Have a UF2 file (`hacked.uf2`)
- Understand the complete IEEE 754 encoding and patching workflow for floats

#### Questions for Reflection

###### Question 1: Why did we only need to patch r3 (the high word) and not r2 (the low word)?

###### Question 2: What would the high word be if we wanted to patch the value to `-99.0` instead? (Hint: which bit controls the sign?)

###### Question 3: Walk through the encoding of `100.0` as a double. What are the high and low words?

###### Question 4: Why do we need the `--family 0xe48bff59` flag when converting to UF2?

#### Tips and Hints
- Always verify your encoding with Python: `import struct; struct.pack('>d', 99.0).hex()`
- Little-endian means the bytes in memory are reversed: `0x4058C000` is stored as `00 C0 58 40`
- If you patch the wrong bytes, use **File** → **Undo** in Ghidra (or re-import the original binary)
- The bias for double-precision is always 1023; for single-precision it's 127
- A clean fractional part (like `.0` or `.5`) means the low word (`r2`) is all zeros

#### Next Steps
- Proceed to Exercise 3 to analyze the double-precision binary
- Try patching to different values: `3.14`, `100.0`, `255.0`
- Compare how many register words change for clean vs. messy fractions

#### Additional Challenge
Patch the float to `3.14` instead of `99.0`. Since `3.14` has a repeating binary fraction, the low word will **not** be zero. This means you need to modify the assembly to load a non-zero value into `r2` as well. Can you figure out where `r2` gets its zero value (`movs r4, #0x0`) and change it?
