pattern_searcher.py 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. from abc import ABC, abstractmethod
  2. from typing import List, Tuple, Dict, Optional
  3. import sys
  4. import os
  5. # Agregar el directorio padre al path para importar config
  6. sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  7. from config import MEMORY_SEARCH_CONFIG, UI_MESSAGES
  8. from core.memory_manager import MemoryManager
  9. class PatternSearcher(ABC):
  10. """Interfaz base para buscadores de patrones (Strategy Pattern)"""
  11. def __init__(self):
  12. pass
  13. @abstractmethod
  14. def get_patterns(self) -> Dict[str, Tuple[bytes, List[str]]]:
  15. """Retorna los patrones a buscar"""
  16. pass
  17. @abstractmethod
  18. def search(self, memory_manager: MemoryManager) -> List[Tuple[str, int]]:
  19. """Busca los patrones en memoria"""
  20. pass
  21. def pattern_matches(self, data: bytes, pattern: bytes, mask: List[str], offset: int) -> bool:
  22. """Verifica si un patrón coincide en una posición específica"""
  23. pattern_len = len(pattern)
  24. if offset + pattern_len > len(data):
  25. return False
  26. data_slice = data[offset:offset + pattern_len]
  27. for i, (p_byte, m_char) in enumerate(zip(pattern, mask)):
  28. if m_char != '?' and data_slice[i] != p_byte:
  29. return False
  30. return True
  31. class StaminaPatternSearcher(PatternSearcher):
  32. """Buscador específico para patrones de stamina"""
  33. def get_patterns(self) -> Dict[str, Tuple[bytes, List[str]]]:
  34. """Define los patrones específicos para stamina"""
  35. return {
  36. "stamina_pattern_1": (
  37. bytes([0x75, 0x00, 0xF3, 0x0F, 0x10, 0x44, 0x24, 0x08,
  38. 0xF3, 0x0F, 0x5A, 0xC0, 0xF2, 0x0F, 0x5A, 0xE8,
  39. 0xF3, 0x0F, 0x11, 0xAE, 0x8C, 0x01, 0x00, 0x00]),
  40. ['x', '?', 'x', 'x', 'x', 'x', 'x', 'x',
  41. 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
  42. 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x']
  43. )
  44. }
  45. def search(self, memory_manager: MemoryManager) -> List[Tuple[str, int]]:
  46. """Busca patrones de stamina en memoria"""
  47. patterns = self.get_patterns()
  48. regions = memory_manager.get_memory_regions()
  49. found_addresses = []
  50. print(UI_MESSAGES['info']['searching_patterns'].format(region_count=len(regions)))
  51. # Pre-calcular longitudes de patrones
  52. pattern_info = {name: (pattern, mask, len(pattern))
  53. for name, (pattern, mask) in patterns.items()}
  54. for region_idx, region in enumerate(regions):
  55. print(f" Región {region_idx + 1}/{len(regions)}: 0x{region['base']:X} - 0x{region['base'] + region['size']:X}")
  56. # Configuración optimizada de chunks desde config
  57. chunk_size = MEMORY_SEARCH_CONFIG['chunk_size']
  58. overlap = MEMORY_SEARCH_CONFIG['overlap']
  59. for offset in range(0, region['size'], chunk_size):
  60. current_address = region['base'] + offset
  61. read_size = min(chunk_size + overlap, region['size'] - offset)
  62. data = memory_manager.read_memory(current_address, read_size)
  63. if not data:
  64. continue
  65. # Buscar cada patrón
  66. data_len = len(data)
  67. for pattern_name, (pattern, mask, pattern_len) in pattern_info.items():
  68. search_limit = data_len - pattern_len + 1
  69. for i in range(search_limit):
  70. if self.pattern_matches(data, pattern, mask, i):
  71. found_address = current_address + i
  72. found_addresses.append((pattern_name, found_address))
  73. print(UI_MESSAGES['info']['pattern_found'].format(pattern_name=pattern_name, address=found_address))
  74. print(" 🛑 Deteniendo búsqueda - primer patrón encontrado")
  75. return found_addresses
  76. return found_addresses