Skip to main content
Glama

scan_changed

Identifies memory addresses where values have changed since the previous scan, enabling detection of dynamic game variables for reverse engineering and modification.

Instructions

Find addresses where value has changed since last scan. Returns: Number of changed addresses.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • MCP tool handler implementing scan_changed: filters scan results to addresses where value changed since last scan using batched Frida Memory.readByteArray and comparison to stored last_values. Updates scan_state.results and last_values.
    @mcp.tool() def scan_changed() -> Dict[str, Any]: """ Find addresses where value has changed since last scan. Returns: Number of changed 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) addresses = [a for a in _session.scan_state.results if a in _session.scan_state.last_values] if not addresses: return {"success": True, "remaining": 0} expected_map = {} for addr in addresses: last_val = _session.scan_state.last_values[addr] if value_type == "string": expected_map[addr] = str(last_val).encode('utf-8').hex() else: expected_map[addr] = _pack_value(last_val, value_type).hex() batch_size = 1000 new_results = [] new_last_values = {} for batch_start in range(0, len(addresses), batch_size): batch = addresses[batch_start:batch_start + batch_size] addr_expected = ", ".join(f'["{hex(a)}", "{expected_map[a]}"]' for a in batch) script_code = f""" var pairs = [{addr_expected}]; var size = {value_size}; var changed = []; for (var i = 0; i < pairs.length; i++) {{ try {{ var data = Memory.readByteArray(ptr(pairs[i][0]), 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 !== pairs[i][1]) {{ changed.push({{address: pairs[i][0], hex: hex}}); }} }} catch (e) {{ }} }} send(JSON.stringify(changed)); """ 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 changed = json.loads(result_data[0]) for c in changed: addr = int(c['address'], 16) try: current_value = _unpack_value(bytes.fromhex(c['hex']), value_type) new_results.append(addr) new_last_values[addr] = current_value except: pass _session.scan_state.results = new_results _session.scan_state.last_values = new_last_values return {"success": True, "remaining": len(new_results)} except Exception as e: return {"error": f"Scan changed failed: {str(e)}"}
  • Dataclass managing global scan state (results list, last_values dict, value_type, active flag) used by scan_changed and related tools.
    @dataclass 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 to unpack raw bytes from memory read into typed value (int/float/string) for scan_changed value comparisons.
    def _unpack_value(data: bytes, value_type: str) -> Any: """Unpack bytes to value 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.unpack(fmt, data)[0] elif value_type == "string": return data.split(b'\x00')[0].decode('utf-8', errors='replace') return struct.unpack("<i", data)[0]
  • Helper returning byte size for value_type used in scan_changed for Memory.readByteArray size.
    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)
  • Tool name 'scan_changed' listed in memory_operations category within list_capabilities tool response.
    "memory_operations": [ "read_memory", "write_memory", "scan_value", "scan_next", "scan_changed", "scan_unchanged", "scan_pattern", "get_scan_results", "clear_scan", "list_memory_regions"

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