about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorserpilliere <serpilliere@users.noreply.github.com>2017-07-05 13:42:38 +0200
committerGitHub <noreply@github.com>2017-07-05 13:42:38 +0200
commite40e9a70b6693a0de4bffa7d83ae4a7adb410c0a (patch)
tree1049b3ec144bc7aaa1b7d439b61f1f25e6954d20
parentc7718a8d0c1263771ca8e0a31b3717c7063d50e4 (diff)
parent81ba101de2fd128d4fbc99efdac02600d8fcb06f (diff)
downloadmiasm-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.py27
-rw-r--r--example/ida/depgraph.py176
-rw-r--r--example/ida/graph_ir.py161
-rw-r--r--example/ida/menu.py77
-rw-r--r--example/ida/symbol_exec.py15
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
+    """