Skip to main content
Glama
0xhackerfren

Frida Game Hacking MCP

by 0xhackerfren

scan_next

Refine memory scan results by searching for a specific value to narrow down addresses in game hacking and reverse engineering processes.

Instructions

Narrow scan results with new value.

Args:
    value: New value to search for

Returns:
    Number of remaining addresses.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
valueYes

Implementation Reference

  • The scan_next tool handler: narrows previous scan results by batch-reading memory from candidate addresses via Frida scripts and filtering those whose current value bytes match the packed new value.
    @mcp.tool()
    def scan_next(value: Union[int, float, str]) -> Dict[str, Any]:
        """
        Narrow scan results with new value.
        
        Args:
            value: New value to search for
        
        Returns:
            Number of remaining addresses.
        """
        global _session
        
        if not _session.is_attached():
            return {"error": "Not attached. Use attach() first."}
        
        if not _session.scan_state.scan_active:
            return {"error": "No active scan. Use scan_value() first."}
        
        try:
            value_type = _session.scan_state.value_type
            value_size = _get_value_size(value_type)
            
            if value_type == "string":
                expected_hex = value.encode('utf-8').hex()
            else:
                expected_hex = _pack_value(value, value_type).hex()
            
            addresses = _session.scan_state.results
            if not addresses:
                return {"success": True, "value": value, "remaining": 0}
            
            batch_size = 1000
            new_results = []
            
            for batch_start in range(0, len(addresses), batch_size):
                batch = addresses[batch_start:batch_start + batch_size]
                addr_list = ", ".join(f'"{hex(a)}"' for a in batch)
                
                script_code = f"""
                var addresses = [{addr_list}];
                var size = {value_size};
                var expected = "{expected_hex}";
                var matches = [];
                
                for (var i = 0; i < addresses.length; i++) {{
                    try {{
                        var data = Memory.readByteArray(ptr(addresses[i]), size);
                        var hex = '';
                        var bytes = new Uint8Array(data);
                        for (var j = 0; j < bytes.length; j++) {{
                            hex += ('0' + bytes[j].toString(16)).slice(-2);
                        }}
                        if (hex === expected) matches.push(addresses[i]);
                    }} catch (e) {{ }}
                }}
                send(JSON.stringify(matches));
                """
                
                result_data = []
                def on_message(message, data):
                    if message['type'] == 'send':
                        result_data.append(message['payload'])
                
                script = _session.session.create_script(script_code)
                script.on('message', on_message)
                script.load()
                script.unload()
                
                if result_data:
                    import json
                    matches = json.loads(result_data[0])
                    new_results.extend([int(a, 16) for a in matches])
            
            _session.scan_state.results = new_results
            _session.scan_state.last_values = {addr: value for addr in new_results}
            
            return {
                "success": True,
                "value": value,
                "remaining": len(new_results),
                "message": f"Narrowed to {len(new_results)} addresses."
            }
        
        except Exception as e:
            return {"error": f"Scan next failed: {str(e)}"}
  • Dataclass used by scan_next to maintain scan results list, last known values per address, value type, and active state.
    class ScanState:
        """Tracks memory scan state for Cheat Engine-style scanning."""
        value_type: str = ""
        results: List[int] = field(default_factory=list)
        last_values: Dict[int, Any] = field(default_factory=dict)
        scan_active: bool = False
  • Helper function used by scan_next to determine byte size of value_type for memory reads.
    def _get_value_size(value_type: str) -> int:
        """Get byte size for value type."""
        sizes = {
            "int8": 1, "uint8": 1,
            "int16": 2, "uint16": 2,
            "int32": 4, "uint32": 4,
            "int64": 8, "uint64": 8,
            "float": 4, "double": 8
        }
        return sizes.get(value_type, 4)
  • Helper function used by scan_next to pack the new value into bytes/hex for comparison in Frida script.
    def _pack_value(value: Any, value_type: str) -> bytes:
        """Pack value to bytes based on type."""
        formats = {
            "int8": "<b", "uint8": "<B",
            "int16": "<h", "uint16": "<H",
            "int32": "<i", "uint32": "<I",
            "int64": "<q", "uint64": "<Q",
            "float": "<f", "double": "<d"
        }
        fmt = formats.get(value_type)
        if fmt:
            return struct.pack(fmt, value)
        elif value_type == "string":
            return value.encode('utf-8') + b'\x00'
        return struct.pack("<i", int(value))

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xhackerfren/frida-game-hacking-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server