iflow-mcp_bethington-cheat-engine-server-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/METADATA +16 -0
  2. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/RECORD +40 -0
  3. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/WHEEL +5 -0
  4. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/top_level.txt +1 -0
  7. server/cheatengine/__init__.py +19 -0
  8. server/cheatengine/ce_bridge.py +1670 -0
  9. server/cheatengine/lua_interface.py +460 -0
  10. server/cheatengine/table_parser.py +1221 -0
  11. server/config/__init__.py +20 -0
  12. server/config/settings.py +347 -0
  13. server/config/whitelist.py +378 -0
  14. server/gui_automation/__init__.py +43 -0
  15. server/gui_automation/core/__init__.py +8 -0
  16. server/gui_automation/core/integration.py +951 -0
  17. server/gui_automation/demos/__init__.py +8 -0
  18. server/gui_automation/demos/basic_demo.py +754 -0
  19. server/gui_automation/demos/notepad_demo.py +460 -0
  20. server/gui_automation/demos/simple_demo.py +319 -0
  21. server/gui_automation/tools/__init__.py +8 -0
  22. server/gui_automation/tools/mcp_tools.py +974 -0
  23. server/main.py +519 -0
  24. server/memory/__init__.py +0 -0
  25. server/memory/analyzer.py +0 -0
  26. server/memory/reader.py +0 -0
  27. server/memory/scanner.py +0 -0
  28. server/memory/symbols.py +0 -0
  29. server/process/__init__.py +16 -0
  30. server/process/launcher.py +608 -0
  31. server/process/manager.py +185 -0
  32. server/process/monitors.py +202 -0
  33. server/process/permissions.py +131 -0
  34. server/process_whitelist.json +119 -0
  35. server/pyautogui/__init__.py +0 -0
  36. server/utils/__init__.py +37 -0
  37. server/utils/data_types.py +368 -0
  38. server/utils/formatters.py +430 -0
  39. server/utils/validators.py +340 -0
  40. server/window_automation/__init__.py +59 -0
@@ -0,0 +1,340 @@
1
+ """
2
+ Validation Utilities
3
+ Input validation and sanitization functions
4
+ """
5
+
6
+ import re
7
+ import logging
8
+ from typing import Optional, Any
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ def validate_address(address_str: str) -> Optional[int]:
13
+ """Validate and parse a memory address string
14
+
15
+ Args:
16
+ address_str: Address string in hex format (e.g., "0x12345678", "12345678")
17
+
18
+ Returns:
19
+ Parsed address as integer, or None if invalid
20
+ """
21
+ try:
22
+ if not isinstance(address_str, str):
23
+ return None
24
+
25
+ # Remove whitespace
26
+ address_str = address_str.strip()
27
+
28
+ if not address_str:
29
+ return None
30
+
31
+ # Handle different hex formats
32
+ if address_str.startswith('0x') or address_str.startswith('0X'):
33
+ address_str = address_str[2:]
34
+
35
+ # Validate hex characters
36
+ if not re.match(r'^[0-9A-Fa-f]+$', address_str):
37
+ return None
38
+
39
+ # Convert to integer
40
+ address = int(address_str, 16)
41
+
42
+ # Basic sanity checks
43
+ if address < 0:
44
+ return None
45
+
46
+ # Check reasonable address bounds
47
+ if address > 0x7FFFFFFFFFFFFFFFFFFF: # 64-bit max
48
+ return None
49
+
50
+ # Warn about suspicious addresses
51
+ if address < 0x1000:
52
+ logger.warning(f"Address {address:X} is in null page range")
53
+
54
+ return address
55
+
56
+ except (ValueError, OverflowError) as e:
57
+ logger.debug(f"Invalid address format '{address_str}': {e}")
58
+ return None
59
+
60
+ def validate_size(size: Any) -> bool:
61
+ """Validate a size parameter
62
+
63
+ Args:
64
+ size: Size value to validate
65
+
66
+ Returns:
67
+ True if valid, False otherwise
68
+ """
69
+ try:
70
+ if not isinstance(size, int):
71
+ if isinstance(size, str):
72
+ size = int(size)
73
+ else:
74
+ return False
75
+
76
+ # Must be positive
77
+ if size <= 0:
78
+ return False
79
+
80
+ # Reasonable upper limit (100MB)
81
+ if size > 100 * 1024 * 1024:
82
+ logger.warning(f"Large size requested: {size} bytes")
83
+ return False
84
+
85
+ return True
86
+
87
+ except (ValueError, TypeError):
88
+ return False
89
+
90
+ def validate_pattern(pattern: str) -> bool:
91
+ """Validate a byte pattern string
92
+
93
+ Args:
94
+ pattern: Pattern string to validate (e.g., "48 8B 05 ?? ?? ?? ??")
95
+
96
+ Returns:
97
+ True if valid, False otherwise
98
+ """
99
+ try:
100
+ if not isinstance(pattern, str):
101
+ return False
102
+
103
+ # Remove extra whitespace
104
+ pattern = re.sub(r'\s+', ' ', pattern.strip())
105
+
106
+ if not pattern:
107
+ return False
108
+
109
+ # Split into byte components
110
+ bytes_parts = pattern.split(' ')
111
+
112
+ for byte_part in bytes_parts:
113
+ if byte_part in ['??', '?']:
114
+ continue # Wildcard is valid
115
+
116
+ # Must be valid hex byte
117
+ if not re.match(r'^[0-9A-Fa-f]{1,2}$', byte_part):
118
+ return False
119
+
120
+ # Convert to ensure it's a valid byte value
121
+ byte_val = int(byte_part, 16)
122
+ if byte_val > 255:
123
+ return False
124
+
125
+ return True
126
+
127
+ except (ValueError, TypeError):
128
+ return False
129
+
130
+ def validate_process_identifier(identifier: str) -> bool:
131
+ """Validate a process identifier (PID or name)
132
+
133
+ Args:
134
+ identifier: Process identifier to validate
135
+
136
+ Returns:
137
+ True if valid, False otherwise
138
+ """
139
+ try:
140
+ if not isinstance(identifier, str):
141
+ return False
142
+
143
+ identifier = identifier.strip()
144
+
145
+ if not identifier:
146
+ return False
147
+
148
+ # Check if it's a PID (numeric)
149
+ if identifier.isdigit():
150
+ pid = int(identifier)
151
+ return 1 <= pid <= 65535 # Reasonable PID range
152
+
153
+ # Check if it's a valid process name
154
+ # Allow alphanumeric, underscore, dash, dot
155
+ if re.match(r'^[a-zA-Z0-9_\-\.]+$', identifier):
156
+ return len(identifier) <= 255 # Reasonable name length
157
+
158
+ return False
159
+
160
+ except (ValueError, TypeError):
161
+ return False
162
+
163
+ def validate_data_type(data_type: str) -> bool:
164
+ """Validate a data type string
165
+
166
+ Args:
167
+ data_type: Data type to validate
168
+
169
+ Returns:
170
+ True if valid, False otherwise
171
+ """
172
+ valid_types = {
173
+ 'raw', 'bytes',
174
+ 'int8', 'uint8', 'byte',
175
+ 'int16', 'uint16', 'short', 'ushort',
176
+ 'int32', 'uint32', 'int', 'uint', 'dword',
177
+ 'int64', 'uint64', 'long', 'ulong', 'qword',
178
+ 'float', 'single',
179
+ 'double',
180
+ 'string', 'str', 'ascii', 'utf8', 'utf16',
181
+ 'pointer', 'ptr',
182
+ 'auto', 'structure', 'struct'
183
+ }
184
+
185
+ if not isinstance(data_type, str):
186
+ return False
187
+
188
+ return data_type.lower() in valid_types
189
+
190
+ def sanitize_filename(filename: str) -> str:
191
+ """Sanitize a filename for safe file operations
192
+
193
+ Args:
194
+ filename: Filename to sanitize
195
+
196
+ Returns:
197
+ Sanitized filename
198
+ """
199
+ if not isinstance(filename, str):
200
+ return "invalid_filename"
201
+
202
+ # Remove or replace invalid characters
203
+ sanitized = re.sub(r'[<>:"/\\|?*]', '_', filename)
204
+
205
+ # Remove control characters
206
+ sanitized = ''.join(char for char in sanitized if ord(char) >= 32)
207
+
208
+ # Limit length
209
+ sanitized = sanitized[:255]
210
+
211
+ # Ensure it's not empty or just dots
212
+ if not sanitized or sanitized in ['.', '..']:
213
+ sanitized = "unnamed_file"
214
+
215
+ return sanitized
216
+
217
+ def validate_region_list(regions: Any) -> bool:
218
+ """Validate a list of memory regions
219
+
220
+ Args:
221
+ regions: Region list to validate
222
+
223
+ Returns:
224
+ True if valid, False otherwise
225
+ """
226
+ try:
227
+ if not isinstance(regions, list):
228
+ return False
229
+
230
+ if len(regions) > 100: # Reasonable limit
231
+ return False
232
+
233
+ for region in regions:
234
+ if isinstance(region, str):
235
+ # Should be a hex address
236
+ if not validate_address(region):
237
+ return False
238
+ elif isinstance(region, dict):
239
+ # Should have 'base' and 'size' keys
240
+ if 'base' not in region or 'size' not in region:
241
+ return False
242
+ if not validate_address(str(region['base'])):
243
+ return False
244
+ if not validate_size(region['size']):
245
+ return False
246
+ else:
247
+ return False
248
+
249
+ return True
250
+
251
+ except (TypeError, KeyError):
252
+ return False
253
+
254
+ def validate_config_value(key: str, value: Any) -> bool:
255
+ """Validate a configuration value
256
+
257
+ Args:
258
+ key: Configuration key
259
+ value: Value to validate
260
+
261
+ Returns:
262
+ True if valid, False otherwise
263
+ """
264
+ config_validators = {
265
+ 'max_memory_read': lambda v: isinstance(v, int) and 0 < v <= 1024 * 1024 * 1024,
266
+ 'enable_disassembly': lambda v: isinstance(v, bool),
267
+ 'log_level': lambda v: isinstance(v, str) and v.upper() in ['DEBUG', 'INFO', 'WARNING', 'ERROR'],
268
+ 'read_only_mode': lambda v: isinstance(v, bool),
269
+ 'process_whitelist': lambda v: isinstance(v, list) and all(isinstance(p, str) for p in v),
270
+ 'audit_log_path': lambda v: isinstance(v, str) and len(v) > 0,
271
+ 'symbol_cache_size': lambda v: isinstance(v, int) and v >= 0,
272
+ 'scan_chunk_size': lambda v: isinstance(v, int) and 1024 <= v <= 10 * 1024 * 1024,
273
+ }
274
+
275
+ validator = config_validators.get(key)
276
+ if validator:
277
+ try:
278
+ return validator(value)
279
+ except Exception:
280
+ return False
281
+
282
+ # Unknown config key - allow but warn
283
+ logger.warning(f"Unknown configuration key: {key}")
284
+ return True
285
+
286
+ def validate_permissions(access_level: str) -> bool:
287
+ """Validate an access level string
288
+
289
+ Args:
290
+ access_level: Access level to validate
291
+
292
+ Returns:
293
+ True if valid, False otherwise
294
+ """
295
+ valid_levels = {'read', 'debug', 'full'}
296
+
297
+ if not isinstance(access_level, str):
298
+ return False
299
+
300
+ return access_level.lower() in valid_levels
301
+
302
+ def validate_encoding(encoding: str) -> bool:
303
+ """Validate a text encoding string
304
+
305
+ Args:
306
+ encoding: Encoding to validate
307
+
308
+ Returns:
309
+ True if valid, False otherwise
310
+ """
311
+ valid_encodings = {
312
+ 'ascii', 'utf-8', 'utf8', 'utf-16', 'utf16', 'utf-16le', 'utf-16be',
313
+ 'latin1', 'cp1252', 'cp437'
314
+ }
315
+
316
+ if not isinstance(encoding, str):
317
+ return False
318
+
319
+ return encoding.lower() in valid_encodings
320
+
321
+ def sanitize_log_message(message: str) -> str:
322
+ """Sanitize a log message to prevent log injection
323
+
324
+ Args:
325
+ message: Message to sanitize
326
+
327
+ Returns:
328
+ Sanitized message
329
+ """
330
+ if not isinstance(message, str):
331
+ return str(message)
332
+
333
+ # Remove newlines and carriage returns to prevent log injection
334
+ sanitized = message.replace('\n', '\\n').replace('\r', '\\r')
335
+
336
+ # Limit length
337
+ if len(sanitized) > 1000:
338
+ sanitized = sanitized[:997] + "..."
339
+
340
+ return sanitized
@@ -0,0 +1,59 @@
1
+ """
2
+ PyWinAuto Integration Module for MCP Cheat Engine Server
3
+ =======================================================
4
+
5
+ This module provides comprehensive PyWinAuto integration for Windows application
6
+ automation through the MCP Cheat Engine Server.
7
+
8
+ Key Features:
9
+ - Application lifecycle management (launch, attach, close)
10
+ - Window and UI element discovery and manipulation
11
+ - Framework-agnostic automation (Win32, WPF, Qt, etc.)
12
+ - Element-based interaction (more reliable than coordinate-based)
13
+ - Advanced UI navigation and property inspection
14
+ - Integration with MCP server architecture
15
+
16
+ Components:
17
+ - core.integration: Main PyWinAuto controller and automation engine
18
+ - tools.mcp_tools: MCP tool definitions for Claude Desktop integration
19
+ - demos: Example scripts and usage demonstrations
20
+ - tests: Comprehensive testing suite
21
+
22
+ Usage:
23
+ from server.window_automation import get_pywinauto_controller
24
+
25
+ controller = get_pywinauto_controller()
26
+ if controller.available:
27
+ app = controller.connect_application("notepad.exe")
28
+ window = controller.find_window(app, title="Untitled - Notepad")
29
+ controller.type_text(window, "Hello PyWinAuto!")
30
+ """
31
+
32
+ from .core.integration import (
33
+ PyWinAutoController,
34
+ get_pywinauto_controller,
35
+ PYWINAUTO_AVAILABLE
36
+ )
37
+
38
+ from .tools.mcp_tools import (
39
+ ALL_PYWINAUTO_TOOLS,
40
+ PyWinAutoToolHandler
41
+ )
42
+
43
+ __version__ = "1.0.0"
44
+ __author__ = "MCP Cheat Engine Server"
45
+
46
+ __all__ = [
47
+ # Core integration
48
+ "PyWinAutoController",
49
+ "get_pywinauto_controller",
50
+ "PYWINAUTO_AVAILABLE",
51
+
52
+ # MCP tools
53
+ "ALL_PYWINAUTO_TOOLS",
54
+ "PyWinAutoToolHandler",
55
+
56
+ # Version info
57
+ "__version__",
58
+ "__author__"
59
+ ]