GDB is a powerful text based debugger that is run from the terminal. We will use it extensively throughout this tutorial,
and start by examing the hello_x86 binary we just created. To begin, invoke the gdb debugger with:
gdb hello_x86
pete@XPS:~/Documents/ASM/hello_world/x86$ gdb hello_x86
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello_x86...
(No debugging symbols found in hello_x86)
(gdb)
We are greated with the gdb prompt.
We wrote our assembly using the Intel syntax, so we will switch our disassembly output to that syntax with:
set disassembly-flavor intel
We want to view the disassembly code and the CPU registers while we are running our program, we can enable them with:
lay asm
lay reg
Your terminal window should now look similar this this:
|------------------------------------------------------------------------------------------------------------------------------------------|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| [ Register Values Unavailable ] |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| [ No Assembly Available ] |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------|
exec No process In: L?? PC: ??
(gdb) lay reg
(gdb)
Note: If at any time the screen output appears corrupted, you can enter ctrl + l to redraw the screen.
You can use ctrl + x then o or p to switch between the assembly, register, and gdb command frames.
We will now set a break point for debugging our code by entering:
break _start
This will set a break point at the beginning of the _start label.
We can now begin our program execution by entering:
run
Your terminal should now look similar to the output below:
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------|
|eax 0x0 0 ecx 0x0 0 edx 0x0 0 |
|ebx 0x0 0 esp 0xffffd950 0xffffd950 ebp 0x0 0x0 |
|esi 0x0 0 edi 0x0 0 eip 0x8049000 0x8049000 <_start> |
|eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 43 |
|ds 0x2b 43 es 0x2b 43 fs 0x0 0 |
|gs 0x0 0 k0 0x0 0 k1 0x0 0 |
|k2 0x0 0 k3 0x0 0 k4 0x0 0 |
|k5 0x0 0 k6 0x0 0 k7 0x0 0 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|B+> 0x8049000 <_start> mov eax,0x4 |
| 0x8049005 <_start+5> mov ebx,0x1 |
| 0x804900a <_start+10> lea ecx,ds:0x804a000 |
| 0x8049010 <_start+16> mov edx,0xd |
| 0x8049015 <_start+21> int 0x80 |
| 0x8049017 <print_hex_message> mov eax,0x4 |
| 0x804901c <print_hex_message+5> mov ebx,0x1 |
| 0x8049021 <print_hex_message+10> lea ecx,ds:0x804a00d |
| 0x8049027 <print_hex_message+16> mov edx,0xd |
| 0x804902c <print_hex_message+21> int 0x80 |
| 0x804902e <exit_program> mov eax,0x1 |
| 0x8049033 <exit_program+5> mov ebx,0x0 |
| 0x8049038 <exit_program+10> int 0x80 |
| 0x804903a add BYTE PTR [eax],al |
| 0x804903c add BYTE PTR [eax],al |
| 0x804903e add BYTE PTR [eax],al |
| 0x8049040 add BYTE PTR [eax],al |
| 0x8049042 add BYTE PTR [eax],al |
| 0x8049044 add BYTE PTR [eax],al |
| 0x8049046 add BYTE PTR [eax],al |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
native process 84922 In: _start L?? PC: 0x8049000
(gdb) lay reg
(gdb) break _start
Breakpoint 1 at 0x8049000
(gdb) run
Starting program: /home/pete/Documents/ASM/hello_world/x86/hello_x86
Breakpoint 1, 0x08049000 in _start ()
(gdb)
Our program is now running inside the debugger. We can see that our breakpoint was set at the beginning of the _start label which is at
memory address 0x0804900. The first instruction at that address should be highlighted in the assembly frame, and if we look at the register group,
we can see that our eip register has the address of the next instruction to mov 0x4 into eax.
We will now execute a single instruction by entering:
si
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------|
|eax 0x4 4 ecx 0x0 0 edx 0x0 0 |
|ebx 0x0 0 esp 0xffffd950 0xffffd950 ebp 0x0 0x0 |
|esi 0x0 0 edi 0x0 0 eip 0x8049005 0x8049005 <_start+5> |
|eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 43 |
|ds 0x2b 43 es 0x2b 43 fs 0x0 0 |
|gs 0x0 0 k0 0x0 0 k1 0x0 0 |
|k2 0x0 0 k3 0x0 0 k4 0x0 0 |
|k5 0x0 0 k6 0x0 0 k7 0x0 0 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|B+ 0x8049000 <_start> mov eax,0x4 |
| > 0x8049005 <_start+5> mov ebx,0x1 |
| 0x804900a <_start+10> lea ecx,ds:0x804a000 |
| 0x8049010 <_start+16> mov edx,0xd |
| 0x8049015 <_start+21> int 0x80 |
| 0x8049017 <print_hex_message> mov eax,0x4 |
| 0x804901c <print_hex_message+5> mov ebx,0x1 |
| 0x8049021 <print_hex_message+10> lea ecx,ds:0x804a00d |
| 0x8049027 <print_hex_message+16> mov edx,0xd |
| 0x804902c <print_hex_message+21> int 0x80 |
| 0x804902e <exit_program> mov eax,0x1 |
| 0x8049033 <exit_program+5> mov ebx,0x0 |
| 0x8049038 <exit_program+10> int 0x80 |
| 0x804903a add BYTE PTR [eax],al |
| 0x804903c add BYTE PTR [eax],al |
| 0x804903e add BYTE PTR [eax],al |
| 0x8049040 add BYTE PTR [eax],al |
| 0x8049042 add BYTE PTR [eax],al |
| 0x8049044 add BYTE PTR [eax],al |
| 0x8049046 add BYTE PTR [eax],al |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
native process 84922 In: _start L?? PC: 0x8049005
(gdb) lay reg
(gdb) break _start
Breakpoint 1 at 0x8049000
(gdb) run
Starting program: /home/pete/Documents/ASM/hello_world/x86/hello_x86
Breakpoint 1, 0x08049000 in _start ()
(gdb) si
0x08049005 in _start ()
(gdb)
The first instruction was executed, and looking at the registers, we can see that now eax holds the value 0x4,
and eip holds the address of the next instruction at 0x08049005. This is also highlighted in our assembly frame
and pointed to with the > symbol. The >_start+5< tag indicates that this memory location is offset 5 bytes from the
beginning of our _start label, which means our first instruction was 5 bytes long. Or gdb command window
indicates we are at memory address 0x08049005 in the _start label.
Enter si to execute the next instruction:
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------|
|eax 0x4 4 ecx 0x0 0 edx 0x0 0 |
|ebx 0x1 1 esp 0xffffd950 0xffffd950 ebp 0x0 0x0 |
|esi 0x0 0 edi 0x0 0 eip 0x804900a 0x804900a <_start+10 |
|eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 43 |
|ds 0x2b 43 es 0x2b 43 fs 0x0 0 |
|gs 0x0 0 k0 0x0 0 k1 0x0 0 |
|k2 0x0 0 k3 0x0 0 k4 0x0 0 |
|k5 0x0 0 k6 0x0 0 k7 0x0 0 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|B+ 0x8049000 <_start> mov eax,0x4 |
| 0x8049005 <_start+5> mov ebx,0x1 |
| > 0x804900a <_start+10> lea ecx,ds:0x804a000 |
| 0x8049010 <_start+16> mov edx,0xd |
| 0x8049015 <_start+21> int 0x80 |
| 0x8049017 <print_hex_message> mov eax,0x4 |
| 0x804901c <print_hex_message+5> mov ebx,0x1 |
| 0x8049021 <print_hex_message+10> lea ecx,ds:0x804a00d |
| 0x8049027 <print_hex_message+16> mov edx,0xd |
| 0x804902c <print_hex_message+21> int 0x80 |
| 0x804902e <exit_program> mov eax,0x1 |
| 0x8049033 <exit_program+5> mov ebx,0x0 |
| 0x8049038 <exit_program+10> int 0x80 |
| 0x804903a add BYTE PTR [eax],al |
| 0x804903c add BYTE PTR [eax],al |
| 0x804903e add BYTE PTR [eax],al |
| 0x8049040 add BYTE PTR [eax],al |
| 0x8049042 add BYTE PTR [eax],al |
| 0x8049044 add BYTE PTR [eax],al |
| 0x8049046 add BYTE PTR [eax],al |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
native process 84922 In: _start L?? PC: 0x804900a
(gdb) lay reg
(gdb) break _start
Breakpoint 1 at 0x8049000
(gdb) run
Starting program: /home/pete/Documents/ASM/hello_world/x86/hello_x86
Breakpoint 1, 0x08049000 in _start ()
(gdb) si
0x08049005 in _start ()
(gdb) si
0x0804900a in _start ()
(gdb)
Notice that ebx has been set to 0x1 and the eip register has been updated again to point to the next instruction.
Enter si again:
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------|
|eax 0x4 4 ecx 0x804a000 134520832 edx 0x0 0 |
|ebx 0x1 1 esp 0xffffd950 0xffffd950 ebp 0x0 0x0 |
|esi 0x0 0 edi 0x0 0 eip 0x8049010 0x8049010 <_start+16 |
|eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 43 |
|ds 0x2b 43 es 0x2b 43 fs 0x0 0 |
|gs 0x0 0 k0 0x0 0 k1 0x0 0 |
|k2 0x0 0 k3 0x0 0 k4 0x0 0 |
|k5 0x0 0 k6 0x0 0 k7 0x0 0 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|B+ 0x8049000 <_start> mov eax,0x4 |
| 0x8049005 <_start+5> mov ebx,0x1 |
| 0x804900a <_start+10> lea ecx,ds:0x804a000 |
| > 0x8049010 <_start+16> mov edx,0xd |
| 0x8049015 <_start+21> int 0x80 |
| 0x8049017 <print_hex_message> mov eax,0x4 |
| 0x804901c <print_hex_message+5> mov ebx,0x1 |
| 0x8049021 <print_hex_message+10> lea ecx,ds:0x804a00d |
| 0x8049027 <print_hex_message+16> mov edx,0xd |
| 0x804902c <print_hex_message+21> int 0x80 |
| 0x804902e <exit_program> mov eax,0x1 |
| 0x8049033 <exit_program+5> mov ebx,0x0 |
| 0x8049038 <exit_program+10> int 0x80 |
| 0x804903a add BYTE PTR [eax],al |
| 0x804903c add BYTE PTR [eax],al |
| 0x804903e add BYTE PTR [eax],al |
| 0x8049040 add BYTE PTR [eax],al |
| 0x8049042 add BYTE PTR [eax],al |
| 0x8049044 add BYTE PTR [eax],al |
| 0x8049046 add BYTE PTR [eax],al |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
native process 84922 In: _start L?? PC: 0x8049010
(gdb) lay reg
(gdb) break _start
Breakpoint 1 at 0x8049000
(gdb) run
Starting program: /home/pete/Documents/ASM/hello_world/x86/hello_x86
Breakpoint 1, 0x08049000 in _start ()
(gdb) si
0x08049005 in _start ()
(gdb) si
0x0804900a in _start ()
(gdb) si
0x08049010 in _start ()
(gdb)
Now we can see our ecx register has been loaded with a memory address. This should be the memory address of our message label.
We can view a list of variable labels in our program by entering the command:
info variables
Which outputs:
(gdb) info variables
All defined variables:
Non-debugging symbols:
0x0804a000 message
0x0804a00d hex_message
0x0804a01a __bss_start
0x0804a01a _edata
0x0804a01c _end
(gdb)
We can see that the address for our message matches what is loaded into the ecx register.
Let's look at the actual data stored at this address. To view the data, we need to let gdb know how many bytes
we want to view. We can see that message starts at 0x0804a000, and hex_message is the next label at
0x0804a00d, which means message should be 0xd (or 13) bytes long.
To view 13 bytes starting at the message label, enter:
x /13xb 0x0804a000
Which outputs:
(gdb) x /13xb 0x0804a000
0x804a000: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f
0x804a008: 0x72 0x6c 0x64 0x21 0x0a
This shows us the 13 bytes of data stored at 0x804a000 in hexadecimal, but since we know that the data contains
ASCII characters, let's output the data in character format.
Enter:
x /13cb 0x0804a000
This outputs:
(gdb) x /13cb 0x0804a000
0x804a000: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x804a008: 114 'r' 108 'l' 100 'd' 33 '!' 10 '\n'
(gdb)
We can easily recognize our "Hello World!\n" message.
Now let's view the contents of the entire .data section of our program.
To do so, wee need to find the memory range that it occupies.
To view the memory ranges for our program's sections, enter:
info file
This outputs:
Symbols from "/home/pete/Documents/ASM/hello_world/x86/hello_x86".
Native process:
Using the running image of child process 84922.
While running this, GDB does not access memory from...
Local exec file:
`/home/pete/Documents/ASM/hello_world/x86/hello_x86', file type elf32-i386.
Entry point: 0x8049000
0x08049000 - 0x0804903a is .text
0x0804a000 - 0x0804a01a is .data
0xf7ffc0b4 - 0xf7ffc0f4 is .hash in system-supplied DSO at 0xf7ffc000
0xf7ffc0f4 - 0xf7ffc140 is .gnu.hash in system-supplied DSO at 0xf7ffc000
0xf7ffc140 - 0xf7ffc1f0 is .dynsym in system-supplied DSO at 0xf7ffc000
0xf7ffc1f0 - 0xf7ffc2b0 is .dynstr in system-supplied DSO at 0xf7ffc000
0xf7ffc2b0 - 0xf7ffc2c6 is .gnu.version in system-supplied DSO at 0xf7ffc000
0xf7ffc2c8 - 0xf7ffc31c is .gnu.version_d in system-supplied DSO at 0xf7ffc000
0xf7ffc31c - 0xf7ffc3ac is .dynamic in system-supplied DSO at 0xf7ffc000
0xf7ffc3ac - 0xf7ffc3b8 is .rodata in system-supplied DSO at 0xf7ffc000
0xf7ffc3b8 - 0xf7ffc40c is .note in system-supplied DSO at 0xf7ffc000
0xf7ffc40c - 0xf7ffc430 is .eh_frame_hdr in system-supplied DSO at 0xf7ffc000
0xf7ffc430 - 0xf7ffc53c is .eh_frame in system-supplied DSO at 0xf7ffc000
0xf7ffc540 - 0xf7ffd262 is .text in system-supplied DSO at 0xf7ffc000
--Type for more, q to quit, c to continue without paging--
The .text and .data entries are the two entires we care about right now. The entries listed below them
are Dynamic Shared Objects (DSO) that we are not currently interested in. Looking at the entry for our .data section, we can see that
it occupies memory addresses 0x0804a000 - 0x0804a01a.
We can have gdb calculate the size of the .data section for us by entering the command:
print (0x0804a01a - 0x0804a000)
This subtracts the starting address of .data from the ending address and prints the result, which should be 26 bytes.
To view all 26 bytes stored in the .data section, enter:
x /26xb 0x0804a000
This outputs:
(gdb) x /26xb 0x0804a000
0x804a000: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f
0x804a008: 0x72 0x6c 0x64 0x21 0x0a 0x48 0x65 0x6c
0x804a010: 0x6c 0x6f 0x20 0x57 0x6f 0x72 0x6c 0x64
0x804a018: 0x21 0x0a
(gdb)
Again, since we know this should contain ASCII characters, we can output it in character format with:
x /26cb 0x0804a000
Which outputs:
0x804a000: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x804a008: 114 'r' 108 'l' 100 'd' 33 '!' 10 '\n' 72 'H' 101 'e' 108 'l'
0x804a010: 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o' 114 'r' 108 'l' 100 'd'
0x804a018: 33 '!' 10 '\n'
(gdb)
This shows the data for both our message label which starts at 0x804a000, and our hex_message label at 0x804a00d.
Let's continue to step through our program execution by entering si:
|-Register group: general------------------------------------------------------------------------------------------------------------------------------------------------|
|eax 0x4 4 ecx 0x804a000 134520832 |
|edx 0xd 13 ebx 0x1 1 |
|esp 0xffffd950 0xffffd950 ebp 0x0 0x0 |
|esi 0x0 0 edi 0x0 0 |
|eip 0x8049015 0x8049015 <_start+21> eflags 0x202 [ IF ] |
|cs 0x23 35 ss 0x2b 43 |
|ds 0x2b 43 es 0x2b 43 |
|fs 0x0 0 gs 0x0 0 |
|k0 0x0 0 k1 0x0 0 |
|k2 0x0 0 k3 0x0 0 |
|k4 0x0 0 k5 0x0 0 |
|k6 0x0 0 k7 0x0 0 |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|B+ 0x8049000 <_start> mov eax,0x4 |
| 0x8049005 <_start+5> mov ebx,0x1 |
| 0x804900a <_start+10> lea ecx,ds:0x804a000 |
| 0x8049010 <_start+16> mov edx,0xd |
| > 0x8049015 <_start+21> int 0x80 |
| 0x8049017 <print_hex_message> mov eax,0x4 |
| 0x804901c <print_hex_message+5> mov ebx,0x1 |
| 0x8049021 <print_hex_message+10> lea ecx,ds:0x804a00d |
| 0x8049027 <print_hex_message+16> mov edx,0xd |
| 0x804902c <print_hex_message+21> int 0x80 |
| 0x804902e <exit_program> mov eax,0x1 |
| 0x8049033 <exit_program+5> mov ebx,0x0 |
| 0x8049038 <exit_program+10> int 0x80 |
| 0x804903a add BYTE PTR [eax],al |
| 0x804903c add BYTE PTR [eax],al |
| 0x804903e add BYTE PTR [eax],al |
| 0x8049040 add BYTE PTR [eax],al |
| 0x8049042 add BYTE PTR [eax],al |
| 0x8049044 add BYTE PTR [eax],al |
| 0x8049046 add BYTE PTR [eax],al |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
native process 84922 In: _start L?? PC: 0x8049015
0xf7ffc430 - 0xf7ffc53c is .eh_frame in system-supplied DSO at 0xf7ffc000
0xf7ffc540 - 0xf7ffd262 is .text in system-supplied DSO at 0xf7ffc000
--Type for more, q to quit, c to continue without paging-- 0xf7ffd262 - 0xf7ffd2c2 is .altinstructions in system-supplied DSO at 0xf7ffc000
0xf7ffd2c2 - 0xf7ffd2e2 is .altinstr_replacement in system-supplied DSO at 0xf7ffc000
(gdb) x /26b 0x0804a000
0x804a000: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x804a008: 114 'r' 108 'l' 100 'd' 33 '!' 10 '\n' 72 'H' 101 'e' 108 'l'
0x804a010: 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o' 114 'r' 108 'l' 100 'd'
0x804a018: 33 '!' 10 '\n'
(gdb) x /26xb 0x0804a000
0x804a000: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f
0x804a008: 0x72 0x6c 0x64 0x21 0x0a 0x48 0x65 0x6c
0x804a010: 0x6c 0x6f 0x20 0x57 0x6f 0x72 0x6c 0x64
0x804a018: 0x21 0x0a
(gdb) x /26cb 0x0804a000
0x804a000: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x804a008: 114 'r' 108 'l' 100 'd' 33 '!' 10 '\n' 72 'H' 101 'e' 108 'l'
0x804a010: 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o' 114 'r' 108 'l' 100 'd'
0x804a018: 33 '!' 10 '\n'
(gdb) si
0x08049015 in _start ()
(gdb)
The edx register has been set to 0xd now, which reflects the length of our message, whose address is stored in ecx.
Enter si again:
|eax 0x4 4 ecx 0x804a000 134520832 edx 0xd 13 |
|eax 0xd 13 esp 0xffffd950 0xffffd950 edx 0xd 13 |
|esi 0x0 0 edi 0x0 0 eip 0x8049015 0x8049015 <_start+21 |
|eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 7 43 7 <print_hex |
|ds 0x2b 43 es 0x2b 43 fs 0x0 0 |
|gs 0x0 0 k0 0x0 0 k1 0x0 0 |
|k2 0x0 0 k3 0x0 0 k4 0x0 0 |
|k5 0x0 0 k6 0x0 0 k7 0x0 0 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|B+ 0x8049000 <_start> mov eax,0x4 |
| 0x8049005 <_start+5> mov ebx,0x1 |
| 0x804900a <_start+10> lea ecx,ds:0x804a000 |
| 0x8049010 <_start+16> mov edx,0xd |
| > 0x8049015 <_start+21> int 0x80 |
| 0x8049015 <_start+21> int 0x800x4 |
| > 0x8049017 <print_hex_message> mov eax,0x4 |
| 0x8049021 <print_hex_message+10> lea ecx,ds:0x804a00d |
| 0x8049027 <print_hex_message+16> mov edx,0xd |
| 0x804902c <print_hex_message+21> int 0x80 |
| 0x804902e <exit_program> mov eax,0x1 |
| 0x8049033 <exit_program+5> mov ebx,0x0 |
| 0x8049038 <exit_program+10> int 0x80 |
| 0x804903a add BYTE PTR [eax],al |
| 0x804903c add BYTE PTR [eax],al |
| 0x804903e add BYTE PTR [eax],al |
| 0x8049040 add BYTE PTR [eax],al |
| 0x8049042 add BYTE PTR [eax],al |
| 0x8049044 add BYTE PTR [eax],al |
| 0x8049046 add BYTE PTR [eax],al |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
native process 96349 In: _start L?? PC: 0x8049015
0xf7ffc31c - 0xf7print_hex_messagec in system-supplied DSO at 0xf7ffc000 7
0xf7ffc3b8 - 0xf7ffc40c is .note in system-supplied DSO at 0xf7ffc000
0xf7ffc40c - 0xf7ffc430 is .eh_frame_hdr in system-supplied DSO at 0xf7ffc000
0xf7ffc430 - 0xf7ffc53c is .eh_frame in system-supplied DSO at 0xf7ffc000
0xf7ffc540 - 0xf7ffd262 is .text in system-supplied DSO at 0xf7ffc000
--Type for more, q to quit, c to continue without paging-- 0xf7ffd262 - 0xf7ffd2c2 is .altinstructions in system-supplied DSO at 0xf7ffc000
0xf7ffd2c2 - 0xf7ffd2e2 is .altinstr_replacement in system-supplied DSO at 0xf7ffc000
(gdb) x /26xb 0x0804a000
0x804a000: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f
0x804a008: 0x72 0x6c 0x64 0x21 0x0a 0x48 0x65 0x6c
0x804a010: 0x6c 0x6f 0x20 0x57 0x6f 0x72 0x6c 0x64
0x804a018: 0x21 0x0a
(gdb) x /26cb 0x0804a000
0x804a000: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x804a008: 114 'r' 108 'l' 100 'd' 33 '!' 10 '\n' 72 'H' 101 'e' 108 'l'
0x804a010: 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o' 114 'r' 108 'l' 100 'd'
0x804a018: 33 '!' 10 '\n'
(gdb) si
0x08049015 in _start ()
(gdb) si
Hello World!
0x08049017 in print_hex_message ()
(gdb)
Our interrupt 0x80 instruction was reached, and it invoked the write syscall, passing the parameters we set in the ebx, ecx, and edx registers.
ebx was set to 0x1, for stdout, so our program wrote "Hello World!\n" to the terminal. Note, this output may be injected into the gdb command
frame, which can corrupt the dislay output. Enter ctrl + l (Lower case L) to redraw the screen and fix this.
In my example, it appears that there are duplicate 0x8049015 instruction lines and a phantom 0x800x4 interrupt instruction.
Re-drawing the output corrects this.
GDB shows that we have reached the print_hex_message label which will execute the same steps as before to invoke a write syscall.
We can continue the program to completion by entering:
continue
Our gdb command window should display:
(gdb) continue
Continuing.
[Inferior 1 (process 96349) exited normally]
(gdb)
This indicates that our program has completed without error.
We can exit gdb by entering:
quit