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