From c4fe56273aeb3a915b137856537d3b75fb4db6d2 Mon Sep 17 00:00:00 2001 From: hugsy Date: Mon, 17 Jul 2023 17:53:22 -0700 Subject: [PATCH 1/4] Fixes #965 --- gef.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/gef.py b/gef.py index 8875fc48f..d720422a6 100644 --- a/gef.py +++ b/gef.py @@ -29,7 +29,7 @@ ####################################################################################### # # gef is distributed under the MIT License (MIT) -# Copyright (c) 2013-2022 crazy rabbidz +# Copyright (c) 2013-2023 crazy rabbidz # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -1202,6 +1202,7 @@ class GlibcHeapInfo: @staticmethod def heap_info_t() -> Type[ctypes.Structure]: + assert gef.libc.version class heap_info_cls(ctypes.Structure): pass pointer = ctypes.c_uint64 if gef.arch.ptrsize == 8 else ctypes.c_uint32 @@ -3508,7 +3509,7 @@ def is_hex(pattern: str) -> bool: return len(pattern) % 2 == 0 and all(c in string.hexdigits for c in pattern[2:]) -def continue_handler(_: "gdb.Event") -> None: +def continue_handler(_: "gdb.ContinueEvent") -> None: """GDB event handler for new object continue cases.""" return @@ -3552,13 +3553,27 @@ def new_objfile_handler(evt: Optional["gdb.NewObjFileEvent"]) -> None: def exit_handler(_: "gdb.ExitedEvent") -> None: """GDB event handler for exit cases.""" global gef + # flush the caches reset_all_caches() + + # disconnect properly the remote session gef.session.qemu_mode = False if gef.session.remote: gef.session.remote.close() del gef.session.remote gef.session.remote = None gef.session.remote_initializing = False + + # if `autosave_breakpoints_file` setting is configured, save the breakpoints to disk + bkp_fpath = pathlib.Path(gef.config["gef.autosave_breakpoints_file"]).expanduser().absolute() + if bkp_fpath.exists(): + warn(f"{bkp_fpath} exists, content will be overwritten") + + with bkp_fpath.open("w+") as fd: + for bp in gdb.breakpoints(): + if not bp.enabled or not bp.is_valid: + continue + fd.write(f"{'t' if bp.temporary else ''}break {bp.location}\n") return @@ -3931,7 +3946,7 @@ def set_arch(arch: Optional[str] = None, _: Optional[str] = None) -> None: # @only_if_events_supported("cont") -def gef_on_continue_hook(func: Callable[["gdb.ThreadEvent"], None]) -> None: +def gef_on_continue_hook(func: Callable[["gdb.ContinueEvent"], None]) -> None: gdb.events.cont.connect(func) @@ -10383,6 +10398,7 @@ def main_arena(self, value: GlibcArena) -> None: @staticmethod @lru_cache() def find_main_arena_addr() -> int: + assert gef.libc.version """A helper function to find the glibc `main_arena` address, either from symbol, from its offset from `__malloc_hook` or by brute force.""" # Before anything else, use libc offset from config if available @@ -10499,6 +10515,7 @@ def min_chunk_size(self) -> int: @property def malloc_alignment(self) -> int: + assert gef.libc.version __default_malloc_alignment = 0x10 if gef.libc.version >= (2, 26) and is_x86_32(): # Special case introduced in Glibc 2.26: @@ -11104,7 +11121,8 @@ def reset_caches(self) -> None: gef_on_memchanged_hook(memchanged_handler) gef_on_regchanged_hook(regchanged_handler) - if gdb.current_progspace().filename is not None: + progspace = gdb.current_progspace() + if progspace and progspace.filename: # if here, we are sourcing gef from a gdb session already attached, force call to new_objfile (see issue #278) new_objfile_handler(None) @@ -11114,3 +11132,8 @@ def reset_caches(self) -> None: errmsg = "Using `target remote` with GEF does not work, use `gef-remote` instead. You've been warned." gdb.execute(f"define target hook-remote\n pi if calling_function() != \"connect\": err(\"{errmsg}\") \nend") gdb.execute(f"define target hook-extended-remote\n pi if calling_function() != \"connect\": err(\"{errmsg}\") \nend") + + # restore saved breakpoints (if any) + bkp_fpath = pathlib.Path(gef.config["gef.autosave_breakpoints_file"]).expanduser().absolute() + if bkp_fpath.exists() and bkp_fpath.is_file(): + gdb.execute(f"source {bkp_fpath}") From 16b3aff5cf0cbf428295292a8f00527608281eb2 Mon Sep 17 00:00:00 2001 From: hugsy Date: Mon, 17 Jul 2023 17:53:35 -0700 Subject: [PATCH 2/4] 2022 -> 2023 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index e84b43ea8..32ae4ca98 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2022 crazy rabbidz +Copyright (c) 2013-2023 crazy rabbidz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From df2781a07b351360a3dbba5f0e310f2639dbcc14 Mon Sep 17 00:00:00 2001 From: hugsy Date: Fri, 21 Jul 2023 13:33:30 -0700 Subject: [PATCH 3/4] make sure the path exists --- gef.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/gef.py b/gef.py index f938db60a..c64be100c 100644 --- a/gef.py +++ b/gef.py @@ -3565,7 +3565,11 @@ def exit_handler(_: "gdb.ExitedEvent") -> None: gef.session.remote_initializing = False # if `autosave_breakpoints_file` setting is configured, save the breakpoints to disk - bkp_fpath = pathlib.Path(gef.config["gef.autosave_breakpoints_file"]).expanduser().absolute() + setting = (gef.config["gef.autosave_breakpoints_file"] or "").strip() + if not setting: + return + + bkp_fpath = pathlib.Path(setting).expanduser().absolute() if bkp_fpath.exists(): warn(f"{bkp_fpath} exists, content will be overwritten") @@ -6024,7 +6028,7 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: args : argparse.Namespace = kwargs["arguments"] address = parse_address(args.address) num_instructions = args.n - + last_addr = gdb_get_nth_next_instruction_address(address, num_instructions) total_bytes = (last_addr - address) + gef_get_instruction_at(last_addr).size() target_addr = address + total_bytes @@ -6032,7 +6036,7 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: info(f"skipping {num_instructions} instructions ({total_bytes} bytes) from {address:#x} to {target_addr:#x}") gdb.execute(f"set $pc = {target_addr:#x}") return - + @register class NopCommand(GenericCommand): @@ -6065,10 +6069,10 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: address = parse_address(args.address) nop = gef.arch.nop_insn num_items = args.i or 1 - fill_bytes = args.b + fill_bytes = args.b fill_nops = args.n force_flag = args.f or False - + if fill_nops and fill_bytes: err("only is possible specify --b or --n at same time") return @@ -6102,11 +6106,11 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: curr_ins = gef_next_instruction(curr_ins.address) final_ins_end_addr = curr_ins.address + curr_ins.size() - + if final_ins_end_addr != target_end_address: warn(f"Patching {total_bytes} bytes at {address:#x} will result in LAST-INSTRUCTION " f"({curr_ins.address:#x}) being partial overwritten and may cause a crash or " - f"break disassembly. You must use --f to allow misaligned patching.") + "break disassembly. You must use --f to allow misaligned patching.") if not force_flag: return From 6b9b6661ccef47b18a3607926e9c682ffb7b3d33 Mon Sep 17 00:00:00 2001 From: crazy hugsy Date: Sat, 22 Jul 2023 08:40:56 -0700 Subject: [PATCH 4/4] w+ -> w --- gef.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gef.py b/gef.py index 33294136e..1af8c3847 100644 --- a/gef.py +++ b/gef.py @@ -3573,7 +3573,7 @@ def exit_handler(_: "gdb.ExitedEvent") -> None: if bkp_fpath.exists(): warn(f"{bkp_fpath} exists, content will be overwritten") - with bkp_fpath.open("w+") as fd: + with bkp_fpath.open("w") as fd: for bp in gdb.breakpoints(): if not bp.enabled or not bp.is_valid: continue