Recently i’ve been working with GDB scripting, and GDB allows scripting through its python api to automate specific tasks by writing a script that executes debugger commands. Examples include writing a disassembler to perform a disassembly of a VM obfuscated binary during runtime. There are many plugins for GDB, such as peda, gef and pwndbg. GEF is a powerful plugin with many features and the cheatsheet below covers how to use GEF’s API for GDB scripting.

setup gef

# via the install script
$ wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh

# manually 
$ wget -O ~/.gdbinit-gef.py -q https://github.com/hugsy/gef/raw/master/gef.py
$ echo source ~/.gdbinit-gef.py >> ~/.gdbinit

Execute GDB commands

gdb.execute(command: str, to_string: bool = False) 

Get Register Values

gef.arch.register(regname: str)
# Return a register's value.

gef.arch.pc
# Returns the program counter value.

gef.arch.sp
# Returns the stack pointer value.

gef.arch.fp
# Returns the file pointer value.

Get Instructions

gef_current_instruction(addr: int)
# Return the current instruction.

gef_next_instruction(addr: int)
# Return the next instruction.

gef_instruction_n(addr: int, n: int)
# Return the `n`-th instruction after `addr`.

gef_get_instruction_at(addr: int)
# Return the full Instruction found at the specified address.

Assemble/Disassemble

keystone_assemble(code: str, arch: int, mode: int)
# Assemble function based on keystone

gef_disassemble(addr: int, nb_insn: int)
# Disassembles `nb_insn` after the specified address `addr`

capstone_disassemble(addr: int, nb_insn: int)
# Disassembles `nb_insn` after the specified address `addr` using the Capstone-Engine disassembler

Memory operations

gef.memory.maps
# Return the mapped memory sections

gef.memory.write(address: int, buffer: ByteString) 
# Write `buffer` at address `address`.

gef.memory.read(addr: int, length: int = 0x10)
# Return a `length` long byte array with the copy of the process memory at `addr`.

gef.memory.read_integer(addr: int)
# Return an integer read from memory.

gef.memory.read_cstring(address: int)
# Return a C-string read from memory.

gef.memory.read_ascii_string(address: int)
# Read an ASCII string from memory.

Miscellaneous

gef.libc.version
# Retrun the current libc version

gef.session.file
# Return the absolute Path object of the target process.

parse_address(address: str)
# Parse an address and return it as an Integer.

p8(x: int),  u8(x: bytes) 
p16(x: int), u16(x: bytes)
p32(x: int), u32(x: bytes)
p64(x: int), u64(x: bytes)
# Pack and unpack one byte, word, dword and qword respecting the current architecture endianness.

xor(data: ByteString, key: str)
# Return `data` xor-ed with `key`.

hexdump() 
# Return the hexdump of the argument.

gef.session.pid
# Returns PID of the debugged process

conclusion

GDB has an extremely powerful range of functionality, and when used with its python scripting api, we can tap into its full functionality to analyze the program. And now that we’ve used gef, we can write gdb scripts much more easily, and I plan to update the cheatsheet eventually.

References