/// <summary>
        /// Loads a library into a foreign process and returns the module handle of the loaded library.
        /// </summary>
        private static IntPtr LoadLibraryInForeignProcess(ProcessWrapper processWrapper, string pathToDll)
        {
            LogMessage($"Trying to load \"{pathToDll}\" in process \"{processWrapper.Id}\"...");

            if (File.Exists(pathToDll) == false)
            {
                throw new FileNotFoundException("Could not find file for loading in foreign process.", pathToDll);
            }

            var stringForRemoteProcess = pathToDll;

            Trace.WriteLine(Marshal.GetLastWin32Error());

            var bufLen        = (stringForRemoteProcess.Length + 1) * Marshal.SizeOf(typeof(char));
            var remoteAddress = NativeMethods.VirtualAllocEx(processWrapper.Handle, IntPtr.Zero, (uint)bufLen, NativeMethods.AllocationType.Commit, NativeMethods.MemoryProtection.ReadWrite);

            if (remoteAddress == IntPtr.Zero)
            {
                throw new Win32Exception();
            }

            var address = Marshal.StringToHGlobalUni(stringForRemoteProcess);
            var size    = (uint)(sizeof(char) * stringForRemoteProcess.Length);

            try
            {
                LogMessage($"Trying to write {size} bytes in foreign process");
                var writeProcessMemoryResult = NativeMethods.WriteProcessMemory(processWrapper.Handle, remoteAddress, address, size, out var bytesWritten);

                if (writeProcessMemoryResult == false ||
                    bytesWritten == 0)
                {
                    throw Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());
                }

                var hLibrary = NativeMethods.GetModuleHandle("kernel32");

                // Load dll into the remote process
                // (via CreateRemoteThread & LoadLibrary)
                var procAddress = NativeMethods.GetProcAddress(hLibrary, "LoadLibraryW");

                if (procAddress == UIntPtr.Zero)
                {
                    LogMessage("Could get proc address for LoadLibraryW.");
                    throw new Win32Exception();
                }

                var remoteThread = NativeMethods.CreateRemoteThread(processWrapper.Handle,
                                                                    IntPtr.Zero,
                                                                    0,
                                                                    procAddress,
                                                                    remoteAddress,
                                                                    0,
                                                                    out _);

                IntPtr moduleHandleInForeignProcess;
                try
                {
                    if (remoteThread == IntPtr.Zero)
                    {
                        LogMessage("Could not create remote thread.");
                        throw new Win32Exception();
                    }
                    else
                    {
                        NativeMethods.WaitForSingleObject(remoteThread);

                        // Get handle of the loaded module
                        if (NativeMethods.GetExitCodeThread(remoteThread, out moduleHandleInForeignProcess) == false)
                        {
                            throw new Win32Exception();
                        }
                    }
                }
                finally
                {
                    NativeMethods.CloseHandle(remoteThread);
                }

                try
                {
                    NativeMethods.VirtualFreeEx(processWrapper.Handle, remoteAddress, bufLen, NativeMethods.AllocationType.Release);
                }
                catch (Exception e)
                {
                    LogMessage(e.ToString());
                }

                if (moduleHandleInForeignProcess == IntPtr.Zero)
                {
                    throw new Exception($"Could not load \"{pathToDll}\" in process \"{processWrapper.Id}\".");
                }

                var remoteHandle = NativeMethods.GetRemoteModuleHandle(processWrapper.Process, Path.GetFileName(pathToDll));

                LogMessage($"Successfully loaded \"{pathToDll}\" with handle \"{moduleHandleInForeignProcess}\" (\"{remoteHandle}\") in process \"{processWrapper.Id}\".");

                return(remoteHandle);
            }
            finally
            {
                Marshal.FreeHGlobal(address);
            }
        }
 public static void InjectIntoProcess(ProcessWrapper processWrapper, InjectorData injectorData)
 {
     InjectSnoop(processWrapper, injectorData);
 }
        private static void InjectSnoop(ProcessWrapper processWrapper, InjectorData injectorData)
        {
            var injectorDllName   = $"Snoop.GenericInjector.{processWrapper.Bitness}.dll";
            var pathToInjectorDll = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), injectorDllName);

            LogMessage($"Trying to load \"{pathToInjectorDll}\"...");

            if (File.Exists(pathToInjectorDll) == false)
            {
                throw new FileNotFoundException("Could not find injector dll.", pathToInjectorDll);
            }

            var parameters = new[]
            {
                processWrapper.SupportedFrameworkName,
                injectorData.FullAssemblyPath,
                injectorData.ClassName,
                injectorData.MethodName,
                injectorData.SettingsFile
            };

            var stringForRemoteProcess = string.Join("<|>", parameters);

            var bufLen = (stringForRemoteProcess.Length + 1) * Marshal.SizeOf(typeof(char));

            LogMessage($"Trying to allocate {bufLen} bytes in foreign process...");
            Trace.WriteLine(Marshal.GetLastWin32Error());

            var remoteAddress = NativeMethods.VirtualAllocEx(processWrapper.Handle, IntPtr.Zero, (uint)bufLen, NativeMethods.AllocationType.Commit | NativeMethods.AllocationType.Reserve, NativeMethods.MemoryProtection.ReadWrite);

            if (remoteAddress == IntPtr.Zero)
            {
                throw new Win32Exception();
            }

            LogMessage("Successfully allocated memory in foreign process.");

            var address = Marshal.StringToHGlobalUni(stringForRemoteProcess);
            var size    = (uint)(sizeof(char) * stringForRemoteProcess.Length);

            try
            {
                var writeProcessMemoryResult = NativeMethods.WriteProcessMemory(processWrapper.Handle, remoteAddress, address, size, out var bytesWritten);

                if (writeProcessMemoryResult == false ||
                    bytesWritten == 0)
                {
                    throw Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());
                }

                var hLibrary = IntPtr.Zero;

                try
                {
                    // Load library into current process before trying to get the remote proc address
                    hLibrary = NativeMethods.LoadLibrary(pathToInjectorDll);

                    // Load library into foreign process before invoking our method
                    var moduleHandleInForeignProcess = LoadLibraryInForeignProcess(processWrapper, pathToInjectorDll);

                    try
                    {
                        var remoteProcAddress = NativeMethods.GetRemoteProcAddress(processWrapper.Process, injectorDllName, "ExecuteInDefaultAppDomain");

                        if (remoteProcAddress == UIntPtr.Zero)
                        {
                            LogMessage("Could not get proc address for \"ExecuteInDefaultAppDomain\".");
                            return;
                        }

                        var remoteThread = NativeMethods.CreateRemoteThread(processWrapper.Handle, IntPtr.Zero, 0, remoteProcAddress, remoteAddress, 0, out _);

                        try
                        {
                            if (remoteThread == IntPtr.Zero)
                            {
                                LogMessage("Could not create remote thread.");
                                throw new Win32Exception();
                            }

                            NativeMethods.WaitForSingleObject(remoteThread);

                            // Get handle of the loaded module
                            NativeMethods.GetExitCodeThread(remoteThread, out var resultFromExecuteInDefaultAppDomain);

                            LogMessage($"Received \"{resultFromExecuteInDefaultAppDomain}\" from injector component.");

                            if (resultFromExecuteInDefaultAppDomain != IntPtr.Zero)
                            {
                                throw Marshal.GetExceptionForHR((int)resultFromExecuteInDefaultAppDomain.ToInt64());
                            }
                        }
                        finally
                        {
                            NativeMethods.CloseHandle(remoteThread);
                        }
                    }
                    finally
                    {
                        FreeLibraryInForeignProcess(processWrapper, injectorDllName, moduleHandleInForeignProcess);
                    }
                }
                finally
                {
                    if (hLibrary != IntPtr.Zero)
                    {
                        NativeMethods.FreeLibrary(hLibrary);
                    }

                    try
                    {
                        NativeMethods.VirtualFreeEx(processWrapper.Handle, remoteAddress, bufLen, NativeMethods.AllocationType.Release);
                    }
                    catch (Exception e)
                    {
                        LogMessage(e.ToString());
                    }
                }
            }
            finally
            {
                Marshal.FreeHGlobal(address);
            }
        }
 public static void InjectIntoProcess(IntPtr windowHandle, InjectorData injectorData)
 {
     InjectIntoProcess(ProcessWrapper.FromWindowHandle(windowHandle), injectorData);
 }
Пример #5
0
        private static int Run(InjectorLauncherCommandLineOptions commandLineOptions)
        {
            Injector.LogMessage("Starting the injection process...", false);

            try
            {
                if (commandLineOptions.Debug)
                {
                    Debugger.Launch();
                }

                var processWrapper = ProcessWrapper.From(commandLineOptions.TargetPID, new IntPtr(commandLineOptions.TargetHwnd));

                // Check for target process and our bitness.
                // If they don't match we redirect everything to the appropriate injector launcher.
                {
                    var currentProcess        = Process.GetCurrentProcess();
                    var currentProcessBitness = ProcessWrapper.GetBitnessAsString(currentProcess);
                    if (processWrapper.Bitness.Equals(currentProcessBitness) == false)
                    {
                        Injector.LogMessage("Target process and injector process have different bitness, trying to redirect to secondary process...");

                        var originalProcessFileName = currentProcess.MainModule.ModuleName;
                        var correctBitnessFileName  = originalProcessFileName.Replace(currentProcessBitness, processWrapper.Bitness);
                        var processStartInfo        = new ProcessStartInfo(currentProcess.MainModule.FileName.Replace(originalProcessFileName, correctBitnessFileName), Parser.Default.FormatCommandLine(commandLineOptions))
                        {
                            CreateNoWindow   = true,
                            WorkingDirectory = currentProcess.StartInfo.WorkingDirectory
                        };

                        using (var process = Process.Start(processStartInfo))
                        {
                            if (process == null)
                            {
                                Injector.LogMessage("Failed to start process for redirection.");
                                return(1);
                            }

                            process.WaitForExit();
                            return(process.ExitCode);
                        }
                    }
                }

                var settingsFile = string.IsNullOrEmpty(commandLineOptions.SettingsFile) == false
                    ? commandLineOptions.SettingsFile
                    : new TransientSettingsData
                {
                    StartTarget        = SnoopStartTarget.SnoopUI,
                    TargetWindowHandle = processWrapper.WindowHandle.ToInt64()
                }.WriteToFile();

                var injectorData = new InjectorData
                {
                    FullAssemblyPath = GetAssemblyPath(processWrapper, commandLineOptions.Assembly),
                    ClassName        = commandLineOptions.ClassName,
                    MethodName       = commandLineOptions.MethodName,
                    SettingsFile     = settingsFile
                };
                Injector.LogMessage($"Start injecting \"{injectorData.FullAssemblyPath}\".");
                if (File.Exists(injectorData.FullAssemblyPath) == false)
                {
                    Injector.LogMessage($"Could not find \"{injectorData.FullAssemblyPath}\".");
                    return(1);
                }

                try
                {
                    Injector.InjectIntoProcess(processWrapper, injectorData);
                }
                catch (Exception exception)
                {
                    Injector.LogMessage($"Failed to inject Snoop into process {processWrapper.Process.ProcessName} (PID = {processWrapper.Process.Id})");
                    Injector.LogMessage(exception.ToString());
                    return(1);
                }

                Injector.LogMessage($"Successfully injected Snoop into process {processWrapper.Process.ProcessName} (PID = {processWrapper.Process.Id})");

                return(0);
            }
            catch (Exception ex)
            {
                Injector.LogMessage(ex.ToString());
                return(1);
            }
        }