mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-06-02 04:21:39 +02:00
Update WEEK06
This commit is contained in:
+42
-45
@@ -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!
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user