Ejemplo n.º 1
0
    def thread_cache(self):
        tcache_addr = pwndbg.symbol.address('tcache')

        # The symbol.address returns ptr to ptr to tcache struct, as in:
        # pwndbg> p &tcache
        # $1 = (tcache_perthread_struct **) 0x7ffff7fd76f0
        # so we need to dereference it
        if tcache_addr is not None:
            tcache_addr = pwndbg.memory.pvoid(tcache_addr)

        if tcache_addr is None:
            tcache_addr = self._fetch_tcache_addr()

        if tcache_addr is not None:
            try:
                self._thread_cache = pwndbg.memory.poi(self.tcache_perthread_struct, tcache_addr)
                _ = self._thread_cache['entries'].fetch_lazy()
            except Exception as e:
                print(message.error('Error fetching tcache. GDB cannot access '
                                    'thread-local variables unless you compile with -lpthread.'))
                return None
        else:
            if not self.has_tcache():
                print(message.warn('Your libc does not use thread cache'))
                return None

            print(message.error('Symbol \'tcache\' not found. Try installing libc '
                                'debugging symbols and try again.'))

        return self._thread_cache
Ejemplo n.º 2
0
def validate_context_sections():
    valid_values = [context.__name__.replace('context_', '') for context in context_sections.values()]

    # If someone tries to set an empty string, we let to do that informing about possible values
    # (so that it is possible to have no context at all)
    if not config_context_sections.value or config_context_sections.value.lower() in ('none', 'empty'):
        config_context_sections.value = ''
        print(message.warn("Sections set to be empty. FYI valid values are: %s" % ', '.join(valid_values)))
        return

    for section in config_context_sections.split():
        if section not in valid_values:
            print(message.warn("Invalid section: %s, valid values: %s" % (section, ', '.join(valid_values))))
            print(message.warn("(setting none of them like '' will make sections not appear)"))
            config_context_sections.revert_default()
            return
Ejemplo n.º 3
0
def validate_context_sections():
    valid_values = [context.__name__.replace('context_', '') for context in context_sections.values()]

    # If someone tries to set an empty string, we let to do that informing about possible values
    # (so that it is possible to have no context at all)
    if not config_context_sections.value or config_context_sections.value.lower() in ('none', 'empty'):
        config_context_sections.value = ''
        print(message.warn("Sections set to be empty. FYI valid values are: %s" % ', '.join(valid_values)))
        return

    for section in config_context_sections.split():
        if section not in valid_values:
            print(message.warn("Invalid section: %s, valid values: %s" % (section, ', '.join(valid_values))))
            print(message.warn("(setting none of them like '' will make sections not appear)"))
            config_context_sections.revert_default()
            return
Ejemplo n.º 4
0
def update():
    global abi
    global linux

    # Detect current ABI of client side by 'show osabi'
    #
    # Examples of strings returned by `show osabi`:
    # 'The current OS ABI is "auto" (currently "GNU/Linux").\nThe default OS ABI is "GNU/Linux".\n'
    # 'The current OS ABI is "GNU/Linux".\nThe default OS ABI is "GNU/Linux".\n'
    # 'El actual SO ABI es «auto» (actualmente «GNU/Linux»).\nEl SO ABI predeterminado es «GNU/Linux».\n'
    # 'The current OS ABI is "auto" (currently "none")'
    #
    # As you can see, there might be GDBs with different language versions
    # and so we have to support it there too.
    # Lets assume and hope that `current osabi` is returned in first line in all languages...
    current_osabi = gdb.execute('show osabi', to_string=True).split('\n')[0]

    # Currently we support those osabis:
    # 'GNU/Linux': linux
    # 'none': bare metal

    linux = 'GNU/Linux' in current_osabi

    if not linux:
        msg = M.warn(
            "The bare metal debugging is enabled since the gdb's osabi is '%s' which is not 'GNU/Linux'.\n"
            "Ex. the page resolving and memory de-referencing ONLY works on known pages.\n"
            "This option is based ib gdb client compile arguments (by default) and will be corrected if you load an ELF which has the '.note.ABI-tag' section.\n"
            "If you are debuging a program that runs on Linux ABI, please select the correct gdb client."
            % abi)
        print(msg)
Ejemplo n.º 5
0
def check_title_position():
    valid_values = ['center', 'left', 'right']
    if title_position not in valid_values:
        print(
            message.warn('Invalid title position: %s, must be one of: %s' %
                         (title_position, ', '.join(valid_values))))
        title_position.revert_default()
Ejemplo n.º 6
0
    def thread_cache(self):
        """Locate a thread's tcache struct. If it doesn't have one, use the main
        thread's tcache.
        """
        if self.has_tcache():
            tcache = self.mp['sbrk_base'] + 0x10
            if self.multithreaded:
                tcache_addr = pwndbg.memory.pvoid(
                    pwndbg.symbol.address('tcache'))
                if tcache_addr != 0:
                    tcache = tcache_addr

            try:
                self._thread_cache = pwndbg.memory.poi(
                    self.tcache_perthread_struct, tcache)
                _ = self._thread_cache['entries'].fetch_lazy()
            except Exception as e:
                print(
                    message.error(
                        'Error fetching tcache. GDB cannot access '
                        'thread-local variables unless you compile with -lpthread.'
                    ))
                return None

            return self._thread_cache

        else:
            print(
                message.warn(
                    'This version of GLIBC was not compiled with tcache support.'
                ))
            return None
Ejemplo n.º 7
0
Archivo: abi.py Proyecto: jsarzy/pwndbg
def update():
    global abi
    global linux

    # Detect current ABI of client side by 'show osabi'
    osabi_string = gdb.execute('show osabi', to_string=True)

    # The return string will be:
    # The current OS ABI is "auto" (currently "GNU/Linux").
    match = re.search('currently "([^"]+)"', osabi_string)
    if match:
        # 'GNU/Linux': linux
        # 'none': bare metal
        abi = match.group(1)

        linux = 'Linux' in abi

    if not linux:
        msg = M.warn(
            "The bare metal debugging is enabled since the gdb's osabi is '%s' which is not 'GNU/Linux'.\n"
            "Ex. the page resolving and memory de-referencing ONLY works on known pages.\n"
            "This option is based ib gdb client compile arguments (by default) and will be corrected if you load an ELF which has the '.note.ABI-tag' section.\n"
            "If you are debuging a program that runs on Linux ABI, please select the correct gdb client."
            % abi)
        print(msg)
Ejemplo n.º 8
0
def probeleak(address=None, count=0x40, max_distance=0x0):

    address = int(address)
    address &= pwndbg.arch.ptrmask
    ptrsize = pwndbg.arch.ptrsize
    count = max(int(count), ptrsize)
    off_zeros = int(math.ceil(math.log(count, 2) / 4))

    if count > address > 0x10000:  # in case someone puts in an end address and not a count (smh)
        print(
            message.warn(
                "Warning: you gave an end address, not a count. Substracting 0x%x from the count."
                % (address)))
        count -= address

    try:
        data = pwndbg.memory.read(address, count, partial=True)
    except gdb.error as e:
        print(message.error(str(e)))
        return

    if not data:
        print(
            message.error(
                "Couldn't read memory at 0x%x. See 'probeleak -h' for the usage."
                % (address, )))
        return

    found = False
    for i in range(0, len(data) - ptrsize + 1):
        p = pwndbg.arch.unpack(data[i:i + ptrsize])
        page = find_module(p, max_distance)
        if page:
            if not found:
                print(M.legend())
                found = True

            mod_name = page.objfile
            if not mod_name:
                mod_name = '[anon]'

            if p >= page.end:
                right_text = '(%s) %s + 0x%x + 0x%x (outside of the page)' % (
                    page.permstr, mod_name, page.memsz, p - page.end)
            elif p < page.start:
                right_text = '(%s) %s - 0x%x (outside of the page)' % (
                    page.permstr, mod_name, page.start - p)
            else:
                right_text = '(%s) %s + 0x%x' % (page.permstr, mod_name,
                                                 p - page.start)

            offset_text = '0x%0*x' % (off_zeros, i)
            p_text = '0x%0*x' % (int(ptrsize * 2), p)
            print('%s: %s = %s' % (offset_text, M.get(
                p, text=p_text), M.get(p, text=right_text)))
    if not found:
        print(
            message.hint('No leaks found at 0x%x-0x%x :(' %
                         (address, address + count)))
Ejemplo n.º 9
0
def get_regs(*regs):
    result = []

    if not regs and pwndbg.config.show_retaddr_reg:
        regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack) + pwndbg.regs.retaddr + (pwndbg.regs.current.pc,)
    elif not regs:
        regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack, pwndbg.regs.current.pc)

    if pwndbg.config.show_flags:
        regs += tuple(pwndbg.regs.flags)

    changed = pwndbg.regs.changed

    for reg in regs:
        if reg is None:
            continue

        if reg not in pwndbg.regs:
            print(message.warn("Unknown register: %r" % reg))
            continue

        value = pwndbg.regs[reg]

        # Make the register stand out
        regname = C.register(reg.ljust(4).upper())

        # Show a dot next to the register if it changed
        change_marker = "%s" % C.config_register_changed_marker
        m = ' ' * len(change_marker) if reg not in changed else C.register_changed(change_marker)

        if reg not in pwndbg.regs.flags:
            desc = pwndbg.chain.format(value)

        else:
            names = []
            desc  = C.flag_value('%#x' % value)
            last  = pwndbg.regs.last.get(reg, 0) or 0
            flags = pwndbg.regs.flags[reg]

            for name, bit in sorted(flags.items()):
                bit = 1<<bit
                if value & bit:
                    name = name.upper()
                    name = C.flag_set(name)
                else:
                    name = name.lower()
                    name = C.flag_unset(name)

                if value & bit != last & bit:
                    name = C.flag_changed(name)
                names.append(name)

            if names:
                desc = '%s %s %s %s' % (desc, C.flag_bracket('['), ' '.join(names), C.flag_bracket(']'))

        result.append("%s%s %s" % (m, regname, desc))

    return result
Ejemplo n.º 10
0
def get_regs(*regs):
    result = []

    if not regs and pwndbg.config.show_retaddr_reg:
        regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack
                                  ) + pwndbg.regs.retaddr + (
                                      pwndbg.regs.current.pc, )
    elif not regs:
        regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack,
                                  pwndbg.regs.current.pc)

    if pwndbg.config.show_flags:
        regs += tuple(pwndbg.regs.flags)

    changed = pwndbg.regs.changed

    for reg in regs:
        if reg is None:
            continue

        if reg not in pwndbg.regs:
            message.warn("Unknown register: %r" % reg)
            continue

        value = pwndbg.regs[reg]

        # Make the register stand out
        regname = C.register(reg.ljust(4).upper())

        # Show a dot next to the register if it changed
        change_marker = "%s" % C.config_register_changed_marker
        m = ' ' * len(
            change_marker) if reg not in changed else C.register_changed(
                change_marker)

        if reg in pwndbg.regs.flags:
            desc = C.format_flags(value, pwndbg.regs.flags[reg],
                                  pwndbg.regs.last.get(reg, 0))

        else:
            desc = pwndbg.chain.format(value)

        result.append("%s%s %s" % (m, regname, desc))

    return result
Ejemplo n.º 11
0
def arm_print_psr():
    if pwndbg.arch.current not in ('arm', 'armcm'):
        print(message.warn("This is only available on ARM"))
        return

    reg = 'cpsr' if pwndbg.arch.current == 'arm' else 'xpsr'
    print('%s %s' % (reg,
                     context.format_flags(getattr(pwndbg.regs, reg),
                                          pwndbg.regs.flags[reg])))
Ejemplo n.º 12
0
def check_style():
    global formatter
    try:
        formatter = pygments.formatters.Terminal256Formatter(
            style=str(style)
        )
    except pygments.util.ClassNotFound:
        print(message.warn("The pygment formatter style '%s' is not found, restore to default" % style))
        style.revert_default()
Ejemplo n.º 13
0
def check_style():
    try:
        formatter = pygments.formatters.Terminal256Formatter(
            style=str(style)
        )
    except pygments.util.ClassNotFound:
        msg = message.warn("The pygment formatter style '%s' is not found, restore to default" % style)
        print(msg)
        style.value = style.default
Ejemplo n.º 14
0
def arm_print_psr():
    if pwndbg.arch.current not in ("arm", "armcm"):
        print(message.warn("This is only available on ARM"))
        return

    reg = "cpsr" if pwndbg.arch.current == "arm" else "xpsr"
    print("%s %s" % (reg,
                     context.format_flags(getattr(pwndbg.regs, reg),
                                          pwndbg.regs.flags[reg])))
Ejemplo n.º 15
0
def check_title_position():
    valid_values = ["center", "left", "right"]
    if title_position not in valid_values:
        print(
            message.warn(
                "Invalid title position: %s, must be one of: %s"
                % (title_position, ", ".join(valid_values))
            )
        )
        title_position.revert_default()
Ejemplo n.º 16
0
def resolve_heap(is_first_run=False):
    import pwndbg.heap.ptmalloc

    global current
    if resolve_heap_via_heuristic:
        current = pwndbg.heap.ptmalloc.HeuristicHeap()
        if not is_first_run and pwndbg.proc.alive and current.libc_has_debug_syms(
        ):
            print(
                message.warn(
                    "You are going to resolve the heap via heuristic even though you have libc debug symbols."
                    " This is not recommended!"))
        else:
            print(
                message.warn(
                    "You are going to resolve the heap via heuristic. This might not work in all cases."
                ))
    else:
        current = pwndbg.heap.ptmalloc.DebugSymsHeap()
Ejemplo n.º 17
0
def probeleak(address=None, count=0x40, max_distance=0x0):

    address = int(address)
    address &= pwndbg.arch.ptrmask
    ptrsize = pwndbg.arch.ptrsize
    count   = max(int(count), ptrsize)
    off_zeros = int(math.ceil(math.log(count,2)/4))

    if count > address > 0x10000: # in case someone puts in an end address and not a count (smh)
        print(message.warn("Warning: you gave an end address, not a count. Substracting 0x%x from the count." % (address)))
        count -= address

    try:
        data = pwndbg.memory.read(address, count, partial=True)
    except gdb.error as e:
        print(message.error(str(e)))
        return

    if not data:
        print(message.error("Couldn't read memory at 0x%x. See 'probeleak -h' for the usage." % (address,)))
        return

    found = False
    for i in range(0, len(data) - ptrsize + 1):
        p = pwndbg.arch.unpack(data[i:i+ptrsize])
        page = find_module(p, max_distance)
        if page:
            if not found:
                print(M.legend())
                found = True

            mod_name = page.objfile
            if not mod_name:
                mod_name = '[anon]'

            if p >= page.end:
                right_text = '(%s) %s + 0x%x + 0x%x (outside of the page)' % (page.permstr, mod_name, page.memsz, p - page.end)
            elif p < page.start:
                right_text = '(%s) %s - 0x%x (outside of the page)' % (page.permstr, mod_name, page.start - p)
            else:
                right_text = '(%s) %s + 0x%x' % (page.permstr, mod_name, p - page.start)

            offset_text = '0x%0*x' % (off_zeros, i)
            p_text = '0x%0*x' % (int(ptrsize*2), p)
            text = '%s: %s = %s' % (offset_text, M.get(p, text=p_text), M.get(p, text=right_text))

            symbol = pwndbg.symbol.get(p)
            if symbol:
                text += ' (%s)' % symbol

            print(text)

    if not found:
        print(message.hint('No leaks found at 0x%x-0x%x :(' % (address, address+count)))
Ejemplo n.º 18
0
def find_module(addr):
    mod_filter = lambda page: page.vaddr <= addr < page.vaddr + page.memsz
    pages = list(filter(mod_filter, pwndbg.vmmap.get()))

    if not pages:
        return None

    if len(pages) > 1:
        print(message.warn('Warning: There is more than one page containing address 0x%x (wtf?)', addr))

    return pages[0]
Ejemplo n.º 19
0
def check_style():
    global formatter
    try:
        formatter = pygments.formatters.Terminal256Formatter(
            style=str(style)
        )

        # Reset the highlighted source cache
        from pwndbg.commands.context import get_highlight_source
        get_highlight_source._reset()
    except pygments.util.ClassNotFound:
        print(message.warn("The pygment formatter style '%s' is not found, restore to default" % style))
        style.revert_default()
def check_style():
    global formatter
    try:
        formatter = pygments.formatters.Terminal256Formatter(style=str(style))

        # Reset the highlighted source cache
        from pwndbg.commands.context import get_highlight_source
        get_highlight_source._reset()
    except pygments.util.ClassNotFound:
        print(
            message.warn(
                "The pygment formatter style '%s' is not found, restore to default"
                % style))
        style.revert_default()
Ejemplo n.º 21
0
def initial_hook(*a):
    if show_tip and not pwndbg.decorators.first_prompt:
        colored_tip = re.sub(
            "`(.*?)`", lambda s: message.warn(s.group()[1:-1]), get_tip_of_the_day()
        )
        print(
            message.prompt("------- tip of the day")
            + message.system(" (disable with %s)" % message.notice("set show-tips off"))
            + message.prompt(" -------")
        )
        print((colored_tip))
    pwndbg.decorators.first_prompt = True

    prompt_hook(*a)
    gdb.prompt_hook = prompt_hook
Ejemplo n.º 22
0
def validate_context_sections():
    # if trying to set an empty string, we assume default is wanted
    if not config_context_sections.value:
        config_context_sections.value = config_context_sections.default

    valid_values = [
        context.__name__.replace('context_', '')
        for context in context_sections.values()
    ]
    for section in config_context_sections.split():
        if section not in valid_values:
            print(
                message.warn("Invalid section: %s, valid values: %s" %
                             (section, ', '.join(valid_values))))
            config_context_sections.value = config_context_sections.default
            return
Ejemplo n.º 23
0
def attachp(target):
    try:
        resolved_target = int(target)
    except ValueError:
        # GDB supposedly supports device files, so let's try it here...:
        #    <disconnect3d> hey, does anyone know what does `attach <device-file>` do?
        #    <disconnect3d> is this an alias for `target extended /dev/ttyACM0` or similar?
        #    <disconnect3d> I mean, `help attach` suggests that the `attach` command supports a device file target...
        #    <simark> I had no idea
        #    <simark> what you pass to attach is passed directly to target_ops::attach
        #    <simark> so it must be very target-specific
        #    <disconnect3d> how can it be target specific if it should  attach you to a target?
        #    <disconnect3d> or do you mean osabi/arch etc?
        #    <simark> in "attach foo", foo is interpreted by the target you are connected to
        #    <simark> But all targets I can find interpret foo as a PID
        #    <simark> So it might be that old targets had some other working mode
        if _is_device(target):
            resolved_target = target

        else:
            try:
                pids = check_output(["pidof",
                                     target]).decode().rstrip("\n").split(" ")
            except FileNotFoundError:
                print(message.error("Error: did not find `pidof` command"))
                return
            except CalledProcessError:
                pids = []

            if not pids:
                print(message.error("Process %s not found" % target))
                return

            if len(pids) > 1:
                print(
                    message.warn("Found pids: %s (use `attach <pid>`)" %
                                 ", ".join(pids)))
                return

            resolved_target = int(pids[0])

    print(message.on("Attaching to %s" % resolved_target))
    try:
        gdb.execute("attach %s" % resolved_target)
    except gdb.error as e:
        print(message.error("Error: %s" % e))
Ejemplo n.º 24
0
def get_file(path):
    """
    Downloads the specified file from the system where the current process is
    being debugged.

    If the `path` is prefixed with "target:" the prefix is stripped
    (to support remote target paths properly).

    Returns:
        The local path to the file
    """
    assert path.startswith("/") or path.startswith(
        "target:"), "get_file called with incorrect path"

    if path.startswith("target:"):
        path = path[7:]  # len('target:') == 7

    local_path = path
    qemu_root = pwndbg.qemu.root()

    if qemu_root:
        return os.path.join(qemu_root, path)

    elif pwndbg.remote.is_remote():
        if not pwndbg.qemu.is_qemu():
            local_path = tempfile.mktemp(dir=pwndbg.symbol.remote_files_dir)
            error = None
            try:
                error = gdb.execute('remote get "%s" "%s"' %
                                    (path, local_path),
                                    to_string=True)
            except gdb.error as e:
                error = e

            if error:
                raise OSError("Could not download remote file %r:\n"
                              "Error: %s" % (path, error))
        else:
            print(
                message.warn(
                    "pwndbg.file.get(%s) returns local path as we can't download file from QEMU"
                    % path))

    return local_path
Ejemplo n.º 25
0
    def thread_cache(self):
        tcache_addr = pwndbg.symbol.address('tcache')

        if tcache_addr is not None:
            try:
                self._thread_cache = pwndbg.memory.poi(self.tcache_perthread_struct, tcache_addr)
                _ = self._thread_cache['entries'].fetch_lazy()
            except Exception as e:
                print(message.error('Error fetching tcache. GDB cannot access '
                                    'thread-local variables unless you compile with -lpthread.'))
        else:
            if not self.has_tcache():
                print(message.warn('Your libc does not use thread cache'))
                return None

            print(message.error('Symbol \'tcache\' not found. Try installing libc '
                                'debugging symbols and try again.'))

        return self._thread_cache
Ejemplo n.º 26
0
def canary():
    global_canary, at_random = canary_value()

    if global_canary is None or at_random is None:
        print(message.error("Couldn't find AT_RANDOM - can't display canary."))
        return

    print(message.notice("AT_RANDOM = %#x # points to (not masked) global canary value" % at_random))
    print(message.notice("Canary    = 0x%x" % global_canary))

    stack_canaries = list(
        pwndbg.search.search(pwndbg.arch.pack(global_canary), mappings=pwndbg.stack.stacks.values())
    )

    if not stack_canaries:
        print(message.warn('No valid canaries found on the stacks.'))
        return

    print(message.success('Found valid canaries on the stacks:'))
    for stack_canary in stack_canaries:
        pwndbg.commands.telescope.telescope(address=stack_canary, count=1)
Ejemplo n.º 27
0
def canary():
    global_canary, at_random = canary_value()

    if global_canary is None or at_random is None:
        print(message.error("Couldn't find AT_RANDOM - can't display canary."))
        return

    print(message.notice("AT_RANDOM = %#x # points to (not masked) global canary value" % at_random))
    print(message.notice("Canary    = 0x%x (may be incorrect on != glibc)" % global_canary))

    stack_canaries = list(
        pwndbg.search.search(pwndbg.arch.pack(global_canary), mappings=pwndbg.stack.stacks.values())
    )

    if not stack_canaries:
        print(message.warn('No valid canaries found on the stacks.'))
        return

    print(message.success('Found valid canaries on the stacks:'))
    for stack_canary in stack_canaries:
        pwndbg.commands.telescope.telescope(address=stack_canary, count=1)
Ejemplo n.º 28
0
Archivo: heap.py Proyecto: yy221/pwndbg
def find_fake_fast(addr, size=None):
    """Find candidate fake fast chunks overlapping the specified address."""
    psize = pwndbg.arch.ptrsize
    allocator = pwndbg.heap.current
    align = allocator.malloc_alignment
    min_fast = allocator.min_chunk_size
    max_fast = allocator.global_max_fast
    max_fastbin = allocator.fastbin_index(max_fast)
    start = int(addr) - max_fast + psize
    if start < 0:
        print(
            message.warn(
                'addr - global_max_fast is negative, if the max_fast is not corrupted, you gave wrong address'
            ))
        start = 0  # TODO, maybe some better way to handle case when global_max_fast is overwritten with something large
    mem = pwndbg.memory.read(start, max_fast - psize, partial=True)

    fmt = {
        'little': '<',
        'big': '>'
    }[pwndbg.arch.endian] + {
        4: 'I',
        8: 'Q'
    }[psize]

    if size is None:
        sizes = range(min_fast, max_fast + 1, align)
    else:
        sizes = [int(size)]

    print(C.banner("FAKE CHUNKS"))
    for size in sizes:
        fastbin = allocator.fastbin_index(size)
        for offset in range((max_fastbin - fastbin) * align,
                            max_fast - align + 1):
            candidate = mem[offset:offset + psize]
            if len(candidate) == psize:
                value = struct.unpack(fmt, candidate)[0]
                if allocator.fastbin_index(value) == fastbin:
                    malloc_chunk(start + offset - psize, fake=True)
Ejemplo n.º 29
0
def cpsr():
    if pwndbg.arch.current != 'arm':
        print(message.warn("This is only available on ARM"))
        return

    cpsr = pwndbg.regs.cpsr

    N = cpsr & (1 << 31)
    Z = cpsr & (1 << 30)
    C = cpsr & (1 << 29)
    V = cpsr & (1 << 28)
    T = cpsr & (1 << 5)

    result = [
        context.flag_set('N') if N else context.flag_unset('n'),
        context.flag_set('Z') if Z else context.flag_unset('z'),
        context.flag_set('C') if C else context.flag_unset('c'),
        context.flag_set('V') if V else context.flag_unset('v'),
        context.flag_set('T') if T else context.flag_unset('t')
    ]

    print('CPSR %s %s %s %s' % (context.flag_value('%#x' % cpsr),
          context.flag_bracket('['), ' '.join(result), context.flag_bracket(']')))
Ejemplo n.º 30
0
    def thread_cache(self):
        tcache_addr = pwndbg.symbol.address('tcache')

        # The symbol.address returns ptr to ptr to tcache struct, as in:
        # pwndbg> p &tcache
        # $1 = (tcache_perthread_struct **) 0x7ffff7fd76f0
        # so we need to dereference it
        if tcache_addr is not None:
            tcache_addr = pwndbg.memory.pvoid(tcache_addr)

        if tcache_addr is None:
            tcache_addr = self._fetch_tcache_addr()

        if tcache_addr is not None:
            try:
                self._thread_cache = pwndbg.memory.poi(
                    self.tcache_perthread_struct, tcache_addr)
                _ = self._thread_cache['entries'].fetch_lazy()
            except Exception as e:
                print(
                    message.error(
                        'Error fetching tcache. GDB cannot access '
                        'thread-local variables unless you compile with -lpthread.'
                    ))
                return None
        else:
            if not self.has_tcache():
                print(message.warn('Your libc does not use thread cache'))
                return None

            print(
                message.error(
                    'Symbol \'tcache\' not found. Try installing libc '
                    'debugging symbols and try again.'))

        return self._thread_cache
Ejemplo n.º 31
0
def cpsr():
    if pwndbg.arch.current != 'arm':
        print(message.warn("This is only available on ARM"))
        return

    cpsr = pwndbg.regs.cpsr

    N = cpsr & (1 << 31)
    Z = cpsr & (1 << 30)
    C = cpsr & (1 << 29)
    V = cpsr & (1 << 28)
    T = cpsr & (1 << 5)

    result = [
        context.flag_set('N') if N else context.flag_unset('n'),
        context.flag_set('Z') if Z else context.flag_unset('z'),
        context.flag_set('C') if C else context.flag_unset('c'),
        context.flag_set('V') if V else context.flag_unset('v'),
        context.flag_set('T') if T else context.flag_unset('t')
    ]

    print('CPSR %s %s %s %s' %
          (context.flag_value('%#x' % cpsr), context.flag_bracket('['),
           ' '.join(result), context.flag_bracket(']')))
Ejemplo n.º 32
0
def check_title_position():
    valid_values = ['center', 'left', 'right']
    if title_position not in valid_values:
        print(message.warn('Invalid title position: %s, must be one of: %s' %
              (title_position, ', '.join(valid_values))))
        title_position.revert_default()
Ejemplo n.º 33
0
def leakfind(address=None,
             page_name=None,
             max_offset=0x40,
             max_depth=0x4,
             step=0x1,
             negative_offset=0x0):
    if address is None:
        raise argparse.ArgumentTypeError('No starting address provided.')
    foundPages = pwndbg.vmmap.find(address)

    if not foundPages:
        raise argparse.ArgumentTypeError('Starting address is not mapped.')

    if not pwndbg.memory.peek(address):
        raise argparse.ArgumentTypeError(
            'Unable to read from starting address.')

    max_depth = int(max_depth)
    # Just warn the user that a large depth might be slow.
    # Probably worth checking offset^depth < threshold. Do this when more benchmarking is established.
    if max_depth > 8:
        print(
            message.warn("leakfind may take a while to run on larger depths."))

    stride = int(step)
    address = int(address)
    max_offset = int(max_offset)
    negative_offset = int(negative_offset)

    # The below map stores a map of child address->(parent_address,parent_start_address)
    # In the above tuple, parent_address is the exact address with a pointer to the child adddress.
    # parent_start_address is an address that a previous address pointed to.
    # We need to store both so that we can nicely create our leak chain.
    visited_map = {}
    visited_set = {int(address)}
    address_queue = Queue()
    address_queue.put(int(address))
    depth = 0
    time_to_depth_increase = 0

    # Run a bfs
    # TODO look into performance gain from checking if an address is mapped before calling pwndbg.memory.pvoid()
    # TODO also check using pwndbg.memory.read for possible performance boosts.
    while address_queue.qsize() > 0 and depth < max_depth:
        if time_to_depth_increase == 0:
            depth = depth + 1
            time_to_depth_increase = address_queue.qsize()
        cur_start_addr = address_queue.get()
        time_to_depth_increase -= 1
        for cur_addr in range(cur_start_addr - negative_offset,
                              cur_start_addr + max_offset, stride):
            try:
                cur_addr &= pwndbg.arch.ptrmask
                result = int(pwndbg.memory.pvoid(cur_addr))
                if result in visited_map or result in visited_set:
                    continue
                visited_map[result] = (
                    cur_addr, cur_start_addr
                )  # map is of form child->(parent,parent_start)
                address_queue.put(result)
                visited_set.add(result)
            except gdb.error:
                # That means the memory was unmapped. Just skip it if we can't read it.
                break

    # A map of length->list of lines. Used to let us print in a somewhat nice manner.
    output_map = {}
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    for child in visited_map:
        child_page = pwndbg.vmmap.find(child)
        if child_page is not None:
            if page_name is not None and page_name not in child_page.objfile:
                continue
            line = get_rec_addr_string(
                child, visited_map) + M.get(child) + " " + M.get(
                    child, text=child_page.objfile)
            chain_length = line.count(arrow_right)
            if chain_length in output_map:
                output_map[chain_length].append(line)
            else:
                output_map[chain_length] = [line]

    # Output sorted by length of chain
    for chain_length in output_map:
        for line in output_map[chain_length]:
            print(line)

    if pwndbg.qemu.is_qemu():
        print(
            "\n[QEMU target detected - leakfind result might not be accurate; see `help vmmap`]"
        )
Ejemplo n.º 34
0
def get_regs(*regs):
    result = []

    if not regs and pwndbg.config.show_retaddr_reg:
        regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack
                                  ) + pwndbg.regs.retaddr + (
                                      pwndbg.regs.current.pc, )
    elif not regs:
        regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack,
                                  pwndbg.regs.current.pc)

    if pwndbg.config.show_flags:
        regs += tuple(pwndbg.regs.flags)

    changed = pwndbg.regs.changed

    for reg in regs:
        if reg is None:
            continue

        if reg not in pwndbg.regs:
            message.warn("Unknown register: %r" % reg)
            continue

        value = pwndbg.regs[reg]

        # Make the register stand out
        regname = C.register(reg.ljust(4).upper())

        # Show a dot next to the register if it changed
        change_marker = "%s" % C.config_register_changed_marker
        m = ' ' * len(
            change_marker) if reg not in changed else C.register_changed(
                change_marker)

        if reg not in pwndbg.regs.flags:
            desc = pwndbg.chain.format(value)

        else:
            names = []
            desc = C.flag_value('%#x' % value)
            last = pwndbg.regs.last.get(reg, 0) or 0
            flags = pwndbg.regs.flags[reg]

            for name, bit in sorted(flags.items()):
                bit = 1 << bit
                if value & bit:
                    name = name.upper()
                    name = C.flag_set(name)
                else:
                    name = name.lower()
                    name = C.flag_unset(name)

                if value & bit != last & bit:
                    name = C.flag_changed(name)
                names.append(name)

            if names:
                desc = '%s %s %s %s' % (desc, C.flag_bracket('['),
                                        ' '.join(names), C.flag_bracket(']'))

        result.append("%s%s %s" % (m, regname, desc))

    return result