How to Write Ghidra Scripts in Java vs Python Using PyGhidra

Write Ghidra scripts in Java by compiling classes that extend GhidraScript, or use PyGhidra to run native Python 3 code with full access to Ghidra's Java API through an automatic bridge.

Ghidra's reverse engineering framework supports multiple scripting languages through a provider-based architecture implemented in the NationalSecurityAgency/ghidra repository. Whether you choose Java for tight JVM integration or Python for rapid prototyping with scientific libraries, both approaches leverage the same underlying ghidra.app.script.GhidraScript base class. This guide explains how to write Ghidra scripts in both languages and when to use each approach.

Understanding Ghidra's Script Architecture

All Ghidra scripts inherit from the abstract class ghidra.app.script.GhidraScript located in Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java. This base class provides the FlatProgramAPI—giving you access to currentProgram, println, askString, and other utilities—plus the abstract run() method you must implement.

The framework uses the GhidraScriptProvider extension point to map file extensions to runtime environments. Each provider lives in a specific source file:

When you place a script in a script directory, GhidraScriptUtil.getProvider(file)—implemented in Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScriptUtil.java—iterates through registered providers to find a match. You can override the default selection by adding a runtime metadata comment such as # @runtime Jython at the top of your file.

Writing Ghidra Scripts in Java

Java scripts are first-class citizens in Ghidra. To create one, extend GhidraScript and implement the run() method. The JavaScriptProvider—located in Ghidra/Features/Base/src/main/java/ghidra/app/script/JavaScriptProvider.java—compiles your source on-the-fly using the same JDK that runs Ghidra.

import ghidra.app.script.GhidraScript;

public class HelloWorld extends GhidraScript {
    @Override
    public void run() throws Exception {
        println("Hello from Java!");
        // Example: list all functions in the current program
        for (Function f : currentProgram.getFunctionManager().getFunctions(true)) {
            println("Function: " + f.getName() + " @ " + f.getEntryPoint());
        }
    }
}

Key characteristics of Java scripts:

  • Compilation: Performed on-the-fly by JavaScriptProvider. Errors appear in the script console.
  • API Access: Direct Java calls with no bridging overhead.
  • Packaging: Bundle multiple scripts into a Ghidra Extension using the Extension descriptor.
  • Performance: Comparable to native plugins because it runs inside the same JVM.

Writing Ghidra Scripts in Python with PyGhidra

PyGhidra, available since Ghidra 10.2, provides a native CPython 3 interpreter that bridges to Ghidra's Java API. The PyGhidraScriptProvider—located in Ghidra/Features/PyGhidra/src/main/java/ghidra/pyghidra/PyGhidraScriptProvider.java—handles .py files by default when PyGhidra is installed.

How PyGhidra Works

PyGhidra uses a JNI-based bridge to expose Ghidra's Java classes to Python. When you run a script, the provider launches a native Python process and injects a this object that represents the GhidraScript instance. This gives you access to println, currentProgram, and other FlatProgramAPI methods.

Basic PyGhidra Script Structure

Create a .py file in your script directory. Unlike Jython scripts, you do not need a @runtime header unless you specifically want to force Jython. Import Java classes through the bridge using this.getClass().forName or access them directly via the ghidra module.


# PyGhidra scripts get a `this` object that is the GhidraScript instance.

# It provides the same methods as the Java base class.

this.println("Hello from PyGhidra!")

# Access Java types via the pyjnius-style bridge

Function = this.getClass().forName("ghidra.program.model.listing.Function")
funcMgr = currentProgram.getFunctionManager()

# Iterate over functions (identical to the Java version)

for f in funcMgr.getFunctions(True):
    this.println(f"Function: {f.getName()} @ {f.getEntryPoint()}")

Key characteristics of PyGhidra scripts:

  • Interpreter: Native CPython 3 launched by PyGhidraScriptProvider.
  • Bridge: pyghidra creates Python wrappers for Java classes automatically.
  • this Object: Mirrors the Java GhidraScript instance; access via this.println, this.currentProgram, etc.
  • No @runtime needed: PyGhidra is the default for .py files when installed.
  • Performance: Slightly slower than Java due to the CPython ↔ JVM bridge, but sufficient for most analysis.
  • Virtual Environments: Respects active Python virtual environments for third-party packages.

Choosing Between Java and PyGhidra

Select your language based on performance requirements and ecosystem needs:

  • Java: Choose when you need maximum performance, tight integration with Ghidra internals, or plan to distribute your scripts as a Ghidra Extension. Java scripts compile to bytecode and run directly in the same JVM as Ghidra, eliminating bridging overhead.
  • PyGhidra: Choose when you need rapid prototyping, access to Python's scientific ecosystem (NumPy, pandas, etc.), or prefer Python syntax. PyGhidra runs in native CPython 3, allowing you to install packages via pip while still accessing the full Ghidra Java API.

Summary

  • Ghidra scripts inherit from ghidra.app.script.GhidraScript regardless of language.

  • Java scripts use JavaScriptProvider for on-the-fly compilation and direct JVM execution.

  • PyGhidra scripts use PyGhidraScriptProvider to run native Python 3 with automatic Java bridging.

  • Use the # @runtime metadata comment to force Jython if needed.

  • Store scripts in the script directories (e.g., $GHIDRA_HOME/ghidra_scripts) to make them available in the Script Manager.

Frequently Asked Questions

Can I mix Java and Python scripts in the same Ghidra project?

Yes. The GhidraScriptUtil class automatically detects the appropriate GhidraScriptProvider based on file extension and metadata. You can store .java and .py files side-by-side in the same script directory; Ghidra will compile Java scripts with JavaScriptProvider and execute Python scripts with PyGhidraScriptProvider (or JythonScriptProvider if specified).

Do I need to install PyGhidra separately?

No. PyGhidra has been bundled with Ghidra since version 10.2. The PyGhidraScriptProvider is registered automatically when you install Ghidra, and it handles .py files by default. However, you must have a compatible Python 3 installation available on your system path for the bridge to function.

How do I force a Python script to use Jython instead of PyGhidra?

Add the metadata comment # @runtime Jython as the first line of your script. When GhidraScriptUtil.getProvider(file) scans the file, it detects this directive and routes the script to JythonScriptProvider instead of PyGhidraScriptProvider. This is useful for maintaining legacy scripts that depend on Jython-specific behaviors.

Is there a performance difference between Java and PyGhidra scripts?

Yes. Java scripts run directly in the same JVM as Ghidra through JavaScriptProvider, offering native performance with no bridging overhead. PyGhidra scripts run in a separate native CPython 3 process and cross the JNI bridge for every Java API call, introducing slight latency. For most analysis tasks the difference is negligible, but for processing millions of instructions, Java is preferable.

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 →