Debugging bineries with GDB

HacksLand | The computer science playground

Posted by Thilan Dissanayaka on Feb 25, 2020

A debugger is a computer program that can be used toanalyze the structure of a nother program. GDB is packed with GNU tool set. GDB is a CLI tool .But it has a very user friendly interface to work with. In this document we are going to see how to use a Linux debugger for debug and analyze a binary file. If you are planning to learn reverse engineering , malware analysis or exploit development you must be familiar with debuggers.

Get started with GDB

We can open a binary inside GDB with the command gdb ./binary command. Hear binary is the file we want to debug. You can enter this command on your terminal.

To start the debugging process we need a binary. For that I wrote following simple C program.

#include <stdio.h>

int main(int argc, char const *argv[])
	int var, *ptr;
	var = 100;
	ptr = &var;

	if (argc > 1)
		printf("First argument is: %s\n", argv[1] );
	return 0;

This will declare two integers. One of theme is an pointer. After it copy the value 100 to var variable and copy the memory address of var to our pointer

Next if we supply an argument to program it will print that argument to the stdout. So simple. I compiled it with GCC compiler.

Now, let's start the debugging. Hear I openned the binary with GDB. You may see following screen after this command.

You can see abig introduction paragraph when we start the GDB tool. However in general we don't need this banner. I think it disturbs our process. So we can start GDB with -q command for prevent GDB showing this welcome banner.

gdb -q ./binary

So we can get following interface.

selecting the assembly syntax.

By default gdb uses AT&T assembly syntax. But in our previous tutorials we saw Intel's syntax for assembly is more easy to learn and it's clear. So Let's see how we can change the assembly syntax in our debugger.

set disassembly-flavor intel

But if you prefer using AT&T syntax it's totally OK. You can go with it.

Listing the source code

Of you want to see source code when debugging you can use the command list for it . But to use this feature you must compile your source in GCC with additional command -g or -ggdb. If you use list command without compiling the binary with ggdb option you'll get following error massage.

No symbol table is loaded.  Use the "file" command.

Disassembling the binary

After you loading a binary in GDB you can disassemble a function and see how is the assembly code . To do that you can use disassemble function_name or disas function_name. For an example if you want to disassemble main function you may use disassemble main or disas main.

(gdb) disass main
Dump of assembler code for function main:
0x080483c4 :    push   ebp
0x080483c5 :    mov    ebp,esp
0x080483c7 :    and    esp,0xfffffff0
0x080483ca :    sub    esp,0x20
0x080483cd :    mov    DWORD PTR [esp+0x18],0x64
0x080483d5 :   lea    eax,[esp+0x18]
0x080483d9 :   mov    DWORD PTR [esp+0x1c],eax
0x080483dd :   cmp    DWORD PTR [ebp+0x8],0x1
0x080483e1 :   jle    0x80483fc 
0x080483e3 :   mov    eax,DWORD PTR [ebp+0xc]
0x080483e6 :   add    eax,0x4
0x080483e9 :   mov    edx,DWORD PTR [eax]
0x080483eb :   mov    eax,0x80484d0
0x080483f0 :   mov    DWORD PTR [esp+0x4],edx
0x080483f4 :   mov    DWORD PTR [esp],eax
0x080483f7 :   call   0x80482fc 
0x080483fc :   mov    eax,0x0
0x08048401 :   leave
0x08048402 :   ret
End of assembler dump.

At the left side we can see memory addresses. Our CPU instructions are loaded there. We can see the starting point of main function is at 0x080483c4. At right side there are assembly instructions like push ebp, mov ebp,esp etc.

Break points

A break point is an essential thing in debugging. We can stop the execution of program on a decided state and examine the memory and registers . You can set a break point on a function withe command break. If you want break execution at main function you may use break main or short command b main.

But when you set breakpoints with function name GDB will skip function prologue. So if you want to see how stack is building you have another option to set breakpoints. In this method we use a memory address instead of function name.

Dump of assembler code for function main:
   0x00001199 <+0>:	push   ebp
   0x0000119a <+1>:	mov    ebp,esp
   0x0000119c <+3>:	push   ebx
   0x0000119d <+4>:	call   0x11c2 <>
   0x000011a2 <+9>:	add    eax,0x2e5e
   0x000011a7 <+14>:	lea    edx,[eax-0x1ff8]
   0x000011ad <+20>:	push   edx
   0x000011ae <+21>:	mov    ebx,eax
   0x000011b0 <+23>:	call   0x1030 <[email protected]>
   0x000011b5 <+28>:	add    esp,0x4
   0x000011b8 <+31>:	mov    eax,0x0
   0x000011bd <+36>:	mov    ebx,DWORD PTR [ebp-0x4]
   0x000011c0 <+39>:	leave  
   0x000011c1 <+40>:	ret    
End of assembler dump.
(gdb) break main
Breakpoint 1 at 0x119d

(gdb) break *0x00001199
Breakpoint 2 at 0x1199

Did you see that when we use break main, GDB set a breakpoint at 0x119d. But when we use break *0x00001199 the break point was set at 0x1199. So we can see PUSH ebp, mov ebp,esp etc.

Execute program in GDB

To execute our binary , we can use the command run.

Examine the memory

Hi, I'm Thilan. An engineering student from SriLanka. I love to code with Python, JavaScript PHP and C.

Also read

Aug 12
File handling | Python programming

On this tutorial we are going to learn how we can access the file system with python. Hear we have....

Oct 17
Reverse engineering example

So you want to learn Reverse engineering. That's great. RE is used in various topics such as....

Feb 18
Moving data with assembly

In normal Windows/Linux environment you have heard about moving data or files. What we do is....