# 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 1: Analyze the Float Binary in Ghidra

#### Objective
Import and analyze the `0x000e_floating-point-data-type.bin` binary in Ghidra to understand how the compiler handles floating-point variables, discover float-to-double promotion, and decode the IEEE 754 double-precision encoding of `42.5` from two 32-bit registers.

#### Prerequisites
- Ghidra installed and configured
- `0x000e_floating-point-data-type.bin` binary available in your build directory
- Understanding of IEEE 754 encoding from Week 5 Part 2
- Basic Ghidra navigation skills from Weeks 3 and 4

#### Task Description
You will import the float binary into Ghidra, configure it for ARM Cortex-M33, resolve function names, discover that the compiler promotes `float` to `double` when passing to `printf`, and manually decode the 64-bit double `0x4045400000000000` field by field to confirm it represents `42.5`.

#### Step-by-Step Instructions

##### Step 1: Start Ghidra and Create New Project

```bash
ghidraRun
```

1. Click **File** → **New Project**
2. Select **Non-Shared Project**
3. Click **Next**
4. Enter Project Name: `week05-ex01-floating-point`
5. Choose a project directory
6. Click **Finish**

##### Step 2: Import the Binary

1. Navigate to your file explorer
2. Find `Embedded-Hacking/0x000e_floating-point-data-type/build/0x000e_floating-point-data-type.bin`
3. **Drag and drop** the `.bin` file into Ghidra's project window

##### Step 3: Configure Import Settings

When the import dialog appears:

1. Click the three dots (**…**) next to **Language**
2. Search for: `Cortex`
3. Select: **ARM Cortex 32 little endian default**
4. Click **OK**

Now click **Options…** button:
1. Change **Block Name** to: `.text`
2. Change **Base Address** to: `10000000` (XIP flash base)
3. Click **OK**

Then click **OK** on the main import dialog.

##### Step 4: Analyze the Binary

1. Double-click the imported file in the project window
2. When prompted "Analyze now?" click **Yes**
3. Leave all default analysis options selected
4. Click **Analyze**
5. Wait for analysis to complete (watch bottom-right progress bar)

##### Step 5: Locate and Rename the Main Function

Look at the **Symbol Tree** panel on the left. Expand **Functions**.

From previous weeks, we know the boot sequence leads to `main()`:

1. Click on `FUN_10000234`
2. Right-click → **Edit Function Signature**
3. Change to: `int main(void)`
4. Click **OK**

##### Step 6: Resolve stdio_init_all and printf

**Rename stdio_init_all:**
1. Click on `FUN_10002f5c` in the decompile window
2. Right-click → **Edit Function Signature**
3. Change to: `bool stdio_init_all(void)`
4. Click **OK**

**Rename printf:**
1. Click on `FUN_100030ec`
2. Right-click → **Edit Function Signature**
3. Change to: `int __wrap_printf(char *format,...)`
4. Check the **Varargs** checkbox
5. Click **OK**

##### Step 7: Observe the Decompiled Code

After resolving, the decompiled `main` should look like:

```c
int main(void)
{
  undefined4 uVar1;
  undefined4 extraout_r1;
  undefined4 uVar2;
  undefined4 extraout_r1_00;
  
  stdio_init_all();
  uVar1 = DAT_1000024c;
  uVar2 = extraout_r1;
  do {
    __wrap_printf(DAT_10000250,uVar2,0,uVar1);
    uVar2 = extraout_r1_00;
  } while( true );
}
```

**Critical observation:** Where is `float fav_num = 42.5`? The compiler optimized it into constants!

##### Step 8: Identify the Register Pair

Look at the **Listing** window (assembly view) for `main`:

```assembly
1000023a    00 24         movs    r4, #0x0
1000023c    03 4d         ldr     r5, [DAT_1000024c]     = 40454000h
```

Two values are being passed to `printf`:
- `r2 = 0x00000000` (low 32 bits)
- `r3 = 0x40454000` (high 32 bits)

Together they form a 64-bit double: `0x4045400000000000`

**Why a double?** The C standard requires that `float` arguments to variadic functions like `printf` are **promoted to `double`**. So even though our variable is declared as `float fav_num = 42.5`, `printf` always receives a 64-bit double.

##### Step 9: Write Out the Binary Layout

Convert both registers to binary:

```
r3 (high 32 bits): 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
r2 (low  32 bits): 0x00000000 = 0000 0000 0000 0000 0000 0000 0000 0000
```

Map the 64-bit IEEE 754 fields:

```
Bit 63 (sign):           0
Bits 62–52 (exponent):   10000000100
Bits 51–0 (mantissa):    0101010000000000...0000
```

##### Step 10: Decode the Sign Bit

Bit 63 of the double = bit 31 of r3:

```
r3 = 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
                   ^
                   bit 31 = 0  →  Positive number
```

IEEE 754 sign rule: `0` = Positive, `1` = Negative.

##### Step 11: Decode the Exponent

Extract bits 30–20 from r3:

```
0x40454000:  0  10000000100  01010100000000000000
             ^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^
           sign  exponent      mantissa (top 20)
```

Exponent bits: `10000000100` = 2¹⁰ + 2² = 1024 + 4 = **1028**

Subtract the double-precision bias (1023):

$$\text{real exponent} = 1028 - 1023 = \mathbf{5}$$

##### Step 12: Decode the Mantissa

High 20 bits of mantissa (from r3 bits 19–0):
```
0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
```

Low 32 bits of mantissa (from r2):
```
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
```

With the implied leading `1`:
```
1.010101 00000...
```

##### Step 13: Reconstruct the Final Value

$$1.010101_2 \times 2^5 = 101010.1_2$$

Convert to decimal:

| Bit | Power | Value |
|-----|-------|-------|
| 1   | 2⁵    | 32    |
| 0   | 2⁴    | 0     |
| 1   | 2³    | 8     |
| 0   | 2²    | 0     |
| 1   | 2¹    | 2     |
| 0   | 2⁰    | 0     |
| 1   | 2⁻¹   | 0.5   |

$$32 + 8 + 2 + 0.5 = \mathbf{42.5} ✓$$

##### Step 14: Find the Format String

In the Listing view, click on the data reference to locate:

```
s_fav_num:_%f_100034a8    ds    "fav_num: %f\r\n"
```

Note that the format specifier is `%f`, confirming this is a floating-point print call.

##### Step 15: Document Your Findings

Create a table of your observations:

| Item                      | Value              | Notes                              |
| ------------------------- | ------------------ | ---------------------------------- |
| Main function address     | `0x10000234`       | Entry point of program             |
| Float value (original)    | `42.5`             | Declared as `float`                |
| Double hex encoding       | `0x4045400000000000` | Promoted to double for printf    |
| r3 (high word)            | `0x40454000`       | Contains sign + exponent + mantissa top bits |
| r2 (low word)             | `0x00000000`       | All zeros — clean fractional part  |
| Exponent (stored)         | 1028               | Biased value                       |
| Exponent (real)           | 5                  | After subtracting bias 1023        |
| Format string             | `"fav_num: %f\r\n"` | Located at `0x100034a8`          |
| Float-to-double promotion | Yes                | C standard for variadic functions  |

#### Expected Output

After completing this exercise, you should be able to:
- Import and configure ARM binaries in Ghidra for float analysis
- Explain why `printf` receives a `double` even when the variable is a `float`
- Identify the register pair `r2:r3` that holds a 64-bit double
- Manually decode an IEEE 754 double from hex to decimal
- Locate format strings in the binary

#### Questions for Reflection

###### Question 1: Why does the compiler promote a `float` to a `double` when passing it to `printf`?

###### Question 2: The low word (`r2`) is `0x00000000`. What does this tell you about the fractional part of `42.5`?

###### Question 3: What is the purpose of the exponent bias (1023) in IEEE 754 double-precision?

###### Question 4: If the sign bit (bit 63) were `1` instead of `0`, what value would the double represent?

#### Tips and Hints
- The **Listing** window shows raw assembly; the **Decompile** window shows reconstructed C
- Double-click on a `DAT_` reference to jump to the data constant
- Use Python to verify: `import struct; struct.pack('>d', 42.5).hex()` gives `4045400000000000`
- Remember: r3 = high 32 bits (sign + exponent + top mantissa), r2 = low 32 bits (bottom mantissa)
- The bias for doubles is always 1023; for floats it's 127

#### Next Steps
- Proceed to Exercise 2 to patch this float value in Ghidra
- Try computing the IEEE 754 encoding of other values like `3.14` or `100.0` by hand
- Compare the 32-bit float encoding `0x422A0000` with the 64-bit double encoding `0x4045400000000000` — both represent `42.5`

#### Additional Challenge
Find the data constant `DAT_1000024c` in the Listing view. What raw bytes are stored there? Remember that ARM is little-endian — the bytes in memory are in reverse order. Write out the byte order as it appears in memory vs. as a 32-bit value.
