Ryan Malloy 28b81ff359
Some checks are pending
Build Ghidra Plugin / build (push) Waiting to run
feat: Add Python MCP bridge and build tooling
- Add ghydramcp Python package with FastMCP server implementation
- Add docker-compose.yml for easy container management
- Add Makefile with build/run targets
- Add QUICKSTART.md for getting started
- Add uv.lock for reproducible dependencies
2026-01-26 13:51:12 -07:00

130 lines
3.6 KiB
Python

"""Memory mixin for GhydraMCP.
Provides tools for memory read/write operations.
"""
from typing import Any, Dict, Optional
from fastmcp.contrib.mcp_mixin import mcp_tool
from .base import GhydraMixinBase
class MemoryMixin(GhydraMixinBase):
"""Mixin for memory operations.
Provides tools for:
- Reading memory bytes
- Writing memory bytes (use with caution)
"""
@mcp_tool()
def memory_read(
self,
address: str,
length: int = 16,
format: str = "hex",
port: Optional[int] = None,
) -> Dict[str, Any]:
"""Read bytes from memory.
Args:
address: Memory address in hex format
length: Number of bytes to read (default: 16)
format: Output format - "hex", "base64", or "string" (default: "hex")
port: Ghidra instance port (optional)
Returns:
Memory contents in the requested format
"""
if not address:
return {
"success": False,
"error": {
"code": "MISSING_PARAMETER",
"message": "Address parameter is required",
},
}
try:
port = self.get_instance_port(port)
except ValueError as e:
return {"success": False, "error": {"code": "NO_INSTANCE", "message": str(e)}}
params = {
"address": address,
"length": length,
"format": format,
}
response = self.safe_get(port, "memory", params)
simplified = self.simplify_response(response)
if "result" in simplified and isinstance(simplified["result"], dict):
result = simplified["result"]
memory_info = {
"success": True,
"address": result.get("address", address),
"length": result.get("bytesRead", length),
"format": format,
}
if "hexBytes" in result:
memory_info["hexBytes"] = result["hexBytes"]
if "rawBytes" in result:
memory_info["rawBytes"] = result["rawBytes"]
return memory_info
return simplified
@mcp_tool()
def memory_write(
self,
address: str,
bytes_data: str,
format: str = "hex",
port: Optional[int] = None,
) -> Dict[str, Any]:
"""Write bytes to memory (use with caution).
Args:
address: Memory address in hex format
bytes_data: Data to write (format depends on 'format' parameter)
format: Input format - "hex", "base64", or "string" (default: "hex")
port: Ghidra instance port (optional)
Returns:
Operation result
"""
if not address:
return {
"success": False,
"error": {
"code": "MISSING_PARAMETER",
"message": "Address parameter is required",
},
}
if not bytes_data:
return {
"success": False,
"error": {
"code": "MISSING_PARAMETER",
"message": "Bytes parameter is required",
},
}
try:
port = self.get_instance_port(port)
except ValueError as e:
return {"success": False, "error": {"code": "NO_INSTANCE", "message": str(e)}}
payload = {
"bytes": bytes_data,
"format": format,
}
response = self.safe_patch(port, f"programs/current/memory/{address}", payload)
return self.simplify_response(response)