mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-17 21:44:45 +02:00
210 lines
6.2 KiB
Markdown
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
|
|
```
|