gdb::pwndbg

tool gdb · pwndbg dynamic analysis
StartBreakpointsRun & Step InspectMemoryStack pwndbgPatchGEF ScriptsCTF Tips
01Start & Load
Launch
# Load binary
gdb ./challenge
gdb -q ./challenge          # quiet (no banner)
gdb -q -ex "run" ./challenge  # run immediately

# With arguments
gdb --args ./challenge arg1 arg2

# Attach to running process
gdb -p <pid>
gdb ./challenge <pid>

# Load core dump
gdb ./challenge core

# Inside GDB: load file
(gdb) file ./challenge
(gdb) core core.dump

# Intel syntax (default is AT&T)
(gdb) set disassembly-flavor intel
# Put in ~/.gdbinit to make permanent
~/.gdbinit recommended
# ~/.gdbinit — sensible defaults
set disassembly-flavor intel
set pagination off
set confirm off

# Auto-load pwndbg
source ~/pwndbg/gdbinit.py

# Or peda
source ~/peda/peda.py

# Or GEF
source ~/gef.py

# Install pwndbg
git clone https://github.com/pwndbg/pwndbg
cd pwndbg && ./setup.sh

# Install GEF (one-liner)
bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
02Breakpoints & Watchpoints
Set breakpoints
# By name
b main
b strcmp
b win_function

# By address
b *0x401234
b *main+42        # offset from symbol

# By file:line (if debug info)
b challenge.c:42

# Conditional breakpoint
b *0x401234 if $rdi == 0
b loop_func if i == 100

# Temporary (auto-delete after hit)
tbreak main

# Hardware breakpoint (for ROM/protected memory)
hbreak *0x401234

# Manage
info break         # list all
disable 2          # disable bp #2
enable  2
delete  2          # delete bp #2
delete             # delete all
clear  main        # clear by location
Watchpoints & catchpoints
# Watchpoint: break when memory changes
watch  *0x404060   # break on write
rwatch *0x404060   # break on read
awatch *0x404060   # break on read or write
watch  variable    # watch local variable

# Catchpoints: catch events
catch syscall      # any syscall
catch syscall read # specific syscall
catch syscall 0    # by number
catch exec         # catch exec()
catch fork         # catch fork()
catch throw        # C++ exception

# Commands on breakpoint hit
commands 1
  silent
  printf "rdi=%p\n", $rdi
  continue
end
03Run & Step
Execution control
# Start / restart
r                  # run
r arg1 arg2        # run with args
r < input.txt      # run with stdin from file
r <<< $(python3 -c "print('A'*100)")

# Step / continue
c                  # continue to next bp
c 3                # continue, ignore next 3 hits
n                  # next line (step over)
s                  # step (step into functions)
ni                 # next instruction (step over)
si                 # step instruction (step into)
finish             # run until function returns
until 0x401234     # run until address
advance main+100   # advance to location
jump  *0x401234    # jump to address (no call)
kill               # kill the process
q                  # quit gdb
Reverse debugging (rr)
# rr: record and replay execution
rr record ./challenge
rr replay

# Inside rr replay session:
reverse-continue   # (rc) go backwards
reverse-step       # (rs) step backwards
reverse-next       # (rn)
reverse-finish     # back to caller

# Set watchpoint then go backwards → find writer
watch *0x404060
rc                 # find who wrote this address

# Checkpoint: save execution state
checkpoint         # save
info checkpoints   # list
restart 1          # restore checkpoint 1
04Inspect State
Registers
# All registers
info registers      # (i r)
info all-registers  # include float/vector

# Single register
p $rax
p/x $rax            # hex
p/d $rax            # decimal
p/t $rax            # binary
p/c $rax            # char

# x86-64 calling convention registers
# rdi=arg1  rsi=arg2  rdx=arg3  rcx=arg4
# r8=arg5   r9=arg6   rax=return value
# rsp=stack ptr  rbp=frame ptr  rip=instr ptr

# Modify register
set $rax = 0
set $rip = 0x401234  # redirect execution
set $rsp = $rsp - 8  # move stack
Disassemble & functions
# Disassemble
disas              # current function
disas main
disas 0x401000, 0x401050
disas/r main       # with raw bytes

# x/i — disassemble N instructions from addr
x/10i $rip         # next 10 instructions
x/10i main
x/10i 0x401234

# List functions / symbols
info functions     # all known functions
info functions win # filter by name
info variables     # global variables
info address main  # address of symbol
info symbol 0x401234  # symbol at address
05Memory Examination
x command — examine memory
# Syntax: x/[N][FORMAT][SIZE] ADDR
# N      = count
# FORMAT = x hex | d dec | s string | i instr
#          c char | b binary | f float | u unsigned
# SIZE   = b byte | h halfword | w word | g giant(8)

x/20x  $rsp        # 20 hex words at stack
x/20xg $rsp        # 20 hex 8-byte (64-bit)
x/s    0x402010    # string at address
x/s    $rdi        # string arg1 points to
x/4xb  0x404060    # 4 raw bytes
x/10i  $rip        # 10 instructions
x/wx   &variable   # variable by name

# Print memory map
info proc mappings
vmmap              # pwndbg: colored map
Search memory
# pwndbg search
search -s "flag"    # string
search -b 0x41      # byte value
search -4 0xdeadbeef # 4-byte value
search -8 0x401234  # 8-byte (address)

# GDB find command
find 0x400000, 0x500000, "flag"
find 0x400000, +0x10000, 0x41, 0x42

# Dump memory to file
dump binary memory out.bin 0x400000 0x401000
dump hex memory    out.hex 0x400000 0x401000

# Write to memory
set {int}0x404060 = 0x41424344
set {char[5]}0x404060 = "AAAA"
06Stack & Frames
Stack inspection
# Backtrace (call stack)
bt                 # backtrace
bt full            # with local variables
bt 5               # only 5 frames

# Frame navigation
frame 0            # switch to frame 0
up                 # go up one frame
down               # go down one frame
info frame         # current frame details
info locals        # local variables
info args          # function arguments

# Stack canary: usually at rbp-0x8
x/gx $rbp-8        # read canary value

# pwndbg: visual stack
stack              # smart stack display
telescope $rsp 20  # resolve pointers
Find overflow offset
# pwndbg cyclic (de Bruijn pattern)
cyclic 200          # generate 200-char pattern
r <<< $(cyclic 200)  # run with pattern as input
# → SIGSEGV at 0x6161616e
cyclic -l 0x6161616e # → offset = 44
cyclic -l $rsp       # if RSP contains pattern

# Manual: what's at rsp on crash?
x/gx $rsp           # read return address
# If it shows pattern bytes → leak offset

# Check offset for 32-bit (eip)
cyclic -l $eip
cyclic -l 0x61616165
07pwndbg-Specific Commands
pwndbgContext & navigation
# Context view (auto on break)
context            # full: regs + stack + code
context regs
context stack
context code
context backtrace

# Memory layout
vmmap              # all mappings with perms
vmmap libc         # filter by name
piebase            # PIE base address
libcbase           # libc base address
aslr               # ASLR status
checksec           # mitigations

# Pointer resolution
telescope $rsp 20  # smart pointer chain
telescope 0x404060
dereference $rsp 10 # dereference chain
pwndbgHeap & ROP
# Heap analysis
heap               # all chunks
heap -v            # verbose
bins               # all freelist bins
fastbins           # fastbin list
smallbins
tcache             # tcache bins (glibc 2.26+)
vis_heap_chunks    # visual heap layout
malloc_chunk addr  # parse chunk struct
arena              # main_arena info

# ROP gadgets
rop                # find ROP gadgets
ropper             # alias
got                # GOT table entries
plt                # PLT entries
canary             # stack canary value
08Patching & Modifying Execution
Patch bytes & values
# NOP an instruction (0x90 = NOP x86)
set *(unsigned char*)0x401234 = 0x90
# NOP a sequence
set {char[6]}0x401234 = "\x90\x90\x90\x90\x90\x90"

# Change JNE (0x75) to JE (0x74) — invert branch
set *(unsigned char*)0x401234 = 0x74

# Change JNE → JMP (0xeb) — always jump
set *(unsigned char*)0x401234 = 0xeb

# Force return value
set $rax = 0       # return 0 (success)
set $rax = 1

# Skip function: advance past it
set $rip = 0x401250  # jump over check

# pwndbg patch command
patch 0x401234 "nop; nop"
patch byte 0x401234 0x90
Call & signal
# Call a function directly
call (void)win_function()
call (int)strcmp("hello", "world")
call (void*)malloc(256)

# Signal handling
handle SIGSEGV nostop     # don't stop on SIGSEGV
handle SIGALRM ignore     # ignore alarm (anti-debug)
handle all nostop noprint # ignore all signals
info signals

# Fork following
set follow-fork-mode child   # follow child
set follow-fork-mode parent
set detach-on-fork off       # debug both
09GEF Extras (if using GEF)
GEF-specific commands
# Pattern (like cyclic)
pattern create 200
pattern search $rsp
pattern search 0x61616165

# Memory
xinfo $rip         # info about address
memory watch 0x404060 4 # watch 4 bytes
highlight add 0x404060

# Heap (GEF version)
heap chunks
heap bins
heap arenas

# Assemble / disassemble
assemble           # interactive assembler
assemble -a x64 "xor rax,rax; ret"

# libc resolver
got                # GOT with resolved names
xfiles             # loaded files/libraries
Format & print
# p — print expressions
p 0xff + 1         # → 256
p (int)$rax
p (char*)$rdi      # cast register to string
p &global_var      # address of symbol

# Format specifiers for p
p/x  $rax          # hex
p/d  $rax          # decimal signed
p/u  $rax          # decimal unsigned
p/t  $rax          # binary
p/o  $rax          # octal
p/c  $rax          # character
p/f  $xmm0         # float
p/a  0x401234      # address + symbol name
10Scripting GDB
GDB scripting
# Run commands from file
gdb -x cmds.gdb ./challenge

# cmds.gdb:
b main
r
p $rdi
x/s $rdi
c
quit

# Inline with -ex
gdb -q -ex "b main" -ex "r" -ex "p \$rax" ./challenge

# Python scripting inside GDB
(gdb) python
import gdb
frame = gdb.selected_frame()
rax = frame.read_register('rax')
print(f"rax = {int(rax):#x}")
end

# Python script file
gdb -x script.py ./challenge
pwntools GDB integration
from pwn import *

# Launch with GDB attached (stops at entry)
p = gdb.debug('./challenge', '''
set follow-fork-mode child
break main
continue
''')

# Attach GDB to running process
p = process('./challenge')
gdb.attach(p, '''
break strcmp
continue
''')

# Pause to let you set breakpoints
p = process('./challenge')
gdb.attach(p)
pause()   # wait for Enter before continuing
11CTF Tips
Common CTF scenarios
ScenarioGDB Commands
Find strcmp args (flag comparison)b strcmprx/s $rdi / x/s $rsi
Find overflow offsetcyclic 200 → crash → cyclic -l $rsp
Bypass a checkb *0x401234set $rax = 0c
Patch a jne to jmpset *(char*)0x401234 = 0xeb
Leak libc addressb putsp $rip → compute base
Read stack canaryx/gx $rbp-8
PIE: find basepiebase (pwndbg) or info proc mappings
Find /bin/sh in libcsearch -s "/bin/sh"
Trace all callscatch syscall + commands: bt; c
Anti-debug: SIGALRMhandle SIGALRM ignore
QUICK REFERENCE →  b func breakpoint  · r run  · ni/si step  · x/s $rdi string arg  · x/20gx $rsp stack  · telescope $rsp smart stack  · cyclic / cyclic -l offset  · vmmap memory map  · checksec mitigations  · set $rax=0 patch register