Exemple #1
0
 def __exec_mips_set_gp(self, args):
     try:
         self.gctx.dis.mips_gp = int(args[1], 16)
         self.db.mips_gp = self.gctx.dis.mips_gp
     except:
         error("bad address")
     self.db.modified = True
Exemple #2
0
    def decompile(self):
        self.is_dump = False
        self.gph, pe_nb_new_syms = self.gctx.dis.get_graph(self.entry)

        if self.gph is None:
            error("capstone can't disassemble here")
            return None
        self.gph.simplify()

        if self.gctx.db.loaded and pe_nb_new_syms:
            self.gctx.db.modified = True

        try:
            self.gph.loop_detection(self.entry)
            ast, correctly_ended = generate_ast(self)
            if not correctly_ended:
                debug__("Second try...")
                self.gph.loop_detection(self.entry, True)
                ast, _ = generate_ast(self)

            self.ast = ast
        except ExcIfelse as e:
            error("can't have a ifelse here     %x" % e.addr)
            if self.gctx.interactive_mode:
                return None
            die()

        o = self.gctx.libarch.output.Output(self)
        o._ast(self.entry, ast)
        self.output = o
        return o
Exemple #3
0
    def decompile(self):
        self.is_dump = False
        self.gph, pe_nb_new_syms = self.gctx.dis.get_graph(self.entry)

        if self.gph is None:
            error("capstone can't disassemble here")
            return None
        self.gph.simplify()

        if self.gctx.db.loaded and pe_nb_new_syms:
            self.gctx.db.modified = True
        
        try:
            self.gph.loop_detection(self.entry)
            ast, correctly_ended = generate_ast(self)
            if not correctly_ended:
                debug__("Second try...")
                self.gph.loop_detection(self.entry, True)
                ast, _ = generate_ast(self)

            self.ast = ast
        except ExcIfelse as e:
            error("can't have a ifelse here     %x" % e.addr)
            if self.gctx.interactive_mode:
                return None
            die()

        o = self.gctx.libarch.output.Output(self)
        o._ast(self.entry, ast)
        self.output = o
        return o
Exemple #4
0
 def __exec_mips_set_gp(self, args):
     try:
         self.gctx.dis.mips_gp = int(args[1], 16)
         self.db.mips_gp = self.gctx.dis.mips_gp
         self.db.mem.mm.clear()
         self.db.xrefs.clear()
         self.db.data_sub_xrefs.clear()
         self.db.immediates.clear()
     except:
         error("bad address")
     self.db.modified = True
Exemple #5
0
 def __exec_mips_set_gp(self, args):
     try:
         self.gctx.dis.mips_gp = int(args[1], 16)
         self.db.mips_gp = self.gctx.dis.mips_gp
         self.db.mem.mm.clear()
         self.db.xrefs.clear()
         self.db.data_sub_xrefs.clear()
         self.db.immediates.clear()
     except:
         error("bad address")
     self.db.modified = True
Exemple #6
0
    def __exec_hexdump(self, args):
        nb_lines = self.gctx.nb_lines
        if len(args) <= 1:
            self.gctx.entry = None
            error("no address in parameter")
            return

        if len(args) == 3:
            try:
                nb_lines = int(args[2])
            except:
                pass

        ctx = self.gctx.get_addr_context(args[1])
        if ctx:
            self.gctx.dis.hexdump(ctx, nb_lines)
Exemple #7
0
    def __exec_jmptable(self, args):
        try:
            inst_addr = int(args[1], 16)
            table_addr = int(args[2], 16)
            nb_entries = int(args[3])
            entry_size = int(args[4])
        except:
            error("one parameter is invalid, be sure that addresses start with 0x")
            return

        if entry_size not in [2, 4, 8]:
            error("error the entry size should be in [2, 4, 8]")
            return

        self.db.modified = True
        self.api.create_jmptable(inst_addr, table_addr, entry_size, nb_entries)
Exemple #8
0
    def __exec_jmptable(self, args):
        try:
            inst_addr = int(args[1], 16)
            table_addr = int(args[2], 16)
            nb_entries = int(args[3])
            entry_size = int(args[4])
        except:
            error("one parameter is invalid, be sure that addresses start with 0x")
            return

        if entry_size not in [2, 4, 8]:
            error("error the entry size should be in [2, 4, 8]")
            return

        self.db.modified = True
        self.api.create_jmptable(inst_addr, table_addr, nb_entries, entry_size)
Exemple #9
0
    def exec_command(self, line):
        args = shlex.split(line)
        if args[0] not in self.COMMANDS:
            error("unknown command")
            return
        c = self.COMMANDS[args[0]]

        if len(args)-1 > c.max_args:
            error("%s takes max %d args" % (args[0], c.max_args))
            return

        if c.callback_exec is not None:
            try:
                c.callback_exec(args)
            except:
                traceback.print_exc()
Exemple #10
0
    def __exec_hexdump(self, args):
        nb_lines = self.gctx.nb_lines
        if len(args) <= 1:
            self.gctx.entry = None
            error("no address in parameter")
            return

        if len(args) == 3:
            try:
                nb_lines = int(args[2])
            except:
                pass

        ctx = self.gctx.get_addr_context(args[1])
        if ctx:
            self.gctx.dis.hexdump(ctx, nb_lines)
Exemple #11
0
    def exec_command(self, line):
        args = shlex.split(line)
        if not args:
            return
        if args[0] not in self.COMMANDS:
            error("unknown command")
            return
        c = self.COMMANDS[args[0]]

        if c.max_args != -1 and len(args) - 1 > c.max_args:
            error("%s takes max %d args" % (args[0], c.max_args))
            return

        if c.callback_exec is not None:
            try:
                c.callback_exec(args)
            except:
                traceback.print_exc()
Exemple #12
0
    def init_address(self, entry, quiet=False):
        if isinstance(entry, int):
            self.entry = entry
            return True

        if entry == "EP":
            self.entry = self.gctx.dis.binary.get_entry_point()
            return True

        if entry is None:
            if self.gctx.raw_type is not None:
                self.entry = 0
                return True

            self.entry = self.gctx.db.symbols.get("main", None) or \
                         self.gctx.db.symbols.get("_main", None) or \
                         self.gctx.dis.binary.get_entry_point()

            if self.entry is None:
                error("symbol main or _main not found, try with EP")
                if self.gctx.interactive_mode:
                    return False
                die()
            return True

        is_hexa = entry.startswith("0x")

        if not is_hexa and self.gctx.api.is_reserved_prefix(entry):
            entry = entry[entry.index("_") + 1:]
            is_hexa = True

        if is_hexa:
            try:
                self.entry = int(entry, 16)
            except:
                if not quiet:
                    error("bad hexa string %s" % entry)
                if self.gctx.interactive_mode:
                    return False
                die()
            return True

        self.entry = self.gctx.db.demangled.get(entry, None) or \
                     self.gctx.db.symbols.get(entry, None) or \
                     self.gctx.dis.binary.section_names.get(entry, None)

        if self.entry is None:
            if not quiet:
                error("symbol %s not found" % entry)
            if self.gctx.interactive_mode:
                return False
                die()

        return True
Exemple #13
0
    def init_address(self, entry, quiet=False):
        if isinstance(entry, int):
            self.entry = entry
            return True

        if entry == "EP":
            self.entry = self.gctx.dis.binary.get_entry_point()
            return True

        if entry is None:
            if self.gctx.raw_type is not None:
                self.entry = 0
                return True

            self.entry = self.gctx.db.symbols.get("main", None) or \
                         self.gctx.db.symbols.get("_main", None) or \
                         self.gctx.dis.binary.get_entry_point()

            if self.entry is None:
                error("symbol main or _main not found, try with EP")
                if self.gctx.interactive_mode:
                    return False
                die()
            return True

        is_hexa = entry.startswith("0x")

        if not is_hexa and self.gctx.api.is_reserved_prefix(entry):
            entry = entry[entry.index("_") + 1:]
            is_hexa = True

        if is_hexa:
            try:
                self.entry = int(entry, 16)
            except:
                if not quiet:
                    error("bad hexa string %s" % entry)
                if self.gctx.interactive_mode:
                    return False
                die()
            return True

        self.entry = self.gctx.db.demangled.get(entry, None) or \
                     self.gctx.db.symbols.get(entry, None) or \
                     self.gctx.dis.binary.section_names.get(entry, None)

        if self.entry is None:
            if not quiet:
                error("symbol %s not found" % entry)
            if self.gctx.interactive_mode:
                return False
                die()

        return True
Exemple #14
0
    def __exec_sym(self, args):
        if len(args) == 1:
            self.gctx.dis.print_symbols()
            return

        if args[1][0] == "|":
            if len(args) == 2 or len(args) > 3:
                error("bad arguments (warn: need spaces between |)")
                return
            self.gctx.dis.print_symbols(args[2])
            return

        if len(args) == 2:
            error("an address is required to save the symbol")
            return

        if not args[2].startswith("0x"):
            error("the address should starts with 0x")
            return

        if args[1].startswith("loc_"):
            error("loc_ is a reserved prefix")
            return

        # Save new symbol
        try:
            if not self.api.add_symbol(int(args[2], 16), args[1]):
                error("cannot rename")
                return
            self.db.modified = True
        except:
            error("there was an error when creating a symbol")
Exemple #15
0
    def __init__(self, gctx, ad, analyzer, api, last_widgets=None):
        Window.__init__(self)

        saved_quiet = gctx.quiet
        gctx.quiet = True

        # Start curses

        self.screen = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)

        curses.start_color()
        curses.use_default_colors()

        if gctx.color:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, i, -1)

            try:
                curses.init_pair(1, COLOR_SEARCH_FG, COLOR_SEARCH_BG)
            except:
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                gctx.quiet = saved_quiet
                error("is your terminal supports 256 colours ? check the issue #58")
                return
        else:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, 7, -1) # white


        # Init widgets

        (h, w) = self.screen.getmaxyx()

        if last_widgets is not None:
            self.widgets = last_widgets
            for wdgt in self.widgets:
                wdgt.has_focus = False
                if isinstance(wdgt, Disasmbox):
                    wdgt.reload_asm()
        else:
            self.widgets = [Disasmbox(0, 0, w, h, gctx, ad, analyzer, api, mode=MODE_DUMP)]
            if self.widgets[0].ctx is None:
                self.error_occurs = True
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                gctx.quiet = saved_quiet
                print("error: bad address or symbol")
                return

        self.widgets[0].has_focus = True

        try:
            curses.wrapper(self.start_view)
        except:
            curses.nocbreak()
            curses.echo()
            curses.endwin()
            gctx.quiet = saved_quiet
            traceback.print_exc()
            self.error_occurs = True
            return

        self.error_occurs = False
        curses.nocbreak()
        curses.echo()
        curses.endwin()
        gctx.quiet = saved_quiet
Exemple #16
0
    def parse_args(self):
        parser = ArgumentParser(
            description=
            'Reverse engineering for x86/ARM/MIPS binaries. Generation of pseudo-C. '
            'Supported formats : ELF, PE. More commands available in the interactive'
            ' mode.    https://github.com/joelpx/plasma')
        parser.add_argument('filename', nargs='?', metavar='FILENAME')
        parser.add_argument('-nc', '--nocolor', action='store_true')
        parser.add_argument('-g',
                            '--graph',
                            action='store_true',
                            help='Generate a file graph.dot.')
        parser.add_argument('--noandif',
                            action='store_true',
                            help="Print normal 'if' instead of 'andif'")
        parser.add_argument(
            '--datasize',
            type=int,
            default=30,
            metavar='N',
            help=
            'default 30, maximum of chars to display for strings or bytes array.'
        )
        parser.add_argument(
            '-x',
            '--entry',
            metavar='SYMBOLNAME|0xXXXXX|EP',
            help=
            'Pseudo-decompilation, default is main. EP stands for entry point.'
        )
        parser.add_argument('--vim',
                            action='store_true',
                            help='Generate syntax colors for vim')
        parser.add_argument('-s',
                            '--symbols',
                            action='store_true',
                            help='Print all symbols')
        parser.add_argument('--sections',
                            action='store_true',
                            help='Print all sections')
        parser.add_argument('--dump',
                            action='store_true',
                            help='Dump asm without decompilation')
        parser.add_argument('-l',
                            '--lines',
                            type=int,
                            default=30,
                            metavar='N',
                            help='Max lines used with --dump')
        parser.add_argument('--nbytes',
                            type=int,
                            default=0,
                            metavar='N',
                            help='Print n bytes.')
        parser.add_argument('-i',
                            '--interactive',
                            action='store_true',
                            help='Interactive mode')
        parser.add_argument('-d', '--opt_debug', action='store_true')
        parser.add_argument('--raw',
                            metavar='x86|x64|arm|mips|mips64',
                            help='Consider the input file as a raw binary')
        parser.add_argument('--rawbase',
                            metavar='0xXXXXX',
                            help='Set base address of a raw file (default=0)')
        parser.add_argument('--rawbe',
                            action='store_true',
                            help='If not set it\'s in little endian')
        parser.add_argument(
            '-na',
            '--noautoanalyzer',
            action='store_true',
            help=
            'Disable analysis on the entry point / symbols and don\'t scan memmory. You can force it with the command push_analyze_symbols.'
        )
        parser.add_argument(
            '--debugsp',
            action='store_true',
            help=
            "Print the stack offset on each instructions. Warning: these values will not be saved in the database."
        )

        args = parser.parse_args()

        self.debug = args.opt_debug
        self.print_andif = not args.noandif
        self.color = not args.nocolor
        self.max_data_size = args.datasize
        self.filename = args.filename
        self.raw_type = args.raw
        self.raw_base = args.rawbase
        self.syms = args.symbols
        self.entry = args.entry
        self.do_dump = args.dump
        self.vim = args.vim
        self.interactive_mode = args.interactive
        self.nb_lines = args.lines
        self.graph = args.graph
        self.raw_big_endian = args.rawbe
        self.list_sections = args.sections
        self.autoanalyzer = not args.noautoanalyzer
        self.debugsp = args.debugsp

        if args.nbytes == 0:
            self.nbytes = 4
            self.print_bytes = False
        else:
            self.nbytes = int(args.nbytes)
            self.print_bytes = True

        if self.raw_base is not None:
            try:
                self.raw_base = int(self.raw_base, 16)
            except:
                error("--rawbase must be in hex format")
                die()
        else:
            self.raw_base = 0
Exemple #17
0
    def __init__(self,
                 gctx,
                 ad,
                 analyzer,
                 api,
                 stack,
                 saved_stack,
                 mode=MODE_DUMP):

        self.gctx = gctx
        self.dis = gctx.dis
        self.db = gctx.db
        self.analyzer = analyzer
        self.api = api
        self.last_curr_line_ad = None

        # Disassemble

        self.ctx = self.gctx.get_addr_context(ad)
        if not self.ctx:
            return

        ad = self.ctx.entry
        ad_disasm = ad

        if mode == MODE_DECOMPILE:
            if self.db.mem.is_code(ad_disasm):
                fid = self.db.mem.get_func_id(ad_disasm)
                if fid != -1:
                    self.ctx.entry = self.db.func_id[fid]
                else:
                    mode = MODE_DUMP
            else:
                mode = MODE_DUMP

        if mode == MODE_DUMP:
            self.ctx.output = self.ctx.dump_asm()
        else:
            self.ctx.output = self.ctx.decompile()

        # Some init...

        Window.__init__(self, self.ctx.output, has_statusbar=True)
        self.mode = mode

        # Last/first address printed (only in MODE_DUMP)
        self.set_last_addr()
        self.set_first_addr()

        self.stack = stack
        self.saved_stack = saved_stack  # when we enter, go back, then re-enter

        saved_quiet = self.gctx.quiet
        self.gctx.quiet = True

        # Note: all these functions should return a boolean. The value is true
        # if the screen must be refreshed (not re-drawn, in this case call
        # explictly self.redraw or self.reload_output if the output changed).

        new_mapping = {
            b"z": self.main_cmd_line_middle,
            b"g": self.main_k_top,
            b"G": self.main_k_bottom,
            b";": self.view_inline_comment_editor,
            b"%": self.main_cmd_next_bracket,
            b"\t": self.main_cmd_switch_mode,
            b"{": self.main_k_prev_paragraph,
            b"}": self.main_k_next_paragraph,
            b"x": self.main_cmd_xrefs,
            b"r": self.main_cmd_rename,
            b"I": self.main_cmd_inst_output,
            b"M": self.main_cmd_show_mangling,
            b"B": self.main_cmd_show_bytes,
            b"/": self.main_cmd_search,
            b"n": self.main_cmd_search_forward,
            b"N": self.main_cmd_search_backward,
            b"c": self.main_cmd_set_code,
            b"p": self.main_cmd_set_function,
            b"b": self.main_cmd_set_byte,
            b"w": self.main_cmd_set_word,
            b"d": self.main_cmd_set_dword,
            b"Q": self.main_cmd_set_qword,
            b"a": self.main_cmd_set_ascii,
            b"o": self.main_cmd_set_offset,
            b"*": self.main_cmd_set_array,
            b"U": self.main_cmd_undefine,
            b"S": self.main_cmd_set_frame_size,
            b"\n": self.main_cmd_enter,
            b"\x1b": self.main_cmd_escape,
            # I wanted ctrl-enter but it cannot be mapped on my terminal
            b"u": self.main_cmd_reenter,  # u for undo
        }

        self.mapping.update(new_mapping)

        # Start curses

        self.screen = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.mousemask(curses.ALL_MOUSE_EVENTS
                         | curses.REPORT_MOUSE_POSITION)

        curses.start_color()
        curses.use_default_colors()

        if self.gctx.color:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, i, -1)

            try:
                curses.init_pair(1, COLOR_SEARCH_FG, COLOR_SEARCH_BG)
            except:
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                self.gctx.quiet = saved_quiet
                error(
                    "is your terminal supports 256 colours ? check the issue #58"
                )
                return
        else:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, 7, -1)  # white

        (h, w) = self.screen.getmaxyx()
        h -= 1  # status bar

        # Init some y coordinate, used to compute the cursor position
        self.init_section_coords()

        self.win_y = self.dump_update_up(h, self.win_y)
        self.goto_address(ad, h, w)
        self.main_cmd_line_middle(h, w)

        try:
            curses.wrapper(self.start_view)
        except:
            curses.nocbreak()
            curses.echo()
            curses.endwin()
            self.gctx.quiet = saved_quiet
            traceback.print_exc()
            return

        curses.nocbreak()
        curses.echo()
        curses.endwin()

        self.gctx.quiet = saved_quiet
Exemple #18
0
    def load_file(self, filename=None):
        if filename is None:
            filename = self.filename

        if not os.path.exists(filename):
            error("file {self.filename} doesn't exist".format(self=self))
            if self.interactive_mode:
                return False
            die()

        if not os.path.isfile(filename):
            error("this is not a file".format(self=self))
            if self.interactive_mode:
                return False
            die()

        self.db = Database()
        self.db.load(filename)

        if self.raw_base != 0:
            self.db.raw_base = self.raw_base

        if self.raw_type is not None:
            self.db.raw_type = self.raw_type

        if self.raw_big_endian is not None:
            self.db.raw_is_big_endian = self.raw_big_endian

        if self.db.loaded:
            self.raw_base = self.db.raw_base
            self.raw_type = self.db.raw_type
            self.raw_big_endian = self.db.raw_is_big_endian

        try:
            dis = Disassembler(filename, self.raw_type, self.raw_base,
                               self.raw_big_endian, self.db)
        except ExcArch as e:
            error("arch %s is not supported" % e.arch)
            if self.interactive_mode:
                return False
            die()
        except ExcFileFormat:
            error("the file is not PE or ELF binary")
            if self.interactive_mode:
                return False
            die()
        except ExcPEFail as e:
            error(str(e.e))
            error(
                "it seems that there is a random bug in pefile, you shoul retry."
            )
            error(
                "please report here https://github.com/joelpx/plasma/issues/16"
            )
            if self.interactive_mode:
                return False
            die()

        self.dis = dis
        self.libarch = dis.load_arch_module()

        return True
Exemple #19
0
    def __init__(self, gctx, ad, analyzer, api, last_widgets=None):
        Window.__init__(self)

        saved_quiet = gctx.quiet
        gctx.quiet = True

        # Start curses

        self.screen = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.mousemask(curses.ALL_MOUSE_EVENTS
                         | curses.REPORT_MOUSE_POSITION)

        curses.start_color()
        curses.use_default_colors()

        if gctx.color:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, i, -1)

            try:
                curses.init_pair(1, COLOR_SEARCH_FG, COLOR_SEARCH_BG)
            except:
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                gctx.quiet = saved_quiet
                error(
                    "is your terminal supports 256 colours ? check the issue #58"
                )
                return
        else:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, 7, -1)  # white

        # Init widgets

        (h, w) = self.screen.getmaxyx()

        if last_widgets is not None:
            self.widgets = last_widgets
            for wdgt in self.widgets:
                wdgt.has_focus = False
                if isinstance(wdgt, Disasmbox):
                    wdgt.reload_asm()
        else:
            self.widgets = [
                Disasmbox(0, 0, w, h, gctx, ad, analyzer, api, mode=MODE_DUMP)
            ]
            if self.widgets[0].ctx is None:
                self.error_occurs = True
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                gctx.quiet = saved_quiet
                print("error: bad address or symbol")
                return

        self.widgets[0].has_focus = True

        try:
            curses.wrapper(self.start_view)
        except:
            curses.nocbreak()
            curses.echo()
            curses.endwin()
            gctx.quiet = saved_quiet
            traceback.print_exc()
            self.error_occurs = True
            return

        self.error_occurs = False
        curses.nocbreak()
        curses.echo()
        curses.endwin()
        gctx.quiet = saved_quiet
Exemple #20
0
    def parse_args(self):
        parser = ArgumentParser(description=
            'Reverse engineering for x86/ARM/MIPS binaries. Generation of pseudo-C. '
            'Supported formats : ELF, PE. More commands available in the interactive'
            ' mode.    https://github.com/joelpx/plasma')
        parser.add_argument('filename', nargs='?', metavar='FILENAME')
        parser.add_argument('-nc', '--nocolor', action='store_true')
        parser.add_argument('-g', '--graph', action='store_true',
                help='Generate a file graph.dot.')
        parser.add_argument('--noandif', action='store_true',
                help="Print normal 'if' instead of 'andif'")
        parser.add_argument('--datasize', type=int, default=30, metavar='N',
                help='default 30, maximum of chars to display for strings or bytes array.')
        parser.add_argument('-x', '--entry', metavar='SYMBOLNAME|0xXXXXX|EP',
                help='Pseudo-decompilation, default is main. EP stands for entry point.')
        parser.add_argument('--vim', action='store_true',
                help='Generate syntax colors for vim')
        parser.add_argument('-s', '--symbols', action='store_true',
                help='Print all symbols')
        parser.add_argument('--sections', action='store_true',
                help='Print all sections')
        parser.add_argument('--dump', action='store_true',
                help='Dump asm without decompilation')
        parser.add_argument('-l', '--lines', type=int, default=30, metavar='N',
                help='Max lines used with --dump')
        parser.add_argument('--nbytes', type=int, default=0, metavar='N',
                help='Print n bytes.')
        parser.add_argument('-i', '--interactive', action='store_true',
                help='Interactive mode')
        parser.add_argument('-d', '--opt_debug', action='store_true')
        parser.add_argument('--raw', metavar='x86|x64|arm|mips|mips64',
                help='Consider the input file as a raw binary')
        parser.add_argument('--rawbase', metavar='0xXXXXX',
                help='Set base address of a raw file (default=0)')
        parser.add_argument('--rawbe', action='store_true',
                help='If not set it\'s in little endian')
        parser.add_argument('-na', '--noautoanalyzer', action='store_true',
                help='Disable analysis on the entry point / symbols and don\'t scan memmory. You can force it with the command push_analyze_symbols.')
        parser.add_argument('--debugsp', action='store_true',
                help="Print the stack offset on each instructions. Warning: these values will not be saved in the database.")

        args = parser.parse_args()

        self.debug           = args.opt_debug
        self.print_andif     = not args.noandif
        self.color           = not args.nocolor
        self.max_data_size   = args.datasize
        self.filename        = args.filename
        self.raw_type        = args.raw
        self.raw_base        = args.rawbase
        self.syms            = args.symbols
        self.entry           = args.entry
        self.do_dump         = args.dump
        self.vim             = args.vim
        self.interactive_mode = args.interactive
        self.nb_lines        = args.lines
        self.graph           = args.graph
        self.raw_big_endian  = args.rawbe
        self.list_sections   = args.sections
        self.autoanalyzer    = not args.noautoanalyzer
        self.debugsp         = args.debugsp

        if args.nbytes == 0:
            self.nbytes = 4
            self.print_bytes = False
        else:
            self.nbytes = int(args.nbytes)
            self.print_bytes = True

        if self.raw_base is not None:
            try:
                self.raw_base = int(self.raw_base, 16)
            except:
                error("--rawbase must be in hex format")
                die()
        else:
            self.raw_base = 0
Exemple #21
0
    def load_file(self, filename=None):
        if filename is None:
            filename = self.filename

        if not os.path.exists(filename):
            error("file {self.filename} doesn't exist".format(self=self))
            if self.interactive_mode:
               return False
            die()

        if not os.path.isfile(filename):
            error("this is not a file".format(self=self))
            if self.interactive_mode:
               return False
            die()

        self.db = Database()
        self.db.load(filename)

        if self.raw_base != 0:
            self.db.raw_base = self.raw_base

        if self.raw_type is not None:
            self.db.raw_type = self.raw_type

        if self.raw_big_endian is not None:
            self.db.raw_is_big_endian = self.raw_big_endian

        if self.db.loaded:
            self.raw_base = self.db.raw_base
            self.raw_type = self.db.raw_type
            self.raw_big_endian = self.db.raw_is_big_endian

        try:
            dis = Disassembler(filename, self.raw_type,
                               self.raw_base, self.raw_big_endian,
                               self.db)
        except ExcArch as e:
            error("arch %s is not supported" % e.arch)
            if self.interactive_mode:
                return False
            die()
        except ExcFileFormat:
            error("the file is not PE or ELF binary")
            if self.interactive_mode:
                return False
            die()
        except ExcPEFail as e:
            error(str(e.e))
            error("it seems that there is a random bug in pefile, you shoul retry.")
            error("please report here https://github.com/joelpx/plasma/issues/16")
            if self.interactive_mode:
                return False
            die()

        self.dis = dis
        self.libarch = dis.load_arch_module()

        return True
Exemple #22
0
    def __exec_sym(self, args):
        if len(args) == 1:
            self.gctx.dis.print_symbols(self.gctx.sectionsname)
            return

        if args[1][0] == "|":
            if len(args) == 2 or len(args) > 3:
                error("bad arguments (warn: need spaces between |)")
                return
            self.gctx.dis.print_symbols(self.gctx.sectionsname, args[2])
            return

        if len(args) > 3:
            error("bad arguments")
            return

        if len(args) == 2:
            error("an address is required to save the symbol")
            return

        if not args[2].startswith("0x"):
            error("the address should starts with 0x")
            return

        if args[1].startswith("loc_"):
            error("loc_ is a reserved prefix")
            return

        # Save new symbol
        try:
            if not self.api.add_symbol(int(args[2], 16), args[1]):
                error("cannot rename")
                return
            self.db.modified = True
        except:
            error("there was an error when creating a symbol")
Exemple #23
0
    def __init__(self, gctx, ctx, analyzer, api, stack, saved_stack):
        Window.__init__(self, ctx.output, has_statusbar=True)

        self.ctx = ctx
        self.gctx = gctx
        self.mode = MODE_DUMP
        self.dis = gctx.dis
        self.db = gctx.db
        self.analyzer = analyzer
        self.api = api

        # Last/first address printed (only in MODE_DUMP)
        self.last_addr = max(self.output.addr_line)
        self.first_addr = min(self.output.addr_line)

        self.last_cursor_ad = None

        self.stack = stack
        self.saved_stack = saved_stack # when we enter, go back, then re-enter

        new_mapping = {
            b"z": self.main_cmd_line_middle,
            b"g": self.main_k_top,
            b"G": self.main_k_bottom,
            b";": self.view_inline_comment_editor,
            b"%": self.main_cmd_next_bracket,
            b"\t": self.main_cmd_switch_mode,
            b"{": self.main_k_prev_paragraph,
            b"}": self.main_k_next_paragraph,
            b"x": self.main_cmd_xrefs,
            b"r": self.main_cmd_rename,
            b"I": self.main_cmd_inst_output,
            b"M": self.main_cmd_show_mangling,
            b"B": self.main_cmd_show_bytes,
            b"/": self.main_cmd_search,
            b"n": self.main_cmd_search_forward,
            b"N": self.main_cmd_search_backward,

            b"c": self.main_cmd_set_code,
            b"p": self.main_cmd_set_function,
            b"b": self.main_cmd_set_byte,
            b"w": self.main_cmd_set_word,
            b"d": self.main_cmd_set_dword,
            b"Q": self.main_cmd_set_qword,
            b"a": self.main_cmd_set_ascii,
            b"o": self.main_cmd_set_offset,
            b"*": self.main_cmd_set_array,

            b"\n": self.main_cmd_enter,
            b"\x1b": self.main_cmd_escape,
            # I wanted ctrl-enter but it cannot be mapped on my terminal
            b"u": self.main_cmd_reenter, # u for undo
        }

        self.mapping.update(new_mapping)

        saved_quiet = self.gctx.quiet
        self.gctx.quiet = True

        self.screen = curses.initscr()

        (h, w) = self.screen.getmaxyx()
        h -= 1 # status bar

        curses.noecho()
        curses.cbreak()
        curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)

        curses.start_color()
        curses.use_default_colors()

        if self.gctx.color:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, i, -1)

            try:
                curses.init_pair(1, 253, 66) # for the highlight search
                curses.init_pair(2, 255, 238) # for the status bar
            except:
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                self.gctx.quiet = saved_quiet
                error("is your terminal supports 256 colours ? check the issue #58")
                return
        else:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, 7, -1) # white

        self.win_y = self.dump_update_up(h, self.win_y)
        self.goto_address(ctx.entry, h, w)
        self.main_cmd_line_middle(h, w)

        try:
            curses.wrapper(self.start_view)
        except:
            curses.nocbreak()
            curses.echo()
            curses.endwin()
            self.gctx.quiet = saved_quiet
            traceback.print_exc()
            return

        curses.nocbreak()
        curses.echo()
        curses.endwin()

        self.gctx.quiet = saved_quiet
Exemple #24
0
    def __init__(self, gctx, ctx, analyzer, api, stack, saved_stack):
        Window.__init__(self, ctx.output, has_statusbar=True)

        self.ctx = ctx
        self.gctx = gctx
        self.mode = MODE_DUMP
        self.dis = gctx.dis
        self.db = gctx.db
        self.analyzer = analyzer
        self.api = api

        # Last/first address printed (only in MODE_DUMP)
        self.set_last_addr()
        self.first_addr = min(self.output.addr_line)

        self.last_curr_line_ad = None

        self.stack = stack
        self.saved_stack = saved_stack  # when we enter, go back, then re-enter

        new_mapping = {
            b"z": self.main_cmd_line_middle,
            b"g": self.main_k_top,
            b"G": self.main_k_bottom,
            b";": self.view_inline_comment_editor,
            b"%": self.main_cmd_next_bracket,
            b"\t": self.main_cmd_switch_mode,
            b"{": self.main_k_prev_paragraph,
            b"}": self.main_k_next_paragraph,
            b"x": self.main_cmd_xrefs,
            b"r": self.main_cmd_rename,
            b"I": self.main_cmd_inst_output,
            b"M": self.main_cmd_show_mangling,
            b"B": self.main_cmd_show_bytes,
            b"/": self.main_cmd_search,
            b"n": self.main_cmd_search_forward,
            b"N": self.main_cmd_search_backward,
            b"c": self.main_cmd_set_code,
            b"p": self.main_cmd_set_function,
            b"b": self.main_cmd_set_byte,
            b"w": self.main_cmd_set_word,
            b"d": self.main_cmd_set_dword,
            b"Q": self.main_cmd_set_qword,
            b"a": self.main_cmd_set_ascii,
            b"o": self.main_cmd_set_offset,
            b"*": self.main_cmd_set_array,
            b"U": self.main_cmd_undefine,
            b"\n": self.main_cmd_enter,
            b"\x1b": self.main_cmd_escape,
            # I wanted ctrl-enter but it cannot be mapped on my terminal
            b"u": self.main_cmd_reenter,  # u for undo
        }

        self.mapping.update(new_mapping)

        saved_quiet = self.gctx.quiet
        self.gctx.quiet = True

        self.screen = curses.initscr()

        curses.noecho()
        curses.cbreak()
        curses.mousemask(curses.ALL_MOUSE_EVENTS
                         | curses.REPORT_MOUSE_POSITION)

        curses.start_color()
        curses.use_default_colors()

        if self.gctx.color:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, i, -1)

            try:
                curses.init_pair(1, COLOR_SEARCH_FG, COLOR_SEARCH_BG)
            except:
                curses.nocbreak()
                curses.echo()
                curses.endwin()
                self.gctx.quiet = saved_quiet
                error(
                    "is your terminal supports 256 colours ? check the issue #58"
                )
                return
        else:
            for i in range(0, curses.COLORS):
                curses.init_pair(i, 7, -1)  # white

        (h, w) = self.screen.getmaxyx()
        h -= 1  # status bar

        # Init some y coordinate, used to compute the cursor position
        self.init_section_coords()

        self.win_y = self.dump_update_up(h, self.win_y)
        self.goto_address(ctx.entry, h, w)
        self.main_cmd_line_middle(h, w)

        try:
            curses.wrapper(self.start_view)
        except:
            curses.nocbreak()
            curses.echo()
            curses.endwin()
            self.gctx.quiet = saved_quiet
            traceback.print_exc()
            return

        curses.nocbreak()
        curses.echo()
        curses.endwin()

        self.gctx.quiet = saved_quiet
Exemple #25
0
    def parse_args(self):
        parser = ArgumentParser(
            description="Reverse engineering for x86/ARM/MIPS binaries. Generation of pseudo-C. "
            "Supported formats : ELF, PE. More commands available in the interactive"
            " mode.    https://github.com/joelpx/plasma"
        )
        parser.add_argument("filename", nargs="?", metavar="FILENAME")
        parser.add_argument("-nc", "--nocolor", action="store_true")
        parser.add_argument("-g", "--graph", action="store_true", help="Generate a file graph.dot.")
        parser.add_argument("--noandif", action="store_true", help="Print normal 'if' instead of 'andif'")
        parser.add_argument(
            "--datasize",
            type=int,
            default=30,
            metavar="N",
            help="default 30, maximum of chars to display for strings or bytes array.",
        )
        parser.add_argument(
            "-x",
            "--entry",
            metavar="SYMBOLNAME|0xXXXXX|EP",
            help="Pseudo-decompilation, default is main. EP stands for entry point.",
        )
        parser.add_argument("--vim", action="store_true", help="Generate syntax colors for vim")
        parser.add_argument("-s", "--symbols", action="store_true", help="Print all symbols")
        parser.add_argument("--sections", action="store_true", help="Print all sections")
        parser.add_argument("--dump", action="store_true", help="Dump asm without decompilation")
        parser.add_argument("-l", "--lines", type=int, default=30, metavar="N", help="Max lines used with --dump")
        parser.add_argument("--nbytes", type=int, default=0, metavar="N", help="Print n bytes.")
        parser.add_argument("-i", "--interactive", action="store_true", help="Interactive mode")
        parser.add_argument("-d", "--opt_debug", action="store_true")
        parser.add_argument("-ns", "--nosectionsname", action="store_true")
        parser.add_argument("--raw", metavar="x86|x64|arm|mips|mips64", help="Consider the input file as a raw binary")
        parser.add_argument("--rawbase", metavar="0xXXXXX", help="Set base address of a raw file (default=0)")
        parser.add_argument("--rawbe", action="store_true", help="If not set it's in little endian")
        parser.add_argument(
            "-na",
            "--noautoanalyzer",
            action="store_true",
            help="Disable analysis on the entry point / symbols and don't scan memmory. You can force it with the command push_analyze_symbols.",
        )

        args = parser.parse_args()

        self.debug = args.opt_debug
        self.print_andif = not args.noandif
        self.color = not args.nocolor
        self.sectionsname = not args.nosectionsname
        self.max_data_size = args.datasize
        self.filename = args.filename
        self.raw_type = args.raw
        self.raw_base = args.rawbase
        self.syms = args.symbols
        self.entry = args.entry
        self.do_dump = args.dump
        self.vim = args.vim
        self.interactive_mode = args.interactive
        self.nb_lines = args.lines
        self.graph = args.graph
        self.raw_big_endian = args.rawbe
        self.list_sections = args.sections
        self.autoanalyzer = not args.noautoanalyzer

        if args.nbytes == 0:
            self.nbytes = 4
            self.print_bytes = False
        else:
            self.nbytes = int(args.nbytes)
            self.print_bytes = True

        if self.raw_base is not None:
            try:
                self.raw_base = int(self.raw_base, 16)
            except:
                error("--rawbase must be in hex format")
                die()
        else:
            self.raw_base = 0