mirror of
https://github.com/cemu-project/idapython.git
synced 2024-11-30 21:14:20 +01:00
216 lines
6.6 KiB
Python
216 lines
6.6 KiB
Python
|
# -----------------------------------------------------------------------
|
||
|
# 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 idaapi
|
||
|
import idautils
|
||
|
import idc
|
||
|
import os
|
||
|
|
||
|
# ----------------------------------------------------------------------
|
||
|
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 asmview_t(idaapi.simplecustviewer_t, asm_colorizer_t):
|
||
|
def Create(self, fn):
|
||
|
# Create the customview
|
||
|
if not idaapi.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
|
||
|
|
||
|
self.id_refresh = self.AddPopupMenu("Refresh")
|
||
|
self.id_close = self.AddPopupMenu("Close")
|
||
|
|
||
|
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 idaapi.COLSTR(s, idaapi.SCOLOR_RPTCMT)
|
||
|
|
||
|
def as_id(self, s):
|
||
|
t = s.lower()
|
||
|
if t in self.register_list:
|
||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_REG)
|
||
|
elif t in self.instruction_list:
|
||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_INSN)
|
||
|
else:
|
||
|
return s
|
||
|
|
||
|
def as_string(self, s):
|
||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_STRING)
|
||
|
|
||
|
def as_num(self, s):
|
||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_NUMBER)
|
||
|
|
||
|
def as_directive(self, s):
|
||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_KEYWORD)
|
||
|
|
||
|
def OnPopupMenu(self, menu_id):
|
||
|
"""
|
||
|
A context (or popup) menu item was executed.
|
||
|
@param menu_id: ID previously registered with AddPopupMenu()
|
||
|
@return: Boolean
|
||
|
"""
|
||
|
if self.id_refresh == menu_id:
|
||
|
return self.reload_file()
|
||
|
elif self.id_close == menu_id:
|
||
|
self.Close()
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
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] != idaapi.SCOLOR_INV:
|
||
|
s = idaapi.SCOLOR_INV + line + idaapi.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
|
||
|
|
||
|
# -----------------------------------------------------------------------
|
||
|
class asmviewplg(idaapi.plugin_t):
|
||
|
flags = 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):
|
||
|
return idaapi.PLUGIN_KEEP
|
||
|
def run(self, arg):
|
||
|
if self.view:
|
||
|
self.Close()
|
||
|
fn = idc.AskFile(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()
|
||
|
|
||
|
def term(self):
|
||
|
if self.view:
|
||
|
self.view.Close()
|
||
|
|
||
|
def PLUGIN_ENTRY():
|
||
|
return asmviewplg()
|