Skip to content

Commit

Permalink
glibc function call argument definition (#577)
Browse files Browse the repository at this point in the history
This change adds functionality to optionally parse a json file for glibc
arguments. If this setting is set and the file can be found, then GEF
will lookup imported functions in the json, and if there's a match, it
will use the number and type of args provided instead of guessing.
  • Loading branch information
theguly committed Nov 15, 2020
1 parent 6dd16eb commit 1441d90
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
6 changes: 6 additions & 0 deletions docs/commands/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,9 @@ gef➤ gef config context.ignore_registers "$cs $ds $gs"
```
gef➤ gef config context.show_source_code_variable_values 0
```

* Show better definitions for call to libc functions.
```
gef➤ gef config context.libc_args True
gef➤ gef config context.libc_args_path /path/to/gef-extras/libc_args
```
72 changes: 63 additions & 9 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import importlib
import inspect
import itertools
import json
import os
import platform
import re
Expand All @@ -88,6 +89,7 @@
from io import StringIO
from urllib.request import urlopen #pylint: disable=import-error,no-name-in-module


lru_cache = functools.lru_cache #pylint: disable=no-member

LEFT_ARROW = " \u2190 "
Expand Down Expand Up @@ -177,6 +179,8 @@ def update_gef(argv):
current_elf = None
current_arch = None

libc_args_definitions = {}

highlight_table = {}
ANSI_SPLIT_RE = r"(\033\[[\d;]*m)"

Expand Down Expand Up @@ -2937,6 +2941,7 @@ def new_objfile_handler(event):
"""GDB event handler for new object file cases."""
reset_all_caches()
set_arch()
load_libc_args()
return


Expand All @@ -2951,6 +2956,39 @@ def exit_handler(event):
__gef_remote__ = None
return

def load_libc_args():
# load libc function arguments' definitions
if not get_gef_setting("context.libc_args"):
return

path = get_gef_setting("context.libc_args_path")
if path is None:
warn("Config context.libc_args_path not set but context.libc_args is True. Make sure you have gef-extras installed")
return
elif not os.path.isdir(path):
warn("Config context.libc_args_path_path set but it's not a directory")
return

_arch_mode = "{}_{}".format(current_arch.arch.lower(), current_arch.mode)
_libc_args_file = "{}/{}.json".format(path, _arch_mode)

global libc_args_definitions

# current arch and mode already loaded
if _arch_mode in libc_args_definitions:
return

libc_args_definitions[_arch_mode] = {}
try:
with open(_libc_args_file) as _libc_args:
libc_args_definitions[_arch_mode] = json.load(_libc_args)
except FileNotFoundError:
del(libc_args_definitions[_arch_mode])
warn("Config context.libc_args is set but definition cannot be loaded: file {} not found".format(_libc_args_file))
except json.decoder.JSONDecodeError as e:
del(libc_args_definitions[_arch_mode])
warn("Config context.libc_args is set but definition cannot be loaded from file {}: {}".format(_libc_args_file, e))
return

def get_terminal_size():
"""Return the current terminal size."""
Expand Down Expand Up @@ -7429,6 +7467,8 @@ def __init__(self):
self.add_setting("clear_screen", True, "Clear the screen before printing the context")
self.add_setting("layout", "legend regs stack code args source memory threads trace extra", "Change the order/presence of the context sections")
self.add_setting("redirect", "", "Redirect the context information to another TTY")
self.add_setting("libc_args", False, "Show libc function call args description")
self.add_setting("libc_args_path", "", "Path to libc function call args json files, provided via gef-extras")

if "capstone" in list(sys.modules.keys()):
self.add_setting("use_capstone", False, "Use capstone as disassembler in the code pane (instead of GDB)")
Expand Down Expand Up @@ -7792,18 +7832,32 @@ def __get_current_block_start_address():
if op in extended_registers[exreg]:
parameter_set.add(exreg)

if is_x86_32():
nb_argument = len(parameter_set)
else:
nb_argument = 0
for p in parameter_set:
nb_argument = max(nb_argument, function_parameters.index(p)+1)
nb_argument = None
_arch_mode = "{}_{}".format(current_arch.arch.lower(), current_arch.mode)
if function_name.endswith('@plt'):
_function_name = function_name.split('@')[0]
try:
nb_argument = len(libc_args_definitions[_arch_mode][_function_name])
except KeyError:
pass

if not nb_argument:
if is_x86_32():
nb_argument = len(parameter_set)
else:
nb_argument = max(function_parameters.index(p)+1 for p in parameter_set)

args = []
for i in range(nb_argument):
_key, _value = current_arch.get_ith_parameter(i, in_func=False)
_value = RIGHT_ARROW.join(DereferenceCommand.dereference_from(_value))
args.append("{} = {}".format(Color.colorify(_key, arg_key_color), _value))
_key, _values = current_arch.get_ith_parameter(i, in_func=False)
_values = DereferenceCommand.dereference_from(_values)

_values = RIGHT_ARROW.join(_values)
try:
args.append("{} = {} (def: {})".format(Color.colorify(_key, arg_key_color), _values,
libc_args_definitions[_arch_mode][_function_name][_key]))
except:
args.append("{} = {}".format(Color.colorify(_key, arg_key_color), _values))

self.context_title("arguments (guessed)")
gef_print("{} (".format(function_name))
Expand Down
2 changes: 2 additions & 0 deletions scripts/gef-extras.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ git clone https://github.com/hugsy/gef-extras.git ${DIR}/gef-extras
gdb -q -ex "gef config gef.extra_plugins_dir '${DIR}/gef-extras/scripts'" \
-ex "gef config pcustom.struct_path '${DIR}/gef-extras/structs'" \
-ex "gef config syscall-args.path '${DIR}/gef-extras/syscall-tables'" \
-ex "gef config libc_args True" \
-ex "gef config libc_args_path '${DIR}/gef-extras/glibc-function-args'" \
-ex 'gef save' \
-ex quit

Expand Down

0 comments on commit 1441d90

Please sign in to comment.