patcher.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import sys
  2. import os
  3. # Agregar el directorio padre al path para importar config
  4. sys.path.append(os.path.dirname(os.path.abspath(__file__)))
  5. from config import TARGET_PROCESS, UI_MESSAGES
  6. from core.memory_manager import MemoryManager
  7. from patterns.pattern_searcher import StaminaPatternSearcher, SpeedPatternSearcher
  8. from patches.patch_factory import PatchFactory
  9. from utils.helpers import HexDumper, BackupManager, UserInterface
  10. class AdvancedPatcher:
  11. """Clase principal del patcher que coordina todos los módulos (Facade Pattern)"""
  12. def __init__(self):
  13. self.memory_manager = MemoryManager()
  14. self.patch_factory = PatchFactory()
  15. self.hex_dumper = HexDumper()
  16. self.backup_manager = BackupManager(self.memory_manager)
  17. self.ui = UserInterface()
  18. self.target_process = TARGET_PROCESS['name']
  19. def show_patch_menu(self) -> tuple:
  20. """Muestra el menú de selección de parches"""
  21. print("\n🎯 Selecciona el tipo de parche a aplicar:")
  22. print("1. Stamina infinita")
  23. print("2. Velocidad de movimiento")
  24. print("3. Salir")
  25. while True:
  26. try:
  27. choice = input("\n➤ Ingresa tu opción (1-3): ").strip()
  28. if choice == '1':
  29. return ('stamina', None)
  30. elif choice == '2':
  31. return self.show_speed_menu()
  32. elif choice == '3':
  33. return (None, None)
  34. else:
  35. print("❌ Opción inválida. Por favor ingresa 1, 2 o 3.")
  36. except KeyboardInterrupt:
  37. return (None, None)
  38. def show_speed_menu(self) -> tuple:
  39. """Muestra el menú de selección de velocidad"""
  40. multipliers = self.patch_factory.get_speed_multipliers()
  41. print("\n🏃 Selecciona el multiplicador de velocidad:")
  42. for i, mult in enumerate(multipliers, 1):
  43. print(f"{i}. {mult}")
  44. while True:
  45. try:
  46. choice = input(f"\n➤ Ingresa tu opción (1-{len(multipliers)}): ").strip()
  47. try:
  48. index = int(choice) - 1
  49. if 0 <= index < len(multipliers):
  50. return ('speed', multipliers[index])
  51. else:
  52. print(f"❌ Opción inválida. Por favor ingresa un número entre 1 y {len(multipliers)}.")
  53. except ValueError:
  54. print("❌ Por favor ingresa un número válido.")
  55. except KeyboardInterrupt:
  56. return (None, None)
  57. def apply_patch(self, patch_type: str, speed_multiplier: str = None) -> bool:
  58. """Aplica el parche especificado usando todos los módulos"""
  59. # Buscar y abrir el proceso
  60. if not self.memory_manager.open_process(self.target_process):
  61. print(UI_MESSAGES['error']['process_not_found'].format(process_name=self.target_process))
  62. return False
  63. # Seleccionar el buscador de patrones apropiado
  64. if patch_type == 'stamina':
  65. pattern_searcher = StaminaPatternSearcher()
  66. print(UI_MESSAGES['info']['searching_stamina'])
  67. elif patch_type == 'speed':
  68. pattern_searcher = SpeedPatternSearcher()
  69. print(UI_MESSAGES['info']['searching_speed'])
  70. else:
  71. print(f"❌ Tipo de parche no soportado: {patch_type}")
  72. return False
  73. # Buscar patrones
  74. found_addresses = pattern_searcher.search(self.memory_manager)
  75. if not found_addresses:
  76. print(UI_MESSAGES['error']['no_patterns_found'])
  77. return False
  78. # Mostrar direcciones encontradas
  79. self.ui.print_found_addresses(found_addresses)
  80. # Seleccionar dirección objetivo
  81. target_address = self.ui.select_target_address(found_addresses)
  82. # Crear el parche
  83. if patch_type == 'speed' and speed_multiplier:
  84. patch = self.patch_factory.create_patch(patch_type, speed_multiplier=speed_multiplier)
  85. else:
  86. patch = self.patch_factory.create_patch(patch_type)
  87. if not patch:
  88. print(f"❌ No se pudo crear el parche de {patch_type}")
  89. return False
  90. print(f"\n📋 {patch.get_description()}")
  91. # Leer código original
  92. original_size = patch.get_patch_size()
  93. original_code = self.memory_manager.read_memory(target_address, original_size)
  94. if not original_code:
  95. print("❌ No se pudo leer el código original")
  96. return False
  97. # Crear backup
  98. self.backup_manager.backup_original_code(target_address, len(original_code))
  99. # Mostrar código original
  100. print(UI_MESSAGES['info']['original_code'])
  101. self.hex_dumper.print_hex_dump(original_code, target_address)
  102. # Generar datos del parche
  103. patch_data = patch.create_patch(original_code)
  104. # Mostrar código del parche
  105. print(UI_MESSAGES['info']['patch_to_apply'])
  106. self.hex_dumper.print_hex_dump(patch_data)
  107. # Confirmar aplicación
  108. if not self.ui.confirm_patch():
  109. print(UI_MESSAGES['error']['operation_cancelled'])
  110. return False
  111. # Aplicar el parche
  112. print(UI_MESSAGES['info']['applying_patch'])
  113. if self.memory_manager.write_memory(target_address, patch_data):
  114. print(UI_MESSAGES['success']['patch_applied'])
  115. # Verificar que el patch se escribió correctamente
  116. verification_data = self.memory_manager.read_memory(target_address, len(patch_data))
  117. if verification_data == patch_data:
  118. print(UI_MESSAGES['success']['verification_successful'])
  119. return True
  120. else:
  121. print(UI_MESSAGES['error']['verification_failed'])
  122. return False
  123. else:
  124. print(UI_MESSAGES['error']['patch_failed'])
  125. return False
  126. def cleanup(self):
  127. """Limpia los recursos utilizados"""
  128. self.memory_manager.close_process()
  129. def run(self) -> bool:
  130. """Ejecuta el proceso completo de patcheo"""
  131. print(UI_MESSAGES['info']['starting_patch_process'])
  132. success = False
  133. try:
  134. # Mostrar menú de selección
  135. patch_type, speed_multiplier = self.show_patch_menu()
  136. if patch_type is None:
  137. print(UI_MESSAGES['info']['goodbye'])
  138. return False
  139. success = self.apply_patch(patch_type, speed_multiplier)
  140. if success:
  141. print(UI_MESSAGES['success']['patching_completed'])
  142. if patch_type == 'stamina':
  143. print(UI_MESSAGES['success']['stamina_maintained'])
  144. elif patch_type == 'speed':
  145. print(UI_MESSAGES['success']['speed_modified'])
  146. else:
  147. print(UI_MESSAGES['error']['patching_failed'])
  148. except Exception as e:
  149. print(UI_MESSAGES['error']['patching_error'].format(error=e))
  150. finally:
  151. self.cleanup()
  152. return success