/// <summary> /// Create a process, inject the .NET Core runtime into it and load a .NET assembly. /// </summary> /// <param name="processConfig">Arguments used for starting the new process.</param> /// <param name="nativeModulesConfig32">Native modules required for starting CoreCLR in 32-bit applications.</param> /// <param name="nativeModulesConfig64">Native modules required for starting CoreCLR in 64-bit applications.</param> /// <param name="remoteInjectorConfig">Configuration settings for starting CoreCLR and executing .NET assemblies.</param> /// <param name="pipePlatform">Class for creating pipes for communication with the target process.</param> /// <param name="createdProcessId">Process ID of the newly created process.</param> /// <param name="passThruArguments">Arguments passed to the .NET hooking library in the target process.</param> public static void CreateAndInject( ProcessCreationConfiguration processConfig, NativeModulesConfiguration nativeModulesConfig32, NativeModulesConfiguration nativeModulesConfig64, RemoteInjectorConfiguration remoteInjectorConfig, IPipePlatform pipePlatform, out int createdProcessId, params object[] passThruArguments ) { var process = Process.Start(processConfig.ExecutablePath); if (process == null) { throw new InvalidOperationException( $"Failed to start the executable at {processConfig.ExecutablePath}"); } remoteInjectorConfig.SetNativeConfig( process.Is64Bit() ? nativeModulesConfig64 : nativeModulesConfig32); Inject( GetCurrentProcessId(), process.Id, remoteInjectorConfig, pipePlatform, passThruArguments); createdProcessId = process.Id; }
/// <summary> /// Start CoreCLR and execute a .NET assembly in a target process. /// </summary> /// <param name="targetProcessId">The process ID of the process to inject the .NET assembly into.</param> /// <param name="remoteInjectorConfig">Configuration settings for starting CoreCLR and executing .NET assemblies.</param> /// <param name="pipePlatform">Class for creating pipes for communication with the target process.</param> /// <param name="passThruArguments">Arguments passed to the .NET hooking library in the target process.</param> public static void Inject( int targetProcessId, RemoteInjectorConfiguration remoteInjectorConfig, IPipePlatform pipePlatform, params object[] passThruArguments) { Inject( GetCurrentProcessId(), targetProcessId, remoteInjectorConfig, pipePlatform, passThruArguments); }
/// <summary> /// Start CoreCLR and execute a .NET assembly in a target process. /// </summary> /// <param name="localProcessId">Process ID of the process communicating with the target process.</param> /// <param name="targetProcessId">The process ID of the process to inject the .NET assembly into.</param> /// <param name="remoteInjectorConfig">Configuration settings for starting CoreCLR and executing .NET assemblies.</param> /// <param name="pipePlatform">Class for creating pipes for communication with the target process.</param> /// <param name="passThruArguments">Arguments passed to the .NET hooking plugin once it is loaded in the target process.</param> public static void Inject( int localProcessId, int targetProcessId, RemoteInjectorConfiguration remoteInjectorConfig, IPipePlatform pipePlatform, params object[] passThruArguments) { if (string.IsNullOrWhiteSpace(remoteInjectorConfig.InjectionPipeName)) { throw new ArgumentException("Invalid injection pipe name"); } InjectionHelper.BeginInjection(targetProcessId); using (InjectionHelper.CreateServer(remoteInjectorConfig.InjectionPipeName, pipePlatform)) { try { var remoteInfoFormatter = new UserDataBinaryFormatter(); // Initialize the arguments passed to the CoreHook plugin. var remoteInfo = CreateRemoteInfo(localProcessId, remoteInfoFormatter, passThruArguments); using (var pluginArgumentsStream = new MemoryStream()) { // Serialize the plugin information such as the DLL path // and the plugin arguments, which are copied to the remote process. CreatePluginArguments( remoteInfo, remoteInfoFormatter, remoteInjectorConfig.PayloadLibrary, pluginArgumentsStream, remoteInjectorConfig.InjectionPipeName); // Inject the CoreCLR hosting module into the process, start the CoreCLR // and use the CoreLoad dll to resolve the dependencies of the hooking library // and then call the IEntryPoint.Run method located in the hooking library. try { var process = GetProcessById(targetProcessId); var pluginArgumentsLength = (int)pluginArgumentsStream.Length; using (var assemblyLoader = CreateAssemblyLoader(process)) { var pathConfig = GetPathConfig(); // Load the CoreCLR hosting module in the remote process. assemblyLoader.LoadModule(remoteInjectorConfig.HostLibrary); // Load the function detour module into remote process. assemblyLoader.LoadModule(remoteInjectorConfig.DetourLibrary); // Initialize CoreCLR in the remote process using the native CoreCLR hosting module. assemblyLoader.CreateThread( new RemoteFunctionCall { Arguments = new HostFunctionArguments(pathConfig, new HostArguments { Verbose = remoteInjectorConfig.VerboseLog, PayloadFileName = remoteInjectorConfig.ClrBootstrapLibrary, CoreRootPath = remoteInjectorConfig.ClrRootPath, CoreLibrariesPath = remoteInjectorConfig.ClrLibrariesPath }), FunctionName = new FunctionName { Module = remoteInjectorConfig.HostLibrary, Function = GetClrStartFunctionName() }, }); // Execute a .NET function in the remote process now that CoreCLR is started. assemblyLoader.CreateThread(new RemoteFunctionCall { Arguments = new AssemblyFunctionArguments( pathConfig, CoreHookLoaderDelegate, new PluginConfigurationArguments( process.Is64Bit(), assemblyLoader.CopyMemory(pluginArgumentsStream.GetBuffer(), pluginArgumentsLength), pluginArgumentsLength) ), FunctionName = new FunctionName { Module = remoteInjectorConfig.HostLibrary, Function = GetClrExecuteManagedFunctionName() } }, false); InjectionHelper.WaitForInjection(targetProcessId); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } finally { InjectionHelper.EndInjection(targetProcessId); } } }