fix(ghidra): headless decompilation on modern Ghidra (Java scripts + JDK discovery)#13
Merged
Merged
Conversation
…installs Verified the whole-app decompiler against a real Ghidra 12 install and found two problems, now fixed: - Ghidra 11.3+/12 route `.py` scripts through PyGhidra (CPython), which our headless invocation doesn't enable, so both post-scripts failed with "Ghidra was not started with PyGhidra." Rewrote PCDumpProgram and PCDecompileFunction as Java GhidraScripts, which Ghidra compiles itself — no Python/pip dependency, works on every Ghidra version. This also fixes the pre-existing single-function "Decompile" action on network call sites. - The install locator used the URL's `hasDirectoryPath`, which is false for a symlink, so it missed symlinked Ghidra installs (e.g. a Homebrew Ghidra linked into ~/Applications). It now follows symlinks via FileManager. Adds an opt-in integration test (PC_GHIDRA_INTEGRATION=1 + JAVA_HOME) that actually runs headless Ghidra and asserts real decompiled C for both the whole-app dump and the single-function path. Verified green against Ghidra 12.1.2 / JDK 21. Full suite 276 tests (3 integration skipped by default); app builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…I app A Finder-launched .app has no JAVA_HOME and no TTY, so Ghidra's analyzeHeadless couldn't find a JDK and couldn't prompt for one — it died with "Unable to locate a Java Runtime", making the decompile features look broken in the app even though the logic is correct. GhidraDecompiler now locates a JDK itself (via /usr/libexec/java_home, then Homebrew's keg-only openjdk under /opt/homebrew/opt and /usr/local/opt) and sets JAVA_HOME on the Ghidra process when it isn't already set. Applies to both the whole-app dump and the single-function decompile (shared runHeadless). Verified: the Ghidra integration tests pass with NO JAVA_HOME in the environment (i.e. the app self-discovers the JDK the way it must for a Finder-launched app). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-lands two verified Ghidra fixes that missed the #12 merge
PR #12 was merged at its feature commit, but two follow-up fix commits were
pushed to that branch after it merged, so they never landed on
main. Withoutthem the whole-app decompiler (and the pre-existing single-function decompile)
is broken on modern Ghidra. This re-lands them (cherry-picked, unchanged),
now verified against a real Ghidra 12.1.2 install.
Fixes
.pypost-scripts don't work on Ghidra 11.3+/12 — those versions routePython scripts through PyGhidra (CPython), which our headless invocation
doesn't enable, so scripts fail with "Ghidra was not started with PyGhidra."
PCDumpProgramandPCDecompileFunctionare now Java GhidraScripts(Ghidra compiles them itself — no Python/pip dep, works on every version).
This also fixes the existing single-function "Decompile" on network call sites.
hasDirectoryPathis falsefor a symlink) — e.g. a Homebrew Ghidra linked into
~/Applications. Nowfollows symlinks.
JAVA_HOMEand no TTY, so Ghidra died with "Unable to locate a Java Runtime."
GhidraDecompilernow discovers a JDK itself (/usr/libexec/java_home, thenHomebrew's keg-only openjdk) and sets
JAVA_HOMEon the Ghidra process.Testing
Adds an opt-in integration test (
PC_GHIDRA_INTEGRATION=1) that runs realheadless Ghidra and asserts decompiled C for both the whole-app dump and the
single-function path. Verified green against Ghidra 12.1.2 / JDK 21 — including
with no
JAVA_HOMEset (the app self-discovers the JDK). Full suite 324tests (3 integration skipped by default), 0 failures.
🤖 Generated with Claude Code