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, orHIDDEN.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 callinginit().eventsProduced/eventsConsumed–PluginEventtypes 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– BroadcastsPluginEventobjects 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:
- Tool creation –
PluginToolconstructs aPluginManagerinstance. - Utility plugin installation –
installUtilityPlugins()loads core plugins defined in the default package. - Class instantiation –
addPlugins()callsPluginUtils.instantiatePlugin(), which invokes thePlugin(PluginTool)constructor. - Service registration –
initServices()registers services declared in@PluginInfo.servicesProvided. - Dependency resolution –
resolveDependencies()recursively ensures allservicesRequiredare available. - Initialization ordering –
getPluginsByServiceOrder()sorts plugins so providers initialize before consumers. - Plugin initialization –
init()is called; plugins create UI actions, acquire services, and registerComponentProviderinstances. - 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:
- Create a Gradle module directory (e.g.,
Ghidra/Features/MyExamplePlugin/). - Place source files under
src/main/java/. - Add a
build.gradlewithsourceSets.main.java.srcDirs = ['src/main/java']. - Include the module in
settings.gradle. - Run
gradle buildto 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:
- [
Plugin.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java) – Abstract base class handling lifecycle, service registration (registerServiceProvided), and event firing (firePluginEvent). - [
PluginInfo.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginInfo.java) – Annotation interface defining metadata constants likestatus,servicesProvided, andeventsConsumed. - [
PluginManager.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginManager.java) – Orchestrates loading viaaddPlugins(), resolves dependencies withresolveDependencies(), and orders initialization usinggetPluginsByServiceOrder(). - [
PluginTool.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java) – The running tool window; ownsServiceManagerandEventManager; providesgetService()to plugins. - [
ServiceManager.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ServiceManager.java) – Registry for service interfaces; handlesregisterServiceProvidedand service lookup. - [
EventManager.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/EventManager.java) – BroadcastsPluginEventobjects to listeners registered viaeventsConsumed. - [
PluginEvent.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginEvent.java) – Base class for all inter-plugin messages. - [
ComponentProvider.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/docking/ComponentProvider.java) – Base for dockable UI panels; plugins register these withgetTool().addComponentProvider(). - [
ActionBuilder.java](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Framework/Project/src/main/java/docking/action/builder/ActionBuilder.java) – Fluent API for creating menu items and toolbar buttons.
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
@PluginInfoannotation, specifying status, services, events, and dependencies. - Lifecycle management is handled by
PluginManager, which resolves service dependencies, orders initialization, and callsinit()anddispose(). - Inter-plugin communication occurs through services (interfaces registered with
registerServiceProvidedand consumed viatool.getService()) and events (subclasses ofPluginEventfired withfirePluginEvent). - UI integration uses
ComponentProviderfor dockable windows andActionBuilderfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →