HackBlue

Tools · CTF categories for beginners · 12 / 18

GDB basics for CTF reversing: breakpoints, registers, memory, and stepping

Run a practice binary under gdb, set breakpoints on functions and addresses, inspect registers and memory, and step through a comparison to watch values change.

11 min read · practice only with authorization

Core commands

break sets breakpoints by function or address, run starts the program, continue resumes, stepi and nexti step one instruction, info registers shows registers, and x examines memory, as in x/s for a string or x/8gx for eight 64-bit values. disassemble shows the current function. Extensions such as GEF or pwndbg show registers, stack, and code together after each step.

Snippet
gdb -q ./crackme
(gdb) break main
(gdb) run
(gdb) disassemble
(gdb) break strcmp
(gdb) continue
(gdb) info registers rdi rsi
(gdb) x/s $rdi
(gdb) x/s $rsi
(gdb) finish
(gdb) print $rax

Calling convention reminder

On x86-64 Linux, the first function arguments go in rdi, rsi, rdx, rcx, r8, and r9, and the return value comes back in rax. So at a breakpoint on strcmp, the two strings being compared are at the addresses in rdi and rsi.

Lab: watch the key appear

Use the crackme from the first reversing lesson. Break on strcmp, run, type any input, and examine both arguments with x/s: one is your input, the other is the expected key. Then try the XOR version: set a breakpoint inside the loop at the compare instruction you found in Ghidra, and print the register holding the expected byte on each iteration with a breakpoint command list.

Snippet
(gdb) break *main+142
(gdb) commands
> silent
> printf "%c", $al
> continue
> end
(gdb) run <<< 'AAAAAAAAAAAA'

Tips

Use starti to stop at the very first instruction when main is hard to find. Set disable-randomization on (the default in gdb) to keep addresses stable while learning. Save useful commands in a .gdbinit file in the challenge folder, and only load .gdbinit files you wrote yourself.

Diagram

Debugging a comparison

  1. Break

    Set a breakpoint on the compare function or instruction.

  2. Run

    Supply test input.

  3. Inspect

    Read arguments in rdi and rsi, or the compared register.

  4. Step and confirm

    finish or stepi; check rax for the result.

Check yourself

1. On x86-64 Linux, which registers hold the first two function arguments?

2. Which gdb command prints memory at an address as a string?

3. Where is a function’s return value after it finishes?