Example #1
0
 def handle_key(self, key):
     try:
         return self.handle_key_unprotected(key)
     except Exception as e:
         log.exception("Exception processing user command")
         L = 5
         T = 2
         W = 70
         H = 20
         self.dialog_box(L, T, W, H)
         v = Viewer(L + 1, T + 1, W - 2, H - 2)
         import traceback
         v.set_lines([
             "Exception occured processing the command. Press Esc to continue.",
             "Recommended action is saving database, quitting and comparing",
             "database files with backup copies for possibility of data loss",
             "or corruption. The exception was also logged to scratchabit.log.",
             "Please report way to reproduce it to",
             "https://github.com/pfalcon/ScratchABit/issues",
             "",
         ] + traceback.format_exc().splitlines())
         v.loop()
         self.update_screen()
Example #2
0
def help(screen):
    screen.dialog_box(L, T, W, H)
    v = Viewer(L + 1, T + 1, W - 2, H - 2)
    v.set_lines((HELP + cpu_help).splitlines())
    v.loop()
Example #3
0
def help(screen):
    screen.dialog_box(L, T, W, H)
    v = Viewer(L + 1, T + 1, W - 2, H - 2)
    v.set_lines(HELP.splitlines())
    v.loop()
Example #4
0
    def handle_key_unprotected(self, key):
        if key == editor.KEY_ENTER:
            line = self.get_cur_line()
            log.info("Enter pressed: %s" % line)
            op_no = self.cur_operand_no(line)
            self.show_status("Enter pressed: %s, %s" % (self.col, op_no))
            to_addr = None
            # No longer try to jump only to addresses in args, parse
            # textual representation below
            if False and isinstance(line, engine.DisasmObj):
                if op_no >= 0:
                    o = line[op_no]
                    to_addr = o.get_addr()
                if to_addr is None:
                    o = line.get_operand_addr()
                    if o:
                        to_addr = o.get_addr()
            if to_addr is None:
                pos = self.col - line.LEADER_SIZE - len(line.indent)
                word = utils.get_word_at_pos(line.cache, pos)
                if word:
                    if word[0].isdigit():
                        to_addr = int(word, 0)
                    else:
                        to_addr = self.model.AS.resolve_label(word)
                        if to_addr is None:
                            self.show_status("Unknown address: %s" % word)
                            return
            self.goto_addr(to_addr, from_addr=line.ea)
        elif key == editor.KEY_ESC:
            if self.addr_stack:
                self.show_status("Returning")
                self.goto_addr(self.addr_stack.pop())
        elif key == b"q":
            return editor.KEY_QUIT
        elif key == b"c":
            addr = self.cur_addr()
            self.show_status("Analyzing at %x" % addr)
            engine.add_entrypoint(addr, False)
            engine.analyze(self.analyze_status)
            self.update_model()
        elif key == b"d":
            addr = self.cur_addr()
            fl = self.model.AS.get_flags(addr)
            if fl not in (self.model.AS.DATA, self.model.AS.UNK):
                self.show_status("Undefine first")
                return
            if fl == self.model.AS.UNK:
                self.model.AS.set_flags(addr, 1, self.model.AS.DATA, self.model.AS.DATA_CONT)
            else:
                sz = self.model.AS.get_unit_size(addr)
                self.model.undefine_unit(addr)
                sz *= 2
                if sz > 4: sz = 1
                self.model.AS.set_flags(addr, sz, self.model.AS.DATA, self.model.AS.DATA_CONT)
            self.update_model()
        elif key == b"a":
            addr = self.cur_addr()
            fl = self.model.AS.get_flags(addr)
            if fl != self.model.AS.UNK:
                self.show_status("Undefine first")
                return
            sz = 0
            label = "s_"
            while True:
                b = self.model.AS.get_byte(addr)
                fl = self.model.AS.get_flags(addr)
                if not (0x20 <= b <= 0x7e or b in (0x0a, 0x0d)):
                    if b == 0:
                        sz += 1
                    break
                if fl != self.model.AS.UNK:
                    break
                c = chr(b)
                if c < '0' or c in string.punctuation:
                    c = '_'
                label += c
                addr += 1
                sz += 1
            if sz > 0:
                self.model.AS.set_flags(self.cur_addr(), sz, self.model.AS.STR, self.model.AS.DATA_CONT)
                self.model.AS.make_unique_label(self.cur_addr(), label)
                self.update_model()
        elif key == b"u":
            addr = self.cur_addr()
            self.model.undefine_unit(addr)
            self.update_model()
        elif key == b"o":
            addr = self.cur_addr()
            line = self.get_cur_line()
            o = line.get_operand_addr()
            if not o:
                self.show_status("Cannot convert operand to offset")
                return
            if o.type != idaapi.o_imm or not self.model.AS.is_valid_addr(o.get_addr()):
                self.show_status("Cannot convert operand to offset: #%s: %s" % (o.n, o.type))
                return

            if self.model.AS.get_arg_prop(addr, o.n, "type") == idaapi.o_mem:
                self.model.AS.set_arg_prop(addr, o.n, "type", idaapi.o_imm)
                self.model.AS.del_xref(addr, o.get_addr(), idaapi.dr_O)
            else:
                self.model.AS.make_arg_offset(addr, o.n, o.get_addr())
            self.update_model(True)
        elif key == b";":
            addr = self.cur_addr()
            comment = self.model.AS.get_comment(addr) or ""
            res = self.dialog_edit_line(line=comment, width=60)
            if res is not None:
                self.model.AS.set_comment(addr, res)
                self.update_model()
            else:
                self.update_screen()
        elif key == b"n":
            addr = self.cur_addr()
            label = self.model.AS.get_label(addr)
            def_label = self.model.AS.get_default_label(addr)
            s = label or def_label
            while True:
                res = self.dialog_edit_line(line=s)
                if not res:
                    break
                if res == def_label:
                    res = addr
                else:
                    if self.model.AS.label_exists(res):
                        s = res
                        self.show_status("Duplicate label")
                        continue
                self.model.AS.set_label(addr, res)
                if not label:
                    # If it's new label, we need to add it to model
                    self.update_model()
                    return
                break
            self.update_screen()
        elif key == b"g":
            d = Dialog(4, 4, title="Go to")
            d.add(1, 1, WLabel("Label/addr:"))
            entry = WAutoComplete(20, "", self.model.AS.get_label_list())
            entry.popup_h = 12
            entry.finish_dialog = ACTION_OK
            d.add(13, 1, entry)
            d.add(1, 2, WLabel("Press Down to auto-complete"))
            res = d.loop()
            self.update_screen()

            if res == ACTION_OK:
                value = entry.get_text()
                if '0' <= value[0] <= '9':
                    addr = int(value, 0)
                else:
                    addr = self.model.AS.resolve_label(value)
                self.goto_addr(addr, from_addr=self.cur_addr())

        elif key == editor.KEY_F1:
            help.help(self)
            self.update_screen()
        elif key == b"S":
            saveload.save_state(project_dir)
            self.show_status("Saved.")
        elif key == b"\x11":  # ^Q
            class IssueList(WListBox):
                def render_line(self, l):
                    return "%08x %s" % l
            d = Dialog(4, 4, title="Problems list")
            lw = IssueList(40, 16, self.model.AS.get_issues())
            lw.finish_dialog = ACTION_OK
            d.add(1, 1, lw)
            res = d.loop()
            self.update_screen()
            if res == ACTION_OK:
                val = lw.get_cur_line()
                if val:
                    self.goto_addr(val[0], from_addr=self.cur_addr())

        elif key == b"i":
            off, area = self.model.AS.addr2area(self.cur_addr())
            props = area[engine.PROPS]
            percent = 100 * off / (area[engine.END] - area[engine.START] + 1)
            func = self.model.AS.lookup_func(self.cur_addr())
            func = self.model.AS.get_label(func.start) if func else None
            self.show_status("Area: 0x%x %s (%s): %.1f%%, func: %s" % (
                area[engine.START], props.get("name", "noname"), props["access"], percent, func
            ))
        elif key == b"I":
            L = 5
            T = 2
            W = 66
            H = 20
            self.dialog_box(L, T, W, H)
            v = Viewer(L + 1, T + 1, W - 2, H - 2)
            lines = []
            for area in self.model.AS.get_areas():
                props = area[engine.PROPS]
                lines.append("%s (%08x-%08x):" % (props.get("name", "noname"), area[engine.START], area[engine.END]))
                flags = area[engine.FLAGS]
                l = ""
                for i in range(len(flags)):
                    if i % 64 == 0 and l:
                        lines.append(l)
                        l = ""
                    l += engine.flag2char(flags[i])
                if l:
                    lines.append(l)
            v.set_lines(lines)
            v.loop()
            self.update_screen()
        elif key == b"W":
            out_fname = "out.lst"
            with open(out_fname, "w") as f:
                engine.render_partial(TextSaveModel(f, self), 0, 0, 10000000)
            self.show_status("Disassembly listing written: " + out_fname)
        elif key == b"\x17":  # Ctrl+W
            outfile = self.write_func(self.cur_addr())
            if outfile:
                self.show_status("Wrote file: %s" % outfile)
        elif key in (b"/", b"?"):  # "/" and Shift+"/"
            class FoundException(Exception): pass
            class TextSearchModel:
                def __init__(self, substr, ctrl):
                    self.search = substr
                    self.ctrl = ctrl
                    self.cnt = 0
                def add_line(self, addr, line):
                    line = line.render()
                    if self.search in line:
                        raise FoundException(addr)
                    if self.cnt % 256 == 0:
                        self.ctrl.show_status("Searching: 0x%x" % addr)
                    self.cnt += 1
            if key == b"/":
                d = Dialog(4, 4, title="Text Search")
                d.add(1, 1, WLabel("Search for:"))
                entry = WTextEntry(20, self.search_str)
                entry.finish_dialog = ACTION_OK
                d.add(13, 1, entry)
                res = d.loop()
                self.update_screen()
                self.search_str = entry.get_text()
                if res != ACTION_OK or not self.search_str:
                    return
                addr = self.cur_addr()
            else:
                addr = self.next_addr()

            try:
                engine.render_from(TextSearchModel(self.search_str, self), addr, 10000000)
            except FoundException as res:
                self.goto_addr(res.args[0], from_addr=self.cur_addr())
            else:
                self.show_status("Not found: " + self.search_str)

        else:
            self.show_status("Unbound key: " + repr(key))