"""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)