feat: Add decompiler configuration options
Add toggleCCode, toggleSyntaxTree and setSimplificationStyle controls to the Java plugin. These allow controlling decompiler output format between C code (default) and raw decompiler output with syntax trees. Example usage: decompile_function_by_address(port=8192, address='0x1000', cCode=True) decompile_function_by_address(port=8192, address='0x1000', syntaxTree=True)
This commit is contained in:
parent
bd56f5b6cc
commit
4fe3c16d25
24
CHANGELOG.md
24
CHANGELOG.md
@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added decompiler output controls to customize analysis results:
|
||||||
|
- Choose between clean C-like pseudocode (default) or raw decompiler output
|
||||||
|
- Toggle syntax tree visibility for detailed analysis
|
||||||
|
- Select different simplification styles for alternate views
|
||||||
|
- Useful for comparing different decompilation approaches or focusing on specific aspects of the code
|
||||||
|
|
||||||
|
Example showing how to get raw decompiler output with syntax tree:
|
||||||
|
```xml
|
||||||
|
<use_mcp_tool>
|
||||||
|
<server_name>ghydra</server_name>
|
||||||
|
<tool_name>decompile_function_by_address</tool_name>
|
||||||
|
<arguments>
|
||||||
|
{
|
||||||
|
"address": "0x1000",
|
||||||
|
"cCode": false,
|
||||||
|
"syntaxTree": true
|
||||||
|
}
|
||||||
|
</arguments>
|
||||||
|
</use_mcp_tool>
|
||||||
|
```
|
||||||
|
|
||||||
## [1.4.0] - 2025-04-08
|
## [1.4.0] - 2025-04-08
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -333,9 +333,24 @@ def list_classes(port: int = DEFAULT_GHIDRA_PORT, offset: int = 0, limit: int =
|
|||||||
return safe_get(port, "classes", {"offset": offset, "limit": limit})
|
return safe_get(port, "classes", {"offset": offset, "limit": limit})
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def get_function(port: int = DEFAULT_GHIDRA_PORT, name: str = "") -> dict:
|
def get_function(port: int = DEFAULT_GHIDRA_PORT, name: str = "", cCode: bool = True, syntaxTree: bool = False, simplificationStyle: str = "normalize") -> dict:
|
||||||
"""Get decompiled code for a specific function"""
|
"""Get decompiled code for a specific function
|
||||||
response = safe_get(port, f"functions/{quote(name)}", {})
|
|
||||||
|
Args:
|
||||||
|
port: Ghidra instance port (default: 8192)
|
||||||
|
name: Name of the function to decompile
|
||||||
|
cCode: Whether to output C code (default: True)
|
||||||
|
syntaxTree: Whether to include syntax tree (default: False)
|
||||||
|
simplificationStyle: Decompiler analysis style (default: "normalize")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing function details including decompiled code
|
||||||
|
"""
|
||||||
|
response = safe_get(port, f"functions/{quote(name)}", {
|
||||||
|
"cCode": str(cCode).lower(),
|
||||||
|
"syntaxTree": str(syntaxTree).lower(),
|
||||||
|
"simplificationStyle": simplificationStyle
|
||||||
|
})
|
||||||
|
|
||||||
# Check if the response is a string (old format) or already a dict with proper structure
|
# Check if the response is a string (old format) or already a dict with proper structure
|
||||||
if isinstance(response, dict) and "success" in response:
|
if isinstance(response, dict) and "success" in response:
|
||||||
@ -524,17 +539,25 @@ def get_current_function(port: int = DEFAULT_GHIDRA_PORT) -> dict: # Return dict
|
|||||||
return safe_get(port, "get_current_function")
|
return safe_get(port, "get_current_function")
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def decompile_function_by_address(port: int = DEFAULT_GHIDRA_PORT, address: str = "") -> dict:
|
def decompile_function_by_address(port: int = DEFAULT_GHIDRA_PORT, address: str = "", cCode: bool = True, syntaxTree: bool = False, simplificationStyle: str = "normalize") -> dict:
|
||||||
"""Decompile a function at a specific memory address
|
"""Decompile a function at a specific memory address
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
port: Ghidra instance port (default: 8192)
|
port: Ghidra instance port (default: 8192)
|
||||||
address: Memory address of the function (hex string)
|
address: Memory address of the function (hex string)
|
||||||
|
cCode: Whether to output C code (default: True)
|
||||||
|
syntaxTree: Whether to include syntax tree (default: False)
|
||||||
|
simplificationStyle: Decompiler analysis style (default: "normalize")
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict containing the decompiled pseudocode in the 'result.decompilation' field
|
Dict containing the decompiled pseudocode in the 'result.decompilation' field
|
||||||
"""
|
"""
|
||||||
response = safe_get(port, "decompile_function", {"address": address})
|
response = safe_get(port, "decompile_function", {
|
||||||
|
"address": address,
|
||||||
|
"cCode": str(cCode).lower(),
|
||||||
|
"syntaxTree": str(syntaxTree).lower(),
|
||||||
|
"simplificationStyle": simplificationStyle
|
||||||
|
})
|
||||||
|
|
||||||
# Check if the response is a string (old format) or already a dict with proper structure
|
# Check if the response is a string (old format) or already a dict with proper structure
|
||||||
if isinstance(response, dict) and "success" in response:
|
if isinstance(response, dict) and "success" in response:
|
||||||
|
|||||||
@ -438,6 +438,9 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin {
|
|||||||
if ("GET".equals(exchange.getRequestMethod())) {
|
if ("GET".equals(exchange.getRequestMethod())) {
|
||||||
Map<String, String> qparams = parseQueryParams(exchange);
|
Map<String, String> qparams = parseQueryParams(exchange);
|
||||||
String address = qparams.get("address");
|
String address = qparams.get("address");
|
||||||
|
boolean cCode = Boolean.parseBoolean(qparams.getOrDefault("cCode", "true"));
|
||||||
|
boolean syntaxTree = Boolean.parseBoolean(qparams.getOrDefault("syntaxTree", "false"));
|
||||||
|
String simplificationStyle = qparams.getOrDefault("simplificationStyle", "normalize");
|
||||||
|
|
||||||
if (address == null || address.isEmpty()) {
|
if (address == null || address.isEmpty()) {
|
||||||
sendErrorResponse(exchange, 400, "Address parameter is required");
|
sendErrorResponse(exchange, 400, "Address parameter is required");
|
||||||
@ -472,6 +475,11 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin {
|
|||||||
|
|
||||||
DecompInterface decomp = new DecompInterface();
|
DecompInterface decomp = new DecompInterface();
|
||||||
try {
|
try {
|
||||||
|
// Set decompilation options from parameters
|
||||||
|
decomp.toggleCCode(cCode);
|
||||||
|
decomp.setSimplificationStyle(simplificationStyle);
|
||||||
|
decomp.toggleSyntaxTree(syntaxTree);
|
||||||
|
|
||||||
if (!decomp.openProgram(program)) {
|
if (!decomp.openProgram(program)) {
|
||||||
sendErrorResponse(exchange, 500, "Failed to initialize decompiler");
|
sendErrorResponse(exchange, 500, "Failed to initialize decompiler");
|
||||||
return;
|
return;
|
||||||
@ -1105,6 +1113,11 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin {
|
|||||||
|
|
||||||
DecompInterface decomp = new DecompInterface();
|
DecompInterface decomp = new DecompInterface();
|
||||||
try {
|
try {
|
||||||
|
// Default to C code output and no syntax tree for better readability
|
||||||
|
decomp.toggleCCode(true);
|
||||||
|
decomp.setSimplificationStyle("normalize");
|
||||||
|
decomp.toggleSyntaxTree(false);
|
||||||
|
|
||||||
if (!decomp.openProgram(program)) {
|
if (!decomp.openProgram(program)) {
|
||||||
resultObj.addProperty("decompilation_error", "Failed to initialize decompiler");
|
resultObj.addProperty("decompilation_error", "Failed to initialize decompiler");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user