public EntryPoint( EasyHook.RemoteHooking.IContext context, String channelName, CaptureConfig config) { // Get reference to IPC to host application // Note: any methods called or events triggered against _interface will execute in the host process. _interface = EasyHook.RemoteHooking.IpcConnectClient <CaptureInterface>(channelName); // We try to ping immediately, if it fails then injection fails _interface.Ping(); #region Allow client event handlers (bi-directional IPC) // Attempt to create a IpcServerChannel so that any event handlers on the client will function correctly System.Collections.IDictionary properties = new System.Collections.Hashtable(); properties["name"] = channelName; properties["portName"] = channelName + Guid.NewGuid().ToString("N"); // random portName so no conflict with existing channels of channelName System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider binaryProv = new System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider(); binaryProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; System.Runtime.Remoting.Channels.Ipc.IpcServerChannel _clientServerChannel = new System.Runtime.Remoting.Channels.Ipc.IpcServerChannel(properties, binaryProv); System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(_clientServerChannel, false); #endregion }
/// <summary> /// Prepares capturing in the target process. Note that the process must not already be hooked, and must have a MainWindowHandle/>. /// </summary> /// <param name="process">The process to inject into</param> /// <param name="config"></param> /// <param name="captureInterface"></param> /// <exception cref="ProcessHasNoWindowHandleException">Thrown if the <paramref name="process"/> does not have a window handle. This could mean that the process does not have a UI, or that the process has not yet finished starting.</exception> /// <exception cref="ProcessAlreadyHookedException">Thrown if the <paramref name="process"/> is already hooked</exception> /// <exception cref="InjectionFailedException">Thrown if the injection failed - see the InnerException for more details.</exception> /// <remarks>The target process will have its main window brought to the foreground after successful injection.</remarks> public CaptureProcess(Process process, CaptureConfig config, CaptureInterface captureInterface) { // If the process doesn't have a MainWindowHandle yet, skip it (we need to be able to get the hwnd to set foreground etc) if (process.MainWindowHandle == IntPtr.Zero) { throw new ProcessHasNoWindowHandleException(); } // Skip if the process is already hooked (and we want to hook multiple applications) if (HookManager.IsHooked(process.Id)) { throw new ProcessAlreadyHookedException(); } Process = process; Process.EnableRaisingEvents = true; captureInterface.ProcessId = Process.Id; CaptureInterface = captureInterface; //_serverInterface = new CaptureInterface() { ProcessId = process.Id }; // Initialise the IPC server (with our instance of _serverInterface) RemoteHooking.IpcCreateServer( ref channelName, WellKnownObjectMode.Singleton, CaptureInterface); try { // Inject DLL into target process RemoteHooking.Inject( Process.Id, InjectionOptions.Default, typeof(CaptureInterface).Assembly.Location, // 32-bit (the same because AnyCPU) could use different assembly that links to 32-bit C++ helper dll typeof(CaptureInterface).Assembly.Location, // 64-bit (the same because AnyCPU) could use different assembly that links to 64-bit C++ helper dll // the optional parameter list... channelName, // The name of the IPC channel for the injected assembly to connect to config ); } catch (Exception e) { throw new InjectionFailedException(e); } HookManager.AddHookedProcess(Process.Id); // Ensure the target process is in the foreground, // this prevents an issue where the target app appears to be in // the foreground but does not receive any user inputs. // Note: the first Alt+Tab out of the target application after injection // may still be an issue - switching between windowed and // fullscreen fixes the issue however (see ScreenshotInjection.cs for another option) BringProcessWindowToFront(); Process.Exited += (_, _) => { Dispose(); }; }
/// <summary> /// Prepares capturing in the target process. Note that the process must not already be hooked, and must have a <see cref="Process.MainWindowHandle"/>. /// </summary> /// <param name="process">The process to inject into</param> /// <exception cref="ProcessHasNoWindowHandleException">Thrown if the <paramref name="process"/> does not have a window handle. This could mean that the process does not have a UI, or that the process has not yet finished starting.</exception> /// <exception cref="ProcessAlreadyHookedException">Thrown if the <paramref name="process"/> is already hooked</exception> /// <exception cref="InjectionFailedException">Thrown if the injection failed - see the InnerException for more details.</exception> /// <remarks>The target process will have its main window brought to the foreground after successful injection.</remarks> public CaptureProcess(Process process, CaptureConfig config, CaptureInterface captureInterface) { // If the process doesn't have a mainwindowhandle yet, skip it (we need to be able to get the hwnd to set foreground etc) //if (process.MainWindowHandle == IntPtr.Zero) //{ // throw new ProcessHasNoWindowHandleException(); //} // Skip if the process is already hooked (and we want to hook multiple applications) if (HookManager.IsHooked(process.Id)) { throw new ProcessAlreadyHookedException(); } captureInterface.ProcessId = process.Id; this._serverInterface = captureInterface; //_serverInterface = new CaptureInterface() { ProcessId = process.Id }; // Initialise the IPC server (with our instance of _serverInterface) this._screenshotServer = RemoteHooking.IpcCreateServer <CaptureInterface>( ref this._channelName, WellKnownObjectMode.Singleton, this._serverInterface); try { var dllName = typeof(CaptureInterface).Assembly.GetName().Name + ".dll"; var location = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dllName); // Inject DLL into target process RemoteHooking.Inject( process.Id, InjectionOptions.NoService | InjectionOptions.DoNotRequireStrongName, location, //"Capture.dll", // 32-bit version (the same because AnyCPU) could use different assembly that links to 32-bit C++ helper dll location, //"Capture.dll", // 64-bit version (the same because AnyCPU) could use different assembly that links to 64-bit C++ helper dll // the optional parameter list... this._channelName, // The name of the IPC channel for the injected assembly to connect to config ); } catch (Exception e) { throw new InjectionFailedException(e); } HookManager.AddHookedProcess(process.Id); this.Process = process; }
public void Run( EasyHook.RemoteHooking.IContext context, String channelName, CaptureConfig config) { // When not using GAC there can be issues with remoting assemblies resolving correctly // this is a workaround that ensures that the current assembly is correctly associated AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += (sender, args) => { return(this.GetType().Assembly.FullName == args.Name ? this.GetType().Assembly : null); }; // NOTE: This is running in the target process _interface.Message(MessageType.Information, "Injected into process Id:{0}.", EasyHook.RemoteHooking.GetCurrentProcessId()); _runWait = new System.Threading.ManualResetEvent(false); _runWait.Reset(); try { // Initialise the Hook if (!InitialiseDirectXHook(config)) { return; } _interface.Disconnected += _clientEventProxy.DisconnectedProxyHandler; // Important Note: // accessing the _interface from within a _clientEventProxy event handler must always // be done on a different thread otherwise it will cause a deadlock _clientEventProxy.Disconnected += () => { // We can now signal the exit of the Run method _runWait.Set(); }; // We start a thread here to periodically check if the host is still running // If the host process stops then we will automatically uninstall the hooks StartCheckHostIsAliveThread(); // Wait until signaled for exit either when a Disconnect message from the host // or if the the check is alive has failed to Ping the host. _runWait.WaitOne(); // we need to tell the check host thread to exit (if it hasn't already) StopCheckHostIsAliveThread(); // Dispose of the DXHook so any installed hooks are removed correctly DisposeDirectXHook(); } catch (Exception e) { _interface.Message(MessageType.Error, "An unexpected error occured: {0}", e.ToString()); } finally { try { _interface.Message(MessageType.Information, "Disconnecting from process {0}", EasyHook.RemoteHooking.GetCurrentProcessId()); } catch { } // Remove the client server channel (that allows client event handlers) System.Runtime.Remoting.Channels.ChannelServices.UnregisterChannel(_clientServerChannel); // Always sleep long enough for any remaining messages to complete sending System.Threading.Thread.Sleep(100); } }
private bool InitialiseDirectXHook(CaptureConfig config) { Direct3DVersion version = config.Direct3DVersion; List <Direct3DVersion> loadedVersions = new List <Direct3DVersion>(); bool isX64Process = EasyHook.RemoteHooking.IsX64Process(EasyHook.RemoteHooking.GetCurrentProcessId()); _interface.Message(MessageType.Information, "Remote process is a {0}-bit process.", isX64Process ? "64" : "32"); try { if (version == Direct3DVersion.AutoDetect) { // Attempt to determine the correct version based on loaded module. // In most cases this will work fine, however it is perfectly ok for an application to use a D3D10 device along with D3D11 devices // so the version might matched might not be the one you want to use IntPtr d3D9Loaded = IntPtr.Zero; IntPtr d3D10Loaded = IntPtr.Zero; IntPtr d3D10_1Loaded = IntPtr.Zero; IntPtr d3D11Loaded = IntPtr.Zero; IntPtr d3D11_1Loaded = IntPtr.Zero; int delayTime = 100; int retryCount = 0; while (d3D9Loaded == IntPtr.Zero && d3D10Loaded == IntPtr.Zero && d3D10_1Loaded == IntPtr.Zero && d3D11Loaded == IntPtr.Zero && d3D11_1Loaded == IntPtr.Zero) { retryCount++; d3D9Loaded = NativeMethods.GetModuleHandle("d3d9.dll"); d3D10Loaded = NativeMethods.GetModuleHandle("d3d10.dll"); d3D10_1Loaded = NativeMethods.GetModuleHandle("d3d10_1.dll"); d3D11Loaded = NativeMethods.GetModuleHandle("d3d11.dll"); d3D11_1Loaded = NativeMethods.GetModuleHandle("d3d11_1.dll"); System.Threading.Thread.Sleep(delayTime); if (retryCount * delayTime > 5000) { _interface.Message(MessageType.Error, "Unsupported Direct3D version, or Direct3D DLL not loaded within 5 seconds."); return(false); } } version = Direct3DVersion.Unknown; if (d3D11_1Loaded != IntPtr.Zero) { _interface.Message(MessageType.Debug, "Autodetect found Direct3D 11.1"); version = Direct3DVersion.Direct3D11_1; loadedVersions.Add(version); } if (d3D11Loaded != IntPtr.Zero) { _interface.Message(MessageType.Debug, "Autodetect found Direct3D 11"); version = Direct3DVersion.Direct3D11; loadedVersions.Add(version); } if (d3D10_1Loaded != IntPtr.Zero) { _interface.Message(MessageType.Debug, "Autodetect found Direct3D 10.1"); version = Direct3DVersion.Direct3D10_1; loadedVersions.Add(version); } if (d3D10Loaded != IntPtr.Zero) { _interface.Message(MessageType.Debug, "Autodetect found Direct3D 10"); version = Direct3DVersion.Direct3D10; loadedVersions.Add(version); } if (d3D9Loaded != IntPtr.Zero) { _interface.Message(MessageType.Debug, "Autodetect found Direct3D 9"); version = Direct3DVersion.Direct3D9; loadedVersions.Add(version); } } foreach (var dxVersion in loadedVersions) { version = dxVersion; switch (version) { case Direct3DVersion.Direct3D9: _directXHook = new DXHookD3D9(_interface); break; case Direct3DVersion.Direct3D10: _directXHook = new DXHookD3D10(_interface); break; case Direct3DVersion.Direct3D10_1: _directXHook = new DXHookD3D10_1(_interface); break; case Direct3DVersion.Direct3D11: _directXHook = new DXHookD3D11(_interface); break; //case Direct3DVersion.Direct3D11_1: // _directXHook = new DXHookD3D11_1(_interface); // return; default: _interface.Message(MessageType.Error, "Unsupported Direct3D version: {0}", version); return(false); } _directXHook.Config = config; _directXHook.Hook(); _directXHooks.Add(_directXHook); } return(true); } catch (Exception e) { // Notify the host/server application about this error _interface.Message(MessageType.Error, "Error in InitialiseHook: {0}", e.ToString()); return(false); } }
/// <summary> /// Prepares capturing in the target process. Note that the process must not already be hooked, and must have a <see cref="Process.MainWindowHandle"/>. /// </summary> /// <param name="process">The process to inject into</param> /// <exception cref="ProcessHasNoWindowHandleException">Thrown if the <paramref name="process"/> does not have a window handle. This could mean that the process does not have a UI, or that the process has not yet finished starting.</exception> /// <exception cref="ProcessAlreadyHookedException">Thrown if the <paramref name="process"/> is already hooked</exception> /// <exception cref="InjectionFailedException">Thrown if the injection failed - see the InnerException for more details.</exception> /// <remarks>The target process will have its main window brought to the foreground after successful injection.</remarks> public CaptureProcess(Process process, CaptureConfig config, CaptureInterface captureInterface) { // If the process doesn't have a mainwindowhandle yet, skip it (we need to be able to get the hwnd to set foreground etc) if (process.MainWindowHandle == IntPtr.Zero) { throw new ProcessHasNoWindowHandleException(); } // Skip if the process is already hooked (and we want to hook multiple applications) if (HookManager.IsHooked(process.Id)) { throw new ProcessAlreadyHookedException(); } captureInterface.ProcessId = process.Id; _serverInterface = captureInterface; //_serverInterface = new CaptureInterface() { ProcessId = process.Id }; // Initialise the IPC server (with our instance of _serverInterface) _screenshotServer = RemoteHooking.IpcCreateServer <CaptureInterface>( ref _channelName, WellKnownObjectMode.Singleton, _serverInterface); try { var location = typeof(CaptureInterface).Assembly.Location; if (String.IsNullOrEmpty(location)) { var dllName = typeof(CaptureInterface).Assembly.GetName().Name + ".dll"; location = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dllName); } // Inject DLL into target process RemoteHooking.Inject( process.Id, InjectionOptions.Default, location, //"Capture.dll", // 32-bit version (the same because AnyCPU) could use different assembly that links to 32-bit C++ helper dll location, //"Capture.dll", // 64-bit version (the same because AnyCPU) could use different assembly that links to 64-bit C++ helper dll // the optional parameter list... _channelName, // The name of the IPC channel for the injected assembly to connect to config ); } catch (Exception e) { throw new InjectionFailedException(e); } HookManager.AddHookedProcess(process.Id); Process = process; // Ensure the target process is in the foreground, // this prevents an issue where the target app appears to be in // the foreground but does not receive any user inputs. // Note: the first Alt+Tab out of the target application after injection // may still be an issue - switching between windowed and // fullscreen fixes the issue however (see ScreenshotInjection.cs for another option) // BringProcessWindowToFront(); }