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