Files
Embedded-Hacking/WEEK03/WEEK03-03.md
T
2026-03-19 15:01:07 -04:00

210 lines
6.2 KiB
Markdown

# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 3
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
### Non-Credit Practice Exercise 3: Examine All Vectors
#### Objective
Examine the first 16 entries of the vector table to understand the exception handler layout, identify valid code addresses, and recognize the Thumb mode addressing convention.
#### Prerequisites
- Raspberry Pi Pico 2 with debug probe connected
- OpenOCD and `arm-none-eabi-gdb` available
- `build\0x0001_hello-world.elf` loaded
- Understanding of the vector table from Week 3 Part 4
- Knowledge of Thumb mode addressing (LSB = 1 indicates Thumb code)
#### Task Description
You will examine 16 consecutive 32-bit values from the vector table, decode each entry, determine if it's a valid code address, and identify which exception handler it points to.
#### Background Information
The ARM Cortex-M vector table structure:
| Offset | Vector # | Handler Name | Purpose |
|--------|----------|---------------------|---------|
| 0x00 | - | Initial SP | Stack pointer initialization |
| 0x04 | 1 | Reset | Power-on/reset entry point |
| 0x08 | 2 | NMI | Non-Maskable Interrupt |
| 0x0C | 3 | HardFault | Serious errors |
| 0x10 | 4 | MemManage | Memory protection fault |
| 0x14 | 5 | BusFault | Bus error |
| 0x18 | 6 | UsageFault | Undefined instruction, etc. |
| 0x1C-0x28 | 7-10 | Reserved | Not used |
| 0x2C | 11 | SVCall | Supervisor call |
| 0x30 | 12 | Debug Monitor | Debug events |
| 0x34 | 13 | Reserved | Not used |
| 0x38 | 14 | PendSV | Pendable service call |
| 0x3C | 15 | SysTick | System tick timer |
#### Step-by-Step Instructions
##### Step 1: Connect and Halt
```gdb
(gdb) target extended-remote :3333
(gdb) monitor reset halt
```
##### Step 2: Examine 16 Vector Table Entries
```gdb
(gdb) x/16x 0x10000000
```
**Expected output (example):**
```
0x10000000 <__vectors>: 0x20082000 0x1000015d 0x1000011b 0x1000011d
0x10000010 <__vectors+16>: 0x1000011f 0x10000121 0x10000123 0x00000000
0x10000020 <__vectors+32>: 0x00000000 0x00000000 0x00000000 0x10000125
0x10000030 <__vectors+48>: 0x00000000 0x00000000 0x10000127 0x10000129
```
##### Step 3: Analyze Each Entry
Create a table documenting each entry:
**Entry 1 (Offset 0x00):**
```
Address: 0x10000000
Value: 0x20082000
Valid Code Address? NO - This is the stack pointer (in RAM region 0x2xxxxxxx)
Handler: Initial Stack Pointer
```
**Entry 2 (Offset 0x04):**
```
Address: 0x10000004
Value: 0x1000015d
Valid Code Address? YES (starts with 0x1000...)
Thumb Mode? YES (LSB = 1, so actual address is 0x1000015c)
Handler: Reset Handler (_reset_handler)
```
**Entry 3 (Offset 0x08):**
```
Address: 0x10000008
Value: 0x1000011b
Valid Code Address? YES
Thumb Mode? YES (actual address: 0x1000011a)
Handler: NMI Handler (isr_nmi)
```
Continue this analysis for all 16 entries...
##### Step 4: Verify Handlers with Symbols
For each code address, check what function it points to:
```gdb
(gdb) info symbol 0x1000015c
```
**Expected output:**
```
_reset_handler in section .text
```
Repeat for other addresses:
```gdb
(gdb) info symbol 0x1000011a
(gdb) info symbol 0x1000011c
(gdb) info symbol 0x1000011e
```
##### Step 5: Examine Handler Code
Look at the actual code at each handler:
```gdb
(gdb) x/3i 0x1000011a
```
**Expected output for NMI handler:**
```
0x1000011a <isr_nmi>: bkpt 0x0000
0x1000011c <isr_hardfault>: bkpt 0x0000
0x1000011e <isr_svcall>: bkpt 0x0000
```
##### Step 6: Identify Reserved Entries
Note any entries with value `0x00000000`:
```
0x00000000 = Reserved/Unused vector
```
These slots are reserved by ARM and not used on Cortex-M33.
##### Step 7: Create a Complete Map
Document all 16 entries in this format:
| Offset | Value | Address Type | Actual Addr | Handler Name |
|--------|------------|--------------|-------------|------------------|
| 0x00 | 0x20082000 | Stack Ptr | N/A | __StackTop |
| 0x04 | 0x1000015d | Code (Thumb) | 0x1000015c | _reset_handler |
| 0x08 | 0x1000011b | Code (Thumb) | 0x1000011a | isr_nmi |
| 0x0C | 0x1000011d | Code (Thumb) | 0x1000011c | isr_hardfault |
| ... | ... | ... | ... | ... |
#### Expected Output
- First entry is the stack pointer in RAM (0x2xxxxxxx range)
- Entries 2-16 are mostly code addresses in flash (0x1000xxxx range)
- Code addresses have LSB = 1 (Thumb mode indicator)
- Reserved entries show 0x00000000
- Most handlers point to simple `bkpt` instructions (default handlers)
#### Questions for Reflection
###### Question 1: Why do all the code addresses end in odd numbers (LSB = 1)?
###### Question 2: What happens if an exception occurs for a reserved/null vector entry?
###### Question 3: Why do most exception handlers just contain `bkpt` instructions?
###### Question 4: How would you replace a default handler with your own custom handler?
#### Tips and Hints
- Use `x/32x 0x10000000` to see even more vectors (up to 48)
- Remember to subtract 1 from addresses before disassembling (remove Thumb bit)
- Use `info functions` to see all available handler symbols
- Compare GDB output with Ghidra's vector table view
#### Next Steps
- Set breakpoints at different exception handlers to see if they're ever called
- Trigger a fault intentionally to see which handler executes
- Move on to Exercise 4 to analyze your main function
#### Additional Challenge
Write a GDB script to automatically decode and display all vector table entries:
```gdb
(gdb) define vectors
> set $i = 0
> while $i < 16
> set $addr = 0x10000000 + ($i * 4)
> set $val = *(int*)$addr
> printf "[%2d] 0x%08x: 0x%08x", $i, $addr, $val
> if $i == 0
> printf " (Stack Pointer)\n"
> else
> if $val != 0
> if ($val & 0x10000000) == 0x10000000
> printf " -> 0x%08x\n", $val & 0xFFFFFFFE
> else
> printf " (Invalid/Reserved)\n"
> end
> else
> printf " (Reserved)\n"
> end
> end
> set $i = $i + 1
> end
> end
```