diff --git a/gef.py b/gef.py index 3300b1c85..5abf9a1ba 100644 --- a/gef.py +++ b/gef.py @@ -3335,7 +3335,7 @@ class MIPS64(MIPS): @staticmethod def supports_gdb_arch(gdb_arch: str) -> Optional[bool]: - return gdb_arch.startswith("mips") and gef.binary.e_class == Elf.Class.ELF_64_BITS + return gdb_arch.startswith("mips") and gef.binary and gef.binary.e_class == Elf.Class.ELF_64_BITS def copy_to_clipboard(data: bytes) -> None: @@ -3551,6 +3551,10 @@ def continue_handler(_: "gdb.ContinueEvent") -> None: def hook_stop_handler(_: "gdb.StopEvent") -> None: """GDB event handler for stop cases.""" + if gef.session.remote: + gef.session.remote.maps.unlink() + gef.session.remote.sync(f"/proc/{gef.session.remote.pid}/maps") + reset_all_caches() gdb.execute("context") return @@ -3718,7 +3722,7 @@ def reset_architecture(arch: Optional[str] = None) -> None: return # last resort, use the info from elf header to find it from the known architectures - if gef.binary.e_machine: + if gef.binary and gef.binary.e_machine: try: gef.arch = arches[gef.binary.e_machine]() except KeyError: @@ -6045,12 +6049,12 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: dbg(f"[remote] initializing remote session with {gef.session.remote.target} under {gef.session.remote.root}") if not gef.session.remote.connect(args.pid): + gef.session.reset_remote() raise EnvironmentError(f"Cannot connect to remote target {gef.session.remote.target}") if not gef.session.remote.setup(): + gef.session.reset_remote() raise EnvironmentError(f"Failed to create a proper environment for {gef.session.remote.target}") - gef.session.remote_initializing = False - reset_all_caches() gdb.execute("context") return @@ -7218,7 +7222,7 @@ def do_invoke(self, argv: List[str]) -> None: return if not os.access(fpath, os.X_OK): - warn(f"The file '{fpath}' is not executable.") + warn(f"The file '{fpath}' does not exists or is not executable.") return if is_alive() and not gef.session.qemu_mode: @@ -10874,6 +10878,12 @@ def reset_caches(self) -> None: self._root: Optional[pathlib.Path] = None return + def reset_remote(self) -> None: + self.remote_initializing = False + self.remote = None + return + + def __str__(self) -> str: return f"Session({'Local' if self.remote is None else 'Remote'}, pid={self.pid or 'Not running'}, os='{self.os}')" @@ -11056,7 +11066,12 @@ def sync(self, src: str, dst: Optional[str] = None) -> bool: return True tgt.parent.mkdir(parents=True, exist_ok=True) dbg(f"[remote] downloading '{src}' -> '{tgt}'") - gdb.execute(f"remote get '{src}' '{tgt.absolute()}'") + + try: + gdb.execute(f"remote get '{src}' '{tgt.absolute()}'") + except gdb.error: + return False + return tgt.exists() def connect(self, pid: int) -> bool: @@ -11085,18 +11100,25 @@ def connect(self, pid: int) -> bool: def setup(self) -> bool: # setup remote adequately depending on remote or qemu mode + success = True + if self.in_qemu_user(): dbg(f"Setting up as qemu session, target={self.__qemu}") - self.__setup_qemu() + if not self.__setup_qemu(): + success = False else: dbg(f"Setting up as remote session") - self.__setup_remote() + if not self.__setup_remote(): + success = False # refresh gef to consider the binary reset_all_caches() - gef.binary = Elf(self.lfile) + + if self.lfile.exists(): + gef.binary = Elf(self.lfile) + reset_architecture() - return True + return success def __setup_qemu(self) -> bool: # setup emulated file in the chroot @@ -11133,27 +11155,45 @@ def __setup_qemu(self) -> bool: return True def __setup_remote(self) -> bool: + success = True + # get the file - fpath = f"/proc/{self.pid}/exe" - if not self.sync(fpath, str(self.file)): - err(f"'{fpath}' could not be fetched on the remote system.") - return False + if not self.sync(str(self.file)): + warn(f"'{str(self.file)}' could not be fetched on the remote system.") + success = False - # pseudo procfs - for _file in ("maps", "environ", "cmdline"): - fpath = f"/proc/{self.pid}/{_file}" - if not self.sync(fpath): - err(f"'{fpath}' could not be fetched on the remote system.") - return False + fpath = f"/proc/{self.pid}/maps" + if not self.sync(fpath): + warn(f"'{fpath}' could not be fetched on the remote system.") + success = False - # makeup a fake mem mapping in case we failed to retrieve it - maps = self.root / f"proc/{self.pid}/maps" - if not maps.exists(): + # make up a fake mem mapping in case we failed to retrieve it + maps = self.root / fpath with maps.open("w") as fd: fname = self.file.absolute() mem_range = "00000000-ffffffff" if is_32bit() else "0000000000000000-ffffffffffffffff" fd.write(f"{mem_range} rwxp 00000000 00:00 0 {fname}\n") - return True + + fpath = f"/proc/{self.pid}/environ" + if not self.sync(fpath): + warn(f"'{fpath}' could not be fetched on the remote system.") + success = False + + # make up a fake environ in case we failed to retrieve it + environ = self.root / fpath + with environ.open("wb") as fd: + fd.write(b"PATH=/bin\x00HOME=/tmp\x00") + + fpath = f"/proc/{self.pid}/cmdline" + if not self.sync(fpath): + warn(f"'{fpath}' could not be fetched on the remote system.") + success = False + + # make up a fake cmdline in case we failed to retrieve it + with (self.root / fpath).open("w") as fd: + fd.write("") + + return success def remote_objfile_event_handler(self, evt: "gdb.NewObjFileEvent") -> None: dbg(f"[remote] in remote_objfile_handler({evt.new_objfile.filename if evt else 'None'}))") @@ -11281,7 +11321,11 @@ def target_remote_posthook(): gef.session.remote = GefRemoteSessionManager("", 0) if not gef.session.remote.setup(): - raise EnvironmentError(f"Failed to create a proper environment for {gef.session.remote}") + gef.session.reset_remote() + warn(f"Failed to create a proper environment for {gef.session.remote}") + return False + + return True if __name__ == "__main__": if sys.version_info[0] == 2: @@ -11372,8 +11416,7 @@ def target_remote_posthook(): f"`{disable_tr_overwrite_setting}` in the config.") hook = f""" define target hookpost-{{}} - pi target_remote_posthook() - context + pi if target_remote_posthook(): gdb.execute("context") pi if calling_function() != "connect": warn("{warnmsg}") end """