## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Intro

The IDAPython API enables you to extend IDA’s core functionality and create custom plugins. Whether running as standalone scripts in the output window or leveraging advanced UI features, these plugins can significantly enhance your workflow.

Compared to C++ plugins, IDAPython plugins are faster and easier to develop—no need for lengthy build or compilation steps—while maintaining almost the same capabilities.

This tutorial outlines how to write plugins using the updated plugin framework and best practices to streamline your development process.

# Before you start

1. Check our IDAPython reference docs for an up-to-date list of all modules, classes, functions, and so on. You can get the latest version of IDAPython SDK from our GitHub repository.

2. Get familiar with the `ida_idaapi.plugin_t` class, a basic and required class that provides the necessary structure for your plugin. It mirrors the C++ SDK `plugin_t` class.

3. Ensure compatibility with the latest IDA version by reviewing our IDAPython Porting Guide for recent updates.

## Get a sample plugin

In this tutorial, we’ll use a simple sample plugin designed to work with the new plugin framework, that simplifies plugin development. The plugin performs a straightforward task: once invoked by the user after loading a database, it lists all functions and their addresses for the current IDA database before exiting.

You can download “My First Plugin” from here: {% file src=“assets/my-first-IDAPython-plugin.zip” %}

# Writing a plugin in IDAPython—basic steps

## Create a single `.py` file to start

To begin, your plugin should consist of a single Python file that serves as the entry point. This file should define the main logic and include necessary imports and primary functions that will be executed when the plugin runs.

## Define base classes

It’s recommended to create a class that inherits from `plugin_t` with specific flags and a class inheriting from `plugmod_t` that performs the core functionality.

### Define a class that inherits from `ida_idaapi.plugin_t`

Include a class that inherits from `plugin_t`. This base class will outline the core functionality and lifecycle of your plugin.

Example of `plugin_t` class implementation:

    class MyPlugin(ida_idaapi.plugin_t):
        flags = ida_idaapi.PLUGIN_UNL | ida_idaapi.PLUGIN_MULTI
        comment = "This is my first simple IDA Pro plugin"
        help = "This plugin lists all functions in the current database"
        wanted_name = "My First Plugin"
        wanted_hotkey = "Shift-P"

        def init(self):
            print(">>>MyPlugin: Init called.")
            return MyPlugmod()

### Define a subclass that inherits from `ida_idaapi.plugmod_t`

To implement the main functionality of your plugin within the new framework, it is recommended to define a subclass of `plugmod_t`, that performs the main task of the plugin.

Example of `plugmod_t` class implementation:

    class MyPlugmod(ida_idaapi.plugmod_t):
        def __del__(self):
            print(">>> MyPlugmod: destructor called.")

        def run(self, arg):
            print(">>> MyPlugmod.run() is invoked with argument value: {arg}.")
            for func_ea in idautils.Functions():
                func_name = ida_funcs.get_func_name(func_ea)
                print(f">>>MyPlugmod: Function{func_name} at address {func_ea:x}")

### Overview of `MyPlugin` class attributes

`flags` attribute

The `flags` attribute defines the behavior and plugin properties, and what is crucial, describe its lifecycle: how and when it is loaded into IDA.

Your plugin may have no flags (`flags = 0`). It is usually a good strategy for basic plugins that perform a specific task once and then are no longer needed. Assigning `0` to flags apply a default behavior to your plugin:

- it can be loaded and reloaded at any time;
- it is triggered by the user and does not run constantly in the background;
- it does not modify the database.

Common `flags` for plugins:

- `PLUGIN_MULTI`: Recommended for all plugins; this flag enables the plugin to run simultaneously across multiple opened IDBs within the same IDA instance.
- `PLUGIN_FIX`: The plugin loads when IDA launches and stays loaded until IDA exits.
- `PLUGIN_DRAW`: The plugin needs to be invoked for every screen refresh.
- `PLUGIN_MOD`: The plugin modifies the IDA database.
- `PLUGIN_PROC`: The plugin is a processor module extension.
- `PLUGIN_DBG`: The plugin will be loaded only when a debugger is active (for debugger-related plugins)
- `PLUGIN_UNL`: The plugin will be unloaded immediately after calling the `run` method.

In our example, we used `PLUGIN_UNL` flag, as after performing a specific task—listing functions in the current database—is no longer needed.

For a full list of available flags, refer to the ida_idaapi module.

`comment` attribute The `comment` attribute allows you to provide a brief description of your plugin.

`wanted_name` attribute The `wanted_name` attribute specifies the preferred short name of the plugin, as it apperas under Edit -> Plugins submenu.

`wanted_hotkey` attribute The `wanted_hotkey` attribute specifies a preferred shortcut to run the plugin.

{% hint style=“info” %} The preferred name and hotkey may be overridden by changing the settings in the `plugins.cfg` file. {% endhint %}

## Specify your plugin lifecycle

Below we scrutinize the key components for defining your plugin lifecycle.

Define a PLUGIN_ENTRY function Declare a function called PLUGIN_ENTRY that returns a `plugin_t` instance (or an object containing all attributes of a plugin_t object).

Initialization

The `init()` method is called when the plugin is loaded into IDA and is responsible for initializing your plugin.

The `init()` method returns an pointer to a `plugmod_t` object and indicate that this object run method is going to be used.

{% hint style=“info” %} In the new plugin framework, run/term functions of `plugin_t` are not used. Virtual functions of `plugmod_t` are used instead. {% endhint %}

In our example, when `MyPlugin.init()` is called it initalizes the plugin and returns a new instance of `MyPlugmod`.

        def init(self):
            print(">>>MyPlugin: Init called.")
            return MyPlugmod()

Activation

The `run` method is executed when the user triggers your plugin activation, whether via hotkey or Edit -> Plugins submenu.

{% hint style=“info” %} An alternative way of activation your plugin is via IDA events and registering a callback functions. {% endhint %}

In our example, when the `run()` method of MyPlugmod is called, it prints function names and addresses in Output window.

        def run(self, arg):
            print(">>> MyPlugmod.run() is invoked with argument value: {arg}.")
            for func_ea in idautils.Functions():
                func_name = ida_funcs.get_func_name(func_ea)
                print(f">>>MyPlugmod: Function{func_name} at address {func_ea:x}")

Unloading

The `__del__()` is called automatically when the plugin is going to be unloaded (destroyed). The conditions that define the circumstances under which the plugin should be unloaded depend on the `flags` setting.

Example of plugin lifecycle implementation:

    class MyPlugmod(ida_idaapi.plugmod_t):
        def __del__(self):
            print(">>> MyPlugmod: destructor called.")

        def run(self, arg):
            print(">>> MyPlugmod.run() is invoked with argument value: {arg}.")
            for func_ea in idautils.Functions():
                func_name = ida_funcs.get_func_name(func_ea)
                print(f">>>MyPlugmod: Function{func_name} at address {func_ea:x}")

    class MyPlugin(ida_idaapi.plugin_t):
        flags = ida_idaapi.PLUGIN_UNL | ida_idaapi.PLUGIN_MULTI
        comment = "This is my first simple IDA Pro plugin"
        help = "This plugin lists all functions in the current database"
        wanted_name = "My First Plugin"
        wanted_hotkey = "Shift-P"

        def init(self):
            print(">>>MyPlugin: Init called.")
            return MyPlugmod()

    def PLUGIN_ENTRY():
        return MyPlugin()

In our example:

- `PLUGIN_ENTRY()` returns an instance of the `MyPlugin` class.
- `MyPlugin.init()` is called to initialize the plugin and returns an instance of `MyPlugmod`. MyPlugmod.run() is called when the plugin is activated by the user via the hotkey or the Plugins menu. Then, the `run()` method of `MyPlugmod` is called, which prints function names and addresses in the current IDA database.
- `MyPlugmod.__del__()` is called automatically when the plugin is destroyed (unloaded), and it prints a termination message. As we defined in `flags`, our exemplary plugin unloads directly after performing its task.

## Include an `ida-plugin.json` file

To ensure your plugin is well-organized and can be easily included in the Hex-Rays plugins repository, add the `ida-plugin.json` file with essential metadata to your plugin directory.

## Install and execute your plugin

1. Copy the plugin directory (in our example, the folder containing `my-first-plugin.py` and `ida-plugin.json` files) or single script to plugins directory in your IDA installation folder. Once it’s done, you may need to restart your IDA to see your plugin name under Edit -> Plugins submenu.
2. Run the plugin by pressing the specified hotkey or execute it from Edit -> Plugins -> <your_plugin>.