From 66d5d6cc512e4813fb6246db6ba89b52e5ef8e1c Mon Sep 17 00:00:00 2001 From: Disconnect3d Date: Sat, 21 Aug 2021 22:01:08 +0200 Subject: [PATCH] Fix early arch detection & the 'Cannot find ELF base!' warning Before this commit, when we did `gdb /bin/ls` and then `entry`, we could see a "Cannot find ELF base!" warning. This occured, because the `pwndbg.arch.ptrmask` was incorrectly set and then the `find_elf_magic` was using the `pwndbg.arch.ptrmask` which was 0xffFFffFF and made an early return. As a result of this early return, the "Cannot find ELF base!" warning was emitted. The reason for incorrect early arch detection is that we used the `gdb.newest_frame().architecture().name()` API while the binary was not using in here: ```python @pwndbg.events.start @pwndbg.events.stop @pwndbg.events.new_objfile def update(): m = sys.modules[__name__] try: m.current = fix_arch(gdb.newest_frame().architecture().name()) except Exception: return m.ptrsize = pwndbg.typeinfo.ptrsize m.ptrmask = (1 << 8*pwndbg.typeinfo.ptrsize)-1 ``` And if the binary was not running, we just returned early and did not set `pwndbg.arch.ptrsize` and `pwndbg.arch.ptrmask` at all, leaving them at their default values. Now, those values were often eventually fixed, but this occured by chance as the `new_objfile` was executed! Anyway, starting from this commit, we will detect the arch from `gdb.newest_frame().architecture().name()` only if the process is running and if it is not, we will fallback to the `show architecture` GDB command and parse it, hoping we detect the arch properly. In case we don't, or, we don't support the given arch, we raise a `RuntimeError` currently. Also, as a side note: the `find_elf_magic` from `elf.py` can be optimized to instead of doing 4kB steps over pages, to just look at the begining of a page. Otherwise, if this doesn't work, we are most likely on a target that may not have an ELF magic/header at all, so we shouldn't bother about it. This fix is done in the next commit. --- pwndbg/arch.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/pwndbg/arch.py b/pwndbg/arch.py index 0c91bf79a2..b58b89fa91 100644 --- a/pwndbg/arch.py +++ b/pwndbg/arch.py @@ -20,8 +20,17 @@ native_endian = str(sys.byteorder) -def fix_arch(arch): - for match in ['x86-64', 'i386', 'mips', 'powerpc', 'sparc', 'aarch64']: +def _get_arch(): + not_exactly_arch = False + + if pwndbg.proc.alive: + arch = gdb.newest_frame().architecture().name() + else: + arch = gdb.execute("show architecture", to_string=True).strip() + not_exactly_arch = True + + # Below, we fix the fetched architecture + for match in ('x86-64', 'i386', 'aarch64', 'mips', 'powerpc', 'sparc'): if match in arch: return match @@ -29,24 +38,20 @@ def fix_arch(arch): if 'arm' in arch: return 'armcm' if '-m' in arch else 'arm' + if not_exactly_arch: + raise RuntimeError("Could not deduce architecture from: %s" % arch) + return arch + + @pwndbg.events.start @pwndbg.events.stop @pwndbg.events.new_objfile def update(): m = sys.modules[__name__] - # GDB 7.7 (Ubuntu Trusty) does not like selected_frame() when EBP/RBP - # is not mapped / pounts to an invalid address. - # - # As a work-around for Trusty users, handle the exception and bail. - # This may lead to inaccurate results, but there's not much to be done. - try: - m.current = fix_arch(gdb.newest_frame().architecture().name()) - except Exception: - return - + m.current = _get_arch() m.ptrsize = pwndbg.typeinfo.ptrsize m.ptrmask = (1 << 8*pwndbg.typeinfo.ptrsize)-1