Examples
1. Print "hello world!"
080483fb <main>:
 80483fb:       8d 4c 24 04             lea    ecx,[esp+0x4]
 80483ff:       83 e4 f0                and    esp,0xfffffff0
 8048402:       ff 71 fc                push   DWORD PTR [ecx-0x4]
 8048405:       55                      push   ebp
 8048406:       89 e5                   mov    ebp,esp
 8048408:       51                      push   ecx
 8048409:       83 ec 04                sub    esp,0x4
 804840c:       83 ec 0c                sub    esp,0xc
 804840f:       68 b0 84 04 08          push   0x80484b0
 8048414:       e8 b7 fe ff ff          call   80482d0 <puts@plt>
 8048419:       83 c4 10                add    esp,0x10
 804841c:       b8 00 00 00 00          mov    eax,0x0
 8048421:       8b 4d fc                mov    ecx,DWORD PTR [ebp-0x4]
 8048424:       c9                      leave  
 8048425:       8d 61 fc                lea    esp,[ecx-0x4]
 8048428:       c3                      ret    
 8048429:       66 90                   xchg   ax,ax
 804842b:       66 90                   xchg   ax,ax
 804842d:       66 90                   xchg   ax,ax
 804842f:       90                      nopThe important instructions
 804840f:       68 b0 84 04 08          push   0x80484b0
 8048414:       e8 b7 fe ff ff          call   80482d0 <puts@plt>a. The first line simply pushes the pointer of the string onto the stack (to the puts() function)
b. The second line calls the puts() function
Rest of the instructions
The rest of the instructions deals with moving the
ESPandEBParound for stack frame setup and restoration, preparing spaces for local variables, and stack alignment
Debugging with GDB
Refer to the following GDB notes for more information on the available commands
We can use gdb to better understand the binary (with the gef extension).
Disassemble the
mainfunction:
$ gdb hello_world
gef> disass main
Dump of assembler code for function main:
   0x080483fb <+0>:     lea    ecx,[esp+0x4]
   0x080483ff <+4>:     and    esp,0xfffffff0
   0x08048402 <+7>:     push   DWORD PTR [ecx-0x4]
   0x08048405 <+10>:    push   ebp
   0x08048406 <+11>:    mov    ebp,esp
   0x08048408 <+13>:    push   ecx
   0x08048409 <+14>:    sub    esp,0x4
   0x0804840c <+17>:    sub    esp,0xc
   0x0804840f <+20>:    push   0x80484b0
   0x08048414 <+25>:    call   0x80482d0 <puts@plt>
   0x08048419 <+30>:    add    esp,0x10
   0x0804841c <+33>:    mov    eax,0x0
   0x08048421 <+38>:    mov    ecx,DWORD PTR [ebp-0x4]
   0x08048424 <+41>:    leave
   0x08048425 <+42>:    lea    esp,[ecx-0x4]
   0x08048428 <+45>:    ret
End of assembler dump.
Set a breakpoint on the
mainfunction
gef> break main
Note: breakpoint 1 also set at pc 0x8048409.
Breakpoint 2 at 0x8048409We notice that the breakpoint is set at
0x8048409, which corresponds with the following line (from thedisass maincommand):
0x08048409 <+14>:    sub    esp,0x4This is the instruction to be executed next, while the final instruction that was already executed right before the main function is called can be found on the previous line:
0x08048408 <+13>:    push   ecxRun
gef> run
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax   : 0x080483fb  →  <main+0000> lea ecx, [esp+0x4]
$ebx   : 0xf7f97e14  →  0x00232d0c ("
                                     -#"?)
$ecx   : 0xffffcf00  →  0x00000001
$edx   : 0xffffcf20  →  0xf7f97e14  →  0x00232d0c ("
                                                    -#"?)
$esp   : 0xffffcee4  →  0xffffcf00  →  0x00000001
$ebp   : 0xffffcee8  →  0x00000000
$esi   : 0x08048430  →  <__libc_csu_init+0000> push ebp
$edi   : 0xf7ffcb60  →  0x00000000
$eip   : 0x08048409  →  <main+000e> sub esp, 0x4
$eflags: [zero carry PARITY adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffcee4│+0x0000: 0xffffcf00  →  0x00000001    ← $esp
0xffffcee8│+0x0004: 0x00000000   ← $ebp
0xffffceec│+0x0008: 0xf7d89cc3  →   add esp, 0x10
0xffffcef0│+0x000c: 0x00000000
0xffffcef4│+0x0010: 0x00000000
0xffffcef8│+0x0014: 0xf7da3029  →   add ebx, 0x1f4deb
0xffffcefc│+0x0018: 0xf7d89cc3  →   add esp, 0x10
0xffffcf00│+0x001c: 0x00000001
────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
    0x8048405 <main+000a>      push   ebp
    0x8048406 <main+000b>      mov    ebp, esp
    0x8048408 <main+000d>      push   ecx
●→  0x8048409 <main+000e>      sub    esp, 0x4
    0x804840c <main+0011>      sub    esp, 0xc
    0x804840f <main+0014>      push   0x80484b0
    0x8048414 <main+0019>      call   0x80482d0 <puts@plt>
    0x8048419 <main+001e>      add    esp, 0x10
    0x804841c <main+0021>      mov    eax, 0x0
────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "hello_world", stopped 0x8048409 in main (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048409 → main()
We can view a bunch of information:
a. Registers
b. Stack
c. Current position in the code
d. Threads
e. Trace
Navigate through the code with
nexti
Let's focus on the register esp. We can see the following line from the "stack" section before running the nexti instruction:
0xffffcee4│+0x0000: 0xffffcf00  →  0x00000001    ← $esp4.1 1st nexti
Now, we can move through the program with the nexti command, which will simply execute the next instruction:
gef> nextiUpdated esp value:
0xffffcee0│+0x0000: 0x00000000   ← $espThe stack value is decremented by 0x4 from the previous value
4.2 2nd nexti
Updated esp value:
0xffffced4│+0x0000: 0x00000000   ← $espThe stack value is decremented by 0xC (decimal value of 12) from the previous value
4.3 3rd nexti
Now, the next instruction will push a new address into the stack:
0x804840f <main+0014>      push   0x80484b0After running nexti again for the 3rd time, updated esp value:
0xffffced0│+0x0000: 0x080484b0  →  "hello world!"        ← $espWe can see that the esp is decremented by 0x4, with the value 0x080484b0 pushed onto the stack, which is expected from the push command. We can also see that the stored address contains the value "hello world!".
We can confirm this with gdb:
gef➤  x/a 0xffffced0 # view address
0xffffced0:     0x80484b0
gef➤  x/10c 0x80484b0 # view 10 chars
0x80484b0:      0x68    0x65    0x6c    0x6c    0x6f    0x20    0x77    0x6f
0x80484b8:      0x72    0x6c
gef➤  x/s 0x80484b0 # view string
0x80484b0:      "hello world!"Last updated