Update WEEK06
@@ -1,6 +1,6 @@
|
||||
# Week 1: Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts
|
||||
# Week 1: Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this week, you will be able to:
|
||||
- Understand what a microcontroller is and how it works
|
||||
@@ -71,11 +71,11 @@ The two Arm ABI documents we verified give the formal proof for these rules. In
|
||||
```
|
||||
Higher Memory Address (0x20082000)
|
||||
+------------------+
|
||||
| | ← Stack starts here (empty)
|
||||
| | ↠Stack starts here (empty)
|
||||
+------------------+
|
||||
| Pushed Item 1 | ← SP points here after 1 push
|
||||
| Pushed Item 1 | ↠SP points here after 1 push
|
||||
+------------------+
|
||||
| Pushed Item 2 | ← SP points here after 2 pushes
|
||||
| Pushed Item 2 | ↠SP points here after 2 pushes
|
||||
+------------------+
|
||||
Lower Memory Address (0x20081FF8)
|
||||
```
|
||||
@@ -87,13 +87,13 @@ When you call a function, the processor needs to remember where to come back to.
|
||||
**Example:**
|
||||
```
|
||||
main() calls print_hello()
|
||||
↓
|
||||
↓
|
||||
LR = address right after the call in main()
|
||||
↓
|
||||
↓
|
||||
print_hello() runs
|
||||
↓
|
||||
↓
|
||||
print_hello() finishes, looks at LR
|
||||
↓
|
||||
↓
|
||||
Jumps back to main() at the address stored in LR
|
||||
```
|
||||
|
||||
@@ -265,26 +265,22 @@ Before we start, make sure you have:
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
|
||||
```
|
||||
|
||||
### Connecting to Your Pico 2 with GDB
|
||||
|
||||
Open another terminal and start GDB with your binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
Connect to your target:
|
||||
|
||||
```powershell
|
||||
(gdb) target extended-remote localhost:3333
|
||||
```cmd
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
@@ -528,7 +524,7 @@ Notice the difference between inspecting memory at `$sp` and inspecting `$lr`.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 5: Static Analysis with Ghidra
|
||||
## Part 5: Static Analysis with Ghidra
|
||||
|
||||
### Setting Up Your First Ghidra Project
|
||||
|
||||
@@ -622,7 +618,7 @@ int main(void)
|
||||
}
|
||||
```
|
||||
|
||||
> 🎯 **Notice how Ghidra reconstructed our original C code!** The decompiler recognized the infinite loop and the `puts` call (the compiler optimized `printf` to `puts` since we're just printing a simple string).
|
||||
> **Notice how Ghidra reconstructed our original C code!** The decompiler recognized the infinite loop and the `puts` call (the compiler optimized `printf` to `puts` since we're just printing a simple string).
|
||||
|
||||
##### Why We Start with .elf Files
|
||||
|
||||
@@ -635,7 +631,7 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 6: Summary and Review
|
||||
## Part 6: Summary and Review
|
||||
|
||||
### What We Learned
|
||||
|
||||
@@ -655,7 +651,7 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols
|
||||
|
||||
| Command | What It Does |
|
||||
| --------------------- | -------------------------------------- |
|
||||
| `target remote :3333` | Connect to OpenOCD debug server |
|
||||
| `target extended-remote :3333` | Connect to OpenOCD debug server |
|
||||
| `monitor reset halt` | Reset and halt the processor |
|
||||
| `b main` | Set breakpoint at main function |
|
||||
| `c` | Continue running until breakpoint |
|
||||
@@ -697,7 +693,7 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Reverse engineering combines static and dynamic analysis** - we look at the code (static with Ghidra) and run it to see what happens (dynamic with GDB).
|
||||
|
||||
@@ -711,7 +707,7 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
@@ -728,3 +724,4 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols
|
||||
| **XIP** | Execute In Place - running code directly from flash |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Week 2: Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Connect to a live embedded system using OpenOCD and GDB
|
||||
@@ -12,7 +12,7 @@ By the end of this tutorial, you will be able to:
|
||||
- Hijack register values to redirect program behavior
|
||||
- Modify a running program's output in real-time
|
||||
|
||||
## 🔄 Review from Week 1
|
||||
## Review from Week 1
|
||||
This week builds directly on Week 1 concepts. You should already be comfortable with:
|
||||
- **Registers** (`r0`-`r12`, SP, LR, PC) - We'll watch them change and manipulate `r0` to change program behavior
|
||||
- **Memory Layout** (Flash at `0x10000000`, RAM at `0x20000000`) - Critical for understanding where we can write
|
||||
@@ -54,7 +54,7 @@ The techniques you'll learn today are *exactly* how this would be done. Understa
|
||||
|
||||
## Part 2: Review - Memory Layout (from Week 1)
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we learned about the RP2350's memory layout. This knowledge is essential for our hack!
|
||||
> **REVIEW:** In Week 1, we learned about the RP2350's memory layout. This knowledge is essential for our hack!
|
||||
|
||||
Before we hack, let's remember where things live in memory on the RP2350:
|
||||
|
||||
@@ -97,7 +97,7 @@ Our goal: **Make it print something else WITHOUT changing the source code!**
|
||||
+-----------------------------------------------------+
|
||||
```
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we saw SP values in the `0x20081xxx` range (for example `0x20081fc8`) - that's in the SRAM region. In this run you may see values like `0x20081ff8` depending on where execution is paused. The stack "grows downward" from the top of SRAM.
|
||||
> **REVIEW:** In Week 1, we saw SP values in the `0x20081xxx` range (for example `0x20081fc8`) - that's in the SRAM region. In this run you may see values like `0x20081ff8` depending on where execution is paused. The stack "grows downward" from the top of SRAM.
|
||||
|
||||
#### Why This Matters for Our Hack
|
||||
|
||||
@@ -152,7 +152,7 @@ You will need **THREE** terminal windows:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 5: GDB Deep Dive - Exploring the Binary
|
||||
## Part 5: GDB Deep Dive - Exploring the Binary
|
||||
|
||||
Before we start hacking, let's use GDB to thoroughly understand our program. This hands-on tutorial will teach you to examine memory, step through code, and watch the stack in action.
|
||||
|
||||
@@ -164,12 +164,8 @@ OpenOCD is the bridge between your computer and the Pico 2's debug interface. It
|
||||
|
||||
**Open Terminal 1 and type:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**What this command means:**
|
||||
@@ -224,7 +220,7 @@ The program is running and printing `"hello, world"` in an infinite loop!
|
||||
|
||||
**Open Terminal 3** and start GDB with your binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
@@ -755,11 +751,11 @@ Let's tell GDB to show this as a string instead of a hex number:
|
||||
|
||||
There's our string! The `\r` is a carriage return character (part of `\r\n`).
|
||||
|
||||
> 🎯 **Key Discovery:** The string `"hello, world"` is stored at address `0x100019cc` in flash memory. This is the value that gets loaded into `r0` before calling `puts()`. We'll use this knowledge in our hack!
|
||||
> **Key Discovery:** The string `"hello, world"` is stored at address `0x100019cc` in flash memory. This is the value that gets loaded into `r0` before calling `puts()`. We'll use this knowledge in our hack!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 6: Continuing the Debug Session for the Hack
|
||||
## Part 6: Continuing the Debug Session for the Hack
|
||||
|
||||
You're right where you need to be from Part 5, so we **do not restart** OpenOCD or GDB here.
|
||||
|
||||
@@ -782,9 +778,9 @@ After that, continue to the analysis steps below.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 7: Analyzing the Target
|
||||
## Part 7: Analyzing the Target
|
||||
|
||||
> 🔄 **REVIEW:** We're using the same GDB commands we learned earlier. The `x` command examines memory, and `/5i` shows 5 instructions.
|
||||
> **REVIEW:** We're using the same GDB commands we learned earlier. The `x` command examines memory, and `/5i` shows 5 instructions.
|
||||
|
||||
##### Step 6: Examine the Main Function
|
||||
|
||||
@@ -812,14 +808,14 @@ Let's look at the main function to understand what we're dealing with:
|
||||
0x10000240 <main+12>: b.n 0x1000023a <main+6>
|
||||
```
|
||||
|
||||
> 🔄 **REVIEW:** This is the same disassembly we analyzed in Week 1! Remember:
|
||||
> **REVIEW:** This is the same disassembly we analyzed in Week 1! Remember:
|
||||
> - `push {r3, lr}` saves registers to the stack
|
||||
> - `bl` is "branch with link" - it calls a function and saves the return address in LR
|
||||
> - `b.n` is the infinite loop that jumps back to the `ldr` instruction
|
||||
|
||||
#### Understanding the Code Flow
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we learned that `r0`-`r3` are used to pass arguments to functions. The first argument always goes in `r0`!
|
||||
> **REVIEW:** In Week 1, we learned that `r0`-`r3` are used to pass arguments to functions. The first argument always goes in `r0`!
|
||||
|
||||
Let's break down what happens each time through the loop:
|
||||
|
||||
@@ -847,9 +843,9 @@ If we can change what `r0` points to, we can make it print **anything we want**!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 8: Setting the Trap
|
||||
## Part 8: Setting the Trap
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we used `b main` and `b *0x10000234` to set breakpoints. Now we'll use the same technique at a more strategic location!
|
||||
> **REVIEW:** In Week 1, we used `b main` and `b *0x10000234` to set breakpoints. Now we'll use the same technique at a more strategic location!
|
||||
|
||||
##### Step 7: Set a Strategic Breakpoint
|
||||
|
||||
@@ -932,9 +928,9 @@ Dump of assembler code for function main:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 9: Examining the Current State
|
||||
## Part 9: Examining the Current State
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we used `x/s $r0` to view the "hello, world" string. We also learned about **little-endian** byte ordering - remember how `0x6c6c6568` spelled "lleh" backwards?
|
||||
> **REVIEW:** In Week 1, we used `x/s $r0` to view the "hello, world" string. We also learned about **little-endian** byte ordering - remember how `0x6c6c6568` spelled "lleh" backwards?
|
||||
|
||||
##### Step 10: Examine What's in r0
|
||||
|
||||
@@ -959,11 +955,11 @@ Let's see what string `r0` is currently pointing to:
|
||||
|
||||
There it is! The register `r0` contains `0x100019cc`, which is the address of our `"hello, world"` string in flash memory.
|
||||
|
||||
> 🔄 **REVIEW:** This is the same address `0x100019cc` we discovered in Week 1, Step 15 when we used `x/s $r0` after executing the `ldr` instruction!
|
||||
> **REVIEW:** This is the same address `0x100019cc` we discovered in Week 1, Step 15 when we used `x/s $r0` after executing the `ldr` instruction!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 10: The Failed Hack Attempt (Learning Why)
|
||||
## Part 10: The Failed Hack Attempt (Learning Why)
|
||||
|
||||
##### Step 11: Try to Directly Change the String (This Will Fail!)
|
||||
|
||||
@@ -1013,7 +1009,7 @@ The original string is still there. Our hack attempt failed... but we're not giv
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 11: The Real Hack - Writing to SRAM
|
||||
## Part 11: The Real Hack - Writing to SRAM
|
||||
|
||||
##### Step 12: Understanding the Solution
|
||||
|
||||
@@ -1022,7 +1018,7 @@ Since we can't use `malloc()`, we need to manually create our string somewhere i
|
||||
- Flash (`0x10000000`): **Read-only** - can't write here
|
||||
- SRAM (`0x20000000`): **Read-write** - we CAN write here!
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1 we observed SP in the `0x20081xxx` range (for example `0x20081fc8`). In this run, after `push {r3, lr}`, you are seeing `0x20081ff8`, which is also correct and still near the top of SRAM. We'll write our string at a safer SRAM address (`0x20040000`) to avoid vector-table and stack conflicts.
|
||||
> **REVIEW:** In Week 1 we observed SP in the `0x20081xxx` range (for example `0x20081fc8`). In this run, after `push {r3, lr}`, you are seeing `0x20081ff8`, which is also correct and still near the top of SRAM. We'll write our string at a safer SRAM address (`0x20040000`) to avoid vector-table and stack conflicts.
|
||||
|
||||
We'll write our malicious string directly to SRAM, then point `r0` to it.
|
||||
|
||||
@@ -1083,9 +1079,9 @@ The important thing is our string is in writable SRAM at a safe offset and ready
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 12: Hijacking the Register
|
||||
## Part 12: Hijacking the Register
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we learned that `r0` holds the first argument to a function. When `puts()` is called, it expects `r0` to contain a pointer to the string it should print. By changing `r0`, we change what gets printed!
|
||||
> **REVIEW:** In Week 1, we learned that `r0` holds the first argument to a function. When `puts()` is called, it expects `r0` to contain a pointer to the string it should print. By changing `r0`, we change what gets printed!
|
||||
|
||||
##### Step 15: Change r0 to Point to Our String
|
||||
|
||||
@@ -1152,7 +1148,7 @@ This is the first 4 bytes (`h a c k`) packed into one 32-bit little-endian word.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 13: Executing the Hack
|
||||
## Part 13: Executing the Hack
|
||||
|
||||
##### Step 17: Continue Execution
|
||||
|
||||
@@ -1189,13 +1185,13 @@ hello, world
|
||||
hacky, world <-- OUR HACK!
|
||||
```
|
||||
|
||||
🎉 **BOOM! WE DID IT!** 🎉
|
||||
**BOOM! WE DID IT!**
|
||||
|
||||
You just modified a running program on real hardware! The processor executed code that was supposed to print "hello, world" but instead printed "hacky, world" because we hijacked the data it was using!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 14: Static Analysis with Ghidra - Understanding the Hack
|
||||
## Part 14: Static Analysis with Ghidra - Understanding the Hack
|
||||
|
||||
Now that we've performed the hack dynamically with GDB, let's use Ghidra to understand the same concepts through static analysis. This shows how you could plan such an attack without even connecting to the hardware!
|
||||
|
||||
@@ -1271,7 +1267,7 @@ Notice:
|
||||
- The previous instruction at `0x1000023a` loaded `r0` with the string address
|
||||
- Ghidra shows `= "hello, world\r"` right in the listing!
|
||||
|
||||
> 🎯 **Key Insight:** Ghidra already tells us the string value! In the Listing, you can see `= "hello, world\r"` and `= 100019CCh`. This is the exact address we discovered through GDB!
|
||||
> **Key Insight:** Ghidra already tells us the string value! In the Listing, you can see `= "hello, world\r"` and `= 100019CCh`. This is the exact address we discovered through GDB!
|
||||
|
||||
##### Step 3: Find the String in Memory
|
||||
|
||||
@@ -1325,7 +1321,7 @@ This starts with `0x10...` which means it's in **Flash memory (XIP region)**!
|
||||
| `0x10000000`+ | Flash (XIP) | **NO** - Read Only |
|
||||
| `0x20000000`+ | SRAM | **YES** - Read/Write |
|
||||
|
||||
> 🎯 **This is why our direct string modification failed in GDB!** The string lives in flash memory, which is read-only at runtime. We had to create our malicious string in SRAM at a safe address (`0x20040000`) instead.
|
||||
> **This is why our direct string modification failed in GDB!** The string lives in flash memory, which is read-only at runtime. We had to create our malicious string in SRAM at a safe address (`0x20040000`) instead.
|
||||
|
||||
##### Step 5: Examine Cross-References
|
||||
|
||||
@@ -1389,13 +1385,13 @@ Ghidra allows you to modify data directly in the binary! Here's how to patch the
|
||||
4. **Type** your new string: `"hacky, world\r"`
|
||||
5. **Press Enter** to apply the patch
|
||||
|
||||
> ⚠️ **Important:** The new string must be the **same length or shorter** than the original! If your new string is longer, it will overwrite adjacent data and likely crash the program.
|
||||
> **Important:** The new string must be the **same length or shorter** than the original! If your new string is longer, it will overwrite adjacent data and likely crash the program.
|
||||
|
||||
| Original String | Patched String | Result |
|
||||
| --------------- | -------------- | ------ |
|
||||
| `hello, world\r` (14 bytes) | `hacky, world\r` (14 bytes) | ✅ Works perfectly |
|
||||
| `hello, world\r` (14 bytes) | `PWNED!\r` (7 bytes) | ✅ Works (shorter is OK) |
|
||||
| `hello, world\r` (14 bytes) | `this is a much longer string\r` | ❌ Overwrites other data! |
|
||||
| `hello, world\r` (14 bytes) | `hacky, world\r` (14 bytes) | Works perfectly |
|
||||
| `hello, world\r` (14 bytes) | `PWNED!\r` (7 bytes) | Works (shorter is OK) |
|
||||
| `hello, world\r` (14 bytes) | `this is a much longer string\r` | Overwrites other data! |
|
||||
|
||||
After patching, you'll see the change reflected in the Listing view:
|
||||
|
||||
@@ -1409,7 +1405,7 @@ Notice how the bytes changed: `68 65 6c 6c 6f` ("hello") became `68 61 63 6b 79`
|
||||
|
||||
#### Looking Ahead: Persistent Binary Patching
|
||||
|
||||
> 🔮 **Coming in Future Lessons:** What we've done in Ghidra so far is just a **preview** of the patch - it modifies the data in Ghidra's view, but doesn't save it back to the actual binary file.
|
||||
> **Coming in Future Lessons:** What we've done in Ghidra so far is just a **preview** of the patch - it modifies the data in Ghidra's view, but doesn't save it back to the actual binary file.
|
||||
|
||||
In future lessons, we will learn how to:
|
||||
|
||||
@@ -1452,7 +1448,7 @@ This step helps you understand the mechanics of modifying binary data. Once you'
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 15: Summary and Review
|
||||
## Part 15: Summary and Review
|
||||
|
||||
#### What We Accomplished
|
||||
|
||||
@@ -1501,7 +1497,7 @@ AFTER OUR HACK:
|
||||
|
||||
| Command | What It Does | New/Review |
|
||||
| ---------------------------- | ----------------------------------- | ---------- |
|
||||
| `target remote :3333` | Connect to OpenOCD debug server | **New** |
|
||||
| `target extended-remote :3333` | Connect to OpenOCD debug server | **New** |
|
||||
| `monitor reset halt` | Reset and halt the processor | **New** |
|
||||
| `disas` | Disassemble the current function | Review |
|
||||
| `x/Ni ADDRESS` | Examine N instructions at ADDRESS | Review |
|
||||
@@ -1524,7 +1520,7 @@ AFTER OUR HACK:
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
#### Building on Week 1
|
||||
|
||||
@@ -1548,7 +1544,7 @@ AFTER OUR HACK:
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Implications
|
||||
## Security Implications
|
||||
|
||||
#### How Would This Work in the Real World?
|
||||
|
||||
@@ -1571,7 +1567,7 @@ Imagine an attacker with physical access to an industrial control system:
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
#### New Terms This Week
|
||||
|
||||
@@ -1598,3 +1594,4 @@ Imagine an attacker with physical access to an industrial control system:
|
||||
| **Little-Endian** | Storing the least significant byte at the lowest address | Part 10 - String storage |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Week 3: Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware 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 the RP2350 boots from the on-chip bootrom
|
||||
@@ -12,7 +12,7 @@ By the end of this tutorial, you will be able to:
|
||||
- Use Ghidra to statically analyze the boot sequence
|
||||
- Understand the difference between Thumb mode addressing and actual addresses
|
||||
|
||||
## 🔄 Review from Weeks 1-2
|
||||
## Review from Weeks 1-2
|
||||
This week builds on your GDB and Ghidra skills from previous weeks:
|
||||
- **GDB Commands** (`x`, `b`, `c`, `si`, `disas`, `i r`) - We'll use all of these to trace the boot process
|
||||
- **Memory Layout** (Flash at `0x10000000`, RAM at `0x20000000`) - Understanding where code and data live
|
||||
@@ -154,7 +154,7 @@ Here's what it looks like in the Pico SDK:
|
||||
|
||||
Use these commands to view the IMAGE_DEF bytes directly in the ELF:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-objdump -s --start-address=0x1000013c --stop-address=0x10000150 build/0x0001_hello-world.elf
|
||||
arm-none-eabi-objdump -s --start-address=0x10000130 --stop-address=0x10000154 build/0x0001_hello-world.elf
|
||||
arm-none-eabi-gdb build/0x0001_hello-world.elf -ex "x/20bx 0x1000013c" -ex quit
|
||||
@@ -202,7 +202,7 @@ assuming a fixed address.
|
||||
|
||||
## Part 3: Understanding XIP (Execute In Place)
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we learned that our code lives at `0x10000000` in flash memory. We used `x/1000i 0x10000000` to find our `main` function. Now we'll understand WHY code is at this address!
|
||||
> **REVIEW:** In Week 1, we learned that our code lives at `0x10000000` in flash memory. We used `x/1000i 0x10000000` to find our `main` function. Now we'll understand WHY code is at this address!
|
||||
|
||||
### What is XIP?
|
||||
|
||||
@@ -346,7 +346,7 @@ This value (`0x20082000`) is what we see at offset `0x00` in the vector table!
|
||||
|
||||
## Part 6: Setting Up Your Environment (GDB - Dynamic Analysis)
|
||||
|
||||
> 🔄 **REVIEW:** This setup is identical to Weeks 1-2. If you need a refresher on OpenOCD and GDB connection, refer back to Week 1 Part 4 or Week 2 Part 5.
|
||||
> **REVIEW:** This setup is identical to Weeks 1-2. If you need a refresher on OpenOCD and GDB connection, refer back to Week 1 Part 4 or Week 2 Part 5.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@@ -361,17 +361,13 @@ Before we start, make sure you have:
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
@@ -384,9 +380,9 @@ arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 7: Hands-On GDB Tutorial - Examining the Vector Table
|
||||
## Part 7: Hands-On GDB Tutorial - Examining the Vector Table
|
||||
|
||||
> 🔄 **REVIEW:** We're using the same `x` (examine) command from Week 1. Remember: `x/Nx` shows N hex values, `x/Ni` shows N instructions, `x/s` shows strings.
|
||||
> **REVIEW:** We're using the same `x` (examine) command from Week 1. Remember: `x/Nx` shows N hex values, `x/Ni` shows N instructions, `x/s` shows strings.
|
||||
|
||||
### Step 1: Examine the Vector Table
|
||||
|
||||
@@ -411,7 +407,7 @@ Let's look at the first 4 entries of the vector table at `0x10000000`:
|
||||
|
||||
### Step 2: Understanding What We See
|
||||
|
||||
> 🔄 **REVIEW:** In Weeks 1-2, we saw both `sp = 0x20082000` at the clean breakpoint at `main` and lower values like `0x20081fc8` or `0x20081ff8` after additional stack activity. Here we are looking at the *initial* stack pointer from the vector table before any code runs.
|
||||
> **REVIEW:** In Weeks 1-2, we saw both `sp = 0x20082000` at the clean breakpoint at `main` and lower values like `0x20081fc8` or `0x20081ff8` after additional stack activity. Here we are looking at the *initial* stack pointer from the vector table before any code runs.
|
||||
|
||||
Let's decode each value:
|
||||
|
||||
@@ -443,13 +439,13 @@ Let's confirm our math by examining what's at `0x10000000`:
|
||||
This matches:
|
||||
- `SCRATCH_Y` starts at `0x20081000`
|
||||
- `SCRATCH_Y` is 4 KB (`0x1000` bytes)
|
||||
- `0x20081000` + `0x1000` = `0x20082000` ✓
|
||||
- `0x20081000` + `0x1000` = `0x20082000`
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 8: Examining the Reset Handler
|
||||
## Part 8: Examining the Reset Handler
|
||||
|
||||
> 🔄 **REVIEW:** We used `x/5i` extensively in Weeks 1-2 to examine our `main` function. Now we'll use the same technique to examine the code that runs BEFORE `main`!
|
||||
> **REVIEW:** We used `x/5i` extensively in Weeks 1-2 to examine our `main` function. Now we'll use the same technique to examine the code that runs BEFORE `main`!
|
||||
|
||||
### Step 4: Disassemble the Reset Handler
|
||||
|
||||
@@ -505,7 +501,7 @@ So the reset handler checks:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 9: The Complete Reset Handler Flow
|
||||
## Part 9: The Complete Reset Handler Flow
|
||||
|
||||
### Step 6: Examine More of the Reset Handler
|
||||
|
||||
@@ -586,11 +582,11 @@ The reset handler performs several phases:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 10: Understanding the Data Copy Phase
|
||||
## Part 10: Understanding the Data Copy Phase
|
||||
|
||||
### What is the Data Copy Phase?
|
||||
|
||||
> 🔄 **REVIEW:** In Week 2, we learned that flash is read-only and SRAM is read-write. That's why the startup code must COPY initialized variables from flash to RAM - they can't be modified in flash!
|
||||
> **REVIEW:** In Week 2, we learned that flash is read-only and SRAM is read-write. That's why the startup code must COPY initialized variables from flash to RAM - they can't be modified in flash!
|
||||
|
||||
When you write C code like this:
|
||||
|
||||
@@ -659,7 +655,7 @@ b.n 0x1000016c <hold_non_core0_in_bootrom+8>
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 11: Understanding the BSS Clear Phase
|
||||
## Part 11: Understanding the BSS Clear Phase
|
||||
|
||||
### What is BSS?
|
||||
|
||||
@@ -713,7 +709,7 @@ The first two `ldr` instructions are still part of the **BSS clear setup**, even
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 12: Examining Exception Handlers
|
||||
## Part 12: Examining Exception Handlers
|
||||
|
||||
### Step 11: Look at the Default Exception Handlers
|
||||
|
||||
@@ -761,7 +757,7 @@ Each type of exception has its own handler:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 13: Finding Where Main is Called
|
||||
## Part 13: Finding Where Main is Called
|
||||
|
||||
### Step 12: Look at Platform Entry
|
||||
|
||||
@@ -804,7 +800,7 @@ After `main()` returns, `exit()` is called to handle cleanup. The `bkpt` instruc
|
||||
|
||||
### Step 13: Set a Breakpoint at Main
|
||||
|
||||
> 🔄 **REVIEW:** We've used `b main` and `b *ADDRESS` many times in Weeks 1-2. This is the same technique!
|
||||
> **REVIEW:** We've used `b main` and `b *ADDRESS` many times in Weeks 1-2. This is the same technique!
|
||||
|
||||
Let's verify we understand the boot process by setting a breakpoint at main:
|
||||
|
||||
@@ -838,11 +834,11 @@ Thread 1 "rp2350.cm0" hit Breakpoint 1, main ()
|
||||
(gdb)
|
||||
```
|
||||
|
||||
🎉 We've traced the entire boot process from power-on to `main()`!
|
||||
We've traced the entire boot process from power-on to `main()`!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 14: Understanding the Binary Info Header
|
||||
## Part 14: Understanding the Binary Info Header
|
||||
|
||||
### Step 14: Examine the Binary Info Header
|
||||
|
||||
@@ -887,9 +883,9 @@ That's not real code - it's the magic number `0xffffded3` being misinterpreted!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 15: Static Analysis with Ghidra - Examining the Boot Sequence
|
||||
## Part 15: Static Analysis with Ghidra - Examining the Boot Sequence
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we set up a Ghidra project and analyzed our hello-world binary. Now we'll use Ghidra to understand the boot sequence from a static analysis perspective!
|
||||
> **REVIEW:** In Week 1, we set up a Ghidra project and analyzed our hello-world binary. Now we'll use Ghidra to understand the boot sequence from a static analysis perspective!
|
||||
|
||||
### Why Use Ghidra for Boot Analysis?
|
||||
|
||||
@@ -901,7 +897,7 @@ While GDB is excellent for dynamic analysis (watching code execute), Ghidra exce
|
||||
|
||||
### Step 15: Open Your Project in Ghidra
|
||||
|
||||
> 🔄 **REVIEW:** If you haven't created the project yet, refer back to Week 1 Part 5 for setup instructions.
|
||||
> **REVIEW:** If you haven't created the project yet, refer back to Week 1 Part 5 for setup instructions.
|
||||
|
||||
1. Launch Ghidra and open your `0x0001_hello-world` project
|
||||
2. Double-click on the `.elf` file to open it in the CodeBrowser
|
||||
@@ -1042,7 +1038,7 @@ In Ghidra, look at `platform_entry`:
|
||||
10000194 fd e7 b LAB_10000192
|
||||
```
|
||||
|
||||
> 🎯 **Key Insight:** Ghidra's decompiler makes the boot sequence crystal clear! You can see exactly what functions are called before `main()`.
|
||||
> **Key Insight:** Ghidra's decompiler makes the boot sequence crystal clear! You can see exactly what functions are called before `main()`.
|
||||
|
||||
### Step 20: Create a Boot Sequence Graph
|
||||
|
||||
@@ -1056,8 +1052,8 @@ Ghidra can visualize the call flow:
|
||||
|
||||
| Aspect | GDB (Dynamic) | Ghidra (Static) |
|
||||
| ------ | ------------- | --------------- |
|
||||
| **Sees runtime values** | ✅ Yes - register contents, memory | ❌ No - must infer from code |
|
||||
| **Needs hardware** | ✅ Yes - Pico 2 must be connected | ❌ No - works offline |
|
||||
| **Sees runtime values** | Yes - register contents, memory | No - must infer from code |
|
||||
| **Needs hardware** | Yes - Pico 2 must be connected | No - works offline |
|
||||
| **Shows code flow** | Step-by-step execution | Full graph visualization |
|
||||
| **Best for** | Watching what happens | Understanding structure |
|
||||
| **Thumb bit handling** | Shows with +1 (0x1000015d) | Shows actual addr (0x1000015c) |
|
||||
@@ -1071,7 +1067,7 @@ Ghidra can visualize the call flow:
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 16: Summary and Review
|
||||
## Part 16: Summary and Review
|
||||
|
||||
### The Complete Boot Sequence
|
||||
|
||||
@@ -1167,7 +1163,7 @@ Ghidra can visualize the call flow:
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
### Building on Weeks 1-2
|
||||
|
||||
@@ -1193,7 +1189,7 @@ Ghidra can visualize the call flow:
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Implications
|
||||
## Security Implications
|
||||
|
||||
### How Boot Sequence Knowledge Applies to Security
|
||||
|
||||
@@ -1314,7 +1310,7 @@ Understanding how an attacker would analyze and exploit the boot sequence is ess
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
### New Terms This Week
|
||||
|
||||
@@ -1358,7 +1354,7 @@ The startup code lives in:
|
||||
- `memmap_default.ld` - Default linker script (section ordering: `.vectors` -> `.binary_info_header` -> `.embedded_block` -> `.reset`)
|
||||
- `embedded_start_block.inc.S` - IMAGE_DEF block (replaces RP2040's `boot2_generic_03h.S`)
|
||||
|
||||
> ⚠️ **Note:** The RP2040 used a `boot2_generic_03h.S` second-stage bootloader occupying the first 256 bytes of flash. The RP2350 eliminated this; the bootrom handles flash XIP setup directly. The SDK still includes a `boot2` mechanism for compatibility, but it is **not** placed at flash address 0 - it is embedded in the data copy table and executed from the stack during startup.
|
||||
> **Note:** The RP2040 used a `boot2_generic_03h.S` second-stage bootloader occupying the first 256 bytes of flash. The RP2350 eliminated this; the bootrom handles flash XIP setup directly. The SDK still includes a `boot2` mechanism for compatibility, but it is **not** placed at flash address 0 - it is embedded in the data copy table and executed from the stack during startup.
|
||||
|
||||
### Bootrom Source
|
||||
|
||||
@@ -1367,7 +1363,7 @@ https://github.com/raspberrypi/pico-bootrom-rp2350
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 17: Proving the Boot Sequence with objdump
|
||||
## Part 17: Proving the Boot Sequence with objdump
|
||||
|
||||
Everything we have learned about the boot sequence can be proven directly from the compiled ELF binary using `arm-none-eabi-objdump`. The bootrom is not in your ELF (it is mask ROM burned into the chip at `0x00000000`), but everything your firmware provides - the vector table, the IMAGE_DEF, and the reset handler - lives in your ELF starting at `0x10000000`.
|
||||
|
||||
@@ -1496,7 +1492,7 @@ and GPIO pin map from any compiled binary without running it.
|
||||
| `0x10000148` | `79 35 12 ab` | `PICOBIN_BLOCK_MARKER_END` - bootrom stops scanning here. |
|
||||
|
||||
The IMAGE_DEF sits at `0x10000138`-`0x1000014b` in this build,
|
||||
well within the 4 KB scan window the bootrom uses (Datasheet §5.9.5, p. 429).
|
||||
well within the 4 KB scan window the bootrom uses (Datasheet 5.9.5, p. 429).
|
||||
|
||||
#### Full Flash Map: 0x10000000-0x1000015c
|
||||
|
||||
@@ -1534,15 +1530,16 @@ well within the 4 KB scan window the bootrom uses (Datasheet §5.9.5, p. 429).
|
||||
+-----------------------------------------------------------------+
|
||||
```
|
||||
|
||||
> 📖 **Datasheet References:**
|
||||
> - §5.1.5.1 (p. 357): Block markers `0xffffded3` (start) and `0xab123579` (end)
|
||||
> - §5.9.5 (p. 429): IMAGE_DEF must appear within first 4 kB of flash image
|
||||
> - §5.9.5.1 (p. 429): Bootrom enters via reset handler at vector table offset +4
|
||||
> **Datasheet References:**
|
||||
> - 5.1.5.1 (p. 357): Block markers `0xffffded3` (start) and `0xab123579` (end)
|
||||
> - 5.9.5 (p. 429): IMAGE_DEF must appear within first 4 kB of flash image
|
||||
> - 5.9.5.1 (p. 429): Bootrom enters via reset handler at vector table offset +4
|
||||
|
||||
---
|
||||
|
||||
**Remember:** Understanding the boot process is fundamental to embedded systems work. Whether you're debugging a system that won't start, reverse engineering firmware, or building secure boot chains, this knowledge is essential!
|
||||
|
||||
Happy exploring! 🔍
|
||||
Happy exploring!
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Week 4: Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
# Week 4: Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand what variables are and how they're stored in memory
|
||||
@@ -128,11 +128,11 @@ uint8_t age; // This will be 0, not garbage!
|
||||
+-----------------------------------------------------------------+
|
||||
| Raspberry Pi Pico 2 |
|
||||
| |
|
||||
| GPIO 16 -------► Red LED |
|
||||
| GPIO 17 -------► Green LED |
|
||||
| GPIO 18 -------► Blue LED |
|
||||
| GPIO 16 -------â–º Red LED |
|
||||
| GPIO 17 -------â–º Green LED |
|
||||
| GPIO 18 -------â–º Blue LED |
|
||||
| ... |
|
||||
| GPIO 25 -------► Onboard LED |
|
||||
| GPIO 25 -------â–º Onboard LED |
|
||||
+-----------------------------------------------------------------+
|
||||
```
|
||||
|
||||
@@ -153,11 +153,11 @@ Each high-level function calls lower-level code. Let's trace `gpio_init()`:
|
||||
|
||||
```
|
||||
gpio_init(LED_PIN)
|
||||
↓
|
||||
↓
|
||||
gpio_set_dir(LED_PIN, GPIO_IN) // Initially set as input
|
||||
↓
|
||||
↓
|
||||
gpio_put(LED_PIN, 0) // Set output value to 0
|
||||
↓
|
||||
↓
|
||||
gpio_set_function(LED_PIN, GPIO_FUNC_SIO) // Connect to SIO block
|
||||
```
|
||||
|
||||
@@ -197,7 +197,7 @@ Embedded-Hacking/
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 5: Hands-On Tutorial - Analyzing Variables in Ghidra
|
||||
## Part 5: Hands-On Tutorial - Analyzing Variables in Ghidra
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
@@ -250,13 +250,13 @@ The program is printing `43` because that's what we assigned after the initial `
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 6: Setting Up Ghidra for Binary Analysis
|
||||
## Part 6: Setting Up Ghidra for Binary Analysis
|
||||
|
||||
### Step 4: Start Ghidra
|
||||
|
||||
**Open a terminal and type:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
@@ -303,7 +303,7 @@ Wait for analysis to complete (watch the progress bar in the bottom right).
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 7: Navigating and Resolving Functions
|
||||
## Part 7: Navigating and Resolving Functions
|
||||
|
||||
### Step 9: Find the Functions
|
||||
|
||||
@@ -337,7 +337,7 @@ For `main`, let's also fix the return type:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 8: Analyzing the Main Function
|
||||
## Part 8: Analyzing the Main Function
|
||||
|
||||
### Step 12: Examine Main in Ghidra
|
||||
|
||||
@@ -395,13 +395,13 @@ The compiler **optimized it out**! Here's what happened:
|
||||
3. Compiler removes the unused `42` and just uses `43` directly
|
||||
|
||||
**What is `0x2b`?** Let's check:
|
||||
- `0x2b` in hexadecimal = `43` in decimal ✓
|
||||
- `0x2b` in hexadecimal = `43` in decimal
|
||||
|
||||
The compiler replaced our variable with the constant value!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 9: Patching the Binary - Changing the Value
|
||||
## Part 9: Patching the Binary - Changing the Value
|
||||
|
||||
### Step 16: Find the Value to Patch
|
||||
|
||||
@@ -437,7 +437,7 @@ The instruction now reads:
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 10: Converting and Flashing the Hacked Binary
|
||||
## Part 10: Converting and Flashing the Hacked Binary
|
||||
|
||||
### Step 19: Convert to UF2 Format
|
||||
|
||||
@@ -445,13 +445,13 @@ The Pico 2 expects UF2 files, not raw BIN files. We need to convert it!
|
||||
|
||||
**Open a terminal and navigate to your project directory:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0005_intro-to-variables
|
||||
```
|
||||
|
||||
**Run the conversion command:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
python ..\uf2conv.py build\0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
@@ -476,11 +476,11 @@ age: 70
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **BOOM! We hacked it!** The value changed from 43 to 70!
|
||||
**BOOM! We hacked it!** The value changed from 43 to 70!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 11: Uninitialized Variables and GPIO
|
||||
## Part 11: Uninitialized Variables and GPIO
|
||||
|
||||
Now let's work with a more complex example that includes GPIO control.
|
||||
|
||||
@@ -539,7 +539,7 @@ The value is `0` because uninitialized variables in the `.bss` section are zeroe
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 12: Analyzing GPIO Code in Ghidra
|
||||
## Part 12: Analyzing GPIO Code in Ghidra
|
||||
|
||||
### Step 23: Set Up Ghidra for the New Binary
|
||||
|
||||
@@ -593,7 +593,7 @@ void FUN_10000234(void)
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 13: Hacking GPIO - Changing the LED Pin
|
||||
## Part 13: Hacking GPIO - Changing the LED Pin
|
||||
|
||||
### Step 26: Find the GPIO Pin Value
|
||||
|
||||
@@ -647,7 +647,7 @@ Let's also change the printed value from `0` to `0x42` (66 in decimal):
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 14: Export and Test the Hacked GPIO
|
||||
## Part 14: Export and Test the Hacked GPIO
|
||||
|
||||
### Step 30: Export the Patched Binary
|
||||
|
||||
@@ -658,7 +658,7 @@ Let's also change the printed value from `0` to `0x42` (66 in decimal):
|
||||
|
||||
### Step 31: Convert to UF2
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0008_uninitialized-variables
|
||||
python ..\uf2conv.py build\0x0008_uninitialized-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
@@ -679,7 +679,7 @@ age: 66
|
||||
|
||||
And now the **GREEN LED on GPIO 17** should be blinking instead of the red one!
|
||||
|
||||
🎉 **We successfully:**
|
||||
**We successfully:**
|
||||
1. Changed the printed value from 0 to 66
|
||||
2. Changed which LED blinks from red (GPIO 16) to green (GPIO 17)
|
||||
|
||||
@@ -780,7 +780,7 @@ delay2:
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 16: Summary and Review
|
||||
## Part 16: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -843,7 +843,7 @@ delay2:
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Variables are just memory locations** - The compiler assigns them addresses in SRAM.
|
||||
|
||||
@@ -861,7 +861,7 @@ delay2:
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ------------------ | --------------------------------------------------------------------- |
|
||||
@@ -880,7 +880,7 @@ delay2:
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### GPIO Coprocessor Reference
|
||||
|
||||
@@ -905,5 +905,6 @@ The RP2350 GPIO coprocessor instructions:
|
||||
|
||||
**Remember:** Every binary you encounter in the real world can be analyzed and understood using these same techniques. Practice makes perfect!
|
||||
|
||||
Happy hacking! 🔧
|
||||
Happy hacking!
|
||||
|
||||
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 📘 Week 6: Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
|
||||
# Week 6: Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand the difference between regular (automatic) variables and static variables
|
||||
@@ -30,18 +30,18 @@ Think of it like this:
|
||||
| |
|
||||
| REGULAR (automatic): |
|
||||
| +------------------------------------------------------------+ |
|
||||
| | Loop 1: Create -> Set to 42 -> Increment to 43 -> Destroy | |
|
||||
| | Loop 2: Create -> Set to 42 -> Increment to 43 -> Destroy | |
|
||||
| | Loop 3: Create -> Set to 42 -> Increment to 43 -> Destroy | |
|
||||
| | Result: Always appears as 42! | |
|
||||
| | Loop 1: Create -> Set to 42 -> Increment to 43 -> Destroy |
|
||||
| | Loop 2: Create -> Set to 42 -> Increment to 43 -> Destroy |
|
||||
| | Loop 3: Create -> Set to 42 -> Increment to 43 -> Destroy |
|
||||
| | Result: Always appears as 42! |
|
||||
| +------------------------------------------------------------+ |
|
||||
| |
|
||||
| STATIC: |
|
||||
| +------------------------------------------------------------+ |
|
||||
| | Loop 1: Already exists -> Read 42 -> Increment -> Store 43 | |
|
||||
| | Loop 2: Already exists -> Read 43 -> Increment -> Store 44 | |
|
||||
| | Loop 3: Already exists -> Read 44 -> Increment -> Store 45 | |
|
||||
| | Result: Keeps incrementing! | |
|
||||
| | Loop 1: Already exists -> Read 42 -> Increment -> Store 43 |
|
||||
| | Loop 2: Already exists -> Read 43 -> Increment -> Store 44 |
|
||||
| | Loop 3: Already exists -> Read 44 -> Increment -> Store 45 |
|
||||
| | Result: Keeps incrementing! |
|
||||
| +------------------------------------------------------------+ |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
@@ -74,19 +74,19 @@ Different types of variables are stored in different memory locations:
|
||||
| Memory Layout |
|
||||
| |
|
||||
| +-------------------+ High Address (0x20082000) |
|
||||
| | STACK | ?? Automatic/local variables |
|
||||
| | (grows down) | Created/destroyed per function |
|
||||
| | STACK | ?? Automatic/local variables |
|
||||
| | (grows down) | Created/destroyed per function |
|
||||
| +-------------------+ |
|
||||
| | | |
|
||||
| | (free space) | |
|
||||
| | | |
|
||||
| +-------------------+ |
|
||||
| | HEAP | ?? Dynamic allocation (malloc/free) |
|
||||
| | HEAP | ?? Dynamic allocation (malloc/free) |
|
||||
| | (grows up) | |
|
||||
| +-------------------+ |
|
||||
| | .bss section | ?? Uninitialized static/global vars |
|
||||
| | .bss section | ?? Uninitialized static/global vars |
|
||||
| +-------------------+ |
|
||||
| | .data section | ?? Initialized static/global vars |
|
||||
| | .data section | ?? Initialized static/global vars |
|
||||
| +-------------------+ Low Address (0x20000000) |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
@@ -174,7 +174,7 @@ The Pico 2 has **internal** pull resistors that you can enable with software - n
|
||||
| +------? GPIO 15 (reads HIGH normally) |
|
||||
| | |
|
||||
| +-+-+ |
|
||||
| |BTN| ?? Button connects GPIO to GND when pressed |
|
||||
| |BTN| ?? Button connects GPIO to GND when pressed |
|
||||
| +-+-+ |
|
||||
| | |
|
||||
| GND |
|
||||
@@ -312,7 +312,7 @@ Embedded-Hacking/
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 5: Hands-On Tutorial - Static Variables and GPIO Input
|
||||
## Part 5: Hands-On Tutorial - Static Variables and GPIO Input
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
@@ -400,10 +400,10 @@ static_fav_num: 45
|
||||
### Step 4: Test the Button
|
||||
|
||||
Now test the button behavior:
|
||||
- **Button NOT pressed:** LED should be ON (because of the inverted logic)
|
||||
- **Button PRESSED:** LED should turn OFF
|
||||
- **Button NOT pressed:** LED should be OFF
|
||||
- **Button PRESSED:** LED should turn ON
|
||||
|
||||
Wait... that seems backwards from what you'd expect! That's because of the pull-up resistor and the ternary operator. We'll hack this later to make it more intuitive!
|
||||
That may feel backwards at first glance, but it matches the pull-up + ternary logic in the code. We'll hack this later to make the behavior more intuitive.
|
||||
|
||||
### Step 5: Watch for Overflow
|
||||
|
||||
@@ -422,7 +422,7 @@ This demonstrates unsigned integer overflow!
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 6: Debugging with GDB (Dynamic Analysis)
|
||||
## Part 6: Debugging with GDB (Dynamic Analysis)
|
||||
|
||||
> ? **REVIEW:** This setup is identical to previous weeks. If you need a refresher on OpenOCD and GDB connection, refer back to Week 3 Part 6.
|
||||
|
||||
@@ -430,24 +430,20 @@ This demonstrates unsigned integer overflow!
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0014_static-variables.elf
|
||||
```
|
||||
|
||||
**Connect to target:**
|
||||
|
||||
```gdb
|
||||
(gdb) target remote :3333
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
@@ -462,44 +458,45 @@ x/38i 0x10000234
|
||||
You should see output like:
|
||||
|
||||
```
|
||||
0x10000234 <+0>: push {r4, lr}
|
||||
0x10000236 <+2>: bl 0x10003014 <stdio_init_all>
|
||||
0x1000023a <+6>: movs r0, #15
|
||||
0x1000023c <+8>: bl 0x10000300 <gpio_init>
|
||||
0x10000240 <+12>: movs r0, #15
|
||||
0x10000242 <+14>: mov.w r3, #0
|
||||
0x10000246 <+18>: mcrr 0, 4, r0, r3, cr4
|
||||
0x1000024a <+22>: movs r2, #0
|
||||
0x1000024c <+24>: movs r1, #1
|
||||
0x1000024e <+26>: bl 0x100002d8 <gpio_set_pulls>
|
||||
0x10000252 <+30>: movs r0, #16
|
||||
0x10000254 <+32>: bl 0x10000300 <gpio_init>
|
||||
0x10000258 <+36>: movs r3, #16
|
||||
0x1000025a <+38>: mov.w r2, #1
|
||||
0x1000025e <+42>: mcrr 0, 4, r3, r2, cr4
|
||||
0x10000262 <+46>: ldr r4, [pc, #44] @ (0x10000290 <main+92>)
|
||||
0x10000264 <+48>: movs r1, #42 @ 0x2a
|
||||
0x10000266 <+50>: ldr r0, [pc, #44] @ (0x10000294 <main+96>)
|
||||
0x10000268 <+52>: bl 0x100031a4 <__wrap_printf>
|
||||
0x1000026c <+56>: ldrb r1, [r4, #0]
|
||||
0x1000026e <+58>: ldr r0, [pc, #40] @ (0x10000298 <main+100>)
|
||||
0x10000270 <+60>: bl 0x100031a4 <__wrap_printf>
|
||||
0x10000274 <+64>: mov.w r1, #3489660928 @ 0xd0000000
|
||||
0x10000278 <+68>: ldrb r3, [r4, #0]
|
||||
0x1000027a <+70>: movs r2, #16
|
||||
0x1000027c <+72>: adds r3, #1
|
||||
0x1000027e <+74>: strb r3, [r4, #0]
|
||||
0x10000280 <+76>: ldr r3, [r1, #4]
|
||||
0x10000282 <+78>: ubfx r3, r3, #15, #1
|
||||
0x10000286 <+82>: eor.w r3, r3, #1
|
||||
0x1000028a <+86>: mcrr 0, 4, r2, r3, cr0
|
||||
0x1000028e <+90>: b.n 0x10000264 <main+48>
|
||||
0x10000290 <+92>: lsls r0, r5, #22
|
||||
0x10000292 <+94>: movs r0, #0
|
||||
0x10000294 <+96>: adds r5, #96 @ 0x60
|
||||
0x10000296 <+98>: asrs r0, r0, #32
|
||||
0x10000298 <+100>: adds r5, #120 @ 0x78
|
||||
0x1000029a <+102>: asrs r0, r0, #32
|
||||
(gdb) x/38i 0x10000234
|
||||
0x10000234 <main>: push {r4, lr}
|
||||
0x10000236 <main+2>: bl 0x10003014 <stdio_init_all>
|
||||
0x1000023a <main+6>: movs r0, #15
|
||||
0x1000023c <main+8>: bl 0x10000300 <gpio_init>
|
||||
0x10000240 <main+12>: movs r0, #15
|
||||
0x10000242 <main+14>: mov.w r3, #0
|
||||
0x10000246 <main+18>: mcrr 0, 4, r0, r3, cr4
|
||||
0x1000024a <main+22>: movs r2, #0
|
||||
0x1000024c <main+24>: movs r1, #1
|
||||
0x1000024e <main+26>: bl 0x100002d8 <gpio_set_pulls>
|
||||
0x10000252 <main+30>: movs r0, #16
|
||||
0x10000254 <main+32>: bl 0x10000300 <gpio_init>
|
||||
0x10000258 <main+36>: movs r3, #16
|
||||
0x1000025a <main+38>: mov.w r2, #1
|
||||
0x1000025e <main+42>: mcrr 0, 4, r3, r2, cr4
|
||||
0x10000262 <main+46>: ldr r4, [pc, #44] @ (0x10000290 <main+92>)
|
||||
0x10000264 <main+48>: movs r1, #42 @ 0x2a
|
||||
0x10000266 <main+50>: ldr r0, [pc, #44] @ (0x10000294 <main+96>)
|
||||
0x10000268 <main+52>: bl 0x100031a4 <__wrap_printf>
|
||||
0x1000026c <main+56>: ldrb r1, [r4, #0]
|
||||
0x1000026e <main+58>: ldr r0, [pc, #40] @ (0x10000298 <main+100>)
|
||||
0x10000270 <main+60>: bl 0x100031a4 <__wrap_printf>
|
||||
0x10000274 <main+64>: mov.w r1, #3489660928 @ 0xd0000000
|
||||
0x10000278 <main+68>: ldrb r3, [r4, #0]
|
||||
0x1000027a <main+70>: movs r2, #16
|
||||
0x1000027c <main+72>: adds r3, #1
|
||||
0x1000027e <main+74>: strb r3, [r4, #0]
|
||||
0x10000280 <main+76>: ldr r3, [r1, #4]
|
||||
0x10000282 <main+78>: ubfx r3, r3, #15, #1
|
||||
0x10000286 <main+82>: eor.w r3, r3, #1
|
||||
0x1000028a <main+86>: mcrr 0, 4, r2, r3, cr0
|
||||
0x1000028e <main+90>: b.n 0x10000264 <main+48>
|
||||
0x10000290 <main+92>: lsls r0, r5, #22
|
||||
0x10000292 <main+94>: movs r0, #0
|
||||
0x10000294 <main+96>: adds r5, #96 @ 0x60
|
||||
0x10000296 <main+98>: asrs r0, r0, #32
|
||||
0x10000298 <main+100>: adds r5, #120 @ 0x78
|
||||
0x1000029a <main+102>: asrs r0, r0, #32
|
||||
```
|
||||
|
||||
### Step 7: Set a Breakpoint at Main
|
||||
@@ -509,26 +506,28 @@ b *0x10000234
|
||||
c
|
||||
```
|
||||
|
||||
GDB responds:
|
||||
```
|
||||
Breakpoint 1 at 0x10000234: file C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0014_static-variables/0x0014_static-variables.c, line 5.
|
||||
Note: automatically using hardware breakpoints for read-only addresses.
|
||||
(gdb) c
|
||||
Continuing.
|
||||
|
||||
Thread 1 "rp2350.cm0" hit Breakpoint 1, main ()
|
||||
at C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0014_static-variables/0x0014_static-variables.c:5
|
||||
5 stdio_init_all();
|
||||
```
|
||||
|
||||
> **Note:** If GDB says `The program is not being run.` when you type `c`, the target hasn't been started yet. Use `monitor reset halt` first, then `c` to continue to your breakpoint.
|
||||
|
||||
### Step 8: Examine the Static Variable Location
|
||||
|
||||
Static variables live at fixed RAM addresses. But how do we find that address? Look at the first instruction in the disassembly from Step 6:
|
||||
Static variables live at fixed RAM addresses. But how do we find that address? Look at `0x10000262` in the disassembly from Step 6:
|
||||
|
||||
```
|
||||
0x10000262: ldr r4, [pc, #44] @ (0x10000290 <main+92>)
|
||||
(gdb) x/16i 0x10000234
|
||||
=> 0x10000234 <main>: push {r4, lr}
|
||||
0x10000236 <main+2>: bl 0x10003014 <stdio_init_all>
|
||||
0x1000023a <main+6>: movs r0, #15
|
||||
0x1000023c <main+8>: bl 0x10000300 <gpio_init>
|
||||
0x10000240 <main+12>: movs r0, #15
|
||||
0x10000242 <main+14>: mov.w r3, #0
|
||||
0x10000246 <main+18>: mcrr 0, 4, r0, r3, cr4
|
||||
0x1000024a <main+22>: movs r2, #0
|
||||
0x1000024c <main+24>: movs r1, #1
|
||||
0x1000024e <main+26>: bl 0x100002d8 <gpio_set_pulls>
|
||||
0x10000252 <main+30>: movs r0, #16
|
||||
0x10000254 <main+32>: bl 0x10000300 <gpio_init>
|
||||
0x10000258 <main+36>: movs r3, #16
|
||||
0x1000025a <main+38>: mov.w r2, #1
|
||||
0x1000025e <main+42>: mcrr 0, 4, r3, r2, cr4
|
||||
0x10000262 <main+46>: ldr r4, [pc, #44] @ (0x10000290 <main+92>)
|
||||
```
|
||||
|
||||
This loads `r4` from the **literal pool** at address `0x10000290`. The literal pool stores constants that are too large for immediate encoding - in this case, a 32-bit RAM address. Let's examine what's stored there:
|
||||
@@ -540,38 +539,259 @@ This loads `r4` from the **literal pool** at address `0x10000290`. The literal p
|
||||
|
||||
That's `0x200005a8` - the RAM address of `static_fav_num`! The compiler placed this address in the literal pool because it can't encode a full 32-bit address in a single Thumb instruction.
|
||||
|
||||
> **Common confusion three things that trip people up here:**
|
||||
>
|
||||
> **1. GDB shows `<striped_spin_lock_num>` instead of `<static_fav_num>`.**
|
||||
> `static_fav_num` is a function-local static, so it does not appear in GDB's global symbol table. GDB labels the address with the nearest *named* global symbol it can find in this case an SDK-internal spin-lock variable that happens to be nearby. The address `0x200005a8` is still correct; the label is just GDB's best guess at a name.
|
||||
```gdb
|
||||
(gdb) x/x 0x200005a8
|
||||
0x200005a8 <striped_spin_lock_num>: 0x0000122a
|
||||
```
|
||||
>
|
||||
> **2. `x/x 0x200005a8` shows `0x0000122a`, not `0x0000002a` (42).**
|
||||
> `x/x` reads a **4-byte word** (32 bits). `static_fav_num` is a `uint8_t` only **1 byte**. The low byte of `0x0000122a` is `0x2a` = 42. That *is* the variable. The upper bytes belong to whatever happens to be in adjacent RAM. To read exactly one byte and see `42`, use:
|
||||
```gdb
|
||||
(gdb) x/1ub 0x200005a8
|
||||
0x200005a8 <striped_spin_lock_num>: 42
|
||||
```
|
||||
>
|
||||
> **3. `x/x *0x200005a8` shows junk at address `0x122a`.**
|
||||
> The `*` is a pointer dereference. GDB first reads the 4-byte word at `0x200005a8` (= `0x0000122a`), then treats that *value* as a new address and reads from `0x0000122a`. You are asking GDB to follow a pointer that was never meant to be a pointer the result is meaningless. Drop the `*`: use `x/1ub 0x200005a8` to read the variable's value directly.
|
||||
|
||||
> Tip: **Why did the disassembly at `0x10000290` show `lsls r0, r5, #22` instead?** Because `x/i` (disassemble) interprets raw data as instructions. The bytes `A8 05 00 20` at that address are the little-endian encoding of `0x200005A8`, but GDB's disassembler doesn't know it's data - it tries to decode it as a Thumb instruction. Using `x/wx` (examine as word) shows the actual value.
|
||||
|
||||
### Step 9: Step Through the Loop
|
||||
|
||||
Set a breakpoint at the start of the loop and step through:
|
||||
The loop body starts at `0x10000264`. Set a breakpoint there and continue:
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x10000264
|
||||
(gdb) c
|
||||
(gdb) x/i $pc
|
||||
=> 0x10000264 <main+48>: movs r1, #42 @ 0x2a
|
||||
```
|
||||
|
||||
Now use `si` (step instruction) to execute one instruction at a time:
|
||||
GDB will stop at `movs r1, #42` that is the compiler's constant for `regular_fav_num`. Let's set a breakpoint and continue at `0x10000278`.
|
||||
|
||||
```gdb
|
||||
(gdb) si
|
||||
(gdb) b *0x10000278
|
||||
(gdb) c
|
||||
(gdb) x/i $pc
|
||||
=> 0x10000278 <main+68>: ldrb r3, [r4, #0]
|
||||
```
|
||||
|
||||
Watch how the static variable gets loaded (`ldrb`), incremented (`adds`), and stored back (`strb`).
|
||||
This is where the static variable is actually manipulated:
|
||||
|
||||
```gdb
|
||||
(gdb) x/4i $pc
|
||||
=> 0x10000278 <main+68>: ldrb r3, [r4, #0] <- load static_fav_num from RAM into r3
|
||||
0x1000027a <main+70>: movs r2, #16 <- load LED pin number (16) into r2 for later
|
||||
0x1000027c <main+72>: adds r3, #1 <- increment r3 by 1
|
||||
0x1000027e <main+74>: strb r3, [r4, #0] <- store incremented value back to RAM
|
||||
```
|
||||
|
||||
Confirm what `r4` actually contains right now:
|
||||
|
||||
```gdb
|
||||
(gdb) x/x $r4
|
||||
0x200005a8 <striped_spin_lock_num>: 0x2a
|
||||
```
|
||||
|
||||
`r4` is `0x200005a8`, a RAM address. The value at that address is `0x2a` (42 in decimal), which is the current value of `static_fav_num`. After `adds r3, #1` and `strb r3, [r4, #0]` execute, examining `r4` again will show `0x0000002b` (43).
|
||||
|
||||
**What is the literal pool?**
|
||||
|
||||
A Thumb `ldr` instruction is only 16 or 32 bits wide. There is no room inside those bits to encode a full 32-bit constant like `0x200005a8`. To solve this, the compiler collects all such large constants and writes them into a small block of **raw data** embedded directly in the flash image this block is called a **literal pool** (also called a constant pool).
|
||||
|
||||
**There is not one literal pool per flash, there is (at least) one per function.** Every function that references large constants gets its own pool appended to its code. A large function can have several pools scattered through it wherever the compiler decides to emit them. Each pool is purely data; the CPU must never try to execute it.
|
||||
|
||||
**Where exactly is a literal pool placed?** Always **after an unconditional branch**, never before or in the middle of a straight-line code path. This is by design: the CPU falls through code sequentially, so the pool must be unreachable by fall-through. In our case the pool sits at `0x10000290`, directly after the `b.n 0x10000264` branch at `0x1000028e` that closes the `while (true)` loop:
|
||||
|
||||
```
|
||||
0x1000028e: b.n 0x10000264 <- unconditional branch back to loop top
|
||||
0x10000290: [literal pool] <- CPU never reaches here by fall-through
|
||||
```
|
||||
|
||||
**Why does the pool have to be nearby?** The `ldr rN, [pc, #offset]` instruction encodes the offset in a limited number of bits. In standard Thumb the maximum reach is **1020 bytes** from the instruction. If the function is long enough that the end is out of range, the assembler emits an intermediate pool mid-function after the next unconditional branch it can find. This is in the ARM v8-M Architecture Reference Manual p. 672.
|
||||
|
||||
**How the load works in our function:** At `0x10000262` the compiler emits:
|
||||
|
||||
```
|
||||
ldr r4, [pc, #44] @ (0x10000290)
|
||||
```
|
||||
|
||||
On ARM, `PC` reads as the address of the instruction **plus 4** during execution. So the effective address is `0x10000262 + 4 + 44 = 0x10000290`. That word in the pool contains `0x200005a8`, the RAM address of `static_fav_num`. The pool is also where the `printf` format-string pointers live (the other `ldr` instructions you saw in the disassembly).
|
||||
|
||||
```
|
||||
Flash (read-only)
|
||||
+-------------------------------------------+ RAM
|
||||
| 0x10000262: ldr r4, [pc, #44] | +------------------+
|
||||
| ...loop body... | | 0x200005a8: 42 | <- static_fav_num
|
||||
| 0x1000028e: b.n 0x10000264 (end of loop) | +------------------+
|
||||
+------- literal pool (data, not code) -----+ ^
|
||||
| 0x10000290: 0x200005a8 --------------------+----------------+
|
||||
| 0x10000294: ptr to "regular_fav_num: %d" | r4 holds this address
|
||||
| 0x10000298: ptr to "static_fav_num: %d" |
|
||||
+------- next function ---------------------+
|
||||
| 0x1000029c: push {r4} |
|
||||
+-------------------------------------------+
|
||||
```
|
||||
|
||||
You can see this directly. Run `x/10i 0x1000028e` in GDB and you will get exactly this:
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x1000028e
|
||||
(gdb) x/10i 0x1000028e
|
||||
0x1000028e <main+90>: b.n 0x10000264 <main+48> <- unconditional branch, loop top
|
||||
0x10000290 <main+92>: lsls r0, r5, #22 <-+
|
||||
0x10000292 <main+94>: movs r0, #0 <-+-- word 1: 0x200005a8 (fixed RAM addr static_fav_num)
|
||||
0x10000294 <main+96>: adds r5, #96 @ 0x60 <-+
|
||||
0x10000296 <main+98>: asrs r0, r0, #32 <-+-- word 2: 0x10004b60 (flash addr regular_fav_num text)
|
||||
0x10000298 <main+100>: adds r5, #120 <-+
|
||||
0x1000029a <main+102>: asrs r0, r0, #32 <-+-- word 3: 0x10004b78 (flash addr static_fav_num text)
|
||||
```
|
||||
|
||||
`0x10000290` - `0x1000029b` is the literal pool 12 bytes, 3 32-bit words. GDB's `x/i` (disassemble) has no idea those bytes are data, so it blindly decodes them as Thumb instructions and produces nonsense (`lsls r0, r5, #22`, etc.). The giveaway that you have entered pool territory is always the same: **garbled, implausible instructions immediately after an unconditional branch**. Use `x/wx` to read those addresses as data and you get the real values:
|
||||
|
||||
```gdb
|
||||
(gdb) x/3wx 0x10000290
|
||||
0x10000290 <main+92>: 0x200005a8 0x10003560 0x10003578
|
||||
```
|
||||
|
||||
```gdb
|
||||
(gdb) x/1ub 0x200005a8
|
||||
0x200005a8 <striped_spin_lock_num>: 42
|
||||
```
|
||||
- `0x200005a8` RAM address of `static_fav_num`, lives in the **`.data` section** (initialized static RAM, `0x20000000``0x200xxxxx`). It is `.data` and not `.bss` because the variable has an explicit initializer (`= 42`). `.bss` is for variables that are zero-initialized or have no initializer at all.
|
||||
|
||||
```gdb
|
||||
(gdb) x/s 0x10003560
|
||||
0x10003560: "regular_fav_num: %d\r\n"
|
||||
```
|
||||
- `0x10003560` flash address of the `"regular_fav_num: %d\r\n"` string literal, lives in the **`.rodata` section** (read-only data) inside flash (`0x10000000`+). String literals are constants baked into the binary at compile time they never change and never move, so they stay in flash.
|
||||
|
||||
```gdb
|
||||
(gdb) x/s 0x10003578
|
||||
0x10003578: "static_fav_num: %d\r\n"
|
||||
- `0x10003578` flash address of the `"static_fav_num: %d\r\n"` string literal, also in **`.rodata`** in flash for the same reason.
|
||||
|
||||
So the pool contains addresses into three different regions: RAM `.data` (the static variable), and flash `.rodata` (both format strings). Only the RAM address needed to be in the pool, the flash addresses could in principle be reached other ways, but they are also too large to encode as 16-bit immediates, so they go in the pool too.
|
||||
|
||||
**Why `.data` and not `.bss`?** The distinction matters:
|
||||
|
||||
| Section | What goes here | Example declarations | Initial value stored in flash? |
|
||||
|---------|---------------|----------------------|-------------------------------|
|
||||
| `.data` | Any static-duration variable with a **non-zero initializer** | `static uint8_t x = 42;` (inside a function) | Yes the initial value lives in flash; startup copies it to RAM |
|
||||
| `.data` | Same rule applies to **global** variables with non-zero initializers | `uint8_t g = 10;` (outside all functions) | Yes same startup copy |
|
||||
| `.bss` | Any static-duration variable with **no initializer or zero initializer** | `static uint8_t x;` or `static uint8_t x = 0;` | No startup just zeroes the RAM range; no flash copy needed |
|
||||
| `.bss` | Same rule for **global** variables that are zero/uninitialized | `uint8_t g;` or `uint8_t g = 0;` (outside functions) | No same zero-fill at startup |
|
||||
|
||||
The rule is not about `static` specifically it is about **lifetime and initial value**. Any variable whose lifetime spans the whole program (static locals, globals) goes into `.data` or `.bss`. The `static` keyword inside a function just forces that lifetime. A global variable without `static` has the same lifetime and follows the same rule.
|
||||
|
||||
`static_fav_num = 42` has an explicit non-zero initializer, so the linker puts it in `.data`. The startup code copies the initial value `42` from flash into RAM address `0x200005a8` before `main()` runs. If it had been `static uint8_t static_fav_num;` (no initializer), the linker would put it in `.bss` instead and the startup code would zero that RAM region no flash copy needed.
|
||||
|
||||
**Why is there no pool entry for the address of `regular_fav_num`?**
|
||||
|
||||
Because `regular_fav_num` is an **automatic (stack) variable** it has no fixed address. Automatic variables are allocated on the call stack at runtime, relative to the current stack pointer (`sp`). Their address changes every time the function runs and is different on every call. There is no constant 32-bit address to put in a pool.
|
||||
|
||||
In this specific case the compiler went even further: it **never gave `regular_fav_num` a stack slot at all**. The compiler saw that the value is always `42` when printed, so it baked the constant `42` directly into the `movs r1, #42` instruction. The variable lives only in a register at the moment it is needed — no stack space reserved, no pool entry, no load-store cycle.
|
||||
|
||||
**You can prove this with three GDB checks:**
|
||||
|
||||
**Proof 1 `info locals` shows the value came from a register, not a stack slot:**
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x10000264
|
||||
(gdb) c
|
||||
(gdb) info locals
|
||||
regular_fav_num = 42 '*'
|
||||
static_fav_num = 42 '*'
|
||||
BUTTON_GPIO = 15
|
||||
LED_GPIO = 16
|
||||
pressed = <optimized out>
|
||||
```
|
||||
|
||||
The `'*'` suffix after `42` means GDB retrieved the value from a **register** (specifically `r1`, which holds `42` at this point), not from a stack slot. The variable has no fixed memory address — GDB can report its current value only because the right register happens to hold it right now. Notice that `pressed` is the one showing `<optimized out>` — the compiler removed it from tracking entirely because its value is never needed after the ternary expression.
|
||||
|
||||
**Proof 2 The function prologue allocates no stack space for locals:**
|
||||
|
||||
```gdb
|
||||
(gdb) x/2i 0x10000234
|
||||
0x10000234 <main>: push {r4, lr}
|
||||
0x10000236 <main+2>: bl 0x10003014 <stdio_init_all>
|
||||
```
|
||||
|
||||
The very first instruction is `push {r4, lr}`, that saves `r4` (a callee-saved register) and `lr` (return address). There is **no** `sub sp, #N` instruction after it. On ARM, allocating stack space for local variables requires subtracting from `sp` to reserve room. If `regular_fav_num` lived on the stack, there would be a `sub sp, #4` (or similar) here. There isn't, so no stack slot was ever created.
|
||||
|
||||
**Proof 3 The loop body contains no store to the stack for `regular_fav_num`:**
|
||||
|
||||
```gdb
|
||||
(gdb) x/6i 0x10000264
|
||||
=> 0x10000264 <main+48>: movs r1, #42 @ 0x2a
|
||||
// constant 42 baked directly into instruction
|
||||
0x10000266 <main+50>: ldr r0, [pc, #44] @ (0x10000294 <main+96>)
|
||||
// load format string address from pool
|
||||
0x10000268 <main+52>: bl 0x100031a4 <__wrap_printf>
|
||||
// call printf
|
||||
0x1000026c <main+56>: ldrb r1, [r4, #0]
|
||||
// load static_fav_num from RAM
|
||||
0x1000026e <main+58>: ldr r0, [pc, #40] @ (0x10000298 <main+100>)
|
||||
// load format string address from pool
|
||||
0x10000270 <main+60>: bl 0x100031a4 <__wrap_printf>
|
||||
call printf
|
||||
```
|
||||
|
||||
For `regular_fav_num`, the value `42` goes straight into `r1` via `movs`, it is never written to memory and never read back from memory. There is no `strb r1, [sp, #N]` storing it to the stack, and no `ldrb r1, [sp, #N]` loading it back. The variable exists only in the source code. In the binary it is just a number in an instruction encoding.
|
||||
|
||||
`static_fav_num` is the exact opposite. It lives in the `.data` section of RAM, a fixed, known address (`0x200005a8`) that is set at link time and never changes for the life of the program. That fixed address is exactly the kind of value that cannot fit in a 16-bit Thumb instruction, so the linker writes it into the literal pool and the CPU fetches it with `ldr r4, [pc, #44]`.
|
||||
|
||||
> **IMPORTANT:** Static variables are **not** on the heap. The heap is for dynamic memory (`malloc`/`free`), memory whose lifetime is controlled explicitly at runtime. Static and global variables live in the `.data` section (if initialized) or `.bss` section (if zero/uninitialized), a region of RAM with a fixed layout determined at link time, not at runtime.
|
||||
|
||||
```
|
||||
Memory regions for our two variables:
|
||||
+------------------------------------------+
|
||||
| FLASH (read-only, 0x10000000+) |
|
||||
| - Code (instructions) |
|
||||
| - Literal pool (our 3 words) |
|
||||
| - String literals ("regular_fav_num...")|
|
||||
+------------------------------------------+
|
||||
| RAM .data section (0x20000000+) |
|
||||
| - static_fav_num @ 0x200005a8 <- pool |
|
||||
+------------------------------------------+
|
||||
| STACK (grows down from 0x20082000) |
|
||||
| - regular_fav_num (if not optimized) |
|
||||
| frame-relative, no fixed address |
|
||||
+------------------------------------------+
|
||||
| HEAP (grows up, between stack and .bss) |
|
||||
| - malloc/free only, nothing here today |
|
||||
+------------------------------------------+
|
||||
```
|
||||
|
||||
The pool ends at `0x1000029b`. At `0x1000029d` a new function begins, specifically `gpio_set_function`. The first two instructions, `push {r4}` (save caller's `r4` to the stack) and `mov.w r4, #256` (load a working constant), are a standard SDK function prologue, nothing to do with `main`. The `ldr r3, [pc, #48]`i r/. at `0x100002a3` (`gpio_set_function+6`) is that next function loading from **its own** literal pool further ahead in flash — proof that every function manages its own pool.
|
||||
|
||||
### Step 10: Examine Register Values
|
||||
|
||||
After stepping to `0x10000262` or later, check the registers:
|
||||
After breaking at `0x10000264`, check the registers:
|
||||
|
||||
```gdb
|
||||
(gdb) i r
|
||||
```
|
||||
|
||||
Pay attention to:
|
||||
- `r4` - Should hold `0x200005a8` (static variable's RAM address, loaded from literal pool)
|
||||
- `r1` - Used for `printf` arguments (holds `42` or the static variable value)
|
||||
- `r3` - Used for load/increment/store of the static variable
|
||||
- `pc` - Program counter (current instruction address)
|
||||
What you will actually see:
|
||||
|
||||
- `r4` = `0x200005a8` — the static variable's fixed RAM address. This was loaded from the literal pool in the function prologue and never changes across loop iterations.
|
||||
- `r1` = leftover value from the previous `printf` call (e.g. `0x40039044`). The breakpoint is stopped **at** `movs r1, #42` — that instruction has not executed yet, so `r1` does not yet hold `42`.
|
||||
- `r3` = leftover from prior operations (e.g. `0x10`). It will be used later in the loop body to load, increment, and store `static_fav_num`, but not yet.
|
||||
- `pc` = `0x10000264` — the loop top, pointing at the `movs r1, #42` instruction.
|
||||
|
||||
You can confirm `r4` holds the right address and value:
|
||||
|
||||
```gdb
|
||||
(gdb) x/1db $r4
|
||||
0x200005a8 <striped_spin_lock_num>: 42
|
||||
```
|
||||
|
||||
The `<striped_spin_lock_num>` label is just the nearest named global symbol in the SDK that GDB finds at that address — the actual variable stored there is our `static_fav_num`.
|
||||
|
||||
### Step 11: Watch the Static Variable Change
|
||||
|
||||
@@ -579,7 +799,7 @@ Now that we know the static variable lives at `0x200005a8`, examine it directly:
|
||||
|
||||
```gdb
|
||||
(gdb) x/1db 0x200005a8
|
||||
0x200005a8: 42
|
||||
0x200005a8 <striped_spin_lock_num>: 42
|
||||
```
|
||||
|
||||
Step through a full loop iteration (back to `0x10000264`) and re-examine:
|
||||
@@ -587,7 +807,7 @@ Step through a full loop iteration (back to `0x10000264`) and re-examine:
|
||||
```gdb
|
||||
(gdb) c
|
||||
(gdb) x/1db 0x200005a8
|
||||
0x200005a8: 43
|
||||
0x200005a8 <striped_spin_lock_num>: 43
|
||||
```
|
||||
|
||||
The value incremented from 42 to 43! Each loop iteration, the `adds r3, #1` at `0x1000027c` bumps it by 1, and `strb r3, [r4, #0]` at `0x1000027e` writes it back to RAM.
|
||||
@@ -598,12 +818,14 @@ Read the GPIO input register to see the button state:
|
||||
|
||||
```gdb
|
||||
(gdb) x/1wx 0xd0000004
|
||||
0xd0000004: 0x00008003
|
||||
```
|
||||
|
||||
The SIO GPIO input register at `0xd0000004` shows the current state of all GPIO pins. Bit 15 corresponds to our button on GPIO 15. To extract just bit 15:
|
||||
|
||||
```gdb
|
||||
(gdb) p/x (*(unsigned int *)0xd0000004 >> 15) & 1
|
||||
$1 = 0x1
|
||||
```
|
||||
|
||||
- Returns `1` when button is **not pressed** (pull-up holds it HIGH)
|
||||
@@ -613,7 +835,7 @@ TRY IT!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 7: Understanding the Assembly
|
||||
## Part 7: Understanding the Assembly
|
||||
|
||||
Now that we've explored the binary in GDB, let's make sense of the key patterns.
|
||||
|
||||
@@ -623,17 +845,22 @@ In GDB, examine the code at the start of the loop:
|
||||
|
||||
```gdb
|
||||
(gdb) x/5i 0x10000262
|
||||
0x10000262 <main+46>: ldr r4, [pc, #44] @ (0x10000290 <main+92>)
|
||||
=> 0x10000264 <main+48>: movs r1, #42 @ 0x2a
|
||||
0x10000266 <main+50>: ldr r0, [pc, #44] @ (0x10000294 <main+96>)
|
||||
0x10000268 <main+52>: bl 0x100031a4 <__wrap_printf>
|
||||
0x1000026c <main+56>: ldrb r1, [r4, #0]
|
||||
```
|
||||
|
||||
Look for this instruction:
|
||||
|
||||
```
|
||||
0x10000264: movs r1, #42 @ 0x2a
|
||||
0x10000264 <main+48>: movs r1, #42 @ 0x2a
|
||||
```
|
||||
|
||||
This loads the value `0x2a` (42 in decimal) directly into register `r1` for the first `printf` call.
|
||||
|
||||
**Key insight:** The compiler **optimized away** the `regular_fav_num` variable entirely! Since it's always 42 when printed, the compiler just uses the constant `42` directly. The `regular_fav_num++` after the print is also removed because it has no observable effect.
|
||||
**Key insight:** The compiler **never allocated stack space** for `regular_fav_num`. Since it is always `42` when printed, the compiler bakes the constant directly into the `movs r1, #42` instruction. The `regular_fav_num++` after the print is also removed because it has no observable effect — the variable is recreated as `42` on the next loop iteration anyway.
|
||||
|
||||
### Step 14: Analyze the Static Variable
|
||||
|
||||
@@ -641,11 +868,6 @@ Examine the static variable operations in the second half of the loop body:
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x10000274
|
||||
```
|
||||
|
||||
Look for the load-increment-store pattern using `r4` (which holds the static variable's RAM address):
|
||||
|
||||
```
|
||||
0x10000274 <main+64>: mov.w r1, #3489660928 @ 0xd0000000
|
||||
0x10000278 <main+68>: ldrb r3, [r4, #0]
|
||||
0x1000027a <main+70>: movs r2, #16
|
||||
@@ -658,14 +880,26 @@ Look for the load-increment-store pattern using `r4` (which holds the static var
|
||||
0x1000028e <main+90>: b.n 0x10000264 <main+48>
|
||||
```
|
||||
|
||||
Look for the load-increment-store pattern using `r4` (which holds the static variable's RAM address):
|
||||
|
||||
```
|
||||
...
|
||||
0x10000278 <main+68>: ldrb r3, [r4, #0]
|
||||
0x1000027a <main+70>: movs r2, #16
|
||||
0x1000027c <main+72>: adds r3, #1
|
||||
0x1000027e <main+74>: strb r3, [r4, #0]
|
||||
...
|
||||
```
|
||||
|
||||
Note that `r4` was loaded earlier at `0x10000262` via `ldr r4, [pc, #44]` - this pulled the static variable's RAM address (`0x200005a8`) from the literal pool at `0x10000290`.
|
||||
|
||||
**Key insight:** The static variable lives at a **fixed RAM address** (`0x200005a8`). It's loaded, incremented, and stored back - unlike the regular variable which was optimized away!
|
||||
**Key insight:** The static variable lives at a **fixed RAM address** (`0x200005a8`). It's loaded, incremented, and stored back. The regular variable, by contrast, never gets a stack slot — the compiler holds it in a register and bakes the constant `42` directly into the instruction, so there is nothing to load or store.
|
||||
|
||||
Verify the static variable value which should be `43`:
|
||||
|
||||
```gdb
|
||||
(gdb) x/1db 0x200005a8
|
||||
0x200005a8 <striped_spin_lock_num>: 43
|
||||
```
|
||||
|
||||
### Step 15: Analyze the GPIO Logic
|
||||
@@ -674,11 +908,6 @@ Examine the GPIO input/output code:
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x10000274
|
||||
```
|
||||
|
||||
Look for this sequence:
|
||||
|
||||
```
|
||||
0x10000274 <main+64>: mov.w r1, #3489660928 @ 0xd0000000
|
||||
0x10000278 <main+68>: ldrb r3, [r4, #0]
|
||||
0x1000027a <main+70>: movs r2, #16
|
||||
@@ -713,14 +942,14 @@ Look for this sequence:
|
||||
The last instruction at `0x1000028e` is already covered in the table above:
|
||||
|
||||
```
|
||||
0x1000028e: b.n 0x10000264
|
||||
0x1000028e <main+90>: b.n 0x10000264 <main+48>
|
||||
```
|
||||
|
||||
This is an **unconditional branch** back to `0x10000264` (the `movs r1, #42` at the top of the loop) - this is the `while (true)` in our code! There is no `pop` or `bx lr` to return from `main` because the loop never exits.
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 8: Hacking the Binary with a Hex Editor
|
||||
## Part 8: Hacking the Binary with a Hex Editor
|
||||
|
||||
Now for the fun part - we'll patch the `.bin` file directly using a hex editor!
|
||||
|
||||
@@ -779,11 +1008,11 @@ This is the 32-bit Thumb-2 encoding of `eor.w r3, r3, #1`. The bytes break down
|
||||
|
||||
```
|
||||
+-----------------------------------------------------------------+
|
||||
| eor.w r3, r3, #1 -> bytes: 83 F0 01 03 |
|
||||
| eor.w r3, r3, #1 -> bytes: 83 F0 01 03 |
|
||||
| |
|
||||
| Byte 0: 0x83 -?? |
|
||||
| Byte 0: 0x83 -?? |
|
||||
| Byte 1: 0xF0 -+ First halfword (opcode + source register) |
|
||||
| Byte 2: 0x01 ---- Immediate value (#1) ?? CHANGE THIS |
|
||||
| Byte 2: 0x01 ---- Immediate value (#1) ?? CHANGE THIS |
|
||||
| Byte 3: 0x03 ---- Destination register (r3) |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
@@ -816,19 +1045,19 @@ This is the **opposite** of the original behavior!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Part 9: Converting and Flashing the Hacked Binary
|
||||
## Part 9: Converting and Flashing the Hacked Binary
|
||||
|
||||
### Step 22: Convert to UF2 Format
|
||||
|
||||
Open a terminal and navigate to your project directory:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables
|
||||
```
|
||||
|
||||
Run the conversion command:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
@@ -859,13 +1088,13 @@ static_fav_num: 43
|
||||
- LED should now be **ON by default** (when button is NOT pressed)
|
||||
- LED should turn **OFF** when you press the button
|
||||
|
||||
🎉 **BOOM! We successfully:**
|
||||
**BOOM! We successfully:**
|
||||
1. Changed the printed value from 42 to 43
|
||||
2. Inverted the LED/button logic
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 10: Summary and Review
|
||||
## Part 10: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -945,7 +1174,7 @@ static_fav_num: 43
|
||||
|
||||
---
|
||||
|
||||
## 💡 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Static variables persist** - They keep their value between function calls and loop iterations.
|
||||
|
||||
@@ -969,7 +1198,7 @@ static_fav_num: 43
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| --------------------- | ---------------------------------------------------------------- |
|
||||
@@ -992,7 +1221,7 @@ static_fav_num: 43
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### GPIO Input Reference
|
||||
|
||||
@@ -1037,3 +1266,4 @@ static_fav_num: 43
|
||||
Happy hacking! ?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 06</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Static Variables in Embedded Systems:</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Debugging and Hacking Static Variables</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">w/ GPIO Input Basics</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,74 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Static vs Regular Vars</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Persistence across loop iterations</text>
|
||||
|
||||
<!-- Regular Variable -->
|
||||
<rect x="40" y="110" width="540" height="310" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Regular (auto)</text>
|
||||
|
||||
<rect x="60" y="168" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="202" class="red">Loop 1: 42 -> 43 -> destroy</text>
|
||||
|
||||
<rect x="60" y="233" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="267" class="red">Loop 2: 42 -> 43 -> destroy</text>
|
||||
|
||||
<rect x="60" y="298" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="332" class="red">Loop 3: 42 -> 43 -> destroy</text>
|
||||
|
||||
<text x="60" y="393" class="txt">Always prints:</text>
|
||||
<text x="340" y="393" class="red">42</text>
|
||||
|
||||
<!-- Static Variable -->
|
||||
<rect x="620" y="110" width="540" height="310" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Static</text>
|
||||
|
||||
<rect x="640" y="168" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="202" class="grn">Loop 1: 42 -> 43 (kept!)</text>
|
||||
|
||||
<rect x="640" y="233" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="267" class="grn">Loop 2: 43 -> 44 (kept!)</text>
|
||||
|
||||
<rect x="640" y="298" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="332" class="grn">Loop 3: 44 -> 45 (kept!)</text>
|
||||
|
||||
<text x="640" y="393" class="txt">Keeps incrementing:</text>
|
||||
<text x="960" y="393" class="grn">42,43,44...</text>
|
||||
|
||||
<!-- Code Example -->
|
||||
<rect x="40" y="440" width="1120" height="160" rx="8" class="pnl"/>
|
||||
<text x="600" y="478" text-anchor="middle" class="sub">Declaration Syntax</text>
|
||||
|
||||
<rect x="60" y="498" width="500" height="80" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="530" class="txt">uint8_t reg = 42;</text>
|
||||
<text x="80" y="558" class="dim">Recreated each iteration</text>
|
||||
|
||||
<rect x="620" y="498" width="520" height="80" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="640" y="530" class="grn">static uint8_t s = 42;</text>
|
||||
<text x="640" y="558" class="dim">Persists for program life</text>
|
||||
|
||||
<!-- Overflow Note -->
|
||||
<rect x="40" y="620" width="1120" height="160" rx="8" class="pnl"/>
|
||||
<text x="600" y="658" text-anchor="middle" class="sub">uint8_t Overflow</text>
|
||||
|
||||
<text x="60" y="698" class="txt">255 + 1 =</text>
|
||||
<text x="260" y="698" class="red">0</text>
|
||||
<text x="320" y="698" class="dim">(wraps around!)</text>
|
||||
|
||||
<text x="60" y="733" class="dim">Binary: 11111111 + 1 = 100000000 (9 bits)</text>
|
||||
<text x="60" y="763" class="dim">Only 8 bits kept: 00000000 = 0</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,93 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Memory Layout</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Where variables live in RAM</text>
|
||||
|
||||
<!-- Memory Diagram -->
|
||||
<rect x="40" y="110" width="540" height="670" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">RP2350 SRAM Map</text>
|
||||
|
||||
<!-- Stack -->
|
||||
<rect x="60" y="170" width="380" height="90" rx="4" fill="#ff0040" stroke="#ff0040" stroke-width="1" opacity="0.15"/>
|
||||
<text x="250" y="205" text-anchor="middle" class="red">STACK (grows down)</text>
|
||||
<text x="250" y="235" text-anchor="middle" class="dim">Local/auto variables</text>
|
||||
|
||||
<text x="455" y="210" class="dim">0x20082000</text>
|
||||
|
||||
<!-- Free Space -->
|
||||
<rect x="60" y="270" width="380" height="100" rx="4" fill="#1a1a2e" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="250" y="325" text-anchor="middle" class="dim">(free space)</text>
|
||||
|
||||
<!-- Heap -->
|
||||
<rect x="60" y="380" width="380" height="90" rx="4" fill="#ffaa00" stroke="#ffaa00" stroke-width="1" opacity="0.15"/>
|
||||
<text x="250" y="415" text-anchor="middle" class="amb">HEAP (grows up)</text>
|
||||
<text x="250" y="445" text-anchor="middle" class="dim">malloc / free</text>
|
||||
|
||||
<!-- .bss -->
|
||||
<rect x="60" y="480" width="380" height="90" rx="4" fill="#00d4ff" stroke="#00d4ff" stroke-width="1" opacity="0.15"/>
|
||||
<text x="250" y="515" text-anchor="middle" class="cyn">.bss section</text>
|
||||
<text x="250" y="545" text-anchor="middle" class="dim">Uninit static/global</text>
|
||||
|
||||
<!-- .data -->
|
||||
<rect x="60" y="580" width="380" height="90" rx="4" fill="#00ff41" stroke="#00ff41" stroke-width="1" opacity="0.15"/>
|
||||
<text x="250" y="615" text-anchor="middle" class="grn">.data section</text>
|
||||
<text x="250" y="645" text-anchor="middle" class="dim">Initialized static/global</text>
|
||||
|
||||
<text x="455" y="650" class="dim">0x20000000</text>
|
||||
|
||||
<text x="60" y="730" class="dim">Static vars: .data (init)</text>
|
||||
<text x="60" y="755" class="dim">Static vars: .bss (uninit)</text>
|
||||
|
||||
<!-- Variable Types Table -->
|
||||
<rect x="620" y="110" width="540" height="390" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Variable Storage</text>
|
||||
|
||||
<text x="640" y="188" class="cyn">Type</text>
|
||||
<text x="880" y="188" class="cyn">Location</text>
|
||||
|
||||
<line x1="640" y1="198" x2="1140" y2="198" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text x="640" y="228" class="txt">Automatic</text>
|
||||
<text x="880" y="228" class="red">Stack</text>
|
||||
|
||||
<text x="640" y="258" class="txt">Static</text>
|
||||
<text x="880" y="258" class="grn">.data / .bss</text>
|
||||
|
||||
<text x="640" y="288" class="txt">Global</text>
|
||||
<text x="880" y="288" class="grn">.data / .bss</text>
|
||||
|
||||
<text x="640" y="318" class="txt">Dynamic</text>
|
||||
<text x="880" y="318" class="amb">Heap</text>
|
||||
|
||||
<text x="640" y="358" class="dim">Static vars are NOT on heap!</text>
|
||||
<text x="640" y="383" class="dim">Fixed location, set at compile</text>
|
||||
<text x="640" y="408" class="dim">time. Lives entire program.</text>
|
||||
<text x="640" y="448" class="grn">Example:</text>
|
||||
<text x="640" y="473" class="dim">static_fav_num @ 0x200005A8</text>
|
||||
|
||||
<!-- Key Insight -->
|
||||
<rect x="620" y="520" width="540" height="260" rx="8" class="pnl"/>
|
||||
<text x="890" y="548" text-anchor="middle" class="sub">Key Insight</text>
|
||||
|
||||
<text x="640" y="588" class="txt">Stack vars:</text>
|
||||
<text x="640" y="618" class="red">Created + destroyed</text>
|
||||
<text x="640" y="648" class="dim">each function call</text>
|
||||
|
||||
<text x="640" y="693" class="txt">Static vars:</text>
|
||||
<text x="640" y="723" class="grn">Fixed RAM address</text>
|
||||
<text x="640" y="753" class="dim">persist entire runtime</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,93 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GPIO Input Basics</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Reading buttons with the RP2350</text>
|
||||
|
||||
<!-- Output vs Input -->
|
||||
<rect x="40" y="110" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">OUTPUT (before)</text>
|
||||
|
||||
<rect x="60" y="170" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="204" class="grn">Pico GPIO 16</text>
|
||||
<text x="370" y="204" class="txt">--></text>
|
||||
<text x="420" y="204" class="amb">LED</text>
|
||||
|
||||
<text x="60" y="268" class="dim">We CONTROL the LED</text>
|
||||
<text x="60" y="293" class="dim">gpio_put(pin, value)</text>
|
||||
|
||||
<rect x="620" y="110" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">INPUT (new!)</text>
|
||||
|
||||
<rect x="640" y="170" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="660" y="204" class="cyn">Pico GPIO 15</text>
|
||||
<text x="950" y="204" class="txt"><--</text>
|
||||
<text x="1000" y="204" class="amb">BTN</text>
|
||||
|
||||
<text x="640" y="268" class="dim">We READ button state</text>
|
||||
<text x="640" y="293" class="dim">gpio_get(pin)</text>
|
||||
|
||||
<!-- Floating Input Problem -->
|
||||
<rect x="40" y="330" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="310" y="368" text-anchor="middle" class="sub">Floating Input</text>
|
||||
|
||||
<text x="60" y="408" class="txt">No connection =</text>
|
||||
<text x="60" y="438" class="red">RANDOM values!</text>
|
||||
|
||||
<text x="60" y="478" class="dim">Read 1: HIGH</text>
|
||||
<text x="260" y="478" class="dim">Read 2: LOW</text>
|
||||
<text x="60" y="503" class="dim">Read 3: HIGH</text>
|
||||
<text x="260" y="503" class="dim">Read 4: HIGH</text>
|
||||
<text x="440" y="503" class="dim">???</text>
|
||||
|
||||
<!-- Pull Resistors -->
|
||||
<rect x="620" y="330" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="890" y="368" text-anchor="middle" class="sub">Pull Resistors</text>
|
||||
|
||||
<text x="640" y="408" class="cyn">Type</text>
|
||||
<text x="840" y="408" class="cyn">Default</text>
|
||||
<text x="1000" y="408" class="cyn">Pressed</text>
|
||||
|
||||
<line x1="640" y1="418" x2="1140" y2="418" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text x="640" y="448" class="amb">Pull-Up</text>
|
||||
<text x="840" y="448" class="grn">HIGH(1)</text>
|
||||
<text x="1000" y="448" class="red">LOW(0)</text>
|
||||
|
||||
<text x="640" y="483" class="amb">Pull-Down</text>
|
||||
<text x="840" y="483" class="red">LOW(0)</text>
|
||||
<text x="1000" y="483" class="grn">HIGH(1)</text>
|
||||
|
||||
<text x="640" y="513" class="dim">Pico 2 has internal pull resistors!</text>
|
||||
|
||||
<!-- GPIO Functions -->
|
||||
<rect x="40" y="550" width="1120" height="230" rx="8" class="pnl"/>
|
||||
<text x="600" y="588" text-anchor="middle" class="sub">GPIO Input Functions</text>
|
||||
|
||||
<text x="60" y="628" class="grn">gpio_init(pin)</text>
|
||||
<text x="500" y="628" class="dim">Initialize pin</text>
|
||||
|
||||
<text x="60" y="658" class="grn">gpio_set_dir(pin, GPIO_IN)</text>
|
||||
<text x="500" y="658" class="dim">Set as input</text>
|
||||
|
||||
<text x="60" y="688" class="grn">gpio_pull_up(pin)</text>
|
||||
<text x="500" y="688" class="dim">Enable pull-up</text>
|
||||
|
||||
<text x="60" y="718" class="grn">gpio_get(pin)</text>
|
||||
<text x="500" y="718" class="dim">Read state (0 or 1)</text>
|
||||
|
||||
<text x="60" y="748" class="dim">No external resistor needed -- internal pull-up!</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,99 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Pull-Up Resistor</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Internal pull-up on GPIO 15</text>
|
||||
|
||||
<!-- Circuit Diagram -->
|
||||
<rect x="40" y="110" width="540" height="370" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Circuit</text>
|
||||
|
||||
<text x="160" y="195" class="amb">3.3V</text>
|
||||
<line x1="195" y1="205" x2="195" y2="240" stroke="#ffaa00" stroke-width="2"/>
|
||||
|
||||
<rect x="175" y="240" width="40" height="60" rx="2" fill="none" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="240" y="275" class="dim">pull-up R</text>
|
||||
|
||||
<line x1="195" y1="300" x2="195" y2="340" stroke="#ffaa00" stroke-width="2"/>
|
||||
<line x1="195" y1="340" x2="350" y2="340" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="370" y="345" class="cyn">GPIO 15</text>
|
||||
|
||||
<line x1="195" y1="340" x2="195" y2="380" stroke="#888" stroke-width="2"/>
|
||||
|
||||
<rect x="170" y="380" width="50" height="30" rx="2" fill="none" stroke="#c0c0c0" stroke-width="2"/>
|
||||
<text x="240" y="400" class="dim">BTN</text>
|
||||
|
||||
<line x1="195" y1="410" x2="195" y2="450" stroke="#888" stroke-width="2"/>
|
||||
<text x="160" y="465" class="dim">GND</text>
|
||||
|
||||
<!-- Logic Table -->
|
||||
<rect x="620" y="110" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Button Logic</text>
|
||||
|
||||
<text x="640" y="188" class="cyn">State</text>
|
||||
<text x="840" y="188" class="cyn">GPIO</text>
|
||||
<text x="1000" y="188" class="cyn">LED</text>
|
||||
|
||||
<line x1="640" y1="198" x2="1140" y2="198" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text x="640" y="233" class="txt">Released</text>
|
||||
<text x="840" y="233" class="grn">HIGH (1)</text>
|
||||
<text x="1000" y="233" class="red">OFF</text>
|
||||
|
||||
<text x="640" y="268" class="txt">Pressed</text>
|
||||
<text x="840" y="268" class="red">LOW (0)</text>
|
||||
<text x="1000" y="268" class="grn">ON</text>
|
||||
|
||||
<text x="640" y="293" class="dim">Inverted! Pull-up = backwards</text>
|
||||
|
||||
<!-- Ternary Operator -->
|
||||
<rect x="620" y="330" width="540" height="150" rx="8" class="pnl"/>
|
||||
<text x="890" y="368" text-anchor="middle" class="sub">Ternary Operator</text>
|
||||
|
||||
<rect x="640" y="390" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="660" y="418" class="amb">gpio_put(LED, pressed?0:1);</text>
|
||||
|
||||
<text x="640" y="460" class="dim">pressed=1 -> LED OFF (inverted!)</text>
|
||||
|
||||
<!-- Wiring -->
|
||||
<rect x="40" y="500" width="1120" height="280" rx="8" class="pnl"/>
|
||||
<text x="600" y="538" text-anchor="middle" class="sub">Hardware Wiring</text>
|
||||
|
||||
<rect x="60" y="560" width="300" height="190" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="210" y="590" text-anchor="middle" class="cyn">Pico 2</text>
|
||||
<text x="80" y="625" class="grn">GPIO 15</text>
|
||||
<text x="80" y="660" class="amb">GPIO 16</text>
|
||||
<text x="80" y="695" class="dim">GND</text>
|
||||
<text x="80" y="725" class="dim">BOOTSEL</text>
|
||||
|
||||
<text x="380" y="625" class="txt">--></text>
|
||||
<text x="380" y="660" class="txt">--></text>
|
||||
<text x="380" y="695" class="txt">--></text>
|
||||
|
||||
<rect x="440" y="560" width="300" height="190" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="590" y="590" text-anchor="middle" class="amb">Components</text>
|
||||
<text x="460" y="625" class="txt">Button (one leg)</text>
|
||||
<text x="460" y="660" class="txt">LED + resistor</text>
|
||||
<text x="460" y="695" class="txt">Button (other leg)</text>
|
||||
<text x="460" y="725" class="dim">Hold to flash UF2</text>
|
||||
|
||||
<rect x="780" y="560" width="360" height="190" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="960" y="590" text-anchor="middle" class="grn">Key Point</text>
|
||||
<text x="800" y="625" class="txt">No external</text>
|
||||
<text x="800" y="655" class="txt">resistor needed!</text>
|
||||
<text x="800" y="695" class="dim">Internal pull-up</text>
|
||||
<text x="800" y="720" class="dim">handles it all</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,83 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Source Code</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">0x0014_static-variables.c</text>
|
||||
|
||||
<!-- Code Panel -->
|
||||
<rect x="40" y="110" width="700" height="510" rx="8" class="pnl"/>
|
||||
<text x="390" y="148" text-anchor="middle" class="sub">main()</text>
|
||||
|
||||
<rect x="60" y="168" width="660" height="440" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="198" class="cyn">int main(void) {</text>
|
||||
<text x="110" y="226" class="txt">stdio_init_all();</text>
|
||||
<text x="110" y="254" class="dim">// GPIO setup</text>
|
||||
<text x="110" y="282" class="txt">gpio_init(15);</text>
|
||||
<text x="110" y="310" class="txt">gpio_set_dir(15, GPIO_IN);</text>
|
||||
<text x="110" y="338" class="amb">gpio_pull_up(15);</text>
|
||||
<text x="110" y="366" class="txt">gpio_init(16);</text>
|
||||
<text x="110" y="394" class="txt">gpio_set_dir(16, GPIO_OUT);</text>
|
||||
<text x="110" y="430" class="cyn">while (true) {</text>
|
||||
<text x="140" y="458" class="txt">uint8_t reg = 42;</text>
|
||||
<text x="140" y="486" class="grn">static uint8_t s = 42;</text>
|
||||
<text x="140" y="514" class="txt">printf(... reg, s);</text>
|
||||
<text x="140" y="542" class="red">reg++; s++;</text>
|
||||
<text x="110" y="570" class="cyn">}</text>
|
||||
<text x="80" y="590" class="cyn">}</text>
|
||||
|
||||
<!-- Annotations -->
|
||||
<rect x="780" y="110" width="380" height="180" rx="8" class="pnl"/>
|
||||
<text x="970" y="148" text-anchor="middle" class="sub">GPIO Setup</text>
|
||||
|
||||
<text x="800" y="183" class="grn">Pin 15:</text>
|
||||
<text x="920" y="183" class="txt">Input</text>
|
||||
<text x="800" y="213" class="dim">Pull-up enabled</text>
|
||||
|
||||
<text x="800" y="248" class="amb">Pin 16:</text>
|
||||
<text x="920" y="248" class="txt">Output</text>
|
||||
<text x="800" y="268" class="dim">LED control</text>
|
||||
|
||||
<!-- Serial Output -->
|
||||
<rect x="780" y="310" width="380" height="200" rx="8" class="pnl"/>
|
||||
<text x="970" y="348" text-anchor="middle" class="sub">Serial Output</text>
|
||||
|
||||
<rect x="800" y="370" width="340" height="115" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="820" y="397" class="txt">reg: 42</text>
|
||||
<text x="820" y="422" class="txt">s: 42</text>
|
||||
<text x="820" y="447" class="txt">reg: 42</text>
|
||||
<text x="820" y="472" class="grn">s: 43</text>
|
||||
|
||||
<text x="800" y="498" class="dim">reg always 42, s grows</text>
|
||||
|
||||
<!-- Button Logic -->
|
||||
<rect x="780" y="530" width="380" height="90" rx="8" class="pnl"/>
|
||||
<text x="970" y="565" text-anchor="middle" class="sub">Button Logic</text>
|
||||
|
||||
<text x="800" y="598" class="dim">pressed = gpio_get(15);</text>
|
||||
|
||||
<!-- Key -->
|
||||
<rect x="40" y="640" width="1120" height="140" rx="8" class="pnl"/>
|
||||
<text x="600" y="678" text-anchor="middle" class="sub">Key Behaviors</text>
|
||||
|
||||
<rect x="60" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="230" y="730" text-anchor="middle" class="red">reg: always 42</text>
|
||||
|
||||
<rect x="420" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="590" y="730" text-anchor="middle" class="grn">s: 42,43,44...</text>
|
||||
|
||||
<rect x="780" y="698" width="360" height="55" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="960" y="730" text-anchor="middle" class="amb">wraps at 255->0</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,65 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Compiler Optimizations</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">What the compiler does to your code</text>
|
||||
|
||||
<!-- Optimization 1: Regular var removed -->
|
||||
<rect x="40" y="110" width="1120" height="220" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Optimization 1: Dead Code Removal</text>
|
||||
|
||||
<rect x="60" y="170" width="500" height="135" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="200" class="red">Your code:</text>
|
||||
<text x="80" y="230" class="txt">uint8_t reg = 42;</text>
|
||||
<text x="80" y="260" class="txt">reg++;</text>
|
||||
<text x="80" y="285" class="dim">// No lasting effect!</text>
|
||||
|
||||
<rect x="620" y="170" width="520" height="135" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="640" y="200" class="grn">Compiler output:</text>
|
||||
<text x="640" y="230" class="amb">movs r1, #42</text>
|
||||
<text x="640" y="260" class="dim">// reg++ is GONE</text>
|
||||
<text x="640" y="285" class="dim">// Uses constant 42 directly</text>
|
||||
|
||||
<!-- Optimization 2: Function Inlining -->
|
||||
<rect x="40" y="350" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="600" y="388" text-anchor="middle" class="sub">Optimization 2: Function Inlining</text>
|
||||
|
||||
<rect x="60" y="410" width="500" height="110" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="440" class="red">Your code:</text>
|
||||
<text x="80" y="470" class="txt">gpio_pull_up(15);</text>
|
||||
<text x="80" y="500" class="dim">// Simple wrapper func</text>
|
||||
|
||||
<rect x="620" y="410" width="520" height="110" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="640" y="440" class="grn">Compiler output:</text>
|
||||
<text x="640" y="470" class="amb">gpio_set_pulls(15,1,0);</text>
|
||||
<text x="640" y="500" class="dim">// Inlined to real func</text>
|
||||
|
||||
<!-- Optimization 3: Instruction Scheduling -->
|
||||
<rect x="40" y="570" width="1120" height="210" rx="8" class="pnl"/>
|
||||
<text x="600" y="608" text-anchor="middle" class="sub">Optimization 3: Scheduling</text>
|
||||
|
||||
<text x="60" y="648" class="txt">Compiler reorders instructions</text>
|
||||
<text x="60" y="678" class="txt">to avoid pipeline stalls:</text>
|
||||
|
||||
<rect x="60" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="732" text-anchor="middle" class="cyn">Load SIO base</text>
|
||||
|
||||
<rect x="420" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="732" text-anchor="middle" class="amb">Increment s</text>
|
||||
|
||||
<rect x="780" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="732" text-anchor="middle" class="grn">Read GPIO</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,90 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Assembly Analysis</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Key instructions in main() loop</text>
|
||||
|
||||
<!-- Assembly Listing -->
|
||||
<rect x="40" y="110" width="700" height="490" rx="8" class="pnl"/>
|
||||
<text x="390" y="148" text-anchor="middle" class="sub">Loop Body (0x10000264)</text>
|
||||
|
||||
<rect x="60" y="168" width="660" height="410" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="196" class="cyn">movs r1, #0x2a</text>
|
||||
<text x="420" y="196" class="dim">; reg=42</text>
|
||||
<text x="80" y="226" class="txt">bl __wrap_printf</text>
|
||||
<text x="420" y="226" class="dim">; print reg</text>
|
||||
<text x="80" y="256" class="amb">ldrb r1, [r4]</text>
|
||||
<text x="420" y="256" class="dim">; load static</text>
|
||||
<text x="80" y="286" class="txt">bl __wrap_printf</text>
|
||||
<text x="420" y="286" class="dim">; print s</text>
|
||||
<text x="80" y="316" class="red">mov.w r1, #0xd0000000</text>
|
||||
<text x="420" y="316" class="dim">; SIO base</text>
|
||||
<text x="80" y="346" class="amb">ldrb r3, [r4]</text>
|
||||
<text x="420" y="346" class="dim">; reload s</text>
|
||||
<text x="80" y="376" class="grn">adds r3, #1</text>
|
||||
<text x="420" y="376" class="dim">; s++</text>
|
||||
<text x="80" y="406" class="grn">strb r3, [r4]</text>
|
||||
<text x="420" y="406" class="dim">; store s</text>
|
||||
<text x="80" y="436" class="cyn">ldr r3, [r1, #4]</text>
|
||||
<text x="420" y="436" class="dim">; read GPIO</text>
|
||||
<text x="80" y="466" class="cyn">ubfx r3, r3, #15, #1</text>
|
||||
<text x="420" y="466" class="dim">; bit 15</text>
|
||||
<text x="80" y="496" class="red">eor.w r3, r3, #1</text>
|
||||
<text x="420" y="496" class="dim">; invert</text>
|
||||
<text x="80" y="526" class="amb">mcrr 0, 4, r2, r3, cr0</text>
|
||||
<text x="420" y="526" class="dim">; GPIO out</text>
|
||||
<text x="80" y="556" class="cyn">b.n 0x10000264</text>
|
||||
<text x="420" y="556" class="dim">; loop</text>
|
||||
|
||||
<!-- Key Registers -->
|
||||
<rect x="780" y="110" width="380" height="220" rx="8" class="pnl"/>
|
||||
<text x="970" y="148" text-anchor="middle" class="sub">Key Registers</text>
|
||||
|
||||
<text x="800" y="188" class="cyn">r1:</text>
|
||||
<text x="860" y="188" class="txt">printf arg</text>
|
||||
<text x="800" y="223" class="amb">r3:</text>
|
||||
<text x="860" y="223" class="txt">temp / static</text>
|
||||
<text x="800" y="258" class="grn">r4:</text>
|
||||
<text x="860" y="258" class="txt">0x200005a8</text>
|
||||
<text x="800" y="283" class="dim">(static var addr)</text>
|
||||
<text x="800" y="308" class="red">r2:</text>
|
||||
<text x="860" y="308" class="txt">LED pin (16)</text>
|
||||
|
||||
<!-- Key Instructions -->
|
||||
<rect x="780" y="350" width="380" height="250" rx="8" class="pnl"/>
|
||||
<text x="970" y="388" text-anchor="middle" class="sub">Key Patterns</text>
|
||||
|
||||
<text x="800" y="428" class="grn">ldrb/adds/strb</text>
|
||||
<text x="800" y="453" class="dim">Load-increment-store</text>
|
||||
<text x="800" y="478" class="dim">(static var update)</text>
|
||||
|
||||
<text x="800" y="518" class="cyn">ubfx #15, #1</text>
|
||||
<text x="800" y="543" class="dim">Extract GPIO bit 15</text>
|
||||
|
||||
<text x="800" y="573" class="red">eor.w #1</text>
|
||||
<text x="800" y="598" class="dim">Inverts (? 0 : 1)</text>
|
||||
|
||||
<!-- Infinite Loop -->
|
||||
<rect x="40" y="620" width="1120" height="160" rx="8" class="pnl"/>
|
||||
<text x="600" y="658" text-anchor="middle" class="sub">Infinite Loop</text>
|
||||
|
||||
<rect x="60" y="680" width="400" height="70" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="715" class="cyn">b.n 0x10000264</text>
|
||||
<text x="80" y="738" class="dim">; while(true)</text>
|
||||
|
||||
<text x="500" y="715" class="txt">No pop/bx lr</text>
|
||||
<text x="500" y="745" class="dim">main() never returns</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GDB: Static Variable</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Finding static_fav_num in RAM</text>
|
||||
|
||||
<!-- Literal Pool -->
|
||||
<rect x="40" y="110" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Literal Pool Lookup</text>
|
||||
|
||||
<rect x="60" y="170" width="700" height="48" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="200" class="cyn">ldr r4, [pc, #44]</text>
|
||||
<text x="400" y="200" class="dim">@ 0x10000290</text>
|
||||
|
||||
<text x="60" y="248" class="txt">Examine literal pool:</text>
|
||||
<rect x="60" y="258" width="700" height="30" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="282" class="grn">x/1wx 0x10000290 = 0x200005A8</text>
|
||||
|
||||
<text x="790" y="248" class="amb">r4 now holds the</text>
|
||||
<text x="790" y="278" class="amb">RAM address of</text>
|
||||
<text x="790" y="298" class="grn">static_fav_num!</text>
|
||||
|
||||
<!-- Examining the Variable -->
|
||||
<rect x="40" y="330" width="540" height="220" rx="8" class="pnl"/>
|
||||
<text x="310" y="368" text-anchor="middle" class="sub">Read Value</text>
|
||||
|
||||
<rect x="60" y="390" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="418" class="grn">x/1db 0x200005a8 = 42</text>
|
||||
|
||||
<text x="60" y="458" class="dim">After one loop iteration:</text>
|
||||
<rect x="60" y="468" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="496" class="amb">x/1db 0x200005a8 = 43</text>
|
||||
|
||||
<text x="60" y="536" class="dim">It incremented! Persists in RAM.</text>
|
||||
|
||||
<!-- Disasm Gotcha -->
|
||||
<rect x="620" y="330" width="540" height="220" rx="8" class="pnl"/>
|
||||
<text x="890" y="368" text-anchor="middle" class="sub">Disasm Gotcha</text>
|
||||
|
||||
<text x="640" y="408" class="txt">x/i 0x10000290 shows:</text>
|
||||
|
||||
<rect x="640" y="425" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="660" y="453" class="red">lsls r0, r5, #22</text>
|
||||
|
||||
<text x="640" y="493" class="dim">GDB decodes DATA as code!</text>
|
||||
<text x="640" y="518" class="dim">Bytes A8 05 00 20 = 0x200005A8</text>
|
||||
<text x="640" y="538" class="dim">Use x/wx not x/i for data</text>
|
||||
|
||||
<!-- GPIO Register -->
|
||||
<rect x="40" y="570" width="1120" height="210" rx="8" class="pnl"/>
|
||||
<text x="600" y="608" text-anchor="middle" class="sub">GPIO Input Register</text>
|
||||
|
||||
<text x="60" y="648" class="txt">Read button state in GDB:</text>
|
||||
|
||||
<rect x="60" y="668" width="700" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="696" class="grn">p/x (*(uint*)0xd0000004 >> 15) & 1</text>
|
||||
|
||||
<text x="60" y="738" class="cyn">Returns 1:</text>
|
||||
<text x="260" y="738" class="dim">not pressed (pull-up)</text>
|
||||
<text x="60" y="758" class="amb">Returns 0:</text>
|
||||
<text x="260" y="758" class="dim">button pressed</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,63 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Hacking the Binary</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Two patches with a hex editor</text>
|
||||
|
||||
<!-- Offset Formula -->
|
||||
<rect x="40" y="110" width="1120" height="100" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">File Offset Formula</text>
|
||||
<text x="60" y="188" class="grn">offset = address - 0x10000000</text>
|
||||
<text x="600" y="188" class="dim">Example: 0x10000264 -> 0x264</text>
|
||||
|
||||
<!-- Hack 1 -->
|
||||
<rect x="40" y="230" width="1120" height="240" rx="8" class="pnl"/>
|
||||
<text x="600" y="268" text-anchor="middle" class="sub">Hack 1: Change 42 to 43</text>
|
||||
|
||||
<text x="60" y="308" class="txt">Target: movs r1, #0x2a</text>
|
||||
<text x="60" y="338" class="dim">at address 0x10000264 (offset 0x264)</text>
|
||||
|
||||
<rect x="60" y="358" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="393" class="red">Before: 2A 21</text>
|
||||
<text x="310" y="393" class="dim">movs r1, #42</text>
|
||||
|
||||
<rect x="620" y="358" width="520" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="640" y="393" class="grn">After: 2B 21</text>
|
||||
<text x="880" y="393" class="dim">movs r1, #43</text>
|
||||
|
||||
<text x="60" y="443" class="dim">Thumb encoding: imm8 byte first, opcode 0x21 second</text>
|
||||
|
||||
<!-- Hack 2 -->
|
||||
<rect x="40" y="490" width="1120" height="290" rx="8" class="pnl"/>
|
||||
<text x="600" y="528" text-anchor="middle" class="sub">Hack 2: Invert Button Logic</text>
|
||||
|
||||
<text x="60" y="568" class="txt">Target: eor.w r3, r3, #1</text>
|
||||
<text x="60" y="598" class="dim">at address 0x10000286 (offset 0x286)</text>
|
||||
|
||||
<rect x="60" y="618" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="653" class="red">Before: 83 F0 01 03</text>
|
||||
|
||||
<rect x="620" y="618" width="520" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="640" y="653" class="grn">After: 83 F0 00 03</text>
|
||||
|
||||
<text x="60" y="703" class="dim">Byte at offset 0x288:</text>
|
||||
<text x="380" y="703" class="red">01</text>
|
||||
<text x="430" y="703" class="txt">-></text>
|
||||
<text x="470" y="703" class="grn">00</text>
|
||||
|
||||
<text x="60" y="738" class="txt">XOR with 0 = no invert</text>
|
||||
<text x="60" y="758" class="dim">LED now ON by default, OFF when pressed</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,112 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Static Vars & GPIO Input</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Static variables, GPIO input, hacking</text>
|
||||
|
||||
<!-- Static vs Auto Table -->
|
||||
<rect x="40" y="110" width="540" height="300" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Static vs Auto</text>
|
||||
|
||||
<text x="60" y="188" class="cyn">Aspect</text>
|
||||
<text x="260" y="188" class="red">Auto</text>
|
||||
<text x="420" y="188" class="grn">Static</text>
|
||||
|
||||
<line x1="60" y1="198" x2="560" y2="198" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text x="60" y="228" class="txt">Where</text>
|
||||
<text x="260" y="228" class="red">Stack</text>
|
||||
<text x="420" y="228" class="grn">.data</text>
|
||||
|
||||
<text x="60" y="258" class="txt">Life</text>
|
||||
<text x="260" y="258" class="red">Scope</text>
|
||||
<text x="420" y="258" class="grn">Forever</text>
|
||||
|
||||
<text x="60" y="288" class="txt">Init</text>
|
||||
<text x="260" y="288" class="red">Every</text>
|
||||
<text x="420" y="288" class="grn">Once</text>
|
||||
|
||||
<text x="60" y="318" class="txt">Keeps?</text>
|
||||
<text x="260" y="318" class="red">No</text>
|
||||
<text x="420" y="318" class="grn">Yes</text>
|
||||
|
||||
<text x="60" y="348" class="txt">Optimized?</text>
|
||||
<text x="260" y="348" class="red">Often</text>
|
||||
<text x="420" y="348" class="grn">In RAM</text>
|
||||
|
||||
<text x="60" y="388" class="dim">Compiler may remove auto vars</text>
|
||||
|
||||
<!-- GPIO Input -->
|
||||
<rect x="620" y="110" width="540" height="300" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">GPIO Input Setup</text>
|
||||
|
||||
<text x="640" y="188" class="grn">1.</text>
|
||||
<text x="680" y="188" class="txt">gpio_init(pin)</text>
|
||||
|
||||
<text x="640" y="223" class="grn">2.</text>
|
||||
<text x="680" y="223" class="txt">gpio_set_dir(pin, GPIO_IN)</text>
|
||||
|
||||
<text x="640" y="258" class="grn">3.</text>
|
||||
<text x="680" y="258" class="txt">gpio_pull_up(pin)</text>
|
||||
|
||||
<text x="640" y="293" class="grn">4.</text>
|
||||
<text x="680" y="293" class="txt">gpio_get(pin)</text>
|
||||
|
||||
<text x="640" y="338" class="dim">Pull-up: released=HIGH</text>
|
||||
<text x="640" y="363" class="dim">pressed=LOW (inverted!)</text>
|
||||
<text x="640" y="388" class="dim">Internal R, no hardware</text>
|
||||
|
||||
<!-- Key Assembly -->
|
||||
<rect x="40" y="430" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="310" y="468" text-anchor="middle" class="sub">Key Instructions</text>
|
||||
|
||||
<text x="60" y="508" class="amb">ubfx r3,r3,#15,#1</text>
|
||||
<text x="60" y="533" class="dim">Extract single GPIO bit</text>
|
||||
|
||||
<text x="60" y="568" class="red">eor.w r3,r3,#1</text>
|
||||
<text x="60" y="593" class="dim">XOR to invert logic</text>
|
||||
|
||||
<text x="60" y="618" class="cyn">b.n 0x10000264</text>
|
||||
|
||||
<!-- Hacking Workflow -->
|
||||
<rect x="620" y="430" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="890" y="468" text-anchor="middle" class="sub">Hacking Workflow</text>
|
||||
|
||||
<text x="640" y="508" class="grn">1.</text>
|
||||
<text x="680" y="508" class="txt">Analyze in GDB</text>
|
||||
|
||||
<text x="640" y="538" class="grn">2.</text>
|
||||
<text x="680" y="538" class="txt">Calculate offset</text>
|
||||
|
||||
<text x="640" y="568" class="grn">3.</text>
|
||||
<text x="680" y="568" class="txt">Patch .bin in HxD</text>
|
||||
|
||||
<text x="640" y="598" class="grn">4.</text>
|
||||
<text x="680" y="598" class="txt">uf2conv.py + flash</text>
|
||||
|
||||
<!-- Key Takeaways -->
|
||||
<rect x="40" y="650" width="1120" height="130" rx="8" class="pnl"/>
|
||||
<text x="600" y="688" text-anchor="middle" class="sub">Takeaways</text>
|
||||
|
||||
<rect x="60" y="708" width="340" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="230" y="740" text-anchor="middle" class="red">42 -> 43 (1 byte)</text>
|
||||
|
||||
<rect x="420" y="708" width="340" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="590" y="740" text-anchor="middle" class="grn">XOR 1->0 (invert)</text>
|
||||
|
||||
<rect x="780" y="708" width="360" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="960" y="740" text-anchor="middle" class="amb">offset = addr - base</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -1,6 +1,6 @@
|
||||
# 📘 Week 7: Constants in Embedded Systems: Debugging and Hacking Constants w/ 1602 LCD I2C Basics
|
||||
# Week 7: Constants in Embedded Systems: Debugging and Hacking Constants w/ 1602 LCD I2C Basics
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand the difference between `#define` macros and `const` variables
|
||||
@@ -385,7 +385,7 @@ Embedded-Hacking/
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 7: Hands-On Tutorial - Constants and I2C LCD
|
||||
## Part 7: Hands-On Tutorial - Constants and I2C LCD
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
@@ -463,7 +463,7 @@ OTHER_FAV_NUM: 1337
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 8: Debugging with GDB (Dynamic Analysis)
|
||||
## Part 8: Debugging with GDB (Dynamic Analysis)
|
||||
|
||||
> ? **REVIEW:** This setup is identical to previous weeks. If you need a refresher on OpenOCD and GDB connection, refer back to Week 3 Part 6.
|
||||
|
||||
@@ -471,24 +471,20 @@ OTHER_FAV_NUM: 1337
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0017_constants.elf
|
||||
```
|
||||
|
||||
**Connect to target:**
|
||||
|
||||
```gdb
|
||||
(gdb) target remote :3333
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
@@ -695,7 +691,7 @@ i r r0 r1
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 9: Understanding the Assembly
|
||||
## Part 9: Understanding the Assembly
|
||||
|
||||
Now that we've explored the binary in GDB, let's make sense of the key patterns we found.
|
||||
|
||||
@@ -766,7 +762,7 @@ These are stored consecutively in the `.rodata` section. Note the addresses - we
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 10: Hacking the Binary with a Hex Editor
|
||||
## Part 10: Hacking the Binary with a Hex Editor
|
||||
|
||||
Now for the fun part - we'll patch the `.bin` file directly using a hex editor!
|
||||
|
||||
@@ -870,19 +866,19 @@ From our GDB analysis in Step 10, we found the string at `0x10003ee8`. File offs
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Part 11: Converting and Flashing the Hacked Binary
|
||||
## Part 11: Converting and Flashing the Hacked Binary
|
||||
|
||||
### Step 21: Convert to UF2 Format
|
||||
|
||||
Open a terminal and navigate to your project directory:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0017_constants
|
||||
```
|
||||
|
||||
Run the conversion command:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
python ..\uf2conv.py build\0x0017_constants-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
@@ -909,11 +905,11 @@ OTHER_FAV_NUM: 1337
|
||||
|
||||
The numbers are unchanged - we only patched the LCD string!
|
||||
|
||||
🎉 **BOOM! We successfully changed the LCD text from "Reverse" to "Exploit" without access to the source code!**
|
||||
**BOOM! We successfully changed the LCD text from "Reverse" to "Exploit" without access to the source code!**
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 12: Summary and Review
|
||||
## Part 12: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -991,7 +987,7 @@ The numbers are unchanged - we only patched the LCD string!
|
||||
|
||||
---
|
||||
|
||||
## 💡 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **#define is text replacement** - It happens before compilation, no memory used.
|
||||
|
||||
@@ -1015,7 +1011,7 @@ The numbers are unchanged - we only patched the LCD string!
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ----------------------- | --------------------------------------------------- |
|
||||
@@ -1036,7 +1032,7 @@ The numbers are unchanged - we only patched the LCD string!
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### I2C Timing Reference
|
||||
|
||||
@@ -1078,3 +1074,4 @@ The numbers are unchanged - we only patched the LCD string!
|
||||
Happy hacking! ?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 📘 Week 9: Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics.
|
||||
# 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
|
||||
## 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)
|
||||
@@ -380,7 +380,7 @@ Embedded-Hacking/
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 11: Hands-On Tutorial - The Operators Code
|
||||
## Part 11: Hands-On Tutorial - The Operators Code
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
@@ -485,18 +485,14 @@ Humidity: 51.0%, Temperature: 23.8 deg C
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 12: Debugging with GDB
|
||||
## Part 12: Debugging with GDB
|
||||
|
||||
### Step 5: Start OpenOCD (Terminal 1)
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.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.
|
||||
@@ -505,7 +501,7 @@ You should see output indicating OpenOCD connected successfully to your Pico 2 v
|
||||
|
||||
Open a **new terminal** and launch GDB with the binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x001a_operators.elf
|
||||
```
|
||||
|
||||
@@ -514,7 +510,7 @@ arm-none-eabi-gdb build\0x001a_operators.elf
|
||||
Inside GDB, type:
|
||||
|
||||
```
|
||||
target remote :3333
|
||||
target extended-remote :3333
|
||||
```
|
||||
|
||||
This connects GDB to OpenOCD.
|
||||
@@ -640,13 +636,13 @@ The program will loop, printing values to serial.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 13: Setting Up Ghidra for Analysis
|
||||
## Part 13: Setting Up Ghidra for Analysis
|
||||
|
||||
### Step 17: Start Ghidra
|
||||
|
||||
Open a terminal and type:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
@@ -686,7 +682,7 @@ Wait for analysis to complete.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 14: Finding the Reset_Handler
|
||||
## Part 14: Finding the Reset_Handler
|
||||
|
||||
### Step 22: Understand the Vector Table
|
||||
|
||||
@@ -773,7 +769,7 @@ Look at the end of Reset_Handler for three function calls. The middle one is `ma
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 15: Resolving Functions in Ghidra
|
||||
## Part 15: Resolving Functions in Ghidra
|
||||
|
||||
### Step 28: Resolve stdio_init_all
|
||||
|
||||
@@ -859,7 +855,7 @@ bl FUN_xxxxx ; puts
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 16: Understanding IEEE-754 Floating-Point
|
||||
## Part 16: Understanding IEEE-754 Floating-Point
|
||||
|
||||
### What is IEEE-754?
|
||||
|
||||
@@ -927,7 +923,7 @@ print(f"Bytes: {encoded.hex()}") # 0000 80bf
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 17: Finding the Temperature Hack Point
|
||||
## Part 17: Finding the Temperature Hack Point
|
||||
|
||||
### Step 34: Locate the dht11_read Function
|
||||
|
||||
@@ -972,7 +968,7 @@ Make note of these offsets in the binary file:
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 18: Manual Hacking in Ghidra
|
||||
## Part 18: Manual Hacking in Ghidra
|
||||
|
||||
### Step 37: Open the Bytes Editor
|
||||
|
||||
@@ -1011,7 +1007,7 @@ print(f"New: {new}") # 5.0
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Part 19: Exporting and Testing
|
||||
## Part 19: Exporting and Testing
|
||||
|
||||
### Step 41: Export the Patched Binary
|
||||
|
||||
@@ -1025,7 +1021,7 @@ print(f"New: {new}") # 5.0
|
||||
|
||||
Open a terminal and run:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators
|
||||
python ..\uf2conv.py build\0x001a_operators-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
@@ -1040,7 +1036,7 @@ You should see dramatically increased temperature readings!
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 20: Summary and Review
|
||||
## Part 20: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -1084,7 +1080,7 @@ You should see dramatically increased temperature readings!
|
||||
|
||||
---
|
||||
|
||||
## 💡 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Post-increment returns the OLD value** - `x++` gives you x, THEN adds 1
|
||||
|
||||
@@ -1106,7 +1102,7 @@ You should see dramatically increased temperature readings!
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ------------------ | --------------------------------------------------- |
|
||||
@@ -1131,7 +1127,7 @@ You should see dramatically increased temperature readings!
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### IEEE-754 Float Quick Reference
|
||||
|
||||
@@ -1158,7 +1154,7 @@ You should see dramatically increased temperature readings!
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Real-World Implications
|
||||
## Real-World Implications
|
||||
|
||||
### Why This Matters
|
||||
|
||||
@@ -1188,3 +1184,4 @@ By manipulating sensor readings, an attacker could:
|
||||
Happy hacking! ?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 📘 Week 10: Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
|
||||
# Week 10: Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand the difference between static and dynamic conditionals in C
|
||||
@@ -468,7 +468,7 @@ Embedded-Hacking/
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 9: Hands-On Tutorial - Static Conditionals Code
|
||||
## Part 9: Hands-On Tutorial - Static Conditionals Code
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
@@ -572,18 +572,14 @@ one
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 10: Debugging with GDB (Static Conditionals)
|
||||
## Part 10: Debugging with GDB (Static Conditionals)
|
||||
|
||||
### Step 5: Start OpenOCD (Terminal 1)
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.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.
|
||||
@@ -592,7 +588,7 @@ You should see output indicating OpenOCD connected successfully to your Pico 2 v
|
||||
|
||||
Open a **new terminal** and launch GDB with the binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x001d_static-conditionals.elf
|
||||
```
|
||||
|
||||
@@ -601,7 +597,7 @@ arm-none-eabi-gdb build\0x001d_static-conditionals.elf
|
||||
In GDB, connect to OpenOCD:
|
||||
|
||||
```gdb
|
||||
target remote :3333
|
||||
target extended-remote :3333
|
||||
```
|
||||
|
||||
### Step 8: Halt the Running Binary
|
||||
@@ -704,13 +700,13 @@ quit
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 11: Setting Up Ghidra for Static Conditionals
|
||||
## Part 11: Setting Up Ghidra for Static Conditionals
|
||||
|
||||
### Step 17: Start Ghidra
|
||||
|
||||
Open a terminal and type:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
@@ -750,7 +746,7 @@ Wait for analysis to complete.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 12: Resolving Functions in Ghidra (Static)
|
||||
## Part 12: Resolving Functions in Ghidra (Static)
|
||||
|
||||
### Step 22: Navigate to Main
|
||||
|
||||
@@ -827,7 +823,7 @@ bl FUN_xxxxx ; sleep_ms
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 13: Hacking Static Conditionals
|
||||
## Part 13: Hacking Static Conditionals
|
||||
|
||||
### Step 28: Open the Bytes Editor
|
||||
|
||||
@@ -881,7 +877,7 @@ Find the sleep_ms delay value:
|
||||
|
||||
Convert and flash:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001d_static-conditionals
|
||||
python ..\uf2conv.py build\0x001d_static-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
@@ -901,7 +897,7 @@ fun
|
||||
|
||||
---
|
||||
|
||||
## 📌 Part 14: Dynamic Conditionals - The Source Code
|
||||
## Part 14: Dynamic Conditionals - The Source Code
|
||||
|
||||
### Step 34: Review the Dynamic Code
|
||||
|
||||
@@ -972,18 +968,14 @@ int main(void) {
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 15: Debugging with GDB (Dynamic Conditionals)
|
||||
## Part 15: Debugging with GDB (Dynamic Conditionals)
|
||||
|
||||
### Step 37: Start OpenOCD (Terminal 1)
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.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.
|
||||
@@ -992,7 +984,7 @@ You should see output indicating OpenOCD connected successfully to your Pico 2 v
|
||||
|
||||
Open a **new terminal** and launch GDB with the binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
|
||||
```
|
||||
|
||||
@@ -1001,7 +993,7 @@ arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
|
||||
In GDB, connect to OpenOCD:
|
||||
|
||||
```gdb
|
||||
target remote :3333
|
||||
target extended-remote :3333
|
||||
```
|
||||
|
||||
### Step 40: Halt the Running Binary
|
||||
@@ -1103,7 +1095,7 @@ quit
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 16: Setting Up Ghidra for Dynamic Conditionals
|
||||
## Part 16: Setting Up Ghidra for Dynamic Conditionals
|
||||
|
||||
### Step 49: Create New Project
|
||||
|
||||
@@ -1159,7 +1151,7 @@ This confirms it's a UART initialization function!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 17: Understanding Branch Instructions
|
||||
## Part 17: Understanding Branch Instructions
|
||||
|
||||
### ARM Branch Instructions
|
||||
|
||||
@@ -1207,7 +1199,7 @@ skip_printf:
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 18: Advanced Hacking - Creating Stealth Commands
|
||||
## Part 18: Advanced Hacking - Creating Stealth Commands
|
||||
|
||||
### The Goal
|
||||
|
||||
@@ -1301,7 +1293,7 @@ Little-endian: 00 00 f0 41
|
||||
1. Export as `0x0020_dynamic-conditionals-h.bin`
|
||||
2. Convert to UF2:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals
|
||||
python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
@@ -1314,7 +1306,7 @@ python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 -
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 19: Summary and Review
|
||||
## Part 19: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -1380,7 +1372,7 @@ python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 -
|
||||
|
||||
---
|
||||
|
||||
## 💡 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Static conditionals have fixed outcomes** - The same path always executes
|
||||
|
||||
@@ -1404,7 +1396,7 @@ python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 -
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ----------------------- | --------------------------------------------------- |
|
||||
@@ -1422,7 +1414,7 @@ python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 -
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### ASCII Reference Table
|
||||
|
||||
@@ -1464,7 +1456,7 @@ python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 -
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Real-World Implications
|
||||
## Real-World Implications
|
||||
|
||||
### Why Stealth Commands Matter
|
||||
|
||||
@@ -1502,3 +1494,4 @@ A fast-moving servo is like a nuclear fuel rod:
|
||||
Happy hacking! ?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 📘 Week 11: Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics
|
||||
# Week 11: Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand C structures (structs) and how they organize related data
|
||||
@@ -476,7 +476,7 @@ Embedded-Hacking/
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 9: Hands-On Tutorial - Structures Code
|
||||
## Part 9: Hands-On Tutorial - Structures Code
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
@@ -588,18 +588,14 @@ int main(void) {
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 10: Debugging with GDB (Structures)
|
||||
## Part 10: Debugging with GDB (Structures)
|
||||
|
||||
### Step 5: Start OpenOCD (Terminal 1)
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.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.
|
||||
@@ -608,7 +604,7 @@ You should see output indicating OpenOCD connected successfully to your Pico 2 v
|
||||
|
||||
Open a **new terminal** and launch GDB with the binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0023_structures.elf
|
||||
```
|
||||
|
||||
@@ -617,7 +613,7 @@ arm-none-eabi-gdb build\0x0023_structures.elf
|
||||
In GDB, connect to OpenOCD:
|
||||
|
||||
```gdb
|
||||
target remote :3333
|
||||
target extended-remote :3333
|
||||
```
|
||||
|
||||
### Step 8: Halt the Running Binary
|
||||
@@ -724,13 +720,13 @@ quit
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Part 11: Setting Up Ghidra for Structures
|
||||
## Part 11: Setting Up Ghidra for Structures
|
||||
|
||||
### Step 17: Start Ghidra
|
||||
|
||||
Open a terminal and type:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
@@ -769,7 +765,7 @@ Wait for analysis to complete.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Part 12: Resolving Functions - Structures Project
|
||||
## Part 12: Resolving Functions - Structures Project
|
||||
|
||||
### Step 22: Navigate to Main
|
||||
|
||||
@@ -858,7 +854,7 @@ bl FUN_xxxxx ; sleep_ms
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 13: Recognizing Struct Patterns in Assembly
|
||||
## Part 13: Recognizing Struct Patterns in Assembly
|
||||
|
||||
### Step 29: Identify GPIO Set Direction
|
||||
|
||||
@@ -896,7 +892,7 @@ Create a mental (or written) map:
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 14: Hacking Structures
|
||||
## Part 14: Hacking Structures
|
||||
|
||||
### Step 31: Open the Bytes Editor
|
||||
|
||||
@@ -935,7 +931,7 @@ LED 2 (0x18) -> GPIO 16 -> Red LED (SWAPPED!)
|
||||
|
||||
Convert and flash:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0023_structures
|
||||
python ..\uf2conv.py build\0x0023_structures-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
@@ -952,7 +948,7 @@ python ..\uf2conv.py build\0x0023_structures-h.bin --base 0x10000000 --family 0x
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 15: Security Implications - Log Desynchronization
|
||||
## Part 15: Security Implications - Log Desynchronization
|
||||
|
||||
### The Danger of Mismatched Logs
|
||||
|
||||
@@ -990,7 +986,7 @@ Our LED example demonstrates the same principle:
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 16: Functions Project - Advanced Code
|
||||
## Part 16: Functions Project - Advanced Code
|
||||
|
||||
### Step 35: Review the Functions Code
|
||||
|
||||
@@ -1084,18 +1080,14 @@ int process_ir_led_command(int ir_command, simple_led_ctrl_t *leds, uint8_t blin
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Part 17: Debugging with GDB (Functions)
|
||||
## Part 17: Debugging with GDB (Functions)
|
||||
|
||||
### Step 38: Start OpenOCD (Terminal 1)
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```cmd
|
||||
openocd -s "%USERPROFILE%\.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.
|
||||
@@ -1104,7 +1096,7 @@ You should see output indicating OpenOCD connected successfully to your Pico 2 v
|
||||
|
||||
Open a **new terminal** and launch GDB with the binary:
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
arm-none-eabi-gdb build\0x0026_functions.elf
|
||||
```
|
||||
|
||||
@@ -1113,7 +1105,7 @@ arm-none-eabi-gdb build\0x0026_functions.elf
|
||||
In GDB, connect to OpenOCD:
|
||||
|
||||
```gdb
|
||||
target remote :3333
|
||||
target extended-remote :3333
|
||||
```
|
||||
|
||||
### Step 41: Halt the Running Binary
|
||||
@@ -1213,7 +1205,7 @@ quit
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 18: Analyzing .ELF Files in Ghidra
|
||||
## Part 18: Analyzing .ELF Files in Ghidra
|
||||
|
||||
### Step 50: Create New Ghidra Project
|
||||
|
||||
@@ -1246,7 +1238,7 @@ With .ELF files, you get more information:
|
||||
|
||||
---
|
||||
|
||||
## ✏️ Part 19: Hacking the Functions Project
|
||||
## Part 19: Hacking the Functions Project
|
||||
|
||||
### Step 53: Find LED Pin Values
|
||||
|
||||
@@ -1288,7 +1280,7 @@ Button 3 -> LED 3 -> GPIO 16 -> Red (SWAPPED!)
|
||||
|
||||
### Step 56: Convert and Flash
|
||||
|
||||
```powershell
|
||||
```cmd
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions
|
||||
python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
@@ -1305,7 +1297,7 @@ python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 20: Summary and Review
|
||||
## Part 20: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
@@ -1384,7 +1376,7 @@ python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe
|
||||
|
||||
---
|
||||
|
||||
## 💡 Key Takeaways
|
||||
## Key Takeaways
|
||||
|
||||
1. **Structs group related data** - Better organization than separate variables
|
||||
|
||||
@@ -1408,7 +1400,7 @@ python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| -------------------------- | -------------------------------------------------- |
|
||||
@@ -1426,7 +1418,7 @@ python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
## Additional Resources
|
||||
|
||||
### NEC IR Command Reference
|
||||
|
||||
@@ -1459,7 +1451,7 @@ python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Real-World Implications
|
||||
## Real-World Implications
|
||||
|
||||
### What You've Learned in This Course
|
||||
|
||||
@@ -1502,3 +1494,4 @@ This is just the beginning:
|
||||
Happy hacking! ?
|
||||
|
||||
|
||||
|
||||
|
||||