/// <summary> /// Create a process, inject the .NET Core runtime into it and load a .NET assembly. /// </summary> /// <param name="processConfig"></param> /// <param name="config32">Native modules required for starting CoreCLR in 32-bit applications.</param> /// <param name="config64">Native modules required for starting CoreCLR in 64-bit applications.</param> /// <param name="remoteHook">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="outProcessId">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( ProcessCreationConfig processConfig, CoreHookNativeConfig config32, CoreHookNativeConfig config64, RemoteHookingConfig remoteHook, IPipePlatform pipePlatform, out int outProcessId, params object[] passThruArguments ) { var process = Process.Start(processConfig.ExecutablePath); if (process == null) { throw new InvalidOperationException( $"Failed to start the executable at {processConfig.ExecutablePath}"); } var config = process.Is64Bit() ? config64 : config32; remoteHook.HostLibrary = config.HostLibrary; remoteHook.CoreCLRPath = config.CoreCLRPath; remoteHook.CoreCLRLibrariesPath = config.CoreCLRLibrariesPath; remoteHook.DetourLibrary = config.DetourLibrary; InjectEx( GetCurrentProcessId(), process.Id, remoteHook, pipePlatform, passThruArguments); outProcessId = process.Id; }
/// <summary> /// Start CoreCLR and execute a .NET assembly in a target process. /// </summary> /// <param name="targetPID">The process ID of the process to inject the .NET assembly into.</param> /// <param name="remoteHookConfig">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 targetPID, RemoteHookingConfig remoteHookConfig, IPipePlatform pipePlatform, params object[] passThruArguments) { InjectEx( GetCurrentProcessId(), targetPID, remoteHookConfig, pipePlatform, passThruArguments); }
/// <summary> /// Start CoreCLR and execute a .NET assembly in a target process. /// </summary> /// <param name="hostPID">Process ID of the process communicating with the target process.</param> /// <param name="targetPID">The process ID of the process to inject the .NET assembly into.</param> /// <param name="remoteHookConfig">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 InjectEx( int hostPID, int targetPID, RemoteHookingConfig remoteHookConfig, IPipePlatform pipePlatform, params object[] passThruArguments) { string injectionPipeName = remoteHookConfig.InjectionPipeName; if (string.IsNullOrWhiteSpace(injectionPipeName)) { throw new ArgumentException("Invalid injection pipe name"); } InjectionHelper.BeginInjection(targetPID); using (InjectionHelper.CreateServer(injectionPipeName, pipePlatform)) { try { var remoteInfo = new ManagedRemoteInfo { HostPID = hostPID }; var format = new BinaryFormatter(); var arguments = new List <object>(); if (passThruArguments != null) { foreach (var arg in passThruArguments) { using (var ms = new MemoryStream()) { format.Serialize(ms, arg); arguments.Add(ms.ToArray()); } } } remoteInfo.UserParams = arguments.ToArray(); using (var passThruStream = new MemoryStream()) { var libraryPath = remoteHookConfig.PayloadLibrary; PrepareInjection( remoteInfo, new UserDataBinaryFormatter(), libraryPath, passThruStream, injectionPipeName); // Inject the corerundll 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(targetPID); var length = (int)passThruStream.Length; using (var binaryLoader = GetBinaryLoader(process)) { binaryLoader.Load(process, remoteHookConfig.HostLibrary, new[] { remoteHookConfig.DetourLibrary }); binaryLoader.ExecuteRemoteFunction(process, new RemoteFunctionCall { Arguments = new BinaryLoaderSerializer(GetBinaryLoaderConfig()) { Arguments = new BinaryLoaderArguments { Verbose = remoteHookConfig.VerboseLog, PayloadFileName = remoteHookConfig.CLRBootstrapLibrary, CoreRootPath = remoteHookConfig.CoreCLRPath, CoreLibrariesPath = remoteHookConfig.CoreCLRLibrariesPath } }, FunctionName = new FunctionName { Module = remoteHookConfig.HostLibrary, Function = GetCoreCLRStartFunctionName() }, }); binaryLoader.ExecuteRemoteManagedFunction(process, new RemoteManagedFunctionCall { ManagedFunction = CoreHookLoaderDel, FunctionName = new FunctionName { Module = remoteHookConfig.HostLibrary, Function = GetCoreCLRExecuteManagedFunctionName() }, Arguments = new RemoteFunctionArguments { Is64BitProcess = process.Is64Bit(), UserData = binaryLoader.CopyMemoryTo(process, passThruStream.GetBuffer(), length), UserDataSize = length } } ); InjectionHelper.WaitForInjection(targetPID); } } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } } } finally { InjectionHelper.EndInjection(targetPID); } } }