from __future__ import print_function # ----------------------------------------------------------------------- # This is an example illustrating how to use customview in Python # The sample will allow you to open an assembly file and display it in color # (c) Hex-Rays # import os import ida_idaapi import ida_kernwin import ida_lines import idautils # ---------------------------------------------------------------------- class asm_colorizer_t(object): def is_id(self, ch): return ch == '_' or ch.isalpha() or '0' <= ch <= '9' def get_identifier(self, line, x, e): i = x is_digit = line[i].isdigit() while i < e: ch = line[i] if not self.is_id(ch): if ch != '.' or not is_digit: break i += 1 return (i, line[x:i]) def get_quoted_string(self, line, x, e): quote = line[x] i = x + 1 while i < e: ch = line[i] if ch == '\\' and line[i+1] == quote: i += 1 elif ch == quote: i += 1 # also take the quote break i += 1 return (i, line[x:i]) def colorize(self, lines): for line in lines: line = line.rstrip() if not line: self.add_line() continue x = 0 e = len(line) s = "" while x < e: ch = line[x] # String? if ch == '"' or ch == "'": x, w = self.get_quoted_string(line, x, e) s += self.as_string(w) # Tab? elif ch == '\t': s += ' ' * 4 x += 1 # Comment? elif ch == ';': s += self.as_comment(line[x:]) # Done with this line break elif ch == '.' and x + 1 < e: x, w = self.get_identifier(line, x + 1, e) s += self.as_directive(ch + w) # Identifiers? elif self.is_id(ch): x, w = self.get_identifier(line, x, e) # Number? if ch.isdigit(): s += self.as_num(w) # Other identifier else: s += self.as_id(w) # Output as is else: s += ch x += 1 self.add_line(s) class base_asmview_ah_t(ida_kernwin.action_handler_t): def __init__(self, obj): ida_kernwin.action_handler_t.__init__(self) self.obj = obj def update(self, ctx): if self.obj.view and self.obj.view.GetWidget() == ctx.widget: return ida_kernwin.AST_ENABLE_FOR_WIDGET else: return ida_kernwin.AST_DISABLE_FOR_WIDGET class refresh_ah_t(base_asmview_ah_t): def activate(self, ctx): self.obj.view.reload_file() print("Reloaded") class close_ah_t(base_asmview_ah_t): def activate(self, ctx): self.obj.view.Close() print("Closed") # ----------------------------------------------------------------------- class asmview_t(ida_kernwin.simplecustviewer_t, asm_colorizer_t): def Create(self, fn): # Create the customview if not ida_kernwin.simplecustviewer_t.Create( self, "Viewing file - %s" % os.path.basename(fn)): return False self.instruction_list = idautils.GetInstructionList() self.instruction_list.extend(["ret"]) self.register_list = idautils.GetRegisterList() self.register_list.extend(["eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"]) self.fn = fn if not self.reload_file(): return False return True def reload_file(self): if not self.colorize_file(self.fn): self.Close() return False return True def colorize_file(self, fn): try: f = open(fn, "r") lines = f.readlines() f.close() self.ClearLines() self.colorize(lines) return True except: return False def add_line(self, s=None): if not s: s = "" self.AddLine(s) def as_comment(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_RPTCMT) def as_id(self, s): t = s.lower() if t in self.register_list: return ida_lines.COLSTR(s, ida_lines.SCOLOR_REG) elif t in self.instruction_list: return ida_lines.COLSTR(s, ida_lines.SCOLOR_INSN) else: return s def as_string(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_STRING) def as_num(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_NUMBER) def as_directive(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_KEYWORD) def OnKeydown(self, vkey, shift): """ User pressed a key @param vkey: Virtual key code @param shift: Shift flag @return Boolean. True if you handled the event """ # ESCAPE if vkey == 27: self.Close() elif vkey == ord('H'): lineno = self.GetLineNo() if lineno is not None: line, fg, bg = self.GetLine(lineno) if line and line[0] != ida_lines.SCOLOR_INV: s = ida_lines.SCOLOR_INV + line + ida_lines.SCOLOR_INV self.EditLine(lineno, s, fg, bg) self.Refresh() elif vkey == ord('C'): self.ClearLines() self.Refresh() elif vkey == ord('S'): print("Selection (x1, y1, x2, y2) = ", self.GetSelection()) elif vkey == ord('I'): print("Position (line, x, y) = ", self.GetPos(mouse = 0)) else: return False return True # ----------------------------------------------------------------------- ACTNAME_REFRESH = "asmview_t::refresh" ACTNAME_CLOSE = "asmview_t::close" class asmviewplg(ida_idaapi.plugin_t): flags = ida_idaapi.PLUGIN_KEEP comment = "ASM viewer" help = "This is help" wanted_name = "ASM file viewer" wanted_hotkey = "Alt-F8" def __init__(self): self.view = None def init(self): # Register actions ida_kernwin.register_action( ida_kernwin.action_desc_t( ACTNAME_REFRESH, "Refresh", refresh_ah_t(self))) ida_kernwin.register_action( ida_kernwin.action_desc_t( ACTNAME_CLOSE, "Close", close_ah_t(self))) return ida_idaapi.PLUGIN_KEEP def run(self, arg): if self.view: self.Close() fn = ida_kernwin.ask_file(0, "*.asm", "Select ASM file to view") if not fn: return self.view = asmview_t() if not self.view.Create(fn): return self.view.Show() widget = self.view.GetWidget() # Attach actions to this widget's popup menu ida_kernwin.attach_action_to_popup(widget, None, ACTNAME_REFRESH) ida_kernwin.attach_action_to_popup(widget, None, ACTNAME_CLOSE) def term(self): if self.view: self.view.Close() def PLUGIN_ENTRY(): return asmviewplg()