Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Read a program's memory with gdb

After this lesson: I can stop a program and read what it compares.

55 min lesson5 commandsReverse engineering lab: reading programs with gdb, radare2, strace and ltrace on one VM

Stop a program and look inside

gdb is the GNU debugger: it runs a program under your control, stops it where you ask and lets you read its registers and memory.

That matters because a program has to hold both words in memory at the moment it compares them. Stopping it at that moment shows you what it compares, with no need to read every instruction. You will use it on a practice program only.

By the end of this lesson

Note

I can stop a program and read what it compares.

Key words

WordWhat it meansExample
Debuggera tool that runs a program and lets you stop itgdb
Breakpointa place where the debugger stops the program
Argumenta value given to a function when it is called
Addressthe number that says where something is in memory
Pointera register or variable that holds an address
Calling conventionthe agreed place for each argument of a call

The cells students fill in are left blank in this preview.

A breakpoint stops the program where you choose

A breakpoint tells the debugger: stop when you reach this place. Here the place is the function strcmp, which compares two strings.

The program stops just as the function is about to run. Its arguments, the two strings, are already in place. You only have to know where to look.

Worked example: strcmp(typed, stored)

RegisterHoldsIn vault
rdiThe first argument, an addressWhere the typed word is
rsiThe second argument, an addressWhere the stored word is
rax or eaxThe answer, after the callZero when the words are equal

The cells students fill in are left blank in this preview.

x/s shows the text at an address

A register such as rdi holds only an address, a number. x/s $rdi means: examine the memory at that address, shown as a string. The dollar sign names the register.

Typing gdb by hand is a conversation. For these Runs each command is given with -ex and gdb exits at the end. The last two lines it prints are the two strings, which is why tail -n 2 keeps only those.

Write the practice program

Command
printf '#include <stdio.h>\n#include <string.h>\nint main(int argc, char **argv) {\n    if (argc != 2) { puts("usage: vault WORD"); return 2; }\n    if (strcmp(argv[1], "blue-harbour") == 0) { puts("Door open."); return 0; }\n    puts("Door shut.");\n    return 1;\n}\n' > vault.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Compile it

Command
gcc -O0 -no-pie -fno-stack-protector -o vault vault.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Stop at strcmp and read both strings

Command
gdb -batch -ex 'set debuginfod enabled off' -ex 'set environment LD_BIND_NOW=1' -ex 'break main' -ex 'run' -ex 'break strcmp' -ex 'continue' -ex 'x/s $rdi' -ex 'x/s $rsi' --args ./vault guess 2>&1 | tail -n 2

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

The two registers themselves

Command
gdb -batch -ex 'set debuginfod enabled off' -ex 'set environment LD_BIND_NOW=1' -ex 'break main' -ex 'run' -ex 'break strcmp' -ex 'continue' -ex 'info registers rdi rsi' --args ./vault guess 2>&1 | tail -n 2

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

The same stop with the right word

Command
gdb -batch -ex 'set debuginfod enabled off' -ex 'set environment LD_BIND_NOW=1' -ex 'break main' -ex 'run' -ex 'break strcmp' -ex 'continue' -ex 'x/s $rdi' -ex 'x/s $rsi' --args ./vault blue-harbour 2>&1 | tail -n 2

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Doing it by hand in gdb

To work in gdb yourself, start it with gdb ./vault and type each command at its prompt: break main, run guess, break strcmp, continue, x/s $rsi, then quit. It never ends until you quit, so it is not a Run.

If gdb offers to use debuginfod, answer n. After each stop, continue carries on to the next breakpoint.

A common mistake

Warning

Many people type break strcmp first and expect to stop in their own program. Other code runs before main, and it can stop there instead, so you read the wrong strings. Stop at main first, then set the breakpoint, then continue.

About this lab and its source: Reverse engineering lab: reading programs with gdb, radare2, strace and ltrace on one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.