Posted by xerzes 16 hours ago
I built this because reverse engineering software across multiple versions is painful. You spend hours annotating functions in version 1.07, then version 1.08 drops and every address has shifted — all your work invisible.
The core idea is a normalized function hashing system. It hashes functions by their logical structure — mnemonics, operand categories, control flow — not raw bytes or absolute addresses. When a binary is recompiled or rebased, the same function produces the same hash. All your documentation (names, types, comments) transfers automatically.
Beyond that, it's a full MCP bridge with 110 tools for Ghidra: decompilation, disassembly, cross-referencing, annotation, batch analysis, and headless/Docker deployment. It integrates with Claude, Claude Code, or any MCP-compliant client.
For context, the most popular Ghidra MCP server (LaurieWired's, 7K+ stars) has about 15 tools. This started as a fork of that project but grew into 28,600 lines of substantially different code.
Architecture:
Java Ghidra Plugin (22K LOC) → embeds HTTP server inside Ghidra
Python MCP Bridge (6.5K LOC) → 110 tools with batch optimization
Any MCP client → Claude, scripts, CI pipelines
I validated the hashing against Diablo II — dozens of patch versions, each rebuilding DLLs at different base addresses. The hash registry holds 154K+ entries, and I can propagate 1,300+ function annotations from one version to the next automatically.The headless mode runs in Docker (docker compose up) for batch processing and CI integration — no GUI required.
v2.0.0 adds localhost-only binding (security), configurable timeouts, label deletion tools, and .env-based configuration.
Happy to discuss the hashing approach, MCP protocol design decisions, or how this fits into modern RE workflows.
Going off of only FunctionID will either have a lot of false positives or false negatives, depending on if you compute them masking out operands or not. If you mask out operands, then it says that "*param_1 = 4" and "*param_1 = 123" are the same hash. If you don't mask out operands, then it says that nearly all functions are different because your call displacements have shifted due to different code layout. That's why the built-in Version Tracker tool uses hashes for only one of the heuristics, and has other correlation heuristics to apply as well in addition.
- pyghidra-mcp - ReVa - GhidrAssistMCP - GhydraMCP - etc...
I think your installation instructions are incomplete. I followed the instructions and installed via file -> install in the project view. Restarted. But GhidraMCP is not visible in Tools after opening a binary.
I learnt a ton in the progress. I highly recommend others do the same, it’s a really fun way of spending an evening.
I will certainly be giving this MCP server a go.
I'm working on a hobby project - reverse-engineering a 30 year old game. Passing a single function disassembly + Ghidra decompiler output + external symbol definitions RAG-style to an agent with a good system prompt does wonders even with inexpensive models such as Gemini 3 Flash.
Then chain decompilation agent outputs to a coding agent, and produced code can be semi-automatically integrated into the codebase. Rinse and repeat.
Decompiled code is wrong sometimes, but for cleaned up disassembly with external symbols annotated and correct function signatures - decompiled output looks more or less like it was written by a human and not mechanically decompiled.
Alternatively, Claude Opus generally output actual code that included more of the original functionality. Even Qwen3-30B-A3B performs better than Gemini, in my experience.
It's honestly really frustrating. The huge context size available with Gemini makes the model family seem like a boon for this task; PCode is very verbose, impinging on the headroom needed for the model's response.
The bug was one-shotted by GPT 5.2.
By the way, this app had embedded the key into the shader, and it was required to actually run this shader on android device to obtain the key.
Oh that's clever. I don't suppose you can share more about how this was done?
For objective C heavy code, I also use Hopper Disassembler (which now has a built in MCP server).
Some related academic work (full recompilation with LLMs and Ghidra): https://dl.acm.org/doi/10.1145/3728958
Is this a bad look for Derrida.org?
Anyway, "not my business"
This also seems to just be vibecoded garbage.
Now just onto the fact that most MCP tools are just transforming API calls and their functionality and return data structures suck for LLM's....
A friend from work just used it (with Claude) to hack River Ride game (https://quesma.com/blog/ghidra-mcp-unlimited-lives/).
Inspired by the, I have it a try as well. While I have no prior experience with reverse engineering, I ported an old game from PowerPC to Apple Silicon.
First, including a few MCPs with Claude Code (including LaurieWired/GhidraMCP you forked from, and https://github.com/jtang613/GhidrAssistMCP). Yet, the agent fabricated as lot of code, instead for translating it from source.
I ended up using headless mode directly in Cursor + GPT 5.2 Codex. The results were the best.
Once I get some time, will share a write-up.
For example, Codex can completely reverse-engineer this 1,300-line example [0] of a so-called C64-SID file within 30 minutes, without any human interaction.
I am working on a multi-agent system that can completely reverse-engineer C64 games. Old MS-DOS games are still too massive to analyze for my budget limit.
[0] https://gist.github.com/s-macke/595982d46d6699b69e1f0e051e7b...
I'm very interested in trying out Codex now.
Curious about the hash collision rate in practice. The README mentions 154K+ entries from Diablo II patches. With that sample size, have you encountered meaningful false positives where structurally similar but semantically different functions matched? The Version Tracker comparison in the comments is fair — seems like combining this hash approach with additional heuristics (xref patterns, call graph structure) could reduce both false positives and negatives.
The headless Docker mode is a nice touch for CI integration. Being able to batch-analyze binaries and auto-propagate annotations without spinning up a GUI opens up some interesting automated diffing workflows.