Want to Join Us ?

you'll be able to discuss, share and send private messages.

Tutorial Python Plugin loader tut for ida pro 7.0

Discussion in 'Plugins developement QT' started by storm shadow, Oct 2, 2017.

Share This Page

  1. storm shadow

    Techbliss Owner Admin Ida Pro Expert Developer

    Many things have changed from older ida pro to 7.0
    Alot of functions have been added to 7.0 python sdk, and alot deprecated.

    In this little tut, i will explain and brakedown, how to make a python plugin loader for ida pro 7.0 , put in the menu at start up, together with a custom icon, and load the real app.
    plugin loader example is from the python editor app found
    here https://github.com/techbliss/Python_editor/blob/master/7.0/plugins/Python_editor.py

    There are many ways to write this, some have intire plugin code included in the plugin loader or elsewhere like i normally do.



    Code (Python):
    # Created by: Storm Shadow http://www.techbliss.org
    import os
    import ida_idaapi, ida_kernwin
    import idc
    from idc import *
    from idaapi import *
    import sys
    sys.path.insert(0 , idaapi.idadir("plugins\\Code editor\\icons"))
    import ico
    from ico import *
     
     
    PLUGIN_VERSION = "1.4"
    IDAVERISONS = "IDA PRO 7.0+"
    AUTHORS     = "Storm Shadow"
    DATE           = "2017"
    TWITTER     = "Twitter @zadow28"
     
    def banner():
        banner_options = (PLUGIN_VERSION, AUTHORS, DATE, TWITTER, IDAVERISONS)
        banner_titles = "Python Editor v%s - (c) %s - %s - %s - %s" % banner_options
     
    # print plugin banner
        print("---[" + banner_titles + "]---\n")
     
    banner()
     
    # 1) Create the handler class
    class MyEditorHandler(idaapi.action_handler_t):
        def __init__(self):
            idaapi.action_handler_t.__init__(self)
     
        # Run editor when invoked.
        def activate(self, ctx):
            g = globals()
            idahome = idaapi.idadir("plugins\\Code editor")
            IDAPython_ExecScript(idahome + "\\pyeditor.py", g)
     
        def update(self, ctx):
            return idaapi.AST_ENABLE_ALWAYS
     
    class ripeye(idaapi.plugin_t):
        flags = idaapi.PLUGIN_FIX
        comment = "Run me"
        help = "Python Editor"
        wanted_name = "Python Editor"
        wanted_hotkey = "" #the tooltip horkey goes away when setting it here DONT DO it! and only is shown in File/Plugins menu
     
     
        def editor_menuaction(self):
            action_desc = idaapi.action_desc_t(
                'my:editoraction',  # The action name. This acts like an ID and must be unique
                'Python Editor!',  # The action text.
                MyEditorHandler(),  # The action handler.
                'Ctrl+H',  # Optional: the action shortcut DO IT  HERE!
                'Script editor',  # Optional: the action tooltip (available in menus/toolbar)
                idaapi.load_custom_icon(":/ico/python.png")  # hackish load action icon , if no custom icon use number from 1-150 from internal ida
            )
     
            # 3) Register the action
            idaapi.register_action(action_desc)
     
            idaapi.attach_action_to_menu(
                'File/Editor...',  # The relative path of where to add the action
                'my:editoraction',  # The action ID (see above)
                idaapi.SETMENU_APP)  # We want to append the action after the 'Manual instruction...
     
            form = idaapi.get_current_tform()
            idaapi.attach_action_to_popup(form, None, "my:editoraction", None)
     
        def init(self):
            """
            This is called by IDA when it is loading the plugin.
            """

            #self._icon_id_file = idaapi.BADADDR
            # attempt plugin initialization
            try:
                self._install_plugin()
     
            # failed to initialize or integrate the plugin, log and skip loading
            except Exception as e:
                form = idaapi.get_current_tform()
                pass
     
            return PLUGIN_KEEP
     
     
        def _install_plugin(self):
            """
            Initialize & integrate the plugin into IDA.
            """

            self.editor_menuaction()
            self._init()
     
        def term(self):
            pass
     
        def run(self, arg = 0):
            #we need the calls again if we wanna load it via File/Plugins/editor
            idaapi.msg("Python Editor Loaded to menu \n use Alt+E hot key to quick load ")
            hackish = MyEditorHandler()
            hackish.activate(self)
     
    def PLUGIN_ENTRY():
        return ripeye()
    lets break it down

    Code (Python):
    import os
    import ida_idaapi, ida_kernwin
    import idc
    from idc import *
    from idaapi import *
    import sys
     
    This import the the modules from ida python folder.
    in the old versions there was only idaapi.py idc.py and idautils.py, but now they have broken up those huge modules with smaller ones.

    Code (Python):
    sys.path.insert(0 , idaapi.idadir("plugins\\Code editor\\icons"))
    import ico
    from ico import *
    idaapi.idadir is our ida pro root folder path, and we insert the icon path where we store the icon.
    Be aware that i have converted the icons with pyrcc5 , so i can import them also as modules.
    You can also just have a *.png in the folder , then you wont need the import ico and from ico import *.

    Code (Python):
    PLUGIN_VERSION = "1.4"
    IDAVERISONS = "IDA PRO 7.0+"
    AUTHORS     = "Storm Shadow"
    DATE           = "2017"
    TWITTER     = "Twitter @zadow28"
     
    def banner():
        banner_options = (PLUGIN_VERSION, AUTHORS, DATE, TWITTER, IDAVERISONS)
        banner_titles = "Python Editor v%s - (c) %s - %s - %s - %s" % banner_options
     
    # print plugin banner
        print("---[" + banner_titles + "]---\n")
     
    banner()
    this is for printing the banner when ida loads, its not needed, but usefull for your users, and looks nice.
    some of the code is taken from Lighthoiuse plugin
    If you add more options, remember to add them to banner_options and add an ekstra %s for each ekstra one.

    Code (Python):
    # 1) Create the handler class
    class MyEditorHandler(idaapi.action_handler_t):
        def __init__(self):
            idaapi.action_handler_t.__init__(self)
     
        # Run editor when invoked.
        def activate(self, ctx):
            g = globals()
            idahome = idaapi.idadir("plugins\\Code editor")
            IDAPython_ExecScript(idahome + "\\pyeditor.py", g)
     
        def update(self, ctx):
            return idaapi.AST_ENABLE_ALWAYS
    Code (Python):
    class MyEditorHandler(idaapi.action_handler_t):
    This is the action handler callback.
    It would be good if you name your class something unique, or else ida would give an error if you have two plugins named the same.

    Code (Python):
    idahome = idaapi.idadir("plugins\\Code editor")
    Meaning ida root folder pluss plugins\\Code editor
    Like ida pro\plugins\\Code editor
    This is where you have your main plugin code.


    Code (Python):
    IDAPython_ExecScript(idahome + "\\pyeditor.py", g)
    This is exencial , this is where we call our main plugin

    Code (Text):
    class ripeye(idaapi.plugin_t):
        flags = idaapi.PLUGIN_FIX
        comment = "Run me"
        help = "Python Editor"
        wanted_name = "Python Editor"
        wanted_hotkey = ""
     
    idaapi.PLUGIN_FIX = this plugin would be fixed at startup, ther are many other option like only proccessors etc., but we wanna have it fixed.

    Wanted hotkey= we do not wanna set it here, since this is the hotkey for File\plugins in ida, and only one can be there, and we wanna have out hotkey present on screen on File menu.
    the hotkey would work but just displayed one place.


    Code (Python):
    def editor_menuaction(self):
            action_desc = idaapi.action_desc_t(
                'my:editoraction',  # The action name. This acts like an ID and must be unique
                'Python Editor!',  # The action text.
                MyEditorHandler(),  # The action handler from first class.
                'Ctrl+H',  # Optional: the action shortcut DO IT  HERE!
                'Script editor',  # Optional: the action tooltip (available in menus/toolbar)
                idaapi.load_custom_icon(":/ico/python.png")  # hackish load action icon , if no custom icon use number from 1-150 from internal ida
            )
    this is the menu for the action we create.
    it is explained in the qutoes, but
    idaapi.load_custom_icon(":/ico/python.png") we can load now since we imported the ico module at the begining, it could also be number from 1-150 internal icons from ida pro.
    But explainen earlier you could do also
    idaapi.load_custom_icon(idahome + "\\my_icon.png")
    Be aware that the action name have also to be unique for each plugin.

    also explained here Augmenting IDA UI with your own actions.
    Code (Python):
            # 3) Register the action
            idaapi.register_action(action_desc)
     
            idaapi.attach_action_to_menu(
                'File/Editor...',  # The relative path of where to add the action
                'my:editoraction',  # The action ID (see above)
                idaapi.SETMENU_APP)  # We want to append the action after the 'Manual instruction...
     
            form = idaapi.get_current_tform()
            idaapi.attach_action_to_popup(form, None, "my:editoraction", None)
    idaapi.register_action(action_desc) we register the action and make sure it is set in the menu.
    be aware of the unique acion ID again.



    Code (Python):
       def init(self):
            """
            This is called by IDA when it is loading the plugin.
            """

            #self._icon_id_file = idaapi.BADADDR
            # attempt plugin initialization
            try:
                self._install_plugin()
     
            # failed to initialize or integrate the plugin, log and skip loading
            except Exception as e:
                form = idaapi.get_current_tform()
                pass
     
            return PLUGIN_KEEP
    we try to run the function self._install_plugin() at start else pass.

    Code (Python):
        def _install_plugin(self):
            """
            Initialize & integrate the plugin into IDA.
            """

            self.editor_menuaction()
            self._init()
    this is called from previous function.
    self.editor_menuaction() = action memory pointer class
    self._init = the init class pointer is called.

    Code (Python):
    def run(self, arg = 0):
    #we need the calls again if we wanna load it via File/Plugins/editor
    idaapi.msg("Python Editor Loaded to menu \n use Alt+E hot key to quick load ")
    hackish = MyEditorHandler()
    hackish.activate(self)
    We make equal function as the MyEditorHandle.activate() from breakup 2.
    this is for loading the plugin if we choose to click File\plugins\myplugin instead of File\myplugin.

    Code (Python):

    def PLUGIN_ENTRY():
        return ripeye()
    wraps up the plugin class , remember to have unique class names , since you cant have the same class two times and
     
    Last edited: Oct 2, 2017
    TechLord and Rip Cord like this.
Top