intermediatecat/rev~2 min read

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.