Debugging EmbSec Labs¶
This guide covers debugging techniques for EmbSec labs using GDB, QEMU, and specialized tools for embedded security research.
Overview¶
The debugging infrastructure provides:
- GDB Integration - Full symbolic debugging
- QEMU Support - Hardware-accurate emulation
- Exploit Development - Specialized helpers
- Automated Scripts - Streamlined workflow
Quick Start¶
# Debug a lab with GDB
make debug-01-buffer-overflow
# Debug with exploit helpers
make exploit-01-buffer-overflow
# Manual GDB session
arm-none-eabi-gdb build/labs/01-buffer-overflow/01-buffer-overflow
GDB Debugging¶
Basic Setup¶
The debug script automatically:
- Starts QEMU with GDB server
- Loads symbols from ELF file
- Sets up useful commands
- Breaks at main
# Start debug session
./tools/scripts/debug_lab.sh 01-buffer-overflow
# With custom port
./tools/scripts/debug_lab.sh -p 1235 01-buffer-overflow
GDB Commands¶
Essential commands for embedded debugging:
# Connection
target remote :1234 # Connect to QEMU
monitor system_reset # Reset target
# Execution
continue # Resume execution
step # Step into
next # Step over
finish # Step out
# Breakpoints
break main # Break at function
break *0x12345 # Break at address
watch *(int*)0x20000000 # Watchpoint
# Memory examination
x/32xw $sp # Stack contents
x/16i $pc # Disassembly
x/s 0x12345 # String at address
# Registers
info registers # All registers
info reg $sp $pc # Specific registers
set $r0 = 0x41414141 # Modify register
Custom Commands¶
The debug script provides helpers:
# Shortcuts
regs # Show all registers
stack # Display stack (32 words)
dis # Disassemble around PC
# Reset helpers
reset # Reset and continue
restart # Reset and break at main
# Memory helpers
xxd 0x20000000 # Hex dump 256 bytes
xxd 0x20000000 0x100 # Hex dump specified size
# Search
find_string "password" # Search memory for string
functions # List all functions
Exploit Development Mode¶
Enabling Exploit Mode¶
# Use -x flag
make exploit-01-buffer-overflow
# Or directly
./tools/scripts/debug_lab.sh -x 01-buffer-overflow
Exploit Helpers¶
Additional commands for vulnerability research:
# Pattern generation
pattern_create 100 # Cyclic pattern
pattern_offset Aa0A # Find offset
# Security features
checksec # Check protections
# ROP gadgets
ropgadget # Find useful gadgets
# Payload testing
send_payload "AAAA" # Send to stdin
Pattern Generation Example¶
Finding buffer overflow offset:
# Generate pattern
(gdb) pattern_create 100
Aa0Aa1Aa2Aa3Aa4Aa5...
# Send to program
(gdb) continue
Enter password: Aa0Aa1Aa2Aa3Aa4Aa5...
# Program crashes, check PC
(gdb) info reg $pc
pc 0x41613341
# Find offset
(gdb) pattern_offset 3Aa4
Offset: 72
QEMU Debugging Features¶
Monitor Commands¶
Access QEMU monitor:
# System control
monitor system_reset # Reset
monitor system_powerdown # Shutdown
monitor stop # Pause execution
# Memory info
monitor info registers # CPU state
monitor info mem # Memory mappings
# Devices
monitor info qtree # Device tree
monitor info irq # Interrupt state
Memory Regions¶
Typical memory map:
0x00000000 - 0x00040000 Flash (256KB)
0x20000000 - 0x20010000 SRAM (64KB)
0x40000000 - 0x44000000 Peripherals
0xE0000000 - 0xE0100000 System Control
Peripheral Access¶
Debug peripheral registers:
Debugging Workflows¶
1. Crash Analysis¶
When program crashes:
# Check crash location
(gdb) info reg $pc $lr $sp
# Examine stack
(gdb) bt
(gdb) x/32xw $sp
# Check last executed instruction
(gdb) x/i $pc-4
# Examine function
(gdb) disas $pc-20,$pc+20
2. Vulnerability Discovery¶
Finding buffer overflows:
# Set breakpoint before strcpy
(gdb) break strcpy
(gdb) commands
> x/s $r1
> continue
> end
# Watch for stack corruption
(gdb) watch *(int*)($sp+0x40)
# Break on return
(gdb) break *($lr)
3. Exploit Development¶
Developing working exploit:
# Find target function
(gdb) print &grant_access
$1 = 0x8001234
# Check Thumb bit
(gdb) set $target = 0x8001234 | 1
# Test payload
(gdb) set {int}($sp+72) = $target
(gdb) continue
4. Format String Analysis¶
Debugging format strings:
# Break at printf
(gdb) break printf
(gdb) commands
> x/s $r0
> x/8xw $sp
> continue
> end
# Find offset
(gdb) x/s $r0
"AAAA %x %x %x %x"
(gdb) x/8xw $sp
0x41414141 ... # Find position
Advanced Debugging¶
Hardware Breakpoints¶
ARM supports limited hardware breakpoints:
# Hardware breakpoint
(gdb) hbreak *0x8001234
# Hardware watchpoint
(gdb) watch -l *(int*)0x20001000
# Check available
(gdb) info breakpoints
Conditional Breakpoints¶
Break on specific conditions:
# Break when buffer contains pattern
(gdb) break vulnerable_function if *(int*)$r0 == 0x41414141
# Break on Nth call
(gdb) break malloc
(gdb) condition 1 $_hit_count == 5
Scripting GDB¶
Automate debugging tasks:
# Save to exploit.gdb
define exploit
# Reset target
monitor system_reset
# Break at vulnerability
break vulnerable_function
continue
# Send payload
set $payload = "A" * 72
set $target = 0x8001235
call (int)write(0, $payload, 72)
call (int)write(0, &$target, 4)
# Continue execution
continue
end
# Run script
(gdb) source exploit.gdb
(gdb) exploit
Python Extensions¶
Create powerful debugging scripts:
# gdb_helper.py
import gdb
class FindVulnCommand(gdb.Command):
def __init__(self):
super().__init__("find-vuln", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
# Search for unsafe functions
unsafe = ["strcpy", "gets", "sprintf"]
for func in unsafe:
try:
addr = gdb.parse_and_eval(f"&{func}")
print(f"Found {func} at {addr}")
except:
pass
FindVulnCommand()
Load in GDB:
Debugging Tips¶
1. Symbol Loading¶
Ensure symbols are loaded:
2. Stack Alignment¶
ARM requires aligned stack:
# Check alignment
(gdb) print $sp & 7
$1 = 0 # Good, aligned
# Fix if needed
(gdb) set $sp = $sp & ~7
3. Thumb Mode¶
Cortex-M uses Thumb exclusively:
4. Endianness¶
ARM is little-endian:
# Pack addresses correctly
(gdb) set {int}0x20001000 = 0x41424344
(gdb) x/4b 0x20001000
0x44 0x43 0x42 0x41 # "DCBA"
Common Issues¶
GDB Won't Connect¶
Solutions:
- Check QEMU is running
- Verify port isn't in use
- Try different port with
-p
No Symbols¶
Solutions:
- Load symbols:
file <binary> - Check binary has debug info
- Rebuild with
-gflag
Wrong Architecture¶
Solutions:
Can't Set Breakpoints¶
Solutions:
- Check address is valid
- Use hardware breakpoints
- Verify memory is mapped
Integration with Tools¶
IDA Pro Integration¶
Export symbols for IDA:
# Generate map file
arm-none-eabi-objdump -t binary > binary.map
# Generate listings
arm-none-eabi-objdump -d binary > binary.lst
Radare2 Integration¶
Debug with radare2:
Binary Ninja Integration¶
Remote debugging setup:
- Start QEMU with GDB
- Connect Binary Ninja debugger
- Set architecture to ARMv7
- Load at base 0x00000000
Debugging Resources¶
Memory Map Reference¶
| Region | Start | Size | Description |
|---|---|---|---|
| Flash | 0x00000000 | 256KB | Code, RO data |
| SRAM | 0x20000000 | 64KB | Stack, heap, data |
| Peripherals | 0x40000000 | 1MB | Memory-mapped I/O |
| System | 0xE0000000 | 1MB | NVIC, SysTick, etc |
Register Reference¶
| Register | Purpose | Notes |
|---|---|---|
| R0-R3 | Arguments/Return | Scratch |
| R4-R11 | Variables | Preserved |
| R12 | Scratch | IP register |
| R13 | Stack Pointer | SP |
| R14 | Link Register | Return address |
| R15 | Program Counter | PC |
Useful Memory Locations¶
Common locations to examine:
- Stack:
$spto$sp+0x100 - Return address:
*(int*)($sp+X) - Global data:
0x20000000+ - Heap (if used): After
.bss
Next Steps¶
- Testing - Test exploits automatically
- Building - Build with debug symbols
- Environment Setup - Install debugging tools