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

6.2 KiB

Embedded Systems Reverse Engineering

Repository

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) target extended-remote :3333
(gdb) monitor reset halt
Step 2: Examine 16 Vector Table Entries
(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) info symbol 0x1000015c

Expected output:

_reset_handler in section .text

Repeat for other addresses:

(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) 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) 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