Exemplo n.º 1
0
    def do_invoke(self, argv):
        argc = len(argv)
        if argc == 0:
            self.usage()
            return None

        if argv[0] == "-l":
            self.list_custom_structures()
            return None

        modname, structname = argv[0].split(
            ":", 1) if ":" in argv[0] else (argv[0], argv[0])
        structname = structname.split(
            ".", 1)[0] if "." in structname else structname

        if argc == 1:
            self.dump_structure(modname, structname)
            return None

        if argv[1] == "-e":
            self.create_or_edit_structure(modname, structname)
            return None

        if not pwngef.proc.alive:
            return None

        try:
            address = int(gdb.parse_and_eval(argv[1]))
        except gdb.error:
            message.error("Failed to parse '{:s}'".format(argv[1]))
            return None

        self.apply_structure_to_address(modname, structname, address)
        return None
Exemplo n.º 2
0
    def do_invoke(self, args):
        self.dont_repeat()
        argc = len(args)

        if argc == 0:
            for setting in sorted(self.settings):
                value = self.get_setting(setting)
                value = Color.colorify(value, value)
                print("{:40s}: {:s}".format(setting, value))
            return None

        setting = args[0]
        if not self.has_setting(setting):
            message.error("Invalid key")
            return None

        if argc == 1:
            value = self.get_setting(setting)
            value = Color.colorify(value, value)
            print("{:40s}: {:s}".format(setting, value))
            return None

        val = [x for x in args[1:] if x in Color.colors]
        self.add_setting(setting, " ".join(val))
        return None
Exemplo n.º 3
0
 def do_invoke(self, argv):
     if not argv:
         message.error("Missing chunk address")
         self.usage()
         return None
     addr = int(gdb.parse_and_eval(argv[0]))
     chunk = GlibcChunk(addr)
     print(chunk.psprint())
     return None
Exemplo n.º 4
0
 def invoke(self, args, from_tty):
     try:
         argv = gdb.string_to_argv(args)
         self.__set_repeat_count(argv, from_tty)
         self.do_invoke(argv)
     except Exception as e:
         message.error(
             "Command '{:s}' failed to execute properly, reason: {:s}".
             format(self._cmdline_, str(e)))
     return None
Exemplo n.º 5
0
    def do_invoke(self, argv):
        if not argv:
            # heap_section = [x for x in get_process_maps() if x.path == "[heap]"]
            heap_section = None
            if not heap_section:
                message.error("No heap section")
                return None
            heap_section = heap_section[0].page_start
        else:
            heap_section = int(argv[0], 0)

        class arena:
            pass

        # arena = get_main_arena()
        # if arena is None:
        # message.error("No valid arena")
        # return None
        arena.top = 0xFFFFFFFF

        nb = self.get_setting("peek_nb_byte")
        current_chunk = GlibcChunk(heap_section, from_base=True)
        chain_arrow_left = pwngef.config.get('chain_arrow_left')

        while True:
            if current_chunk.chunk_base_address == arena.top:
                print("{} {} {}".format(str(current_chunk), chain_arrow_left,
                                        Color.greenify("top chunk")))
                break
            if current_chunk.chunk_base_address > arena.top:
                break
            if current_chunk.size == 0:
                # EOF
                break
            line = str(current_chunk)
            if nb:
                hex_data = pwngef.memory.read(current_chunk.address,
                                              nb,
                                              partial=True)
                for ln in pwngef.hexdump.hexdump(
                        hex_data, address=current_chunk.address):
                    line += '\n [%s]' % ln
            print(line)
            next_chunk = current_chunk.get_next_chunk()
            if next_chunk is None:
                break
            next_chunk_addr = pwngef.memory.peek(next_chunk.address)
            if next_chunk_addr is None:
                # corrupted
                break
            current_chunk = next_chunk
        return None
Exemplo n.º 6
0
    def context_threads(self):
        def reason():
            res = gdb.execute("info program", to_string=True).splitlines()
            if not res:
                return "NOT RUNNING"

            for line in res:
                line = line.strip()
                if line.startswith("It stopped with signal "):
                    return line.replace("It stopped with signal ",
                                        "").split(",", 1)[0]
                if line == "The program being debugged is not being run.":
                    return "NOT RUNNING"
                if line == "It stopped at a breakpoint that has since been deleted.":
                    return "TEMPORARY BREAKPOINT"
                if line.startswith("It stopped at breakpoint "):
                    return "BREAKPOINT"
                if line == "It stopped after being stepped.":
                    return "SINGLE STEP"

            return "STOPPED"

        self.context_title("threads")

        threads = gdb.selected_inferior().threads()[::-1]
        idx = self.get_setting("nb_lines_threads")
        if idx > 0:
            threads = threads[0:idx]

        if idx == 0:
            return None

        if not threads:
            message.error("No thread selected")
            return None

        for i, thread in enumerate(threads):
            line = """[{:s}] Id {:d}, Name: "{:s}", """.format(
                Color.colorify("#{:d}".format(i), "bold pink"), thread.num,
                thread.name or "")
            if thread.is_running():
                line += Color.colorify("running", "bold green")
            elif thread.is_stopped():
                line += Color.colorify("stopped", "bold red")
                line += ", reason: {}".format(
                    Color.colorify(reason(), "bold pink"))
            elif thread.is_exited():
                line += Color.colorify("exited", "bold yellow")
            print(line)
            i += 1
        return None
Exemplo n.º 7
0
    def dump_custom_structure(self, mod_name, struct_name):
        if not self.is_valid_struct(mod_name):
            message.error("Invalid structure name '{:s}'".format(struct_name))
            return None

        _class = self.get_class(mod_name, struct_name)
        _offset = 0

        for _name, _type in _class._fields_:
            _size = ctypes.sizeof(_type)
            print("+{:04x} {:s} {:s} ({:#x})".format(_offset, _name,
                                                     _type.__name__, _size))
            _offset += _size
        return None
Exemplo n.º 8
0
 def context_additional_information(self):
     if not __context_messages__:
         return None
     self.context_title("extra")
     for level, text in __context_messages__:
         if level == "error":
             message.error(text)
         elif level == "warn":
             message.warn(text)
         elif level == "success":
             message.success(text)
         else:
             message.notice(text)
     return None
Exemplo n.º 9
0
    def apply_structure_to_address(self, mod_name, struct_name, addr, depth=0):
        if not self.is_valid_struct(mod_name):
            message.error("Invalid structure name '{:s}'".format(struct_name))
            return None

        try:
            _class = self.get_class(mod_name, struct_name)
            data = read_memory(addr, ctypes.sizeof(_class))
        except gdb.MemoryError:
            message.error("{}Cannot reach memory {:#x}".format(
                " " * depth, addr))
            return None

        self.deserialize(_class, data)

        _regsize = get_memory_alignment()
        _offset = 0

        for field in _class._fields_:
            _name, _type = field
            _size = ctypes.sizeof(_type)
            _value = getattr(_class, _name)

            if (_regsize == 4 and _type is ctypes.c_uint32) \
               or (_regsize == 8 and _type is ctypes.c_uint64) \
               or (_regsize == ctypes.sizeof(ctypes.c_void_p) and _type is ctypes.c_void_p):
                # try to dereference pointers
                _value = RIGHT_ARROW.join(
                    DereferenceCommand.dereference_from(_value))

            line = []
            line += "  " * depth
            line += ("{:#x}+0x{:04x} {} : ".format(addr, _offset,
                                                   _name)).ljust(40)
            line += "{} ({})".format(_value, _type.__name__)
            parsed_value = self.get_ctypes_value(_class, _name, _value)
            if parsed_value:
                line += " {} {}".format(RIGHT_ARROW, parsed_value)
            print("".join(line))

            if issubclass(_type, ctypes.Structure):
                self.apply_structure_to_address(mod_name, _type.__name__,
                                                addr + _offset, depth + 1)
                _offset += ctypes.sizeof(_type)
            else:
                _offset += _size
        return None
Exemplo n.º 10
0
    def list_custom_structures(self):
        path = self.get_struct_path()
        if path is None:
            message.error(
                "Cannot open '{0}': check directory and/or `gef config {0}` "
                "setting, currently: '{1}'".format(
                    "pcustom.struct_path", self.get_setting("struct_path")))
            return None

        message.hint("Listing custom structures from '{:s}'".format(path))
        for filen in os.listdir(path):
            name, ext = os.path.splitext(filen)
            if ext != ".py":
                continue
            _modz = self.list_all_structs(name)
            message.success("{:s} {:s} ({:s})".format(RIGHT_ARROW, name,
                                                      ", ".join(_modz)))
        return None
Exemplo n.º 11
0
    def create_or_edit_structure(self, mod_name, struct_name):
        path = self.get_struct_path()
        if path is None:
            message.error("Invalid struct path")
            return None

        fullname = self.pcustom_filepath(mod_name)
        if not self.is_valid_struct(mod_name):
            message.hint("Creating '{:s}' from template".format(fullname))
            with open(fullname, "w") as f:
                f.write(self.get_template(struct_name))
                f.flush()
        else:
            message.hint("Editing '{:s}'".format(fullname))

        cmd = os.getenv("EDITOR").split() if os.getenv("EDITOR") else [
            "nano",
        ]
        cmd.append(fullname)
        retcode = subprocess.call(cmd)
        return retcode
Exemplo n.º 12
0
    def set_setting(self, argc, argv):
        if "." not in argv[0]:
            message.error("Invalid command format")
            return None

        loaded_commands = [
            x[0] for x in pwngef.config.__pwngef__.loaded_commands
        ] + ["self"]
        plugin_name = argv[0].split(".", 1)[0]
        if plugin_name not in loaded_commands:
            message.error("Unknown plugin '{:s}'".format(plugin_name))
            return None

        _value, _doc = pwngef.config.get(argv[0], get_all=True)
        if _value is None:
            message.error("Failed to get '{:s}' config setting".format(
                argv[0], ))
            return None

        _type = type(_value)
        if isinstance(_value, bool):
            _newval = True if argv[1] == 'True' else False
        else:
            _newval = _type(argv[1])

        pwngef.config.set(argv[0], _newval, _doc)
        pwngef.events.reset_all_caches()
        return None
Exemplo n.º 13
0
    def context_args(self):
        insn = disass.gef_current_instruction(int(pwngef.arch.CURRENT_ARCH.pc))
        if not pwngef.arch.CURRENT_ARCH.is_call(insn):
            return None

        self.size2type = {
            1: "BYTE",
            2: "WORD",
            4: "DWORD",
            8: "QWORD",
        }

        if insn.operands[-1].startswith(
                self.size2type[pwngef.arch.CURRENT_ARCH.ptrsize] + " PTR"):
            target = "*" + insn.operands[-1].split()[-1]
        elif "$" + insn.operands[0] in pwngef.arch.CURRENT_ARCH.all_registers:
            target = "*{:#x}".format(
                int(pwngef.regs.get_register("$" + insn.operands[0])))
        else:
            # is there a symbol?
            ops = " ".join(insn.operands)
            if "<" in ops and ">" in ops:
                # extract it
                target = re.sub(r".*<([^\(> ]*).*", r"\1", ops)
            else:
                # it's an address, just use as is
                target = re.sub(r".*(0x[a-fA-F0-9]*).*", r"\1", ops)

        sym = gdb.lookup_global_symbol(target)
        if sym is None:
            self.print_guessed_arguments(target)
            return None

        if sym.type.code != gdb.TYPE_CODE_FUNC:
            message.error("Symbol '{}' is not a function: type={}".format(
                target, sym.type.code))
            return None

        self.print_arguments_from_symbol(target, sym)
        return None
Exemplo n.º 14
0
    def do_invoke(self, argv):
        if not self.get_setting("enable") or context_hidden:
            return None

        if not all(_ in self.layout_mapping for _ in argv):
            self.usage()
            return None

        if len(argv) > 0:
            current_layout = argv
        else:
            current_layout = self.get_setting("layout").strip().split()

        if not current_layout:
            return None

        self.tty_rows, self.tty_columns = pwngef.ui.get_window_size()

        redirect = self.get_setting("redirect")
        if redirect and os.access(redirect, os.W_OK):
            pwngef.ui.enable_redirect_output(to_file=redirect)

        if self.get_setting("clear_screen") and len(argv) == 0:
            clear_screen(redirect)

        for section in current_layout:
            if section[0] == "-":
                continue

            try:
                self.layout_mapping[section]()
            except gdb.MemoryError as e:
                # a MemoryError will happen when $pc is corrupted (invalid address)
                message.error(str(e))

        self.context_title("")

        if redirect and os.access(redirect, os.W_OK):
            pwngef.ui.disable_redirect_output()
        return None
Exemplo n.º 15
0
    def get_ctypes_value(self, struct, item, value):
        if not hasattr(struct, "_values_"):
            return ""
        values_list = getattr(struct, "_values_")
        default = ""
        for name, values in values_list:
            if name != item:
                continue
            if callable(values):
                return values(value)
            try:
                for val, desc in values:
                    if value == val:
                        return desc
                    if val is None:
                        default = desc
            except:
                message.error(
                    "Error while trying to obtain values from _values_[\"{}\"]"
                    .format(name))

        return default
Exemplo n.º 16
0
def connect(host=None, port=None):
    """Connect to the XML-RPC service."""
    def is_target_alive():
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(1)
            s.connect((host, port))
            s.close()
        except socket.error:
            return False
        return True

    # get config params
    host = host or pwngef.config.get("ida.host")
    port = port or pwngef.config.get("ida.port")
    try:
        sock = xmlrpclib.ServerProxy("http://{:s}:{:d}".format(host, port))
    finally:
        if not is_target_alive():
            message.error("Failed to connect to '{:s}:{:d}'".format(
                host, port))
            sock = None
    return sock
Exemplo n.º 17
0
    def invoke(self, args, from_tty):
        self.dont_repeat()
        argv = gdb.string_to_argv(args)
        argc = len(argv)

        if not (0 <= argc <= 2):
            message.error("Invalid number of arguments")
            return None

        if argc == 0:
            print(message.titlify("PWNGEF configuration settings"))
            self.print_settings()
            return None

        if argc == 1:
            prefix = argv[0]
            names = list(
                filter(lambda x: x.startswith(prefix),
                       pwngef.config.__config__.keys()))
            if names:
                if len(names) == 1:
                    print(
                        message.titlify(
                            "PWNGEF configuration setting: {:s}".format(
                                names[0])))
                    self.print_setting(names[0], verbose=True)
                else:
                    print(
                        message.titlify(
                            "PWNGEF configuration settings matching '{:s}'".
                            format(argv[0])))
                    for name in names:
                        self.print_setting(name)
            return None
        self.set_setting(argc, argv)
        return None
Exemplo n.º 18
0
 def __load_extra_plugins(self):
     nb_added = -1
     try:
         nb_inital = len(self.loaded_commands)
         directories = pwngef.config.get("self.extra_plugins_dir")
         if directories:
             for directory in directories.split(";"):
                 directory = os.path.realpath(os.path.expanduser(directory))
                 if os.path.isdir(directory):
                     sys.path.append(directory)
                     for fname in os.listdir(directory):
                         if not fname.endswith(".py"):
                             continue
                         fpath = "{:s}/{:s}".format(directory, fname)
                         if os.path.isfile(fpath):
                             gdb.execute("source {:s}".format(fpath))
         nb_added = len(self.loaded_commands) - nb_inital
         if nb_added > 0:
             message.success("{:s} extra commands added from '{:s}'".format(
                 Color.colorify(nb_added, "bold green"),
                 Color.colorify(directory, "bold blue")))
     except gdb.error as e:
         message.error("failed: {}".format(str(e)))
     return nb_added
Exemplo n.º 19
0
    def context_stack(self):
        self.context_title("stack")

        show_raw = self.get_setting("show_stack_raw")
        nb_lines = self.get_setting("nb_lines_stack")

        try:
            sp = int(pwngef.arch.CURRENT_ARCH.sp)
            if show_raw is True:
                mem = pwngef.memory.read(sp, 0x10 * nb_lines)
                for _, line in enumerate(
                        pwngef.hexdump.hexdump(mem, address=sp)):
                    print(line)
            else:
                for offset in range(nb_lines):
                    print(
                        pwngef.chain.format(sp +
                                            (offset * pwngef.arch.ptrsize)))
                # gdb.execute("dereference {:#x} l{:d}".format(sp, nb_lines))
        except gdb.MemoryError:
            message.error(
                "Cannot read memory from $SP (corrupted stack pointer?)")

        return None
Exemplo n.º 20
0
def handle(name='Error'):
    """Displays an exception to the user, optionally displaying a full traceback
    and spawning an interactive post-moretem debugger.

    Notes:
        - ``set exception-verbose on`` enables stack traces.
        - ``set exception-debugger on`` enables the post-mortem debugger.
    """

    # This is for unit tests so they fail on exceptions instead of displaying them.
    if getattr(sys, '_pwngef_unittest_run', False) is True:
        E, V, T = sys.exc_info()
        e = E(V)
        e.__traceback__ = T
        raise e

    # Display the error
    if debug or verbose:
        exception_msg = traceback.format_exc()
        print(exception_msg)
        inform_report_issue(exception_msg)

    else:
        exc_type, exc_value, exc_traceback = sys.exc_info()

        print(
            message.error('Exception occured: {}: {} ({})'.format(
                name, exc_value, exc_type)))

        print(
            message.notice('For more info invoke `') +
            message.hint('gef config gef.exception_verbose True') +
            message.notice(
                '` and rerun the command\nor debug it by yourself with `') +
            message.hint('gef config gef.exception_debugger True') +
            message.notice('`'))

    # Break into the interactive debugger
    if debug:
        with pwngef.stdio.stdio:
            pdb.post_mortem()
Exemplo n.º 21
0
 def usage(self):
     message.error("Syntax\n{}".format(self._syntax_))
     return None
Exemplo n.º 22
0
    def context_code(self):
        nb_insn = self.get_setting("nb_lines_code")
        nb_insn_prev = self.get_setting("nb_lines_code_prev")
        use_capstone = self.has_setting("use_capstone") and self.get_setting(
            "use_capstone")
        use_ida = self.get_setting("use_ida")
        cur_insn_color = pwngef.config.get(
            "theme.disassemble_current_instruction")
        pc = int(pwngef.arch.CURRENT_ARCH.pc)

        frame = gdb.selected_frame()
        arch_name = "{}:{}".format(pwngef.arch.CURRENT_ARCH.arch.lower(),
                                   pwngef.arch.CURRENT_ARCH.mode)

        self.context_title("code:{}".format(arch_name))

        try:
            instruction_iterator = disass.capstone_disassemble if use_capstone else disass.gef_disassemble
            instruction_iterator = disass.ida_disassemble if use_ida else instruction_iterator
            for insn in instruction_iterator(pc, nb_insn,
                                             nb_prev=nb_insn_prev):
                line = []
                is_taken = False
                target = None
                text = str(insn)

                if insn.address < pc:
                    line += Color.grayify("   {}".format(text))
                elif insn.address == pc:
                    line += Color.colorify(
                        "{:s}{:s}".format(config_arrow_right.rjust(3), text),
                        cur_insn_color)

                    if pwngef.arch.CURRENT_ARCH.is_conditional_branch(insn):
                        is_taken, reason = pwngef.arch.CURRENT_ARCH.is_branch_taken(
                            insn)
                        if is_taken:
                            target = insn.operands[-1].split()[0]
                            reason = "[Reason: {:s}]".format(
                                reason) if reason else ""
                            line += Color.colorify(
                                "\tTAKEN {:s}".format(reason), "bold green")
                        else:
                            reason = "[Reason: !({:s})]".format(
                                reason) if reason else ""
                            line += Color.colorify(
                                "\tNOT taken {:s}".format(reason), "bold red")
                    elif pwngef.arch.CURRENT_ARCH.is_call(
                            insn) and self.get_setting("peek_calls") is True:
                        target = insn.operands[-1].split()[0]
                    elif pwngef.arch.CURRENT_ARCH.is_ret(
                            insn) and self.get_setting("peek_ret") is True:
                        target = int(
                            pwngef.arch.CURRENT_ARCH.get_ra(insn, frame))
                else:
                    line += "   {}".format(text)

                print("".join(line))
                if target:
                    try:
                        target = int(target, 0)
                    except TypeError:  # Already an int
                        pass
                    except ValueError:
                        # If the operand isn't an address right now we can't parse it
                        continue
                    for i, tinsn in enumerate(
                            instruction_iterator(target, nb_insn)):
                        text = "   {}  {}".format(
                            pwngef.config.DOWN_ARROW if i == 0 else " ",
                            str(tinsn))
                        print(text)
                    break
        except gdb.MemoryError:
            message.error("Cannot disassemble from $PC")
        except Exception:
            import traceback
            print(traceback.format_exc())
        return None