Ghidra Plugin Architecture: How to Create Custom Extensions

Ghidra plugins are Java classes that extend ghidra.framework.plugintool.Plugin, declare metadata via the @PluginInfo annotation, and are loaded into a PluginTool by the PluginManager to extend the reverse‑engineering environment at runtime.

The Ghidra plugin architecture is the modular foundation of the NationalSecurityAgency/ghidra codebase. It allows developers to add menus, UI panels, background analysis, and cross‑plugin services without modifying core Ghidra source. Every window you see in Ghidra—disassembly, decompiler, symbol tree—is implemented as a plugin using this same architecture.

Core Components of the Ghidra Plugin Architecture

Plugin Base Class and Lifecycle

Every extension must inherit from ghidra.framework.plugintool.Plugin, defined in [Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java). This abstract class defines the lifecycle hooks:

  • init() – Called after construction; acquire services, create actions, and register UI components here.
  • dispose() – Cleanup method invoked when the plugin is unloaded; release threads, listeners, and resources.
  • readConfigState() / writeConfigState() – Persist user preferences across sessions.

The constructor must accept exactly one argument: PluginTool. The framework instantiates plugins via PluginUtils.instantiatePlugin(), which looks for this signature.

PluginInfo Annotation Metadata

Static metadata is declared with @PluginInfo, located in [PluginInfo.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginInfo.java). The annotation tells the PluginManager how to treat the extension:

  • status – PluginStatus.RELEASED, STABLE, UNSTABLE, or HIDDEN.
  • packageName – Logical grouping (e.g., "Developer" or a custom package).
  • category – Menu category shown in the Manage Plugins dialog.
  • servicesProvided – Interfaces this plugin registers for other plugins to consume.
  • servicesRequired – Interfaces this plugin needs from others; the manager resolves these before calling init().
  • eventsProduced / eventsConsumed – PluginEvent types for publish‑subscribe messaging.

PluginTool and PluginManager

The PluginTool ([PluginTool.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java)) is the running Ghidra window. It owns:

  • PluginManager – Loads classes, resolves dependencies, and drives the lifecycle.
  • ServiceManager – Registry for service interfaces.
  • EventManager – Broadcasts PluginEvent objects to registered listeners.

When a tool starts, PluginManager.installUtilityPlugins() loads core plugins, then addPlugins() instantiates each class, calls initServices(), resolves dependencies recursively, orders plugins by service requirements, and finally invokes init().

Services and Events

Services are Java interfaces that decouple plugins. A plugin publishes a service via registerServiceProvided() (defined in Plugin.java), and consumers retrieve it with tool.getService(ServiceInterface.class). The ServiceManager ([ServiceManager.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ServiceManager.java)) tracks these registrations.

Events extend PluginEvent ([PluginEvent.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginEvent.java)). Plugins fire events with firePluginEvent() and receive them by listing the event class in @PluginInfo(eventsConsumed). The EventManager ([EventManager.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/EventManager.java)) handles delivery.

How the Ghidra Plugin Architecture Loads Extensions

The loading sequence in PluginManager ensures that dependencies are satisfied before a plugin initializes:

  1. Tool creation – PluginTool constructs a PluginManager instance.
  2. Utility plugin installation – installUtilityPlugins() loads core plugins defined in the default package.
  3. Class instantiation – addPlugins() calls PluginUtils.instantiatePlugin(), which invokes the Plugin(PluginTool) constructor.
  4. Service registration – initServices() registers services declared in @PluginInfo.servicesProvided.
  5. Dependency resolution – resolveDependencies() recursively ensures all servicesRequired are available.
  6. Initialization ordering – getPluginsByServiceOrder() sorts plugins so providers initialize before consumers.
  7. Plugin initialization – init() is called; plugins create UI actions, acquire services, and register ComponentProvider instances.
  8. Runtime – The tool is ready; users can enable or disable plugins via the Manage Plugins dialog, triggering dispose() on removal.

Creating a Custom Ghidra Extension: Step-by-Step Guide

Step 1: Create the Plugin Class

Create a Java class that extends Plugin and annotate it with @PluginInfo. The constructor must accept a single PluginTool argument.

package myghidra.plugins.myexample;

import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import docking.action.builder.ActionBuilder;
import docking.action.DockingAction;
import ghidra.util.Msg;

@PluginInfo(
    status = PluginStatus.RELEASED,
    packageName = MyPluginPackage.NAME,
    category = "My Plugins",
    shortDescription = "Demo plugin for Ghidra",
    description = "Shows how to add a menu action and a simple service.",
    servicesProvided = { MyExampleService.class },
    servicesRequired = {},
    eventsConsumed = {},
    eventsProduced = {}
)
public class MyExamplePlugin extends Plugin {

    public MyExamplePlugin(PluginTool tool) {
        super(tool);
    }

    @Override
    protected void init() {
        registerServiceProvided(MyExampleService.class, new MyExampleServiceImpl());
        createAction();
    }

    private void createAction() {
        DockingAction helloAction = new ActionBuilder("Say Hello", getName())
                .menuPath("My Plugins", "Say Hello")
                .description("Shows a message dialog")
                .onAction(c -> Msg.showInfo(this, null,
                        "Hello from MyExamplePlugin", "Custom Ghidra plugin works!"))
                .buildAndInstall(getTool());
    }

    @Override
    protected void dispose() {
        // Cleanup resources here
    }
}

Step 2: Define the Service Interface

Services allow other plugins to interact with your extension without tight coupling.

package myghidra.plugins.myexample;

/**
 * Simple service that other plugins could call.
 */
public interface MyExampleService {
    String echo(String text);
}

Step 3: Implement the Service

Provide the concrete implementation referenced in init().

package myghidra.plugins.myexample;

class MyExampleServiceImpl implements MyExampleService {
    @Override
    public String echo(String text) {
        return "Echo: " + text;
    }
}

Step 4: Create a Plugin Package

The package descriptor groups related plugins for management in the UI.

package myghidra.plugins.myexample;

import ghidra.framework.plugintool.PluginPackage;

/**
 * The package name that groups related plugins.
 */
public class MyPluginPackage extends PluginPackage {
    public static final String NAME = "MyExamplePackage";

    public MyPluginPackage() {
        super(NAME);
    }
}

Step 5: Build and Deploy

Compile your extension as a Ghidra module:

  1. Create a Gradle module directory (e.g., Ghidra/Features/MyExamplePlugin/).
  2. Place source files under src/main/java/.
  3. Add a build.gradle with sourceSets.main.java.srcDirs = ['src/main/java'].
  4. Include the module in settings.gradle.
  5. Run gradle build to produce the extension JAR.

Alternatively, package your classes into a JAR and place it in Ghidra/Extensions/ or add it to the classpath manually.

Step 6: Consume Services from Other Plugins

Once your plugin is loaded, other extensions can access its services:

MyExampleService svc = getTool().getService(MyExampleService.class);
if (svc != null) {
    System.out.println(svc.echo("test"));
}

Key Source Files in the Ghidra Plugin Architecture

Understanding the framework requires familiarity with these core files:

Summary

  • Ghidra plugin architecture is a Java-based framework where every feature is a plugin extending ghidra.framework.plugintool.Plugin.
  • Metadata is declared via the @PluginInfo annotation, specifying status, services, events, and dependencies.
  • Lifecycle management is handled by PluginManager, which resolves service dependencies, orders initialization, and calls init() and dispose().
  • Inter-plugin communication occurs through services (interfaces registered with registerServiceProvided and consumed via tool.getService()) and events (subclasses of PluginEvent fired with firePluginEvent).
  • UI integration uses ComponentProvider for dockable windows and ActionBuilder for menu actions.
  • Deployment requires compiling the plugin into a Ghidra module or JAR and enabling it via the Manage Plugins dialog.

Frequently Asked Questions

What is the Ghidra plugin architecture?

The Ghidra plugin architecture is a modular framework built on Java that allows developers to extend the reverse‑engineering environment at runtime. It defines a standard lifecycle for components (via the Plugin base class), a dependency‑injection mechanism for services, and an event system for loose coupling, all orchestrated by the PluginManager inside a PluginTool.

How do I debug a Ghidra plugin during development?

Launch Ghidra from your IDE (IntelliJ IDEA or Eclipse) using the GhidraLauncher class with the ghidra.GhidraRun argument. Set breakpoints in your plugin’s init() method or action handlers. Because Ghidra loads plugins dynamically, you can use the Manage Plugins dialog to disable and re‑enable your plugin after recompiling, or use the Script Manager to run quick tests without restarting the tool.

Can I write Ghidra plugins in Python instead of Java?

Yes, but with limitations. Ghidra’s primary plugin architecture is Java‑based, and core extensions must extend Plugin. However, Ghidra includes a Jython interpreter that allows you to write scripts (not full plugins) in Python 2.7. These scripts can access the Ghidra API, manipulate the program, and create temporary UI elements, but they cannot declare services or events in the same way as Java plugins. For deep integration into the Ghidra plugin architecture, Java is required.

Where should I place my custom Ghidra extension files?

Place your compiled JAR or module directory inside the Ghidra/Extensions/ directory of your Ghidra installation, or package it as a proper Ghidra module under Ghidra/Features/ or Ghidra/Processors/ if building from source. Ensure your JAR contains the compiled plugin class, any service interfaces, and the PluginPackage descriptor. After placement, restart Ghidra or open File → Install Extensions, then enable your extension in the Manage Plugins dialog under the category you specified in @PluginInfo.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →