Dynamic Analysis with GDB
Set breakpoints, inspect registers and memory, and step through a binary to find the flag at runtime.
// prerequisite reading
Why dynamic analysis
Some binaries compute the flag at runtime — decrypting it from an embedded blob, deriving it from a seed, or checking input byte-by-byte. Reading disassembly alone won’t give you the answer; you need to watch the program run.
Setup — pwndbg or PEDA
Vanilla GDB is bearable but pwndbg adds colour, context display, and heap/ROP helpers. Install once:
git clone https://github.com/pwndbg/pwndbg && cd pwndbg && ./setup.sh
Basic session
gdb ./challenge
# At the GDB prompt:
(gdb) break main # break on main
(gdb) run # start the program
(gdb) info registers # show all registers
(gdb) x/20s $rsp # examine 20 strings from the stack pointer
(gdb) x/32xb 0x401234 # 32 bytes in hex at address
(gdb) next # step over function call
(gdb) step # step into function call
(gdb) continue # run to next breakpoint
Breaking on a comparison
Once Ghidra shows you the comparison address (e.g., the memcmp call):
(gdb) break *0x401234
(gdb) run
# When the breakpoint hits:
(gdb) x/s $rdi # first argument — often the user input
(gdb) x/s $rsi # second argument — often the expected value
The second argument is your flag.
Conditional breakpoints
# Break only when rax == 0
(gdb) break *0x401234 if $rax == 0
Inspecting strings at runtime
(gdb) find /s 0x400000, 0x500000, "flag{"
Searches the mapped range for the flag prefix and prints every address where it appears.
ASLR and PIE
If the binary has PIE (Position-Independent Executable), load addresses change each run. Get the base at runtime:
(gdb) info proc mappings
Add the base to your Ghidra offset to find the runtime address.