-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding IPython Magics #26
Comments
IPython magic functions should be added to the current notebook using the load_ext magic in IPython (is that what you are referring to?). As long as the file is on the python path it should all just load fine. Here is a magic extension that i was working on some time ago. It has some magics for the debugger, it is still incomplete and hacky atm. import idautils
import idc
import collections
import idaapi
import idautils
from idautils import GetDataList
from IPython.core.magic import Magics, magics_class, cell_magic, line_cell_magic, line_magic
import ast
import itertools
from IPython.core import magic_arguments
from IPython import display
import sys
getmem_func = {
1: idc.Byte,
2: idc.Word,
4: idc.Dword,
8: idc.Qword
}
breakpoints = {}
def frame_struct(props):
return ((props & idaapi.SF_FRAME) != 0)
def display_frame(stack_ptr, func_ea):
func = idaapi.get_func(func_ea)
start_ea = stack_ptr - func.frsize
return display_type(start_ea, idc.GetFrame(func_ea))
def display_type(ea, sid):
members = idautils.StructMembers(sid)
out = ""
for offset, name, size in members:
if size in getmem_func:
out += "{} 0x{:X}\n".format(name, getmem_func[size](ea+offset))
else:
out += "{} 0x{:X} No idea just getting DWORD\n".format(name, Dword(ea+offset))
return out
def bp(ea, func, hardware=False):
breakpoints[ea] = func
# bp_flags = idc.GetBptAttr(ea, idc.BPTATTR_FLAGS)
if hardware:
idc.AddBptEx(ea, 4, idc.BPT_RDWR)
idc.SetBptAttr(ea, idc.BPTATTR_FLAGS, idc.GetBptAttr(ea, idc.BPTATTR_FLAGS) | idc.BPT_TRACE)
else:
idc.AddBpt(ea)
idc.SetBptCnd(ea, "dbghelp.call_breakpoint({})".format(ea))
def bc(ea_or_index):
if ea_or_index in breakpoints:
del breakpoints[ea_or_index]
bp_successfully_deleted = idc.DelBpt(ea_or_index)
if not bp_successfully_deleted:
addr = idc.GetBptEA(ea_or_index)
if addr != idc.BADADDR:
bc(addr)
def list_breakpoints():
return iter(int(idc.GetBptEA(i)) for i in xrange(idc.GetBptQty()))
def clear_all_breakpoints():
for _, addr in enumerate(list_breakpoints()):
bc(addr)
def call_breakpoint(addr):
return breakpoints[addr]()
# -----------------------------------------------------------------------
# each item described as:
# [ delta, [ opcode(s) ] ]
#FF10 call d,[eax]
#FF5000 call d,[eax][0]
#FF9044332211 call d,[eax][011223344]
#FF1500000100 call d,[000010000]
#FF9300000000 call d,[ebx][0]
#FF10 call d,[eax]
CallPattern = [
[-2, [0xFF] ],
[-3, [0xFF] ],
[-5, [0xE8] ],
[-6, [0xFF] ],
]
# -----------------------------------------------------------------------
def prev_call_insn(ea):
global CallPattern
if ea == idaapi.BADADDR or ea < 10:
return None
for delta, opcodes in CallPattern:
# assume caller's ea
caller = ea + delta
# get the bytes
bytes = [x for x in GetDataList(caller, len(opcodes), 1)]
# do we have a match? is it a call instruction?
if bytes == opcodes and idaapi.is_call_insn(caller):
return caller
return None
def executable_segment(seg):
return seg and ((seg.perm & idaapi.SEGPERM_EXEC) == 1)
def call_stack(esp):
stack = []
stack_seg = idaapi.getseg(esp)
word_size = 2 ** (stack_seg.bitness + 1)
start_ea = esp - word_size
end_ea = stack_seg.endEA
for stack_entry in xrange(start_ea, end_ea, word_size):
ptr = idautils.GetDataList(stack_entry, 1, word_size).next()
seg = idaapi.getseg(ptr)
if not executable_segment(seg):
continue
call_insn = prev_call_insn(ptr)
if call_insn:
stack.append(call_insn)
return stack
def register_values(regs):
reg_vals = []
for reg in regs:
reg_vals.append(idc.GetRegValue(str(reg.strip())))
return reg_vals
class PauseProgramExeception(Exception): pass
@magics_class
class DbgMagics(Magics):
BC_CLEAR_ALL = '*'
@line_cell_magic
def bp(self, line='', cell=None, local_ns=None):
#print magic_arguments.parse_argstring(self.bp, line)
opts, stmt = self.parse_options(line,
'rh',
posix=False,
strict=False)
refresh = 'r' in opts
hardware = 'h' in opts
glob = self.shell.user_ns
transform = self.shell.input_splitter.transform_cell
expr_ast = ast.Expression(ast.parse(transform(stmt)).body[0].value)
bp_addr = eval(compile(expr_ast, "<bp>", "eval"), glob, local_ns)
ast_body = ast.parse(transform(cell))
ast_expr = self.shell.transform_ast(ast_body)
code = compile(ast_expr, "<bp body {:X}>".format(bp_addr), "exec")
def bp_func():
try:
if refresh:
display.clear_output(wait=True)
exec code in glob, local_ns
sys.stdout.flush()
except PauseProgramExeception:
return True
bp(bp_addr, bp_func, hardware=hardware)
@line_magic
def bl(self, line):
for i, bp in enumerate(list_breakpoints()):
print "{} {:08X}".format(i, bp)
@line_magic
def bc(self, line, local_ns=None):
stripped_line = str(line).strip()
if stripped_line == self.BC_CLEAR_ALL:
clear_all_breakpoints()
else:
glob = self.shell.user_ns
expr_ast = ast.Expression(ast.parse(line).body[0].value)
bp_addr = eval(compile(expr_ast, "<bp>", "eval"), glob, local_ns)
bc(int(bp_addr))
@line_magic
def jump(self, line, local_ns=None):
glob = self.shell.user_ns
expr_ast = ast.Expression(ast.parse(line).body[0].value)
addr = eval(compile(expr_ast, "<bp>", "eval"), glob, local_ns)
idc.Jump(int(addr))
@magic_arguments.magic_arguments()
@magic_arguments.argument('--pretty', '-p', action='store_true',
default=False,
help="""pretty print the registers to stdout"""
)
@magic_arguments.argument('regs', nargs='*',
help="""List of registers to show"""
)
@line_magic
def r(self, line):
args = magic_arguments.parse_argstring(self.r, line)
reg_vals = register_values(args.regs)
if args.pretty:
for name, val in itertools.izip(args.regs, reg_vals):
print "{} {:X}".format(name.upper(), val)
else:
return reg_vals if len(reg_vals) > 1 else reg_vals[0]
def load_ipython_extension(ipython):
ipython.register_magics(DbgMagics) |
Well, I want to be able to add magics using other plugins, without manually running anything from the IPython shell/notebook. I am not sure it is possible, though. |
You would need to be careful, because magic functions are shared in a global namespace. However you could do something like import idaapi
import ipythonEmbed #add some error handling when this does not exist
class test_plugin_t(idaapi.plugin_t):
flags = 0
comment = "Test plugin"
help = "This is help"
wanted_name = "Test plugin"
wanted_hotkey = "Alt-J"
def init(self):
idaapi.msg('test_plugin_t:init\n')
if ipythonEmbed.kernel_app:
idaapi.msg('test_plugin_t:keep\n')
#the extension must exist on the PythonPath e.g. IDA Pro\Python directory
ipythonEmbed.kernel_app.shell.extension_manager.load_extension("dbghelp")
#Add some error handling ect.
return idaapi.PLUGIN_KEEP
else:
#Failed to load
idaapi.msg('test_plugin_t:fail\n')
return idaapi.PLUGIN_SKIP
def run(self, arg):
idaapi.msg('test_plugin_t:run\n')
def term(self):
idaapi.msg('test_plugin_t:term\n')
def PLUGIN_ENTRY():
return test_plugin_t() |
Trying to add IPython magics I came to a problem - it seems that I have to add them from the IPython console itself. Is there any other way to do it in the context of the plugin?
Being able to add magics from other plugins will be quite powerful.
The text was updated successfully, but these errors were encountered: