GDB baby step 2

Published: March 5, 2024

Description

Continue practicing with debugger0_b by reporting the value in EAX right before main returns. Convert the result to decimal for the final flag.

Debugger practiceDownload debugger0_b

Make the binary executable and load it into gdb with layout asm so you can watch instructions in context.

Place a breakpoint after the final arithmetic instruction (main+59) to read registers at the exact moment main is about to return.

wget https://artifacts.picoctf.net/c/520/debugger0_b
chmod +x debugger0_b
gdb --args ./debugger0_b

Solution

  1. Step 1Break after the math
    Inside gdb, set b *(main+59). This lands execution immediately after the last modification of EAX so the register holds its final value.
    b *(main+59)
    run
    Learn more

    Breakpoints are the primary mechanism for pausing execution at a specific point in GDB. The syntax b *(main+59) sets a breakpoint at the memory address that is 59 bytes into the mainfunction's machine code. The asterisk dereferences the address expression - without it, GDB would try to find a source line rather than an instruction offset.

    Using offset-based breakpoints (rather than source line numbers) is necessary when you do not have debug symbols or source code - exactly the situation in CTF binary challenges. The offset +59 must be determined from the disassembly: look for the last instruction that writes to EAX, count its byte offset from the start of main, and break immediately after it.

    GDB breakpoints are powerful because they support conditions (break main if i == 5), ignore counts (ignore 1 3 skips the first three hits), and commands (commands 1 ... end runs GDB commands automatically when the breakpoint fires). These features let you automate complex debugging scenarios - essential when analyzing loops or deeply nested call chains in real targets.

  2. Step 2Print EAX and convert
    Once the breakpoint hits, run print $eax to capture the register contents. Convert that hexadecimal (if needed) into decimal and wrap it with picoCTF{...}.
    print $eax
    Learn more

    In GDB, registers are accessed with a $ prefix: $eax, $rbp, $rip, and so on. The print command (alias p) evaluates and displays an expression. By default it shows the result in decimal, but you can specify a format: p/x $eax for hex, p/t $eax for binary, p/c $eax for the character representation.

    The info registers command (alias i r) dumps all general-purpose registers at once, which is useful when you are not sure which register holds the value you need. For x86-64, the full set includes RAX/RBX/RCX/RDX/RSI/RDI/RSP/RBP and R8-R15, plus the instruction pointer RIP and the flags register EFLAGS.

    After capturing EAX's value, the conversion to decimal is the same as in earlier challenges. The consistent workflow - set breakpoint, run, print register, convert - is deliberately repetitive across the GDB Baby Step series. Repetition builds muscle memory, so that these actions become automatic before the challenges increase in complexity.

Flag

picoCTF{<eax_decimal>}

Your decimal value depends on the constant embedded in debugger0_b-replace <eax_decimal> with the number you observe in gdb.

Want more picoGym Exclusive writeups?

Useful tools for Reverse Engineering

Related reading

Do these first

What to try next