diff options
| author | serpilliere <serpilliere@users.noreply.github.com> | 2017-07-05 13:42:38 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-07-05 13:42:38 +0200 |
| commit | e40e9a70b6693a0de4bffa7d83ae4a7adb410c0a (patch) | |
| tree | 1049b3ec144bc7aaa1b7d439b61f1f25e6954d20 | |
| parent | c7718a8d0c1263771ca8e0a31b3717c7063d50e4 (diff) | |
| parent | 81ba101de2fd128d4fbc99efdac02600d8fcb06f (diff) | |
| download | miasm-e40e9a70b6693a0de4bffa7d83ae4a7adb410c0a.tar.gz miasm-e40e9a70b6693a0de4bffa7d83ae4a7adb410c0a.zip | |
Merge pull request #576 from commial/feature/ida-menu
Feature/ida menu
| -rw-r--r-- | example/ida/ctype_propagation.py | 27 | ||||
| -rw-r--r-- | example/ida/depgraph.py | 176 | ||||
| -rw-r--r-- | example/ida/graph_ir.py | 161 | ||||
| -rw-r--r-- | example/ida/menu.py | 77 | ||||
| -rw-r--r-- | example/ida/symbol_exec.py | 15 |
5 files changed, 282 insertions, 174 deletions
diff --git a/example/ida/ctype_propagation.py b/example/ida/ctype_propagation.py index b086ef3e..f4fdc3b5 100644 --- a/example/ida/ctype_propagation.py +++ b/example/ida/ctype_propagation.py @@ -1,27 +1,26 @@ import os import tempfile +import ida_kernwin +import idc +import ida_funcs + from miasm2.core.bin_stream_ida import bin_stream_ida from miasm2.expression import expression as m2_expr - from miasm2.expression.simplifications import expr_simp from miasm2.analysis.depgraph import DependencyGraph from miasm2.ir.ir import IRBlock, AssignBlock - -from utils import guess_machine - from miasm2.arch.x86.ctype import CTypeAMD64_unk from miasm2.expression.expression import ExprId - from miasm2.core.objc import CTypesManagerNotPacked, CTypeAnalyzer, ExprToAccessC, CHandler from miasm2.core.ctypesmngr import CAstTypes from miasm2.expression.expression import ExprMem, ExprId, ExprInt, ExprOp, ExprAff from miasm2.ir.symbexec_types import SymbExecCType - from miasm2.expression.parser import str_to_expr +from utils import guess_machine -class TypePropagationForm(Form): +class TypePropagationForm(ida_kernwin.Form): def __init__(self, ira): @@ -31,7 +30,7 @@ class TypePropagationForm(Form): default_types_info = r"""ExprId("RDX", 64): char *""" archs = ["AMD64_unk", "X86_32_unk"] - Form.__init__(self, + ida_kernwin.Form.__init__(self, r"""BUTTON YES* Launch BUTTON CANCEL NONE Dependency Graph Settings @@ -40,14 +39,14 @@ Dependency Graph Settings <Types informations:{strTypesInfo}> <Unalias stack:{rUnaliasStack}>{cMethod}> """, { - 'headerFile': Form.FileInput(swidth=20, open=True), - 'cbReg': Form.DropdownListControl( + 'headerFile': ida_kernwin.Form.FileInput(swidth=20, open=True), + 'cbReg': ida_kernwin.Form.DropdownListControl( items=archs, readonly=False, selval=archs[0]), - 'strTypesInfo': Form.MultiLineTextControl(text=default_types_info, - flags=Form.MultiLineTextControl.TXTF_FIXEDFONT), - 'cMethod': Form.ChkGroupControl(("rUnaliasStack",)), + 'strTypesInfo': ida_kernwin.Form.MultiLineTextControl(text=default_types_info, + flags=ida_kernwin.Form.MultiLineTextControl.TXTF_FIXEDFONT), + 'cMethod': ida_kernwin.Form.ChkGroupControl(("rUnaliasStack",)), }) self.Compile() @@ -164,7 +163,7 @@ def analyse_function(): ir_arch = ira(mdis.symbol_pool) # Get the current function - func = idaapi.get_func(ScreenEA()) + func = ida_funcs.get_func(idc.ScreenEA()) addr = func.startEA blocks = mdis.dis_multibloc(addr) # Generate IR diff --git a/example/ida/depgraph.py b/example/ida/depgraph.py index ab033e15..12d01af9 100644 --- a/example/ida/depgraph.py +++ b/example/ida/depgraph.py @@ -1,6 +1,11 @@ import os import tempfile +import idautils +import idc +import ida_funcs +import ida_kernwin + from miasm2.core.bin_stream_ida import bin_stream_ida from miasm2.core.asmblock import * from miasm2.expression import expression as m2_expr @@ -12,8 +17,7 @@ from miasm2.ir.ir import AssignBlock, IRBlock from utils import guess_machine - -class depGraphSettingsForm(Form): +class depGraphSettingsForm(ida_kernwin.Form): def __init__(self, ira): @@ -21,7 +25,7 @@ class depGraphSettingsForm(Form): self.stk_args = {'ARG%d' % i:i for i in xrange(10)} self.stk_unalias_force = False - self.address = ScreenEA() + self.address = idc.ScreenEA() cur_block = None for block in ira.getby_offset(self.address): if block.label.offset is not None: @@ -36,16 +40,16 @@ class depGraphSettingsForm(Form): assert line_nb is not None cur_label = str(cur_block.label) labels = sorted(map(str, ira.blocks.keys())) - regs = sorted(ir_arch.arch.regs.all_regs_ids_byname.keys()) + regs = sorted(ira.arch.regs.all_regs_ids_byname.keys()) regs += self.stk_args.keys() reg_default = regs[0] for i in xrange(10): - opnd = GetOpnd(self.address, i).upper() + opnd = idc.GetOpnd(self.address, i).upper() if opnd in regs: reg_default = opnd break - Form.__init__(self, + ida_kernwin.Form.__init__(self, r"""BUTTON YES* Launch BUTTON CANCEL NONE Dependency Graph Settings @@ -69,21 +73,22 @@ Method to use: <Highlight color:{cColor}> """, { - 'cbReg': Form.DropdownListControl( + 'cbReg': ida_kernwin.Form.DropdownListControl( items=regs, readonly=False, selval=reg_default), - 'cMode': Form.RadGroupControl(("rBeforeLine", "rAfterLine", - "rEndBlock")), - 'cMethod': Form.ChkGroupControl(("rNoMem", "rNoCall", "rImplicit", - "rUnaliasStack")), - 'iLineNb': Form.NumericInput(tp=Form.FT_RAWHEX, - value=line_nb), - 'cbBBL': Form.DropdownListControl( + 'cMode': ida_kernwin.Form.RadGroupControl( + ("rBeforeLine", "rAfterLine", "rEndBlock")), + 'cMethod': ida_kernwin.Form.ChkGroupControl( + ("rNoMem", "rNoCall", "rImplicit", "rUnaliasStack")), + 'iLineNb': ida_kernwin.Form.NumericInput( + tp=ida_kernwin.Form.FT_RAWHEX, + value=line_nb), + 'cbBBL': ida_kernwin.Form.DropdownListControl( items=labels, readonly=False, selval=cur_label), - 'cColor': Form.ColorInput(value=0xc0c020), + 'cColor': ida_kernwin.Form.ColorInput(value=0xc0c020), }) self.Compile() @@ -113,14 +118,14 @@ Method to use: if value in self.stk_args: line = self.ira.blocks[self.label].irs[self.line_nb].instr arg_num = self.stk_args[value] - stk_high = m2_expr.ExprInt(GetSpd(line.offset), ir_arch.sp.size) + stk_high = m2_expr.ExprInt(idc.GetSpd(line.offset), ir_arch.sp.size) stk_off = m2_expr.ExprInt(self.ira.sp.size/8 * arg_num, ir_arch.sp.size) element = m2_expr.ExprMem(mn.regs.regs_init[ir_arch.sp] + stk_high + stk_off, self.ira.sp.size) element = expr_simp(element) # Force stack unaliasing self.stk_unalias_force = True elif value: - element = ir_arch.arch.regs.all_regs_ids_byname.get(value, None) + element = self.ira.arch.regs.all_regs_ids_byname.get(value, None) else: raise ValueError("Unknown element '%s'!" % value) @@ -142,75 +147,17 @@ Method to use: def color(self): return self.cColor.value - -# Init -machine = guess_machine() -mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira - -bs = bin_stream_ida() -mdis = dis_engine(bs, dont_dis_nulstart_bloc=True) -ir_arch = ira(mdis.symbol_pool) - -# Populate symbols with ida names -for ad, name in Names(): - if name is None: - continue - mdis.symbol_pool.add_label(name, ad) - -# Get the current function -addr = ScreenEA() -func = idaapi.get_func(addr) -blocks = mdis.dis_multibloc(func.startEA) - -# Generate IR -for block in blocks: - ir_arch.add_bloc(block) - -# Get settings -settings = depGraphSettingsForm(ir_arch) -settings.Execute() - -label, elements, line_nb = settings.label, settings.elements, settings.line_nb -# Simplify affectations -for irb in ir_arch.blocks.values(): - irs = [] - fix_stack = irb.label.offset is not None and settings.unalias_stack - for assignblk in irb.irs: - if fix_stack: - stk_high = m2_expr.ExprInt(GetSpd(assignblk.instr.offset), ir_arch.sp.size) - fix_dct = {ir_arch.sp: mn.regs.regs_init[ir_arch.sp] + stk_high} - - new_assignblk = {} - for dst, src in assignblk.iteritems(): - if fix_stack: - src = src.replace_expr(fix_dct) - if dst != ir_arch.sp: - dst = dst.replace_expr(fix_dct) - dst, src = expr_simp(dst), expr_simp(src) - new_assignblk[dst] = src - irs.append(AssignBlock(new_assignblk, instr=assignblk.instr)) - ir_arch.blocks[irb.label] = IRBlock(irb.label, irs) - -# Get dependency graphs -dg = settings.depgraph -graphs = dg.get(label, elements, line_nb, - set([ir_arch.symbol_pool.getby_offset(func.startEA)])) - -# Display the result -comments = {} -sol_nb = 0 - def clean_lines(): "Remove previous comments" global comments for offset in comments: - SetColor(offset, CIC_ITEM, 0xffffff) - MakeComm(offset, "") + idc.SetColor(offset, idc.CIC_ITEM, 0xffffff) + idc.MakeComm(offset, "") comments = {} def treat_element(): "Display an element" - global graphs, comments, sol_nb, settings + global graphs, comments, sol_nb, settings, addr, ir_arch try: graph = graphs.next() @@ -232,7 +179,7 @@ def treat_element(): print "Unable to highlight %s" % node continue comments[offset] = comments.get(offset, []) + [node.element] - SetColor(offset, CIC_ITEM, settings.color) + idc.SetColor(offset, idc.CIC_ITEM, settings.color) if graph.has_loop: print 'Graph has dependency loop: symbolic execution is inexact' @@ -240,13 +187,76 @@ def treat_element(): print "Possible value: %s" % graph.emul().values()[0] for offset, elements in comments.iteritems(): - MakeComm(offset, ", ".join(map(str, elements))) + idc.MakeComm(offset, ", ".join(map(str, elements))) def next_element(): "Display the next element" clean_lines() treat_element() -# Register and launch -idaapi.add_hotkey("Shift-N", next_element) -treat_element() + +def launch_depgraph(): + global graphs, comments, sol_nb, settings, addr, ir_arch + # Init + machine = guess_machine() + mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira + + bs = bin_stream_ida() + mdis = dis_engine(bs, dont_dis_nulstart_bloc=True) + ir_arch = ira(mdis.symbol_pool) + + # Populate symbols with ida names + for ad, name in idautils.Names(): + if name is None: + continue + mdis.symbol_pool.add_label(name, ad) + + # Get the current function + addr = idc.ScreenEA() + func = ida_funcs.get_func(addr) + blocks = mdis.dis_multibloc(func.startEA) + + # Generate IR + for block in blocks: + ir_arch.add_bloc(block) + + # Get settings + settings = depGraphSettingsForm(ir_arch) + settings.Execute() + + label, elements, line_nb = settings.label, settings.elements, settings.line_nb + # Simplify affectations + for irb in ir_arch.blocks.values(): + irs = [] + fix_stack = irb.label.offset is not None and settings.unalias_stack + for assignblk in irb.irs: + if fix_stack: + stk_high = m2_expr.ExprInt(idc.GetSpd(assignblk.instr.offset), ir_arch.sp.size) + fix_dct = {ir_arch.sp: mn.regs.regs_init[ir_arch.sp] + stk_high} + + new_assignblk = {} + for dst, src in assignblk.iteritems(): + if fix_stack: + src = src.replace_expr(fix_dct) + if dst != ir_arch.sp: + dst = dst.replace_expr(fix_dct) + dst, src = expr_simp(dst), expr_simp(src) + new_assignblk[dst] = src + irs.append(AssignBlock(new_assignblk, instr=assignblk.instr)) + ir_arch.blocks[irb.label] = IRBlock(irb.label, irs) + + # Get dependency graphs + dg = settings.depgraph + graphs = dg.get(label, elements, line_nb, + set([ir_arch.symbol_pool.getby_offset(func.startEA)])) + + # Display the result + comments = {} + sol_nb = 0 + + # Register and launch + ida_kernwin.add_hotkey("Shift-N", next_element) + treat_element() + +if __name__ == "__main__": + launch_depgraph() diff --git a/example/ida/graph_ir.py b/example/ida/graph_ir.py index 678ae2ff..8c7e80f5 100644 --- a/example/ida/graph_ir.py +++ b/example/ida/graph_ir.py @@ -1,7 +1,9 @@ import os import tempfile -from idaapi import GraphViewer +import idaapi +import idc +import idautils from miasm2.core.bin_stream_ida import bin_stream_ida from miasm2.core.asmblock import expr_is_label, AsmLabel, is_int @@ -34,7 +36,7 @@ def label_str(self): AsmLabel.__init__ = label_init AsmLabel.__str__ = label_str -def color_irblock(irblock): +def color_irblock(irblock, ir_arch): out = [] lbl = idaapi.COLSTR(str(irblock.label), idaapi.SCOLOR_INSN) out.append(lbl) @@ -52,27 +54,25 @@ def color_irblock(irblock): return "\n".join(out) -class GraphMiasmIR(GraphViewer): +class GraphMiasmIR(idaapi.GraphViewer): def __init__(self, ir_arch, title, result): - GraphViewer.__init__(self, title) - print 'init' + idaapi.GraphViewer.__init__(self, title) self.ir_arch = ir_arch self.result = result self.names = {} def OnRefresh(self): - print 'refresh' self.Clear() addr_id = {} for irblock in self.ir_arch.blocks.values(): - id_irblock = self.AddNode(color_irblock(irblock)) + id_irblock = self.AddNode(color_irblock(irblock, self.ir_arch)) addr_id[irblock] = id_irblock for irblock in self.ir_arch.blocks.values(): if not irblock: continue - all_dst = ir_arch.dst_trackback(irblock) + all_dst = self.ir_arch.dst_trackback(irblock) for dst in all_dst: if not expr_is_label(dst): continue @@ -102,7 +102,7 @@ class GraphMiasmIR(GraphViewer): print "command:", cmd_id def Show(self): - if not GraphViewer.Show(self): + if not idaapi.GraphViewer.Show(self): return False self.cmd_test = self.AddCommand("Test", "F2") if self.cmd_test == 0: @@ -110,64 +110,85 @@ class GraphMiasmIR(GraphViewer): return True -machine = guess_machine() -mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira - -print "Arch", dis_engine - -fname = GetInputFile() -print fname - -bs = bin_stream_ida() -mdis = dis_engine(bs) -ir_arch = ira(mdis.symbol_pool) - -# populate symbols with ida names -for addr, name in Names(): - # print hex(ad), repr(name) - if name is None: - continue - mdis.symbol_pool.add_label(name, addr) - -print "start disasm" -addr = ScreenEA() -print hex(addr) - -blocks = mdis.dis_multibloc(addr) - -print "generating graph" -open('asm_flow.dot', 'w').write(blocks.dot()) - -print "generating IR... %x" % addr - -for block in blocks: - print 'ADD' - print block - ir_arch.add_bloc(block) - - -print "IR ok... %x" % addr - -for irb in ir_arch.blocks.itervalues(): - irs = [] - for assignblk in irb.irs: - new_assignblk = { - expr_simp(dst): expr_simp(src) - for dst, src in assignblk.iteritems() - } - irs.append(AssignBlock(new_assignblk, instr=assignblk.instr)) - ir_arch.blocks[irb.label] = IRBlock(irb.label, irs) - -out = ir_arch.graph.dot() -open(os.path.join(tempfile.gettempdir(), 'graph.dot'), 'wb').write(out) - - -# dead_simp(ir_arch) - -g = GraphMiasmIR(ir_arch, "Miasm IR graph", None) - -g.cmd_a = g.AddCommand("cmd a", "x") -g.cmd_b = g.AddCommand("cmd b", "y") - -g.Show() - +def build_graph(verbose=False, simplify=False): + machine = guess_machine() + mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira + + if verbose: + print "Arch", dis_engine + + fname = idc.GetInputFile() + if verbose: + print fname + + bs = bin_stream_ida() + mdis = dis_engine(bs) + ir_arch = ira(mdis.symbol_pool) + + # populate symbols with ida names + for addr, name in idautils.Names(): + # print hex(ad), repr(name) + if name is None: + continue + mdis.symbol_pool.add_label(name, addr) + + if verbose: + print "start disasm" + addr = idc.ScreenEA() + if verbose: + print hex(addr) + + blocks = mdis.dis_multibloc(addr) + + if verbose: + print "generating graph" + open('asm_flow.dot', 'w').write(blocks.dot()) + + print "generating IR... %x" % addr + + for block in blocks: + if verbose: + print 'ADD' + print block + ir_arch.add_bloc(block) + + if verbose: + print "IR ok... %x" % addr + + for irb in ir_arch.blocks.itervalues(): + irs = [] + for assignblk in irb.irs: + new_assignblk = { + expr_simp(dst): expr_simp(src) + for dst, src in assignblk.iteritems() + } + irs.append(AssignBlock(new_assignblk, instr=assignblk.instr)) + ir_arch.blocks[irb.label] = IRBlock(irb.label, irs) + + if verbose: + out = ir_arch.graph.dot() + open(os.path.join(tempfile.gettempdir(), 'graph.dot'), 'wb').write(out) + title = "Miasm IR graph" + + if simplify: + dead_simp(ir_arch) + + ir_arch.simplify(expr_simp) + modified = True + while modified: + modified = False + modified |= dead_simp(ir_arch) + modified |= ir_arch.remove_empty_assignblks() + modified |= ir_arch.remove_jmp_blocks() + modified |= ir_arch.merge_blocks() + title += " (simplified)" + + g = GraphMiasmIR(ir_arch, title, None) + + g.cmd_a = g.AddCommand("cmd a", "x") + g.cmd_b = g.AddCommand("cmd b", "y") + + g.Show() + +if __name__ == "__main__": + build_graph(verbose=True, simplify=False) diff --git a/example/ida/menu.py b/example/ida/menu.py new file mode 100644 index 00000000..b88cc59f --- /dev/null +++ b/example/ida/menu.py @@ -0,0 +1,77 @@ +"""Implements a menu for IDA with: +- Miasm +- Miasm > Symbolic execution (icon 81, F3) +- Miasm > Dependency graph (icon 79, F4) +- Miasm > Graph IR (icon 188, F7) +- Miasm > Graph IR (simplified) (icon 191, F8) +- Miasm > RPYC server (icon 182, F10) +- Miasm > Type propagation (icon 38, F11) +""" + +from symbol_exec import symbolic_exec +from graph_ir import build_graph +try: + from rpyc_ida import serve_threaded +except ImportError: + serve_threaded = None +from depgraph import launch_depgraph +try: + from ctype_propagation import analyse_function +except ImportError: + analyse_function = None + +class Handler(idaapi.action_handler_t): + + def __init__(self, callback): + """Create a Handler calling @callback when activated""" + super(Handler, self).__init__() + self.callback = callback + + def activate(self, ctx): + return self.callback() + + # This action is always available. + def update(self, ctx): + return idaapi.AST_ENABLE_ALWAYS + + def register(self, name, label, shortcut=None, tooltip=None, icon=-1): + action = idaapi.action_desc_t( + name, # The action name. This acts like an ID and must be unique + label, # The action text. + self, # The action handler. + shortcut,# Optional: the action shortcut + tooltip, # Optional: the action tooltip (available in menus/toolbar) + icon, # Optional: the action icon (shows when in menus/toolbars) + ) + idaapi.register_action(action) + self.name = name + return action + + def attach_to_menu(self, menu): + assert hasattr(self, "name") + idaapi.attach_action_to_menu(menu, self.name, idaapi.SETMENU_APP) + +idaapi.create_menu("Miasm", "Miasm") + +handler_symb = Handler(symbolic_exec) +handler_symb.register("miasm:symbexec", "Symbolic exec", shortcut="F3", icon=81) +handler_symb.attach_to_menu("Miasm/Symbolic exec") +handler_depgraph = Handler(launch_depgraph) +handler_depgraph.register("miasm:depgraph", "Dependency graph", shortcut="F4", icon=79) +handler_depgraph.attach_to_menu("Miasm/Dependency graph") +handler_graph = Handler(build_graph) +handler_graph.register("miasm:graphir", "Graph IR", shortcut="F7", icon=188) +handler_graph.attach_to_menu("Miasm/Graph IR") +handler_graph_simp = Handler(lambda: build_graph(simplify=True)) +handler_graph_simp.register("miasm:graphirsimp", + "Graph IR (simplified)", shortcut="F8", icon=191) +handler_graph_simp.attach_to_menu("Miasm/Graph IR (simplified)") +if serve_threaded is not None: + handler_rpyc = Handler(serve_threaded) + handler_rpyc.register("miasm:rpyc", "RPYC server", shortcut="F10", icon=182) + handler_rpyc.attach_to_menu("Miasm/RPYC server") +if analyse_function is not None: + handler_ctype = Handler(analyse_function) + handler_ctype.register("miasm:ctype", "Type propagation", shortcut="F11", + icon=38) + handler_ctype.attach_to_menu("Miasm/Type propagation") diff --git a/example/ida/symbol_exec.py b/example/ida/symbol_exec.py index 70e1cfc1..7599dde7 100644 --- a/example/ida/symbol_exec.py +++ b/example/ida/symbol_exec.py @@ -84,7 +84,7 @@ def symbolic_exec(): machine = guess_machine() mdis = machine.dis_engine(bs) - start, end = SelStart(), SelEnd() + start, end = idc.SelStart(), idc.SelEnd() mdis.dont_dis = [end] blocks = mdis.dis_multibloc(start) @@ -115,10 +115,11 @@ def symbolic_exec(): view.Show() -idaapi.CompileLine('static key_F3() { RunPythonStatement("symbolic_exec()"); }') -idc.AddHotkey("F3", "key_F3") +if __name__ == "__main__": + idaapi.CompileLine('static key_F3() { RunPythonStatement("symbolic_exec()"); }') + idc.AddHotkey("F3", "key_F3") -print "=" * 50 -print """Available commands: - symbolic_exec() - F3: Symbolic execution of current selection -""" + print "=" * 50 + print """Available commands: + symbolic_exec() - F3: Symbolic execution of current selection + """ |