/// <summary> /// Shuts down the Reloaded Launcher and launches the currently selected game. /// The parameter of this method allows for the specification OPTIONAL ADDITIONAL arguments such as --log or --attach. /// </summary> /// <param name="localArguments">Additional command line arguments/options to pass to Reloaded-Loader.</param> public static void LaunchLoader(string[] localArguments) { // Build filepath and arguments string filePath = $"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\\Reloaded-Loader.exe"; // Build arguments. List <string> argumentsList = new List <string>() { $"\"{Strings.Common.LoaderSettingConfig}\"", $"\"{Global.CurrentGameConfig.ConfigLocation}\"" }; // We are done here. argumentsList.AddRange(localArguments); // Start process ReloadedProcess process = new ReloadedProcess(filePath, argumentsList.ToArray()); process.ResumeAllThreads(); if (Global.LoaderConfiguration.ExitAfterLaunch) { // Self-shutdown. Shutdown(); } }
/* * ------------------------ * Performing DLL Injection * ------------------------ */ /// <summary> /// Finds the mods that are currently enabled for the game and injects into the target process. /// </summary> /// <param name="gameConfiguration">The game configuration which contains the current directory and list of mods to load.</param> /// <param name="reloadedProcess">The reloaded process to inject the modifications into.</param> public static void LoadMods(GameConfig gameConfiguration, ReloadedProcess reloadedProcess) { // Retrieve list of DLLs to be injected. string[] modLibraries = GetModulesToInject(gameConfiguration); // Initialize DLL Injector DllInjector reloadedClassicDllInjector = new DllInjector(reloadedProcess); // For each DLL file, if the DLL exists, load the DLL. foreach (string modLibrary in modLibraries) { if (File.Exists(modLibrary)) { // To handle plugin support for this one, we pass the parameters onto each plugin and // each plugin on their own can decide whether to manually inject themselves or not. // If they return "true", we go to next file; else we inject normally. bool dllInjected = false; foreach (var plugin in PluginLoader.LoaderEventPlugins) { if (plugin.ManualDllInject((int)reloadedProcess.ProcessId, modLibrary, "Main")) { dllInjected = true; break; } } if (!dllInjected) { InjectDLLDefault(reloadedProcess, reloadedClassicDllInjector, modLibrary, "Main"); } } } }
/// <summary> /// Retrieves the game instance we are going to be hacking as a ReloadedProcess /// </summary> private static void GetGameProcess(string[] originalArguments) { // Fast return if soft reboot (game process killed and restarted itself) if (_gameProcess != null) { return; } // Attach if specified by the user. if (_attachTargetName != null) { // Grab current already running game. _gameProcess = ReloadedProcess.GetProcessByName(_attachTargetName); // Check if gameProcess successfully returned. if (_gameProcess == null && !_autoAttach) { LoaderConsole.PrintFormattedMessage("Error: An active running game instance was not found.", LoaderConsole.PrintErrorMessage); Console.ReadLine(); Shutdown(null, null); } // Wait for new process with autoattach if not found. if (_autoAttach && _gameProcess == null) { Bindings.PrintWarning("Process not running. Waiting in Auto-Attach Mode."); do { _gameProcess = ReloadedProcess.GetProcessByName(_attachTargetName); Thread.Sleep(2); }while (_gameProcess == null); } } // Otherwise start process suspended in Reloaded, hook it, exploit it and resume the intended way. else { _gameProcess = new ReloadedProcess($"{Path.Combine(_gameConfig.GameDirectory, _gameConfig.ExecutableLocation)}", _gameConfig.CommandLineArgs.Split(' ')); // The process handle is 0 if the process failed to initialize. if ((int)_gameProcess.ProcessHandle == 0) { // libReloaded will already print the error message. Console.ReadLine(); Shutdown(null, null); } // Check if the game should run normally to toggle the shim. CheckSteamHack(originalArguments); } // Set binding for target process for memory IO Bindings.TargetProcess = _gameProcess; // Obtain the process start time. if (_gameProcess != null) { _processStartTime = _gameProcess.GetProcessFromReloadedProcess().StartTime; } }
/// <summary> /// Injects itself to the game depending on the individual method chosen either from the commandline or in the launcher. /// By default, Reloaded starts the game and injects immediately into suspended, otherwise if --attach is specified, Reloaded /// tries to hook itself into an already running game/application. /// </summary> /// <param name="arguments">A copy of the arguments passed into the application used for optionally rebooting in x64 mode.</param> private static void InjectByMethod(string[] arguments) { // Fast return if soft reboot (game process killed and restarted itself) if (_gameProcess != null) { return; } // Attach if specified by the user. if (_attachTargetName != null) { // Grab current already running game. _gameProcess = ReloadedProcess.GetProcessByName(_attachTargetName); // Check if gameProcess successfully returned. if (_gameProcess == null) { ConsoleFunctions.PrintMessageWithTime("Error: An active running game instance was not found.", ConsoleFunctions.PrintErrorMessage); Console.ReadLine(); Shutdown(null, null); } // Check if the current running architecture matched ~(32 bit), if not, restart as x64. if (!_gameProcess.CheckArchitectureMatch()) { RebootX64(arguments); } } // Otherwise start process suspended in Reloaded, hook it, exploit it and resume the intended way. else { _gameProcess = new ReloadedProcess($"{Path.Combine(_gameConfig.GameDirectory, _gameConfig.ExecutableLocation)}"); // The process handle is 0 if the process failed to initialize. if ((int)_gameProcess.ProcessHandle == 0) { // libReloaded will already print the error message. Console.ReadLine(); Shutdown(null, null); } // Check if the current running architecture matched ~(32 bit), if not, restart as x64. if (!_gameProcess.CheckArchitectureMatch()) { _gameProcess.KillProcess(); RebootX64(arguments); } } // Set binding for target process for memory IO Bindings.TargetProcess = _gameProcess; // Obtain the process start time. if (_gameProcess != null) { _processStartTime = _gameProcess.GetProcessFromReloadedProcess().StartTime; } }
public static bool WriteMemoryExternalFast(this ReloadedProcess process, IntPtr address, byte[] data) { // Write the process memory. bool success = WriteProcessMemory(process.ProcessHandle, address, data, (IntPtr)data.Length, out _); // Return value return(success); }
/// <summary> /// Verifies whether the architecture of a Reloaded Process matches the architecture of /// the current program. /// </summary> public static bool CheckArchitectureMatch(this ReloadedProcess reloadedProcess) { // Check if Process is x64. Native.IsWow64Process(reloadedProcess.ProcessHandle, out IsGame32Bit); // Compare against current process. return(IsGame32Bit == (!Environment.Is64BitProcess)); }
public static unsafe byte[] ReadMemoryFast(this ReloadedProcess process, IntPtr address, int length) { // Read memory byte[] buffer = new byte[length]; fixed(byte *pBuffer = &buffer[0]) Unsafe.CopyBlock(pBuffer, address.ToPointer(), (uint)length); // Return the buffer. return(buffer); }
public static byte[] ReadMemoryExternalFast(this ReloadedProcess process, IntPtr address, int length) { // Initialize the buffer of required length. byte[] buffer = new byte[length]; // Read from the game memory. ReadProcessMemory(process.ProcessHandle, address, buffer, (IntPtr)length, out _); // Return the buffer. return(buffer); }
private static void InjectDLLDefault(ReloadedProcess reloadedProcess, DllInjector dllInjector, string dllPath, string dllMethodName) { // Allocate Memory for Server Port In Game Memory IntPtr parameterAddress = reloadedProcess.AllocateMemory(IntPtr.Size); // Write Server Port to Game Memory byte[] serverPort = BitConverter.GetBytes(LoaderServer.ServerPort); reloadedProcess.WriteMemoryExternal(parameterAddress, ref serverPort); // Inject the individual DLL. dllInjector.InjectDll(dllPath, parameterAddress, dllMethodName); }
public static unsafe void WriteMemory(this ReloadedProcess process, IntPtr address, byte[] data) { // Mark memory we are writing to as ExecuteReadWrite VirtualProtect(address, (IntPtr)data.Length, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Write the process memory fixed(byte *pData = &data[0]) Unsafe.CopyBlock(address.ToPointer(), pData, (uint)data.Length); // Restore the old memory protection. VirtualProtect(address, (IntPtr)data.Length, oldProtection, out oldProtection); }
/// <summary> /// Initializes the libReloaded bindings used for internal Reloaded Mod Loader functions /// such as printing to buffers, logging and other functions. /// </summary> static void InitBindings() { // Set local game process. Program.GameProcess = ReloadedProcess.GetCurrentProcess(); // Set up Reloaded Mod Loader bindings. Bindings.PrintText += Client.Print; Bindings.PrintError += Client.PrintError; Bindings.PrintInfo += Client.PrintInfo; Bindings.PrintWarning += Client.PrintWarning; Bindings.TargetProcess = Program.GameProcess; }
/// <summary> /// AllocateMemory /// Allows for allocation of memory space inside the target process. /// The return value for this method is the address at which the new memory has been allocated. /// </summary> /// <param name="process">The process object of the game, Process.GetCurrentProcess() if injected into the game.</param> /// <param name="length">Length of free bytes you want to allocate.</param> /// <returns>Base pointer address to the newly allocated memory.</returns> public static IntPtr AllocateMemory(this ReloadedProcess process, int length) { // Call VirtualAllocEx to allocate memory of fixed chosen size. return(VirtualAllocEx ( process.ProcessHandle, IntPtr.Zero, (IntPtr)length, AllocationTypes.Commit | AllocationTypes.Reserve, MemoryProtections.ExecuteReadWrite )); }
public static bool WriteMemoryExternal(this ReloadedProcess process, IntPtr address, byte[] data) { // Mark memory we are writing to as ExecuteReadWrite VirtualProtectEx(process.ProcessHandle, address, (IntPtr)data.Length, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Write the process memory. bool success = WriteProcessMemory(process.ProcessHandle, address, data, (IntPtr)data.Length, out _); // Restore the old memory protection. VirtualProtectEx(process.ProcessHandle, address, (IntPtr)data.Length, oldProtection, out oldProtection); // Return value return(success); }
public static unsafe TType ReadMemoryExternalFastUnsafe <TType>(this ReloadedProcess process, IntPtr address) { // Get type size int size = Unsafe.SizeOf <TType>(); // Initializes the buffer of the length of the data to be read. byte[] buffer = new byte[size]; // Read from the game memory. ReadProcessMemory(process.ProcessHandle, address, buffer, (IntPtr)size, out _); fixed(byte *pBuffer = &buffer[0]) return(Unsafe.Read <TType>(pBuffer)); }
/// <summary> /// Reboots the Reloaded Loader in x64 mode by running the x64 wrapper. /// </summary> /// <param name="arguments">A copy of the arguments originally passed to the starting application.</param> private static void RebootX64(string[] arguments) { // Add quotes to each argument in quotes. for (int x = 0; x < arguments.Length; x++) { arguments[x] = $"\"{arguments[x]}\""; } ReloadedProcess reloadedProcess = new ReloadedProcess($"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\\Reloaded-Wrapper-x64.exe", arguments); reloadedProcess.ResumeAllThreads(); Shutdown(null, null); }
public static byte[] ReadMemoryUnsafe(this ReloadedProcess process, IntPtr address, int length) { // Mark memory we are reading to as ExecuteReadWrite VirtualProtect(address, (IntPtr)length, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Read from the game memory. var buffer = ReadMemoryFast(process, address, length); // Restore the old memory protection. VirtualProtect(address, (IntPtr)length, oldProtection, out oldProtection); // Return the buffer. return(buffer); }
public static TType ReadMemoryUnsafe <TType>(this ReloadedProcess process, IntPtr address) { var size = (uint)Unsafe.SizeOf <TType>(); // Mark memory we are reading to as ExecuteReadWrite VirtualProtect(address, (IntPtr)size, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Read value var value = ReadMemoryFastUnsafe <TType>(process, address); // Restore the old memory protection. VirtualProtect(address, (IntPtr)size, oldProtection, out oldProtection); return(value); }
public static TType ReadMemoryExternalUnsafe <TType>(this ReloadedProcess process, IntPtr address) { // Get type size var size = (IntPtr)Unsafe.SizeOf <TType>(); // Mark memory we are writing to as ExecuteReadWrite VirtualProtectEx(process.ProcessHandle, address, size, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); var value = ReadMemoryExternalFastUnsafe <TType>(process, address); // Restore the old memory protection. VirtualProtectEx(process.ProcessHandle, address, size, oldProtection, out oldProtection); // Return the read memory. return(value); }
/// <summary> /// Shuts down the Reloaded Launcher and launches the currently selected game. /// The parameter of this method allows for the specification OPTIONAL ADDITIONAL arguments such as --log or --attach. /// </summary> /// <param name="extraArguments">Additional command line arguments/options to pass to Reloaded-Loader.</param> public static void LaunchLoader(string[] extraArguments) { // Gets a file path of the loader. string filePath = GetLoaderFilePath(); // Start process ReloadedProcess process = new ReloadedProcess(filePath, GetCommandlineParameters(extraArguments).ToArray()); process.ResumeAllThreads(); // Self-shutdown. if (Global.LoaderConfiguration.ExitAfterLaunch) { Shutdown(); } }
/// <summary> /// Checks whether to reattach Reloaded Mod Loader if the game process /// unexpectedly kills itself and then restarts (a standard for some games' launch procedures). /// </summary> private static void ProcessSelfReattach(string[] args) { // Use stopwatch for soft timing. Stopwatch timeoutStopWatch = new Stopwatch(); timeoutStopWatch.Start(); // Set attach name for reattaching. _attachTargetName = Path.GetFileNameWithoutExtension(_gameConfig.ExecutableLocation); // Spin trying to get game process until timeout. while (timeoutStopWatch.ElapsedMilliseconds < 6000) { // Grab current already running game, did we find it? Not? Try again. ReloadedProcess localGameProcess = ReloadedProcess.GetProcessByName(_attachTargetName); if (localGameProcess == null) { continue; } // Ensure we didn't find some background process that was running all along. if (localGameProcess.GetProcessFromReloadedProcess().StartTime > _processStartTime) { Bindings.PrintInfo($"// Game killed itself, probably due to Steam for restarting. Attempting reattach! | {_attachTargetName}"); Bindings.PrintInfo($"// Consider using the Steam shim."); _gameProcess = localGameProcess; // Disconnect all clients foreach (NetPeer peer in LoaderServer.ReloadedServer.GetPeers()) { LoaderServer.ReloadedServer.DisconnectPeer(peer); } InjectMods(args); // Wait infinitely. while (true) { Console.ReadLine(); } } } // Kill the process itself. Shutdown(null, null); }
public static byte[] ReadMemoryExternal(this ReloadedProcess process, IntPtr address, int length) { // Initialize the buffer of required length. byte[] buffer = new byte[length]; // Mark memory we are writing to as ExecuteReadWrite VirtualProtectEx(process.ProcessHandle, address, (IntPtr)length, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Read from the game memory. ReadProcessMemory(process.ProcessHandle, address, buffer, (IntPtr)length, out _); // Restore the old memory protection. VirtualProtectEx(process.ProcessHandle, address, (IntPtr)length, oldProtection, out oldProtection); // Return the buffer. return(buffer); }
/// <summary> /// ReadMemoryExternal /// Reads a specified specific amount of bytes from process memory using ReadProcessMemory. /// Supports classes marked [StructLayout(LayoutKind.Sequential)] and regular structures. /// </summary> /// <param name="process">The process object of the game, Process.GetCurrentProcess() if injected into the game.</param> /// <param name="address">The address of the first byte you want to write memory to.</param> /// <returns>The bytes which have been read from the memory at the specified offset and length.</returns> public static TType ReadMemoryExternalFast <TType>(this ReloadedProcess process, IntPtr address) { // Retrieve the type of the passed in Generic. Type type = typeof(TType); // Retrieve the size of T. int size = Marshal.SizeOf(type); // Initializes the buffer of the length of the data to be read. byte[] buffer = new byte[size]; // Read from the game memory. ReadProcessMemory(process.ProcessHandle, address, buffer, (IntPtr)size, out _); // Return the read memory. return(ConvertToPrimitive <TType>(buffer, type)); }
public static TType ReadMemoryFast <TType>(this ReloadedProcess process, IntPtr address) { // Retrieve the type of the passed in Generic. Type type = typeof(TType); // Retrieve the size of T. int size = Marshal.SizeOf(type); // Initializes the buffer of the length of the data to be read. byte[] buffer = new byte[size]; // Read from the game memory. Marshal.Copy(address, buffer, 0, size); // Return the read memory. return(ConvertToPrimitive <TType>(ref buffer, type)); }
public static unsafe byte[] ReadMemory(this ReloadedProcess process, IntPtr address, int length) { // Initialize the buffer of required length. byte[] buffer = new byte[length]; // Mark memory we are reading to as ExecuteReadWrite VirtualProtect(address, (IntPtr)length, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Read from the game memory. fixed(byte *pBuffer = &buffer[0]) Unsafe.CopyBlock(pBuffer, address.ToPointer(), (uint)length); // Restore the old memory protection. VirtualProtect(address, (IntPtr)length, oldProtection, out oldProtection); // Return the buffer. return(buffer); }
/// <summary> /// Initializes the libReloaded bindings used for internal Reloaded Mod Loader functions /// such as printing to buffers, logging and other functions. /// </summary> static void InitBindings() { // Set local game process. Program.GameProcess = ReloadedProcess.GetCurrentProcess(); Program.ExecutingGameLocation = Environment.GetCommandLineArgs()[0]; Program.ModDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); // For our libraries in a separate AppDomain executing main.dll if (Program.ModDirectory.EndsWith("Libraries")) { Program.ModDirectory = Path.GetDirectoryName(Program.ModDirectory); } // Set up Reloaded Mod Loader bindings. Bindings.PrintText += Client.Print; Bindings.PrintError += Client.PrintError; Bindings.PrintInfo += Client.PrintInfo; Bindings.PrintWarning += Client.PrintWarning; Bindings.TargetProcess = Program.GameProcess; }
/// <summary> /// Returns an individual list of various pages inside the current process' memory, /// </summary> /// <returns></returns> public static List <MEMORY_BASIC_INFORMATION> GetPages(this ReloadedProcess reloadedProcess) { // Retrieve the system information which gives us the range of all pages available for DLL + EXE GetSystemInfo(out var systemInfo); // Used to iterate our memory pages, get our address range of pages. ulong currentAddress; ulong maxAddress; ulong maxIntPtr; // Contains the maximum addressable address. if (IntPtr.Size == 4) { currentAddress = (uint)systemInfo.minimumApplicationAddress; maxAddress = (uint)systemInfo.maximumApplicationAddress; maxIntPtr = Int32.MaxValue; } else { currentAddress = (ulong)systemInfo.minimumApplicationAddress; maxAddress = (ulong)systemInfo.maximumApplicationAddress; maxIntPtr = Int64.MaxValue; } // Shorthand for convenience. IntPtr processHandle = reloadedProcess.ProcessHandle; List <MEMORY_BASIC_INFORMATION> memoryPages = new List <MEMORY_BASIC_INFORMATION>(); // Until we get all of the pages. while (currentAddress < maxAddress && currentAddress < maxIntPtr) { // Get our info from VirtualQueryEx. MEMORY_BASIC_INFORMATION memoryInformation = new MEMORY_BASIC_INFORMATION(); VirtualQueryEx(processHandle, (IntPtr)currentAddress, out memoryInformation, (uint)sizeof(MEMORY_BASIC_INFORMATION)); // Add the page and increment address iterator to go to next page. memoryPages.Add(memoryInformation); currentAddress += (ulong)memoryInformation.RegionSize; } return(memoryPages); }
public static TType ReadMemoryExternal <TType>(this ReloadedProcess process, IntPtr address) { // Retrieve the type of the passed in Generic. Type type = typeof(TType); // Retrieve the size of T. int size = Marshal.SizeOf(type); // Initializes the buffer of the length of the data to be read. byte[] buffer = new byte[size]; // Mark memory we are writing to as ExecuteReadWrite VirtualProtectEx(process.ProcessHandle, address, (IntPtr)size, MemoryProtections.ExecuteReadWrite, out MemoryProtections oldProtection); // Read from the game memory. ReadProcessMemory(process.ProcessHandle, address, buffer, (IntPtr)size, out _); // Restore the old memory protection. VirtualProtectEx(process.ProcessHandle, address, (IntPtr)size, oldProtection, out oldProtection); // Return the read memory. return(ConvertToPrimitive <TType>(ref buffer, type)); }
/// <summary> /// ReadMemory /// Reads a specified specific amount of bytes from memory of the current process and converts into your chosen primitive type or struct. /// Supports classes marked [StructLayout(LayoutKind.Sequential)] and regular structures. /// </summary> /// <param name="process">The process object of the game, Process.GetCurrentProcess() if injected into the game.</param> /// <param name="address">The address of the first byte you want to write memory to.</param> /// <returns>The bytes which have been read from the memory at the specified offset and length.</returns> public static TType ReadMemory <TType>(this ReloadedProcess process, IntPtr address) { // Retrieve the type of the passed in Generic. Type type = typeof(TType); // Retrieve the size of T. int size = Marshal.SizeOf(type); // Initializes the buffer of the length of the data to be read. byte[] buffer = new byte[size]; // Mark memory we are reading to as ExecuteReadWrite VirtualProtect(address, (uint)size, MemoryProtection.ExecuteReadWrite, out MemoryProtection oldProtection); // Read from the game memory. Marshal.Copy(address, buffer, 0, size); // Restore the old memory protection. VirtualProtect(address, (uint)size, oldProtection, out oldProtection); // Return the read memory. return(ConvertToPrimitive <TType>(buffer, type)); }
/// <summary> /// Launches Reloaded's Launcher with the Steam flag set for a specific game. /// </summary> /// <param name="gameConfigDirectory"></param> public static void LaunchGame(string gameConfigDirectory) { // Get launcher location and arguments. string reloadedLauncherLocation = GetLauncherLocation(); var arguments = new List <string>() { $"{Strings.Launcher.LaunchArgumentName}", $"{gameConfigDirectory}", $"{Strings.Common.LoaderSettingSteamShim}" }; // Start Reloaded-Launcher. DateTime currentTime = DateTime.Now; ReloadedProcess process = new ReloadedProcess(reloadedLauncherLocation, arguments.ToArray()); process.ResumeAllThreads(); // Synchronize exit of this application with Reloaded-Loader. bool is64Bit = IsGameConfig64Bit(gameConfigDirectory); FindLoaderAndSynchronizeExit(is64Bit, currentTime); }
/// <summary> /// FreeMemory /// Allows for the freeing of memory space inside the target process. /// Releases memory such that it may be cleaned and re-used by the Windows Operating System. /// </summary> /// <param name="process">The process object of the game, Process.GetCurrentProcess() if injected into the game.</param> /// <param name="address">The address of the first byte you want to free memory from.</param> /// <returns>A value that is not 0 if the operation is successful.</returns> public static bool FreeMemory(this ReloadedProcess process, IntPtr address) { return(VirtualFreeEx(process.ProcessHandle, address, IntPtr.Zero, FreeTypes.Decommit | FreeTypes.Release)); }