Printing data is essential for understanding the contents of registers and memory. This section will cover the various ways to print data in gdb.
Summary Information
We can use various summary commands to see lots of data simultaneously. GEF's preview pane shadows a few of these commands, but they are still useful to know.
info registers
This command shows all the available registers and their current value.
GEF provides a similar command, registers, outputs the registers that it shows in the GEF output. Its output is a bit more verbose and only shows the most important registers.
This gives us extra details on the stack frame. I do not commonly use this command because GEF provides a lot of this information in the GEF output.
gef➤ info frame
Stack level 0, frame at 0xffffd6a0:
eip = 0x804923f in main; saved eip = 0xf7c21519
Arglist at 0xffffd698, args:
Locals at 0xffffd698, Previous frame's sp is 0xffffd6a0
Saved registers:
ebp at 0xffffd698, eip at 0xffffd69c
info proc mappings, vmmap, and elf-info
This is one of the most useful commands in this section. It shows us the memory mappings for the process. This is useful for understanding the memory sections, where data is allocated, and the permissions of each section.
GEF's vmmap performs the same function as info proc mappings, but provides a slightly cleaner output. vmmap also takes an address argument and will resolve the address to a section.
GEF's elf-info provides more detailed information on the binary's segments. This includes the got and plt locations as well as the .text, .data, and .bss sections.
Remember, this function only works during runtime.
info variables
This command shows us the global variables in the program. This is useful for understanding the program's layout and where data is stored. There is a lot of bloat in this output because the binary automatically includes a lot of variables for the C runtime.
If you run this command at runtime, every function from the C runtime will be included in the output. This includes every function in libc.
Printing Data
The print command (p for short) is the driving force behind examining data. It allows us to print the value of an expression.
gef➤ print 0x10-0x8
$1 = 0x8
Examining Memory
We can use the x command to examine memory. It takes an address or a register as its argument:
gef➤ x $esp
0xffffd640: 0xffffd658
gef➤ x 0xffffd640
0xffffd640: 0xffffd658
There are three formatting parameters formatted like so: x/NFU <ADDRESS>. The three format parameters are:
N: The repeat count. The repeat count is the number of times to repeat the format. This is used to print arrays (or large amounts of data from the stack or heap).
F: The display format. The display format is how to display the data. The default is hexadecimal (x). The types available are x (hex), d (decimal), u (unsigned), o (octal), t (binary), f (float), a (address), c (char), s (string), and i (instruction).
U: The unit size. The unit size is the size of each block. The four types are b (byte), h (halfword), w (word), and g (giant, 8 bytes). The default is word size (w). 32-bit binaries used w-sized data and 64-bit uses g-sized data.
Ensure you're comfortable doing this. This is the crux of dynamic analysis with gdb, so get some practice examining data.
Searching Memory
There are two major commands for finding data in memory: find and search-pattern.
find
find is built into GDB directly and is used for finding expressions within memory. The format of the find command is find [/UN] start, +len|end, expr1 [, expr2, ...].
/UN: Unit size and number flags. These are the same flags you would use with x.
start: Start address. Where to start searching.
+len|end: End of search. You can specify a number of bytes to search or an end address. Addresses are inclusive by default.
expr1: Expression. This is the expression to search for.
search-pattern is a GEF command used for finding strings. It takes a string argument and searches across the binary and loaded libraries for all instances of the string.
gef➤ search-pattern "/bin/cat flag.txt"
[+] Searching '/bin/cat flag.txt' in memory
[+] In '/home/joybuzzer/split'(0x601000-0x602000), permission=rw-
0x601060 - 0x601071 → "/bin/cat flag.txt"
gef➤ search-pattern /bin/sh
[+] Searching '/bin/sh' in memory
[+] In '/usr/lib/i386-linux-gnu/libc.so.6'(0xf7da2000-0xf7e27000), permission=r--
0xf7dbd0f5 - 0xf7dbd0fc → "/bin/sh"
search-pattern can also search based on endianness and can restrict search in only a certain part of memory.
gef➤ search-pattern /bin/sh little 0x0-0x80500000
[+] Searching '/bin/sh' in 0x0-0x80500000
If you want to search in only a certain section of memory, the endian argument is required.