diff --git a/pwndbg/commands/xinfo.py b/pwndbg/commands/xinfo.py index 3f7e82e72..8f75db808 100644 --- a/pwndbg/commands/xinfo.py +++ b/pwndbg/commands/xinfo.py @@ -1,6 +1,7 @@ from __future__ import annotations import argparse +import os import pwndbg import pwndbg.color.memory as M @@ -59,6 +60,11 @@ def xinfo_mmap_file(page, addr) -> None: # to beginning of file in memory and on disk file_name = page.objfile + # Check if the file exists on the local system, as we may be attached to a gdb-server or qemu. + # Even so, the file might exist locally, if we are doing `target remote localhost:1234` + if not os.path.exists(file_name): + return None + objpages = filter(lambda p: p.objfile == file_name, pwndbg.gdblib.vmmap.get()) first = sorted(objpages, key=lambda p: p.vaddr)[0] diff --git a/pwndbg/gdblib/vmmap.py b/pwndbg/gdblib/vmmap.py index c6f7441b7..3eb386fbf 100644 --- a/pwndbg/gdblib/vmmap.py +++ b/pwndbg/gdblib/vmmap.py @@ -310,7 +310,7 @@ def coredump_maps() -> Tuple[pwndbg.lib.memory.Page, ...]: Parses `info proc mappings` and `maintenance info sections` and tries to make sense out of the result :) """ - pages = list(info_proc_maps()) + pages = list(info_proc_maps(parse_flags=False)) started_sections = False for line in gdb.execute("maintenance info sections", to_string=True).splitlines(): @@ -392,31 +392,43 @@ def coredump_maps() -> Tuple[pwndbg.lib.memory.Page, ...]: return tuple(pages) -def parse_info_proc_mappings_line(line: str, parse_flags: bool) -> Optional[pwndbg.lib.memory.Page]: +def parse_info_proc_mappings_line( + line: str, perms_available: bool, parse_flags: bool +) -> Optional[pwndbg.lib.memory.Page]: """ Parse a line from `info proc mappings` and return a pwndbg.lib.memory.Page object if the line is valid. + Example lines: + 0x4c3000 0x4c5000 0x2000 0xc2000 rw-p /root/hello_world/main + 0x4c5000 0x4cb000 0x6000 0x0 rw-p + + The objfile column might be empty, and the permissions column is only present in GDB versions >= 12.1 + https://github.com/bminor/binutils-gdb/commit/29ef4c0699e1b46d41ade00ae07a54f979ea21cc + Args: line: A line from `info proc mappings`. Returns: A pwndbg.lib.memory.Page object or None. """ - - # We look for lines like: - # ['0x555555555000', '0x555555556000', '0x1000', '0x1000', 'rw-p', '/home/user/a.out'] try: + # Example line with all fields present: ['0x555555555000', '0x555555556000', '0x1000', '0x1000', 'rw-p', '/home/user/a.out'] split_line = line.split() - # Permission info is only available in GDB versions >=12.1 - # https://github.com/bminor/binutils-gdb/commit/29ef4c0699e1b46d41ade00ae07a54f979ea21cc - # Assume "rwxp" on older gdb versions - if len(split_line) < 6: - start_str, _end, size_str, offset_str, objfile = split_line - perm = "rwxp" + start_str = split_line[0] + _end = split_line[1] + size_str = split_line[2] + offset_str = split_line[3] + + if perms_available: + perm = split_line[4] + # The objfile column may be empty. + objfile = split_line[5] if len(split_line) > 5 else "" else: - start_str, _end, size_str, offset_str, perm, objfile = split_line + perm = "rwxp" + objfile = split_line[4] if len(split_line) > 4 else "" + start, size, offset = int(start_str, 16), int(size_str, 16), int(offset_str, 16) except (IndexError, ValueError): return None @@ -434,10 +446,25 @@ def parse_info_proc_mappings_line(line: str, parse_flags: bool) -> Optional[pwnd @pwndbg.lib.cache.cache_until("start", "stop") -def info_proc_maps(parse_flags=False) -> Tuple[pwndbg.lib.memory.Page, ...]: +def info_proc_maps(parse_flags=True) -> Tuple[pwndbg.lib.memory.Page, ...]: """ Parse the result of info proc mappings. + Example output: + + Start Addr End Addr Size Offset Perms objfile + 0x400000 0x401000 0x1000 0x0 r--p /root/hello_world/main + 0x401000 0x497000 0x96000 0x1000 r-xp /root/hello_world/main + 0x497000 0x4be000 0x27000 0x97000 r--p /root/hello_world/main + 0x4be000 0x4c3000 0x5000 0xbd000 r--p /root/hello_world/main + 0x4c3000 0x4c5000 0x2000 0xc2000 rw-p /root/hello_world/main + 0x4c5000 0x4cb000 0x6000 0x0 rw-p + 0x4cb000 0x4ed000 0x22000 0x0 rw-p [heap] + 0x7ffff7ff9000 0x7ffff7ffd000 0x4000 0x0 r--p [vvar] + 0x7ffff7ffd000 0x7ffff7fff000 0x2000 0x0 r-xp [vdso] + 0x7ffffffde000 0x7ffffffff000 0x21000 0x0 rw-p [stack] + 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 --xp [vsyscall] + Note: this may return no pages due to a bug/behavior of GDB. See https://sourceware.org/bugzilla/show_bug.cgi?id=31207 for more information. @@ -453,9 +480,12 @@ def info_proc_maps(parse_flags=False) -> Tuple[pwndbg.lib.memory.Page, ...]: # On qemu user emulation, we may get: gdb.error: Not supported on this target. info_proc_mappings = [] + # See if "Perms" is in the header line + perms_available = "Perms" in info_proc_mappings[3] + pages: List[pwndbg.lib.memory.Page] = [] for line in info_proc_mappings: - page = parse_info_proc_mappings_line(line, parse_flags) + page = parse_info_proc_mappings_line(line, perms_available, parse_flags) if page is not None: pages.append(page)