/// <summary> /// Called when the user clicks the "'Attach to' (or 'Detach from') game" button. /// </summary> /// <param name="sender">Object which sent the event.</param> /// <param name="e">Arguments from the event.</param> private void ButtonClickAttachToGame(object sender, RoutedEventArgs e) { // Is the trainer currently attached to the game's process? if (GameMemoryIO.Attached) { DetachFromGame(); } else { // Try to find the game's process Process gameProcess = Process.GetProcessesByName(GAME_PROCESS_NAME).FirstOrDefault(); if (gameProcess != null) { // Try to attach to the game's process if (GameMemoryIO.AttachToProcess(gameProcess)) { // Inject the trainer's code and variables into the game's memory! GameMemoryInjector.Inject(); // When the game's process exits, the MainWindow's dispatcher is used to invoke the DetachFromGame() method // in the same thread which "runs" our MainWindow GameMemoryIO.TargetProcess.EnableRaisingEvents = true; GameMemoryIO.TargetProcess.Exited += (caller, args) => { this.Dispatcher.Invoke(() => { this.DetachFromGame(); }); }; #if DEBUG // In debug mode, print some useful debug information Console.WriteLine("[DEBUG]"); Console.WriteLine("Attached to process: {0} (PID: {1}", GameMemoryIO.TargetProcess.ProcessName, GameMemoryIO.TargetProcess.Id); Console.WriteLine("Base injection address: 0x{0}", ((long)GameMemoryInjector.BaseInjectionAddress).ToString("X8")); Console.WriteLine("Injected code caves:"); foreach (ECodeCave curCodeCave in Enum.GetValues(typeof(ECodeCave))) { Console.WriteLine(" {0} at 0x{1}", curCodeCave, ((long)GameMemoryInjector.InjectedCodeCaveAddress[curCodeCave]).ToString("X8")); } Console.WriteLine("Injected variables:"); foreach (EVariable curVariable in Enum.GetValues(typeof(EVariable))) { Console.WriteLine(" {0} at 0x{1}", curVariable, ((long)GameMemoryInjector.InjectedVariableAddress[curVariable]).ToString("X8")); } #endif } else { MessageBox.Show(this, Properties.Resources.strMsgFailedToAttach, Properties.Resources.strMsgFailedToAttachCaption, MessageBoxButton.OK, MessageBoxImage.Exclamation); } } else { MessageBox.Show(this, Properties.Resources.strMsgGamesProcessNotFound, Properties.Resources.strMsgGamesProcessNotFoundCaption, MessageBoxButton.OK, MessageBoxImage.Exclamation); } } }
/// <summary>Starts a timer which is responsible for periodically looking for the game's process.</summary> private void StartLookingForGameProcess() { // Define the callback function to be used for the timer TimerCallback timerCallback = ( object state ) => { // Force timer's task to be executed in the SAME THREAD as the MainWindow this.Dispatcher.Invoke(() => { // This flag controls whether the timer used for looking for the game's process should be restarted or not bool bRestartLookForGameTimer = true; // Try to find the game's process Process gameProcess = Process.GetProcessesByName(GAME_PROCESS_NAME).FirstOrDefault(); if (gameProcess != null) { // Try to attach to the game's process if (GameMemoryIO.AttachToProcess(gameProcess)) { // Inject the trainer's code and variables into the game's memory! GameMemoryInjector.Inject(); // When the game's process exits, the MainWindow's dispatcher is used to invoke the DetachFromGame() method // in the same thread which "runs" our MainWindow GameMemoryIO.TargetProcess.EnableRaisingEvents = true; GameMemoryIO.TargetProcess.Exited += (caller, args) => { this.Dispatcher.Invoke(() => { this.DetachFromGame(); }); }; // Register all of the memory alteration sets that the trainer has IntPtr mainModuleAddress = GameMemoryIO.TargetProcess.MainModule.BaseAddress; RegisterMemoryAlterationSets(mainModuleAddress); // Enable the cheats that the user has checked in the trainer's interface foreach (ECheat curEnabledCheat in m_enabledCheats) { GameMemoryInjector.SetMemoryAlterationsActive(curEnabledCheat, true); } // In DEBUG mode, print some debugging information that might be interesting when developing cheats #if DEBUG int longestCodeCaveNameLength = 0; foreach (ECodeCave curCodeCave in Enum.GetValues(typeof(ECodeCave))) { longestCodeCaveNameLength = Math.Max(longestCodeCaveNameLength, curCodeCave.ToString().Length); } int longestVariableNameLength = 0; foreach (EVariable curVariable in Enum.GetValues(typeof(EVariable))) { longestVariableNameLength = Math.Max(longestVariableNameLength, curVariable.ToString().Length); } Console.WriteLine("[INJECTED: {0}]", DateTime.Now.ToString("yyyy-MM-dd HH':'mm':'ss")); Console.WriteLine("PID: {0}", GameMemoryIO.TargetProcess.Id.ToString("X8")); Console.WriteLine("Main Module: {0} (base address: 0x{1})", GameMemoryIO.TargetProcess.MainModule.ModuleName, mainModuleAddress.ToString("X8")); Console.WriteLine("Injected CODE CAVES:"); foreach (ECodeCave curCodeCave in Enum.GetValues(typeof(ECodeCave))) { Console.WriteLine(" {0}: 0x{1}", curCodeCave.ToString().PadLeft(longestCodeCaveNameLength), GameMemoryInjector.GetInjectedCodeCaveAddress(curCodeCave).ToString("X8")); } Console.WriteLine("Injected VARIABLES:"); foreach (EVariable curVariable in Enum.GetValues(typeof(EVariable))) { Console.WriteLine(" {0}: 0x{1}", curVariable.ToString().PadLeft(longestVariableNameLength), GameMemoryInjector.GetInjectedVariableAddress(curVariable).ToString("X8")); } #endif // The timer which looks for the game shouldn't be restarted, as the game has already been found bRestartLookForGameTimer = false; } else { // Show a message box telling the user that the trainer has failed to attach to the game's process. MessageBox.Show(this, Properties.Resources.strMsgFailedToAttach, Properties.Resources.strMsgFailedToAttachCaption, MessageBoxButton.OK, MessageBoxImage.Exclamation); } } // RESTART the timer as a ONE-SHOT timer if (bRestartLookForGameTimer) { m_gameSearchTimer.Change(TIMER_LOOK_FOR_GAME_PROCESS_PERIOD_MS, Timeout.Infinite); } }); }; // Start the timer as a ONE-SHOT timer m_gameSearchTimer = new Timer(timerCallback, null, TIMER_LOOK_FOR_GAME_PROCESS_PERIOD_MS, Timeout.Infinite); }
/// <summary>Starts a timer which is responsible for periodically looking for the game's process.</summary> private void StartLookingForGameProcess() { // Define the callback function to be used for the timer TimerCallback timerCallback = ( object state ) => { // Force timer's task to be executed in the SAME THREAD as the MainWindow this.Dispatcher.Invoke(() => { // This flag controls whether the timer used for looking for the game's process should be restarted or not bool bRestartLookForGameTimer = true; // Try to find the game's process Process gameProcess = Process.GetProcessesByName(GAME_PROCESS_NAME).FirstOrDefault(); if (gameProcess != null) { // Try to attach to the game's process if (GameMemoryIO.AttachToProcess(gameProcess)) { // Inject the trainer's code and variables into the game's memory! GameMemoryInjector.Inject(); // When the game's process exits, the MainWindow's dispatcher is used to invoke the DetachFromGame() method // in the same thread which "runs" our MainWindow GameMemoryIO.TargetProcess.EnableRaisingEvents = true; GameMemoryIO.TargetProcess.Exited += (caller, args) => { this.Dispatcher.Invoke(() => { this.DetachFromGame(); }); }; // Build the cheat activation steps... IntPtr mainModuleAddress = GameMemoryIO.TargetProcess.MainModule.BaseAddress; GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatHPHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x5866B, ECodeCave.evCodeCaveHPHack, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatManaHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x11B61E8, ECodeCave.evCodeCaveManaHack, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSkillPointsHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x14D60, ECodeCave.evCodeCaveSkillPointsHack1, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSkillPointsHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x14E90, ECodeCave.evCodeCaveSkillPointsHack2, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSkillPointsHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x14FC0, ECodeCave.evCodeCaveSkillPointsHack3, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSkillPointsHack, new MemoryAlterationNOP(GameMemoryIO, mainModuleAddress + 0x14C46, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSkillPointsHack, new MemoryAlterationNOP(GameMemoryIO, mainModuleAddress + 0x14D76, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSkillPointsHack, new MemoryAlterationNOP(GameMemoryIO, mainModuleAddress + 0x14EA6, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatOneHitKillsHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x5A22E4, ECodeCave.evCodeCaveOneHitKills, 6)); // Enable the code cave that keeps track of the address of the player's current character's HP variable m_memAlterationStorePlayerHPAddress = new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x117A80E, ECodeCave.evCodeCaveStorePtrCharHP, 6); m_memAlterationStorePlayerHPAddress.SetEnabled(GameMemoryInjector, true); // Enable the cheats that the user has checked in the trainer's interface foreach (ECheat curEnabledCheat in m_enabledCheats) { GameMemoryInjector.SetMemoryAlterationsActive(curEnabledCheat, true); } // The timer which looks for the game shouldn't be restarted, as the game has already been found bRestartLookForGameTimer = false; } else { MessageBox.Show(this, Properties.Resources.strMsgFailedToAttach, Properties.Resources.strMsgFailedToAttachCaption, MessageBoxButton.OK, MessageBoxImage.Exclamation); } } // RESTART the timer as a ONE-SHOT timer if (bRestartLookForGameTimer) { m_gameSearchTimer.Change(TIMER_LOOK_FOR_GAME_PROCESS_PERIOD_MS, Timeout.Infinite); } }); }; // Start the timer as a ONE-SHOT timer m_gameSearchTimer = new Timer(timerCallback, null, TIMER_LOOK_FOR_GAME_PROCESS_PERIOD_MS, Timeout.Infinite); }
/// <summary> /// Called when the user clicks the "'Attach to' (or 'Detach from') game" button. /// </summary> /// <param name="sender">Object which sent the event.</param> /// <param name="e">Arguments from the event.</param> private void ButtonClickAttachToGame(object sender, RoutedEventArgs e) { // Is the trainer currently attached to the game's process? if (GameMemoryIO.Attached) { DetachFromGame(); } else { // Try to find the game's process Process gameProcess = Process.GetProcessesByName(GAME_PROCESS_NAME).FirstOrDefault(); if (gameProcess != null) { // Try to attach to the game's process if (GameMemoryIO.AttachToProcess(gameProcess)) { // Inject the trainer's code and variables into the game's memory! GameMemoryInjector.Inject(); // When the game's process exits, the MainWindow's dispatcher is used to invoke the DetachFromGame() method // in the same thread which "runs" our MainWindow GameMemoryIO.TargetProcess.EnableRaisingEvents = true; GameMemoryIO.TargetProcess.Exited += (caller, args) => { this.Dispatcher.Invoke(() => { this.DetachFromGame(); }); }; // When trainer's code is injected into the game's memory space, always activate (manually) the code cave that keeps track of the player's HP variable's address IntPtr mainModuleAddress = GameMemoryIO.TargetProcess.MainModule.BaseAddress; m_memAlterationHPAddressTracker = new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x37D9BB, ECodeCave.evCodeCaveHPAddressTracker, 8); m_memAlterationHPAddressTracker.SetEnabled(GameMemoryInjector, true); // Build the cheat activation steps... GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatHPHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x37DABF, ECodeCave.evCodeCaveHPHack, 7)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatMoneyHack, new MemoryAlterationNOP(GameMemoryIO, mainModuleAddress + 0x4BED25, 3)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatMoneyHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x4B074, ECodeCave.evCodeCaveMoneyHack, 5)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSaltsHack, new MemoryAlterationNOP(GameMemoryIO, mainModuleAddress + 0x88079E, 3)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSaltsHack, new MemoryAlterationX86FarJump(GameMemoryIO, mainModuleAddress + 0x6A0048, ECodeCave.evCodeCaveSaltsHack, EJumpInstructionType.evJMP, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatLockpickHack, new MemoryAlterationNOP(GameMemoryIO, mainModuleAddress + 0x67B094, 3)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatLockpickHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x212C8B, ECodeCave.evCodeCaveLockpicksHack, 5)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatAmmoHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x887920, ECodeCave.evCodeCaveAmmoHack, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatOneHitKill, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x9A690, ECodeCave.evCodeCaveOneHitKill1, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatOneHitKill, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x3D2B10, ECodeCave.evCodeCaveOneHitKill2, 6)); GameMemoryInjector.AddMemoryAlteration(ECheat.evCheatSongbirdHack, new MemoryAlterationX86Call(GameMemoryIO, mainModuleAddress + 0x6CEC6D, ECodeCave.evCodeCaveSongBirdHack, 8)); } else { MessageBox.Show(this, Properties.Resources.strMsgFailedToAttach, Properties.Resources.strMsgFailedToAttachCaption, MessageBoxButton.OK, MessageBoxImage.Exclamation); } } else { MessageBox.Show(this, Properties.Resources.strMsgGamesProcessNotFound, Properties.Resources.strMsgGamesProcessNotFoundCaption, MessageBoxButton.OK, MessageBoxImage.Exclamation); } } }