# 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 : bkpt 0x0000 0x1000011c : bkpt 0x0000 0x1000011e : 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 ```