Extending GEF
GEF
intends to provide a battery-included, quickly installable and crazy fast
debugging environment sitting on top of GDB.
But it most importantly provides all the primitives required to allow hackers to
quickly create their own commands. This page intends to summarize how to
create advanced GDB commands in moments using GEF
as a library.
A dedicated repository was born to host
external scripts. This
repo is open to all for contributions, no restrictions and the most valuable
ones will be integrated into gef.py
.
Quick start
Here is the most basic skeleton for creating a new GEF
command named newcmd
:
class NewCommand(GenericCommand):
"""Dummy new command."""
_cmdline_ = "newcmd"
_syntax_ = "{:s}".format(_cmdline_)
@only_if_gdb_running # not required, ensures that the debug session is started
def do_invoke(self, argv):
# do anything allowed by gef, for example show the current running
# architecture as Python object:
print(" = {}".format(current_arch) )
# or showing the current $pc
print("pc = {:#x}".format(current_arch.pc))
return
register_external_command(NewCommand())
Yes, that's it!
Loading it in GEF
is as easy as
gef➤ source /path/to/newcmd.py
[+] Loading 'NewCommand'
We can call it:
Detailed explanation
Our new command must be a class that inherits from GEF's GenericCommand
. The
only requirements are:
- a
_cmdline_
attribute (the command to type on the GDB prompt). - a
_syntax_
attribute, which GEF will use to auto-generate the help menu. - a method
do_invoke(self, args)
which will be executed when the command is invoked.args
is a list of the command line args provided when invoked.
We make GEF aware of this new command by registering it in the __main__
section of the script, by invoking the global function
register_external_command()
.
Now you have a new GEF command which you can load, either from cli:
gef➤ source /path/to/newcmd.py
or add to your ~/.gdbinit
:
$ echo source /path/to/newcmd.py >> ~/.gdbinit
API
Some of the most important parts of the API for creating new commands are
mentioned (but not limited to) below. To see the full help of a function, open
GDB and GEF, and use the embedded Python interpreter's help
command. For
example:
gef➤ pi help(Architecture)
or even from outside GDB:
$ gdb -q -ex 'pi help(hexdump)' -ex quit
Globals
register_external_command()
Procedure to add the new GEF command
current_arch
Global variable associated with the architecture of the currently debugged process. The variable is an instance of the
Architecture
class (see below).
read_memory(addr, length=0x10)
Returns a
length
long byte array with a copy of the process memory read fromaddr
.
write_memory(addr, buffer, length=0x10)
Writes
buffer
to memory at addressaddr
.
read_int_from_memory(addr)
Reads the size of an integer from
addr
, and unpacks it correctly (based on the current arch's endianness)
read_cstring_from_memory(addr)
Return a NULL-terminated array of bytes, from
addr
.
get_register(register_name)
Returns the value of given register.
get_process_maps()
Returns an array of Section objects (see below) corresponding to the current memory layout of the process.
gef_disassemble(addr, nb_insn, from_top=False)
Disassemble
nb_insn
instructions afteraddr
. Iffrom_top
is False (default), it will also disassemble thenb_insn
instructions beforeaddr
. Return an iterator of Instruction objects (see below).
ok(msg)
info(msg)
warn(msg)
err(msg)
Logging functions
gef_on_continue_hook
gef_on_continue_unhook
Takes a callback function FUNC as parameter: add/remove a call to FUNC when GDB continues execution.
gef_on_stop_hook
gef_on_stop_unhook
Takes a callback function FUNC as parameter: add/remove a call to FUNC when GDB stops execution (breakpoints, watchpoints, interrupt, signal, etc.).
gef_on_new_hook
gef_on_new_unhook
Takes a callback function FUNC as parameter: add/remove a call to FUNC when GDB loads a new binary.
gef_on_exit_hook
gef_on_exit_unhook
Takes a callback function FUNC as parameter: add/remove a call to FUNC when GDB exits an inferior.
Decorators
@only_if_gdb_running
Modifies a function to only execute if a GDB session is running. A GDB session is running if:
- a PID exists for the targeted binary
- GDB is running on a coredump of a binary
@only_if_gdb_target_local
Checks if the current GDB session is local i.e. not debugging using GDB
remote
.
@only_if_gdb_version_higher_than( (MAJOR, MINOR) )
Checks if the GDB version is higher or equal to the MAJOR and MINOR provided as arguments (both as Integers). This is required since some commands/API of GDB are only present in the very latest version of GDB.
Classes
For exhaustive documentation, run
$ gdb -q -ex 'pi help(<ClassName>)' -ex quit
Generic
New GEF commands must inherit GenericCommand
, have _cmdline_
and
_syntax_
attrivutes, and have a instance method do_invoke(args)
defined.
Other than that, new commands can enjoy all the GEF abstract layer representation classes, such as:
Instruction
: GEF representation of instruction as pure Python objects.Address
: GEF representation of memory addresses.Section
: GEF representation of process memory sections.Permission
: Page permission object.Elf
: ELF parsing object.
Architectures
Architecture
: Generic metaclass for the architectures supported by GEF.ARM
AARCH64
X86
X86_64
PowerPC
PowerPC64
SPARC
SPARC64
MIPS
Heap
GlibcArena
: Glibc arena classGlibcChunk
: Glibc chunk class.