Skip to content

Instantly share code, notes, and snippets.

@Enigmatrix
Last active June 18, 2024 18:08
Show Gist options
  • Save Enigmatrix/89b09b4c97d541df3dd9e0d8ace9ed1a to your computer and use it in GitHub Desktop.
Save Enigmatrix/89b09b4c97d541df3dd9e0d8ace9ed1a to your computer and use it in GitHub Desktop.
GDB Cheatsheet using pwndbg

GDB Cheatsheet

Setup

First of all, we need to install GDB: sudo apt install gdb

Next we will be installing an extension to GDB called pwndbg that will make our life easier. Instructions for installation are here.

You can verify that your installation works by running gdb /bin/true in your command line, then running start when the prompt shows.

image

You should see something similar to the screenshot above.

Usage

To start off, you may use the below template for your exploits

from pwn import *

p = process("path to bin")
pause()

# actual exploit here

p.interactive()

On execution of the above script, it will pause and print out the target binary's process id: image

We can then attach to the target process using gdb in another terminal (make sure to NOT kill our paused python script): image

This extremely long output that is printed is the context of your program (a minimal view into the state of the program).

Now, you can go to the original terminal where the script is running, then press enter to unpause your script. The below commands are used inside the gdb terminal to interact with the program. Right now, the program is still in a paused state.

Commands

  • continue / c

You can unpause the execution of the program. Execution continues until the program exits or until a breakpoint is reached

  • breakpoint <point> / b <point>

Place a breakpoint at <point> e.g. main (directly at the first instruction of the main function) or main+55 (the instruction 55 bytes after the main function) or *0x404123 (the instruction at 0x404123). A breakpoint is a place where execution is paused when the $rip (instruction pointer) reaches there.

  • si

Execute exactly 1 instruction (step into). If the instruction is a call instruction, we will be stepping INSIDE the target function. For example, if you are at paused at the call puts instruction and you enter this into gdb, you will arrive at the call stub for puts.

  • ni

Execute exactly 1 instruction (step over), without stepping into a function. If the instruction call instruction, the entire target function is executed, then we are the instruction directly after the call instruction.

  • tele <address> <count>

Print out data from <address>, a total of <count> rows. For example, to print relative to the rbp register, at a offset of 0x20, you can use tele rbp+0x20.

  • disass <func>

Print out the assembly for this <func> function.

Good-to-know

Typical Workflow

Worflow is similar to the section above Commands. Right after this, you will need to put a breakpoint right after the first 'input-based' call. For example, consider this function:

image

The first 'input-based' call would be the call to read_long, which reads in a integer. Thus we should put a breakpoint using b main+44.

Calling Convention (x64)

Arguments to functions are stored in registers. In sequence the arguments are stored in (rdi, rsi, rdx, rcx, r8, r9, then the stack). Return value of a function is stored in the rax register.

Registers (x64)

If you see eax instead of rax, do not fret, they are in fact the same register:

image

Stack Frames (x64)

If you are inside the function a, local variables are between the rsp and rbp registers. The saved rbp is at rbp, and the return address is at rbp+8.

image

For example, saved rbp is 0 and return address is libc_start_main+243 in the above image. Which local variable is which, depends on the assembly.

e.g. for based on the above image and the image at Typical Workflow, the output of read_long is saved into a variable at rbp-0x8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment