Examining x86_64 Memory with GDB

The Art of Exploitation book has a nice section on using GDB to inspect memory. We start by disassembling the simple Hello World post.


Start by compiling hello_world.c with the ‘-g’ option.
-g Produce debugging information in the operating system's native format (stabs, COFF , XCOFF , or DWARF 2). GDB can work with this debugging information.


By default, when you disassemble code in GDB, it uses the AT&T format for the assembly instructions. The Art of Exploitation book prefers to use the Intel format. I’m not familiar with either but in case you want to follow along with the book, I’ll use the Intel syntax in my examples.


Since the book was written, GDB has changed the way you set the syntax format so you’ll want to modify it. The book says to do
set dis intel
You’ll want to do
set disassembly-flavor intel
You can create a file in your home directory called .gdbinit so you don’t have to specify this every time you start GDB. You can do all of this in one command
nobody@nobody:~$ echo "set disassembly-flavor intel" > ~/.gdbinit
Now lets fire up GDB. The book uses the ‘-q’ option which is optional
-q ``Quiet''.  Do not print the  introductory  and  copyright  messages.  These messages are also suppressed in batch mode.
nobody@nobody:$ gcc -g hello_world.c
nobody@nobody:$ gdb -q ./a.out 
Reading symbols from a.out...done.
(gdb) 
Now that we have GDB up, lets use it to disassemble the x86_64 code. You can type the full version ‘disassemble main’ or the short version ‘disass main’
(gdb) disass main
Dump of assembler code for function main:
   0x0000000000400524 <+0>:	push   rbp
   0x0000000000400525 <+1>:	mov    rbp,rsp
   0x0000000000400528 <+4>:	mov    edi,0x40062c
   0x000000000040052d <+9>:	call   0x400418 <puts@plt>
   0x0000000000400532 <+14>:	mov    eax,0x0
   0x0000000000400537 <+19>:	leave  
   0x0000000000400538 <+20>:	ret    
End of assembler dump.
If you’re following along in the book, you’ll notice that the output is slightly different. The book uses the older x86 architecture, I’m using the x86_64 architecture. That means all of the 32-bit ‘E’ registers now have their equivalent 64-bit ‘R’ registers. For example, ‘esp’ is the 32-bit version of the “Extended Stack Pointer” and ‘rsp’ is the 64-bit version of the “Register Stack Pointer”.


I’ve highlighted the important part of the code, the body of main. Lets use GDB’s examine memory commands to see exactly what’s going on


GDB uses the ‘x’ command to look at the contents of memory. You can tell GDB what format you’d like to see the memory in and unit you’d like to see it in
Formats:
o - octal
d - decimal
x - hexadecimal
u - unsigned integer
s - string
t - binary
Units:
b - byte
h - half
w - word
g - double word
You can also tell GDB how many you’d like to see by prefixing it’s type with a number. Since we know that “Hello World” is a string, we can use the x/s command to view the contents of memory where we think that string is stored.
(gdb) x/s 0x40062c
0x40062c:	 "Hello World!"
We can also look at the equivalent ASCII characters of “Hello World” in memory
(gdb) x/12db 0x40062c
0x40062c:	72	101	108	108	111	32	87	111
0x400634:	114	108	100	33
An interesting thing about GCC is that it automatically optimizes printf() with 1 argument to use puts(). This confused me at first since the code used printf() but the disassembly shows a call to puts()
   0x000000000040052d <+9>:	call   0x400418 <puts@plt>
The puts() function automatically adds a new line, that’s why when we examine memory in GDB, we don’t see the ‘n’ character that we added when we called printf() in the code


More to come; we’re just getting started!

6 Comments Examining x86_64 Memory with GDB

  1. Alejandro

    Hi, I’m reading The Art of Exploitation too, but I have a doubt. If I want to overwrite the return address in a frame stack, I use perl, for example: (gdb) run $(perl -e ‘print “\xbf\x84\x04\x08″x20′) and that will write 0x080484bf.

    Here is my problem, I’m using x86_64, so the value I want to write as the new return adress is 0x00000000004006ee. I supposed I have to do something like this : (gdb) run $(perl -e ‘print “\xee\x06\x40\x00\x00\x00\x00\x00″x20′). But all the left zeros are being ignored so I can’t change the return address to what it have to be. It write 0x0640ee0640ee0640.

    I would be thankfull if you could help me.

    Best regards and sorry for my english.

    Reply
    1. Dustin Schultz

      Hi Alejandro, unfortunately I didn’t figure out a way to get the examples to work on x86_64. I’d imagine that the null bytes are interpreted as end of line characters. I would imagine you could use some of the same techniques that you would use to remove null bytes from shell code.

      Reply
        1. Hank

          There are other registers that reference the lower 32 bits of the 64-bit registers. Perhaps an xor of the 64-bit register then a mov with a 32-bit register operand would be what you’re looking for.

          Reply
  2. Cleber

    Hi!

    I’m new in this art, so I have a very basic doubt, but, could anyone tell me how do I initialize GDB through the CD??

    Thanks!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>