コード例 #1
0
ファイル: scratchabit.py プロジェクト: noscripter/ScratchABit
 def write_func(self, addr):
     func = self.model.AS.lookup_func(addr)
     if func:
         funcname = self.model.AS.get_label(func.start)
         outfile = funcname + ".lst"
         with open(outfile, "w") as f:
             model = TextSaveModel(f, self)
             for start, end in func.get_ranges():
                 while start < end:
                     start = engine.render_from(model, start, 1)
         return outfile
コード例 #2
0
ファイル: scratchabit.py プロジェクト: aeppert/ScratchABit
    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))
            if isinstance(line, engine.DisasmObj):
                to_addr = None
                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()
                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:
                self.model.AS.set_comment(addr, res)
            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":

            F = npyscreen.FormBaseNew(name='Go to', lines=6, columns=40, show_atx=4, show_aty=4)
            e = F.add(LabelEntry, name="Labels")
            e.set_choices(self.model.AS.get_label_list())

            def h_enter_key(input):
                if not e.value:
                    # Hitting Enter with empty text entry opens autocomplete dropbox
                    e.auto_complete(input)
                else:
                    F.exit_editing()
            e.add_handlers({curses.ascii.CR: h_enter_key})

            F.add(npyscreen.FixedText, value="Press Tab to auto-complete", editable=False)
            F.edit()
            self.update_screen()
            if e.value:
                if '0' <= e.value[0] <= '9':
                    res = int(e.value, 0)
                else:
                    res = self.model.AS.resolve_label(e.value)

                self.goto_addr(res, from_addr=self.cur_addr())
        elif key == editor.KEY_F1:
            help.help(self)
            self.update_screen()
        elif key == b"S":
            save_state(project_dir)
            self.show_status("Saved.")
        elif key == b"\x11":  # ^Q
            F = npyscreen.Popup(name='Problems list', lines=18)
            class IssueList(npyscreen.MultiLine):
                def display_value(self, vl):
                    return "%08x %s" % vl
            lw = F.add(IssueList, name="Problems")
            #lw.return_exit = True
            lw.values = self.model.AS.get_issues()
            lw.add_handlers({curses.ascii.CR: lambda key: (lw.h_select_exit(key), F.exit_editing(), 1)})
            F.edit()
            self.update_screen()
            if lw.value is not None:
                val = lw.values[lw.value][0]
                self.goto_addr(val, 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"W":
            class TextSaveModel:
                def __init__(self, f, ctrl):
                    self.f = f
                    self.ctrl = ctrl
                    self.cnt = 0
                def add_line(self, addr, line):
                    line = ("%08x " % addr) + line.indent + line.render() + "\n"
                    self.f.write(line)
                    if self.cnt % 256 == 0:
                        self.ctrl.show_status("Writing: 0x%x" % addr)
                    self.cnt += 1
            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 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"/":
                F = npyscreen.FormBaseNew(name='Text Search', lines=5, columns=40, show_atx=4, show_aty=4)
                e = F.add(npyscreen.TitleText, name="Search for:")
                e.entry_widget.add_handlers({curses.ascii.CR: lambda k: F.exit_editing()})
                F.edit()
                self.update_screen()
                self.search_str = e.value
                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))
コード例 #3
0
ファイル: scratchabit.py プロジェクト: noscripter/ScratchABit
    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))