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

3.5 KiB

Embedded Systems Reverse Engineering

Repository

Week 1

Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts

Non-Credit Practice Exercise 4 Solution: Connect GDB & Basic Exploration

Answers

Question 1: GDB Connection
  • Was GDB able to connect to OpenOCD? Yes, via target extended-remote localhost:3333
  • Did program stop at breakpoint? Yes, at Breakpoint 1, main () at ../0x0001_hello-world.c:4
Question 2: Memory Address of main
  • Address of main's first instruction: 0x10000234
  • Flash or RAM? Flash memory - the address starts with 0x10000... (XIP region starting at 0x10000000)
Question 3: Stack Pointer Value
  • SP value at main: 0x20082000
  • Flash or RAM? RAM - the address starts with 0x20000... (SRAM starts at 0x20000000)
Question 4: First Instruction
  • First instruction in main: push {r3, lr}
  • What does it do? Saves register r3 and the Link Register (lr) onto the stack. This preserves the return address so main() can call other functions (like stdio_init_all() and __wrap_puts) and they can properly use lr themselves.
Question 5: Comparison to Ghidra

Yes, they match. The GDB disassembly output is identical to what Ghidra shows in the Listing View. Both static analysis (Ghidra) and dynamic analysis (GDB) reveal the same instructions.

Register Values at Breakpoint
Register Value Description
pc 0x10000234 Program Counter - at start of main (Flash)
sp 0x20082000 Stack Pointer - top of stack (RAM)
lr 0x1000018f Link Register - return address after main
r0 0x0 General Purpose - will hold function arguments
r1 0x10000235 General Purpose
r2 0x80808080 General Purpose
r3 0xe000ed08 General Purpose
Full Disassembly of main
0x10000234 <+0>:     push    {r3, lr}           # Save registers to stack
0x10000236 <+2>:     bl      0x1000156c <stdio_init_all>  # Initialize I/O
0x1000023a <+6>:     ldr     r0, [pc, #8]       # Load string pointer
0x1000023c <+8>:     bl      0x100015fc <__wrap_puts>     # Print string
0x10000240 <+12>:    b.n     0x1000023a <main+6>          # Infinite loop
0x10000242 <+14>:    nop
0x10000244 <+16>:    (data: pointer to string)
GDB Connection Sequence
Terminal 1: openocd -s "..." -f interface/cmsis-dap.cfg -f target/rp2350.cfg
Terminal 2: arm-none-eabi-gdb build/0x0001_hello-world.elf
(gdb) target extended-remote localhost:3333
(gdb) monitor reset halt
(gdb) b main
(gdb) c
(gdb) disassemble main
(gdb) i r

Reflection Answers

  1. Why does the stack pointer start at 0x20082000? The initial stack pointer value comes from the first entry in the vector table at 0x10000000. The linker script sets __StackTop to 0x20082000, which is the top of the SCRATCH_Y region in SRAM. The stack grows downward from this address.

  2. Why does push {r3, lr} save r3 even though it doesn't seem to be used? ARM requires 8-byte stack alignment. Pushing lr alone would only move SP by 4 bytes. Including r3 ensures the stack remains 8-byte aligned, which is required by the ARM Architecture Procedure Call Standard (AAPCS).

  3. How does the infinite loop work? The instruction at 0x10000240 is b.n 0x1000023a - an unconditional branch back to main+6, which reloads the string pointer and calls __wrap_puts again. The function never returns.