Skip to content

Commit

Permalink
Added callback to register_external_content_pane to conditionally d…
Browse files Browse the repository at this point in the history
…isplay pane (#866)
  • Loading branch information
hugsy authored Jul 5, 2022
1 parent 17fa7f9 commit 1499023
Showing 1 changed file with 43 additions and 87 deletions.
130 changes: 43 additions & 87 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -3482,7 +3482,6 @@ def new_objfile_handler(evt: "gdb.Event") -> None:
if not gef.binary:
gef.binary = binary
reset_architecture()
load_libc_args()
else:
gef.session.modules.append(binary)
except FileNotFoundError as fne:
Expand Down Expand Up @@ -3516,41 +3515,6 @@ def regchanged_handler(_: "gdb.RegisterChangedEvent") -> None:
return


def load_libc_args() -> bool:
"""Load the LIBC function arguments. Returns `True` on success, `False` or an Exception otherwise."""
global gef
# load libc function arguments' definitions
if not gef.config["context.libc_args"]:
return False

path = gef.config["context.libc_args_path"]
if not path:
return False

path = pathlib.Path(path).expanduser().absolute()
if not path.exists():
raise RuntimeError("Config `context.libc_args_path` set but it's not a directory")

_arch_mode = f"{gef.arch.arch.lower()}_{gef.arch.mode}"
_libc_args_file = path / f"{_arch_mode}.json"

# current arch and mode already loaded
if _arch_mode in gef.ui.libc_args_table:
return True

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


def get_terminal_size() -> Tuple[int, int]:
"""Return the current terminal size."""
if is_debug():
Expand Down Expand Up @@ -4380,20 +4344,25 @@ def stop(self) -> bool:
# Context Panes
#

def register_external_context_pane(pane_name: str, display_pane_function: Callable[[], None], pane_title_function: Callable[[], Optional[str]]) -> None:
def register_external_context_pane(pane_name: str, display_pane_function: Callable[[], None], pane_title_function: Callable[[], Optional[str]], condition : Optional[Callable[[], bool]] = None) -> None:
"""
Registering function for new GEF Context View.
pane_name: a string that has no spaces (used in settings)
display_pane_function: a function that uses gef_print() to print strings
pane_title_function: a function that returns a string or None, which will be displayed as the title.
If None, no title line is displayed.
Example Usage:
def display_pane(): gef_print("Wow, I am a context pane!")
def pane_title(): return "example:pane"
register_external_context_pane("example_pane", display_pane, pane_title)
condition: an optional callback: if not None, the callback will be executed first. If it returns true,
then only the pane title and content will displayed. Otherwise, it's simply skipped.
Example usage for a simple text to show when we hit a syscall:
def only_syscall(): return gef_current_instruction(gef.arch.pc).is_syscall()
def display_pane():
gef_print("Wow, I am a context pane!")
def pane_title():
return "example:pane"
register_external_context_pane("example_pane", display_pane, pane_title, only_syscall)
"""
gef.gdb.add_context_pane(pane_name, display_pane_function, pane_title_function)
gef.gdb.add_context_pane(pane_name, display_pane_function, pane_title_function, condition)
return


Expand Down Expand Up @@ -5695,7 +5664,7 @@ class SearchPatternCommand(GenericCommand):
f"{_cmdline_} 0x555555554000 little stack",
f"{_cmdline_} AAAA 0x600000-0x601000",
f"{_cmdline_} --regex 0x401000 0x401500 ([\\\\x20-\\\\x7E]{{2,}})(?=\\\\x00) <-- It matchs null-end-printable(from x20-x7e) C strings (min size 2 bytes)"]

def __init__(self) -> None:
super().__init__()
self["max_size_preview"] = (10, "max size preview of bytes")
Expand Down Expand Up @@ -5746,7 +5715,7 @@ def search_pattern_by_address(self, pattern: str, start_address: int, end_addres
del mem

return locations

def search_binpattern_by_address(self, binpattern: bytes, start_address: int, end_address: int) -> List[Tuple[int, int, Optional[str]]]:
"""Search a binary pattern within a range defined by arguments."""

Expand All @@ -5763,15 +5732,15 @@ def search_binpattern_by_address(self, binpattern: bytes, start_address: int, en
mem = gef.memory.read(chunk_addr, chunk_size)
except gdb.MemoryError as e:
return []
preview_size = self["max_size_preview"]
preview_size = self["max_size_preview"]
for match in re.finditer(binpattern, mem):
start = chunk_addr + match.start()
preview = str(mem[slice(*match.span())][0:preview_size]) + "..."
size_match = match.span()[1] - match.span()[0]
if size_match > 0:
size_match -= 1
end = start + size_match

locations.append((start, end, preview))

del mem
Expand Down Expand Up @@ -5805,14 +5774,14 @@ def do_invoke(self, argv: List[str]) -> None:
if argc < 1:
self.usage()
return

if argc > 3 and argv[0].startswith("--regex"):
pattern = ' '.join(argv[3:])
pattern = ast.literal_eval("b'" + pattern + "'")

addr_start = parse_address(argv[1])
addr_end = parse_address(argv[2])

for loc in self.search_binpattern_by_address(pattern, addr_start, addr_end):
self.print_loc(loc)

Expand Down Expand Up @@ -7088,20 +7057,20 @@ def __init__(self) -> None:
self["clear_screen"] = (True, "Clear the screen before printing the context")
self["layout"] = ("legend regs stack code args source memory threads trace extra", "Change the order/presence of the context sections")
self["redirect"] = ("", "Redirect the context information to another TTY")
self["libc_args"] = (False, "Show libc function call args description")
self["libc_args_path"] = ("", "Path to libc function call args json files, provided via gef-extras")
self["libc_args"] = (False, "[DEPRECATED - Unused] Show libc function call args description")
self["libc_args_path"] = ("", "[DEPRECATED - Unused] Path to libc function call args json files, provided via gef-extras")

self.layout_mapping = {
"legend": (self.show_legend, None),
"regs": (self.context_regs, None),
"stack": (self.context_stack, None),
"code": (self.context_code, None),
"args": (self.context_args, None),
"memory": (self.context_memory, None),
"source": (self.context_source, None),
"trace": (self.context_trace, None),
"threads": (self.context_threads, None),
"extra": (self.context_additional_information, None),
"legend": (self.show_legend, None, None),
"regs": (self.context_regs, None, None),
"stack": (self.context_stack, None, None),
"code": (self.context_code, None, None),
"args": (self.context_args, None, None),
"memory": (self.context_memory, None, None),
"source": (self.context_source, None, None),
"trace": (self.context_trace, None, None),
"threads": (self.context_threads, None, None),
"extra": (self.context_additional_information, None, None),
}

self.instruction_iterator = gef_disassemble
Expand Down Expand Up @@ -7156,7 +7125,10 @@ def do_invoke(self, argv: List[str]) -> None:
continue

try:
display_pane_function, pane_title_function = self.layout_mapping[section]
display_pane_function, pane_title_function, condition = self.layout_mapping[section]
if condition:
if not condition():
continue
if pane_title_function:
self.context_title(pane_title_function())
display_pane_function()
Expand Down Expand Up @@ -7465,31 +7437,16 @@ def __get_current_block_start_address() -> Optional[int]:
if op in extended_registers[exreg]:
parameter_set.add(exreg)

nb_argument = None
_arch_mode = f"{gef.arch.arch.lower()}_{gef.arch.mode}"
_function_name = None
if function_name.endswith("@plt"):
_function_name = function_name.split("@")[0]
try:
nb_argument = len(gef.ui.libc_args_table[_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], default=0)
if is_x86_32():
nb_argument = len(parameter_set)
else:
nb_argument = max([function_parameters.index(p)+1 for p in parameter_set], default=0)

args = []
for i in range(nb_argument):
_key, _values = gef.arch.get_ith_parameter(i, in_func=False)
_values = RIGHT_ARROW.join(dereference_from(_values))
try:
args.append("{} = {} (def: {})".format(Color.colorify(_key, arg_key_color), _values,
gef.ui.libc_args_table[_arch_mode][_function_name][_key]))
except KeyError:
args.append(f"{Color.colorify(_key, arg_key_color)} = {_values}")
args.append(f"{Color.colorify(_key, arg_key_color)} = {_values}")

self.context_title("arguments (guessed)")
gef_print(f"{function_name} (")
Expand Down Expand Up @@ -7657,11 +7614,11 @@ def context_trace(self) -> None:

def context_threads(self) -> None:
def reason() -> str:
res = gdb.execute("info program", to_string=True).splitlines()
res = gdb.execute("info program", to_string=True)
if not res:
return "NOT RUNNING"

for line in res:
for line in res.splitlines():
line = line.strip()
if line.startswith("It stopped with signal "):
return line.replace("It stopped with signal ", "").split(",", 1)[0]
Expand Down Expand Up @@ -9441,7 +9398,7 @@ def invoke(self, args: Any, from_tty: bool) -> None:
gdb.execute("gef help")
return

def add_context_pane(self, pane_name: str, display_pane_function: Callable, pane_title_function: Callable) -> None:
def add_context_pane(self, pane_name: str, display_pane_function: Callable, pane_title_function: Callable, condition: Optional[Callable]) -> None:
"""Add a new context pane to ContextCommand."""
for _, class_instance in self.commands.items():
if isinstance(class_instance, ContextCommand):
Expand All @@ -9456,7 +9413,7 @@ def add_context_pane(self, pane_name: str, display_pane_function: Callable, pane
gef.config["context.layout"] += f" {corrected_settings_name}"

# overload the printing of pane title
context.layout_mapping[corrected_settings_name] = (display_pane_function, pane_title_function)
context.layout_mapping[corrected_settings_name] = (display_pane_function, pane_title_function, condition)

def load(self) -> None:
"""Load all the commands and functions defined by GEF into GDB."""
Expand Down Expand Up @@ -10739,7 +10696,6 @@ def __init__(self) -> None:
self.context_hidden = False
self.stream_buffer : Optional[StringIO] = None
self.highlight_table: Dict[str, str] = {}
self.libc_args_table: Dict[str, Dict[str, Dict[str, str]]] = {}
self.watches: Dict[int, Tuple[int, str]] = {}
self.context_messages: List[Tuple[str, str]] = []
return
Expand Down

0 comments on commit 1499023

Please sign in to comment.