mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-06-01 20:11:47 +02:00
Update WEEK06
This commit is contained in:
+40
-39
@@ -1,6 +1,6 @@
|
||||
# 📘 Week 5: Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
# Week 5: Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand how integers and floating-point numbers are stored in memory
|
||||
@@ -164,7 +164,7 @@ So the decoded value is exactly `42.5`.
|
||||
| -------------- | ---------------------- | --------------------------- |
|
||||
| **Size** | 1 byte | 4 bytes |
|
||||
| **Precision** | Exact | ~7 decimal digits |
|
||||
| **Range** | 0 to 255 | ±3.4 × 10^38 |
|
||||
| **Range** | 0 to 255 | 3.4 10^38 |
|
||||
| **Encoding** | Direct binary | IEEE 754 (sign/exp/mantissa)|
|
||||
| **printf** | `%d` | `%f` |
|
||||
|
||||
@@ -224,13 +224,13 @@ The program is printing `42.500000` because `printf` with `%f` defaults to 6 dec
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 2.5: Setting Up Ghidra for Float Analysis
|
||||
## Part 2.5: Setting Up Ghidra for Float Analysis
|
||||
|
||||
### Step 3: Start Ghidra
|
||||
|
||||
**Open a terminal and type:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
@@ -277,7 +277,7 @@ Wait for analysis to complete (watch the progress bar in the bottom right).
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 2.6: Navigating and Resolving Functions
|
||||
## Part 2.6: Navigating and Resolving Functions
|
||||
|
||||
### Step 8: Find the Functions
|
||||
|
||||
@@ -311,7 +311,7 @@ For `main`, let's also fix the return type:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 2.7: Analyzing the Main Function
|
||||
## Part 2.7: Analyzing the Main Function
|
||||
|
||||
### Step 11: Examine Main in Ghidra
|
||||
|
||||
@@ -548,7 +548,7 @@ Look at the **Listing** window (assembly view). Find the main function:
|
||||
10000250 a8 34 00 10 undefine 100034A8h * -> 100034a8
|
||||
```
|
||||
|
||||
> 💡 **Key Insight:** The `mov.w r2, #0x0` loads the low 32 bits (all zeros) and `ldr r3, [DAT_...]` loads the high 32 bits (`0x40454000`) of the double. Together, `r2:r3` = `0x40454000_00000000` = `42.5` as a double.
|
||||
> **Key Insight:** The `mov.w r2, #0x0` loads the low 32 bits (all zeros) and `ldr r3, [DAT_...]` loads the high 32 bits (`0x40454000`) of the double. Together, `r2:r3` = `0x40454000_00000000` = `42.5` as a double.
|
||||
|
||||
### Step 17: Find the Format String
|
||||
|
||||
@@ -565,7 +565,7 @@ This confirms `printf` is called with the format string `"fav_num: %f\r\n"` and
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 2.8: Patching the Float - Changing 42.5 to 99.0
|
||||
## Part 2.8: Patching the Float - Changing 42.5 to 99.0
|
||||
|
||||
### Step 18: Calculate the New IEEE 754 Encoding
|
||||
|
||||
@@ -575,13 +575,13 @@ We want to change `42.5` to `99.0`. First, we need to figure out the double-prec
|
||||
|
||||
| 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** |
|
||||
| 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 (base 10) = 1100011 (base 2)
|
||||
|
||||
@@ -634,7 +634,7 @@ This changes the high word from `0x40454000` (42.5 as double) to `0x4058C000` (9
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Part 2.9: Export and Test the Hacked Binary
|
||||
## Part 2.9: Export and Test the Hacked Binary
|
||||
|
||||
### Step 21: Export the Patched Binary
|
||||
|
||||
@@ -648,13 +648,13 @@ This changes the high word from `0x40454000` (42.5 as double) to `0x4058C000` (9
|
||||
|
||||
**Open a terminal and navigate to your project directory:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x000e_floating-point-data-type
|
||||
```
|
||||
|
||||
**Run the conversion command:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
python ..\uf2conv.py build\0x000e_floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
@@ -673,7 +673,7 @@ fav_num: 99.000000
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **BOOM! We hacked the float!** The value changed from `42.5` to `99.0`!
|
||||
**BOOM! We hacked the float!** The value changed from `42.5` to `99.0`!
|
||||
|
||||
---
|
||||
|
||||
@@ -711,7 +711,7 @@ A **double** (short for "double-precision floating-point") is like a `float` but
|
||||
| **Precision** | ~7 decimal digits | ~15 decimal digits |
|
||||
| **Exponent** | 8 bits (bias 127) | 11 bits (bias 1023) |
|
||||
| **Mantissa** | 23 bits | 52 bits |
|
||||
| **Range** | ±3.4 × 10^38 | ±1.8 × 10^308 |
|
||||
| **Range** | 3.4 10^38 | 1.8 10^308 |
|
||||
| **printf** | `%f` | `%lf` |
|
||||
| **ARM passing** | Promoted to double | Native in `r2:r3` |
|
||||
|
||||
@@ -769,13 +769,13 @@ The program is printing `42.525250` because `printf` with `%lf` defaults to 6 de
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 3.5: Setting Up Ghidra for Double Analysis
|
||||
## Part 3.5: Setting Up Ghidra for Double Analysis
|
||||
|
||||
### Step 3: Start Ghidra
|
||||
|
||||
**Open a terminal and type:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
@@ -822,7 +822,7 @@ Wait for analysis to complete (watch the progress bar in the bottom right).
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 3.6: Navigating and Resolving Functions
|
||||
## Part 3.6: Navigating and Resolving Functions
|
||||
|
||||
### Step 8: Find the Functions
|
||||
|
||||
@@ -856,7 +856,7 @@ For `main`, let's also fix the return type:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 3.7: Analyzing the Main Function
|
||||
## Part 3.7: Analyzing the Main Function
|
||||
|
||||
### Step 11: Examine Main in Ghidra
|
||||
|
||||
@@ -938,7 +938,7 @@ A 64-bit double is passed in two 32-bit registers:
|
||||
|
||||
Together they form `0x4045433B645A1CAC` - the IEEE 754 **double-precision** encoding of `42.52525`.
|
||||
|
||||
> 💡 **Key Difference from Float:** In the float example, `r2` was `0x00000000` because `42.5` has a clean fractional part. But `42.52525` has a repeating binary fraction, so the low 32 bits are non-zero (`0x645A1CAC`). This means **both** registers matter when patching doubles with complex fractional values!
|
||||
> **Key Difference from Float:** In the float example, `r2` was `0x00000000` because `42.5` has a clean fractional part. But `42.52525` has a repeating binary fraction, so the low 32 bits are non-zero (`0x645A1CAC`). This means **both** registers matter when patching doubles with complex fractional values!
|
||||
|
||||
### Step 15: Verify the Double Encoding
|
||||
|
||||
@@ -969,7 +969,7 @@ The sign bit is bit 63 of the 64-bit double, which is bit 31 of r3 (the high reg
|
||||
```
|
||||
r3 = 0x4045433B = 0100 0000 0100 0101 0100 0011 0011 1011
|
||||
^
|
||||
r3 bit 31 = 0 -> sign = 0 -> Positive number ✓
|
||||
r3 bit 31 = 0 -> sign = 0 -> Positive number ✓
|
||||
```
|
||||
|
||||
**2. Exponent - bits 62-52 = bits 30-20 of r3**
|
||||
@@ -1097,7 +1097,7 @@ Look at the **Listing** window (assembly view). Find the main function:
|
||||
10000258 3b 43 45 40 undefine 4045433Bh
|
||||
```
|
||||
|
||||
> 💡 **Key Insight:** Notice that **both** `r2` and `r3` are loaded from data constants using `ldr`. Compare this to the float example where `r2` was loaded with `mov.w r2, #0x0`. Because `42.52525` requires all 52 mantissa bits, neither word can be zero - the compiler must store both halves as separate data constants.
|
||||
> **Key Insight:** Notice that **both** `r2` and `r3` are loaded from data constants using `ldr`. Compare this to the float example where `r2` was loaded with `mov.w r2, #0x0`. Because `42.52525` requires all 52 mantissa bits, neither word can be zero - the compiler must store both halves as separate data constants.
|
||||
|
||||
### Step 17: Find the Format String
|
||||
|
||||
@@ -1114,7 +1114,7 @@ This confirms `printf` is called with the format string `"fav_num: %lf\r\n"` and
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 3.8: Patching the Double - Changing 42.52525 to 99.99
|
||||
## Part 3.8: Patching the Double - Changing 42.52525 to 99.99
|
||||
|
||||
### Step 18: Calculate the New IEEE 754 Encoding
|
||||
|
||||
@@ -1163,11 +1163,11 @@ Look in the Listing view for the two data constants:
|
||||
|
||||
This changes the full 64-bit double from `0x4045433B645A1CAC` (42.52525) to `0x4058FF5C28F5C28F` (99.99).
|
||||
|
||||
> 💡 **Key Difference from Float Patching:** When we patched the float `42.5`, we only needed to change one word (the high word in `r3`) because the low word was all zeros. With `42.52525 -> 99.99`, **both** words change. Always check whether the low word is non-zero before patching!
|
||||
> **Key Difference from Float Patching:** When we patched the float `42.5`, we only needed to change one word (the high word in `r3`) because the low word was all zeros. With `42.52525 -> 99.99`, **both** words change. Always check whether the low word is non-zero before patching!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Part 3.9: Export and Test the Hacked Binary
|
||||
## Part 3.9: Export and Test the Hacked Binary
|
||||
|
||||
### Step 21: Export the Patched Binary
|
||||
|
||||
@@ -1181,13 +1181,13 @@ This changes the full 64-bit double from `0x4045433B645A1CAC` (42.52525) to `0x4
|
||||
|
||||
**Open a terminal and navigate to your project directory:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0011_double-floating-point-data-type
|
||||
```
|
||||
|
||||
**Run the conversion command:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
python ..\uf2conv.py build\0x0011_double-floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
@@ -1206,11 +1206,11 @@ fav_num: 99.990000
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **BOOM! We hacked the double!** The value changed from `42.52525` to `99.99`!
|
||||
**BOOM! We hacked the double!** The value changed from `42.52525` to `99.99`!
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 3.95: Summary - Float and Double Analysis
|
||||
## Part 3.95: Summary - Float and Double Analysis
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -1268,7 +1268,7 @@ fav_num: 99.990000
|
||||
|
||||
---
|
||||
|
||||
## 💡 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Integers have fixed sizes** - `uint8_t` is 1 byte (0-255), `int8_t` is 1 byte (-128 to 127). The `u` prefix means unsigned.
|
||||
|
||||
@@ -1286,7 +1286,7 @@ fav_num: 99.990000
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ----------------------- | ------------------------------------------------------------------------------ |
|
||||
@@ -1310,7 +1310,7 @@ fav_num: 99.990000
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### GPIO Coprocessor Reference
|
||||
|
||||
@@ -1349,4 +1349,5 @@ The RP2350 GPIO coprocessor instructions:
|
||||
|
||||
**Remember:** Every binary you encounter in the real world can be analyzed and understood using these same techniques. Whether it's an integer, a float, or a double - it's all just bits waiting to be decoded. Practice makes perfect!
|
||||
|
||||
Happy hacking! 🎉
|
||||
Happy hacking!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user