Files
2025-03-13 16:17:53 +01:00

220 lines
6.4 KiB
Python

"""
summary: create custom listings in IDA
description:
How to create simple listings, that will share many of the features
as the built-in IDA widgets (highlighting, copy & paste,
notifications, ...)
In addition, creates actions that will be bound to the
freshly-created widget (using `ida_kernwin.attach_action_to_popup`.)
keywords: listing, actions
level: intermediate
"""
import ida_kernwin
import ida_lines
# -----------------------------------------------------------------------
class say_something_handler_t(ida_kernwin.action_handler_t):
def __init__(self, thing):
ida_kernwin.action_handler_t.__init__(self)
self.thing = thing
def activate(self, ctx):
print(self.thing)
def update(self, ctx):
return ida_kernwin.AST_ENABLE_ALWAYS
@staticmethod
def compose_action_name(v):
return "custview:say_%s" % v
# create actions
actions_variants = ["Hello", "World"]
for av in actions_variants:
actname = say_something_handler_t.compose_action_name(av)
if ida_kernwin.unregister_action(actname):
print("Unregistered previously-registered action \"%s\"" % actname)
desc = ida_kernwin.action_desc_t(actname, "Say %s" % av, say_something_handler_t(av))
if ida_kernwin.register_action(desc):
print("Registered action \"%s\"" % actname)
# -----------------------------------------------------------------------
class mycv_t(ida_kernwin.simplecustviewer_t):
def Create(self, sn=None, use_colors=True):
# Form the title
title = "Simple custom view test"
if sn:
title += " %d" % sn
self.use_colors = use_colors
# Create the customviewer
if not ida_kernwin.simplecustviewer_t.Create(self, title):
return False
for i in range(0, 100):
prefix, bg = ida_lines.COLOR_DEFAULT, None
# make every 10th line a bit special
if i % 10 == 0:
prefix = ida_lines.COLOR_DNAME # i.e., dark yellow...
bg = 0xFFFF00 # ...on cyan
pfx = ida_lines.COLSTR("%3d" % i, ida_lines.SCOLOR_PREFIX)
if self.use_colors:
self.AddLine("%s: Line %d" % (pfx, i), fgcolor=prefix, bgcolor=bg)
else:
self.AddLine("%s: Line %d" % (pfx, i))
return True
def OnClick(self, shift):
"""
User clicked in the view
@param shift: Shift flag
@return: Boolean. True if you handled the event
"""
print("OnClick, shift=%d" % shift)
return True
def OnDblClick(self, shift):
"""
User dbl-clicked in the view
@param shift: Shift flag
@return: Boolean. True if you handled the event
"""
word = self.GetCurrentWord()
if not word: word = "<None>"
print("OnDblClick, shift=%d, current word=%s" % (shift, word))
return True
def OnCursorPosChanged(self):
"""
Cursor position changed.
@return: Nothing
"""
print("OnCurposChanged")
def OnClose(self):
"""
The view is closing. Use this event to cleanup.
@return: Nothing
"""
print("OnClose " + self.title)
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
"""
print("OnKeydown, vk=%d shift=%d" % (vkey, shift))
# Escape?
if vkey == ida_kernwin.IK_ESCAPE:
self.Close()
# Delete?
elif vkey == ida_kernwin.IK_DELETE:
n = self.GetLineNo()
if n is not None:
self.DelLine(n)
self.Refresh()
print("Deleted line %d" % n)
# Goto?
elif vkey == ord('G'):
n = self.GetLineNo()
if n is not None:
v = ida_kernwin.ask_long(self.GetLineNo(), "Where to go?")
if v:
self.Jump(v, 0, 5)
elif vkey == ord('R'):
print("refreshing....")
self.Refresh()
elif vkey == ord('C'):
print("refreshing current line...")
self.RefreshCurrent()
elif vkey == ord('A'):
s = ida_kernwin.ask_str("NewLine%d" % self.Count(), 0, "Append new line")
self.AddLine(s)
self.Refresh()
elif vkey == ord('X'):
print("Clearing all lines")
self.ClearLines()
self.Refresh()
elif vkey == ord('I'):
n = self.GetLineNo()
s = ida_kernwin.ask_str("InsertedLine%d" % n, 0, "Insert new line")
self.InsertLine(n, s)
self.Refresh()
elif vkey == ord('E'):
l = self.GetCurrentLine(notags=1)
if not l:
return False
n = self.GetLineNo()
print("curline=<%s>" % l)
l = l + ida_lines.COLSTR("*", ida_lines.SCOLOR_VOIDOP)
self.EditLine(n, l)
self.RefreshCurrent()
print("Edited line %d" % n)
else:
return False
return True
def OnHint(self, lineno):
"""
Hint requested for the given line number.
@param lineno: The line number (zero based)
@return:
- tuple(number of important lines, hint string)
- None: if no hint available
"""
return (1, "OnHint, line=%d" % lineno)
def Show(self, *args):
ok = ida_kernwin.simplecustviewer_t.Show(self, *args)
if ok:
# permanently attach actions to this viewer's popup menu
for av in actions_variants:
actname = say_something_handler_t.compose_action_name(av)
ida_kernwin.attach_action_to_popup(self.GetWidget(), None, actname)
return ok
# -----------------------------------------------------------------------
try:
# created already?
mycv
print("Already created, will close it...")
mycv.Close()
del mycv
except:
pass
def show_win():
x = mycv_t()
if not x.Create():
print("Failed to create!")
return None
x.Show()
tcc = x.GetWidget()
return x
mycv = show_win()
if not mycv:
del mycv
def make_many(n):
L = []
for i in range(1, n+1):
v = mycv_t()
if not v.Create(i):
break
v.Show()
L.append(v)
return L