Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

ghidra.nvim

Ghidra development plugin for Neovim. The GhidraDev experience, but for Neovim -- with real LSP.

Write Ghidra scripts in Java and Python with full autocomplete, go-to-definition, hover docs, and diagnostics -- powered by JDTLS and Pyright, automatically configured with Ghidra's API.

How it works

ghidra.nvim does what Eclipse's GhidraDev plugin does under the hood: it points your existing language servers at Ghidra's JARs and Python libraries. No custom LSP server required.

                      ┌──────────────┐
  Neovim              │ JDTLS        │──── Ghidra/Framework/*/lib/*.jar
  ├─ ghidra.nvim ────►│ (Java LSP)   │──── Ghidra/Features/*/lib/*.jar
  │  configures       └──────────────┘
  │  classpath
  │                   ┌──────────────┐
  └─ ghidra.nvim ────►│ Pyright      │──── Ghidra/Features/Python/
     configures       │ (Python LSP) │──── ~/ghidra_scripts/
     extraPaths       └──────────────┘

Java scripts get full GhidraScript, FlatProgramAPI, Program, Listing, Function, etc. completion via JDTLS reading the generated .classpath.

Python scripts get Ghidra's Jython/PyGhidra API completion via Pyright's extraPaths and a generated pyrightconfig.json.

Requirements

Installation

{
  "jdearmas/ghidra.nvim",
  config = function()
    require("ghidra").setup({
      -- Path to your Ghidra installation (or set $GHIDRA_INSTALL_DIR)
      ghidra_install = "/opt/ghidra_11.2",
    })
  end,
}
use {
  "jdearmas/ghidra.nvim",
  config = function()
    require("ghidra").setup({
      ghidra_install = "/opt/ghidra_11.2",
    })
  end,
}

Manual (from GitHub)

Clone into your Neovim packages directory:

git clone https://github.com/jdearmas/ghidra.nvim \
  ~/.local/share/nvim/site/pack/plugins/start/ghidra.nvim

Local install (from a local clone)

If you already have the repo cloned somewhere (e.g. you're hacking on the plugin itself), pick one of these:

Option A: lazy.nvim dir (recommended if you use lazy)

-- In your lazy.nvim plugin spec:
{
  dir = "/absolute/path/to/ghidra.nvim",
  config = function()
    require("ghidra").setup({
      ghidra_install = "/opt/ghidra_11.2",
    })
  end,
}

Option B: Symlink into Neovim's pack path (works with any setup)

# One command — done. Neovim picks it up on next launch.
ln -s /absolute/path/to/ghidra.nvim \
  ~/.local/share/nvim/site/pack/plugins/start/ghidra.nvim

Then add to your Neovim config (init.lua):

require("ghidra").setup({
  ghidra_install = "/opt/ghidra_11.2",
})

Option C: Raw vim.opt.rtp (no plugin manager needed)

-- Add to the very top of your init.lua:
vim.opt.rtp:prepend("/absolute/path/to/ghidra.nvim")

require("ghidra").setup({
  ghidra_install = "/opt/ghidra_11.2",
})

Tip: After any of these, run :checkhealth ghidra to verify everything is wired up.

Configuration

All options with their defaults:

require("ghidra").setup({
  -- Path to Ghidra installation. If nil, auto-detects from
  -- $GHIDRA_INSTALL_DIR or common locations (/opt/ghidra*, ~/ghidra*, etc.)
  ghidra_install = nil,

  java = {
    enabled = true,
    -- Auto-generate .classpath and .project files for JDTLS
    generate_classpath = true,
  },

  python = {
    enabled = true,
    -- "jython" (Ghidra's bundled Jython) or "pyghidra" (Python 3 via PyGhidra)
    interpreter = "jython",
  },

  -- Default directory for new scripts (Ghidra auto-discovers ~/ghidra_scripts)
  scripts_dir = "~/ghidra_scripts",
})

Commands

Command Description
:GhidraSetup [path] Link a Ghidra installation. Auto-detects if no path given.
:GhidraNewScript java|python <name> Create a new script from template with Ghidra boilerplate.
:GhidraRunScript [file] [flags] Run a script headlessly via analyzeHeadless. Defaults to current buffer. --all runs every script in dir.
:GhidraInfo Show linked installation, JAR count, paths, and config in a floating window.
:GhidraRefresh Re-scan Ghidra JARs and push updated settings to running LSP servers.

GhidraRunScript flags

" Run the current buffer headlessly
:GhidraRunScript

" Run a specific script against a binary
:GhidraRunScript ~/ghidra_scripts/MyScript.java --import /path/to/binary.exe

" Skip auto-analysis for faster execution
:GhidraRunScript --noanalysis

" Run as a pre-analysis script instead of post-analysis
:GhidraRunScript --pre

" Open output in a vertical split or new tab
:GhidraRunScript --vertical
:GhidraRunScript --tab

" Run ALL scripts in the current script's directory
:GhidraRunScript --all
:GhidraMake --all

Health check

:checkhealth ghidra

Reports:

  • Ghidra installation validity and version
  • Number of discovered API JARs
  • analyzeHeadless availability
  • Python library paths
  • JDTLS / Pyright availability
  • Scripts directory status

How the LSP integration works

Java

When you open a .java file inside a Ghidra project directory (detected by .ghidra_project marker, Module.manifest, ghidra_scripts/ directory name, or your configured scripts_dir), the plugin:

  1. Discovers all .jar files under Ghidra/Framework/*/lib/, Ghidra/Features/*/lib/, Ghidra/Processors/*/lib/, and Ghidra/Extensions/*/lib/
  2. Generates a .classpath file (Eclipse format) that JDTLS reads natively
  3. Generates a .project file so JDTLS treats the directory as a Java project
  4. Pushes referencedLibraries to any running JDTLS client

This gives you autocomplete, go-to-definition, hover, and diagnostics for the entire Ghidra API -- GhidraScript, FlatProgramAPI, Program, Listing, Function, Address, DataType, and everything else.

Python

When you open a .py file in a Ghidra project context, the plugin:

  1. Discovers Jython/PyGhidra library paths from the Ghidra installation
  2. Generates a pyrightconfig.json with those paths in extraPaths
  3. Pushes python.analysis.extraPaths to any running Pyright/basedpyright/pylsp client

Headless execution

:GhidraRunScript invokes Ghidra's analyzeHeadless (found at <GhidraInstall>/support/analyzeHeadless) in a Neovim terminal split. It automatically:

  • Uses a temporary project in ~/.cache/nvim/ghidra_projects/
  • Sets -scriptPath to include your script's directory and configured scripts_dir
  • Supports importing binaries for analysis with --import

Project detection

The plugin identifies Ghidra project roots by looking for any of:

  • .ghidra_project marker file (create this in your project root)
  • Module.manifest (Ghidra extension module marker)
  • .classpath file containing "ghidra" or "Ghidra"
  • Directory named ghidra_scripts
  • Files inside your configured scripts_dir

Typical workflow

# 1. Set up your scripts directory
mkdir -p ~/ghidra_scripts
-- 2. In your Neovim config
require("ghidra").setup({
  ghidra_install = "/opt/ghidra_11.2",
})
" 3. Create a new script
:GhidraNewScript java MyAnalyzer

" 4. Write your script with full autocomplete (JDTLS kicks in automatically)
"    - Type 'currentProgram.' and get completions
"    - Hover over GhidraScript methods for docs
"    - Go-to-definition on any Ghidra API class

" 5. Run it headlessly against a binary
:GhidraRunScript --import /path/to/firmware.bin

License

MIT

About

A neovim plugin for Ghidra (SRE) development

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages