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
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
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
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)
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)
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)
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()
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()
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
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")
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
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
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
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
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
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
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
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")
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
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
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