/// <summary> /// Ejects a library that this Injector has previously injected into the target process. <paramref name="libName"/> is the name of the module to /// eject, as per the name stored in <see cref="Injector.InjectLibrary"/>. Passing the same value as passed to InjectLibrary should always work unless a /// relative path was used and the program's working directory has changed. /// </summary> /// <param name="libName">The name of the module to eject</param> public void EjectLibrary(string libName) { string libSearchName = File.Exists(libName) ? Path.GetFileName(Path.GetFullPath(libName)) : libName; if (!injectedModules.ContainsKey(libSearchName)) { throw new InvalidOperationException("That module has not been injected into the process and thus cannot be ejected"); } // resources that need to be freed IntPtr hThread = IntPtr.Zero; try { // get handle to kernel32 and FreeLibrary IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32"); if (hKernel32 == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } IntPtr hFreeLib = Imports.GetProcAddress(hKernel32, "FreeLibrary"); if (hFreeLib == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, hFreeLib, injectedModules[libSearchName].BaseAddress, 0, IntPtr.Zero); if (hThread == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } if (Imports.WaitForSingleObject(hThread, (uint)ThreadWaitValue.Infinite) != (uint)ThreadWaitValue.Object0) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // get exit code of FreeLibrary IntPtr pFreeLibRet; // = IntPtr.Zero; if (!Imports.GetExitCodeThread(hThread, out pFreeLibRet)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } if (pFreeLibRet == IntPtr.Zero) { throw new Exception("FreeLibrary failed in remote process"); } } catch { } finally { Imports.CloseHandle(hThread); } }
private IntPtr CallExportInternal(uint timeout, string libName, string funcName, IntPtr data, Type dataType, uint dataSize) { string libSearchName = File.Exists(libName) ? Path.GetFileName(Path.GetFullPath(libName)) : libName; if (!injectedModules.ContainsKey(libSearchName)) { throw new InvalidOperationException("That module has not been injected into the process and thus cannot be ejected"); } IntPtr pFunc = injectedModules[libSearchName][funcName]; // resources that need to be cleaned IntPtr pDataRemote = IntPtr.Zero; IntPtr hThread = IntPtr.Zero; try { // check if we have all required parameters to pass a data parameter // if we don't, assume we aren't passing any data if (!(data == IntPtr.Zero || dataSize == 0 || dataType == null)) { // allocate memory in remote process for parameter pDataRemote = Imports.VirtualAllocEx(_handle, IntPtr.Zero, dataSize, AllocationType.Commit, MemoryProtection.ReadWrite); if (pDataRemote == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // rebase the data so that pointers point to valid memory locations for the target process // this renders the unmanaged structure useless in this process - should be able to re-rebase back to // this target process by calling CustomMarshal.RebaseUnmanagedStructure(data, data, dataType); but not tested CustomMarshal.RebaseUnmanagedStructure(data, pDataRemote, dataType); int bytesWritten; if (!Imports.WriteProcessMemory(_handle, pDataRemote, data, dataSize, out bytesWritten)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, pFunc, pDataRemote, 0, IntPtr.Zero); if (hThread == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint singleObject = Imports.WaitForSingleObject(hThread, timeout); if (!(singleObject == (uint)ThreadWaitValue.Object0 || singleObject == (uint)ThreadWaitValue.Timeout)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } IntPtr pRet; if (!Imports.GetExitCodeThread(hThread, out pRet)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return(pRet); } finally { Imports.VirtualFreeEx(_process.Handle, pDataRemote, 0, AllocationType.Release); Imports.CloseHandle(hThread); } }
/// <summary> /// Injects a library into this Injector's process. <paramref name="libPath"/> can be /// relative or absolute; either way, the injected module will be referred to by module name only. /// I.e. "c:\some\directory\library.dll", "library.dll" and "..\library.dll" will all be referred to /// as "library.dll" /// </summary> /// <param name="libPath">Relative or absolute path to the dll to be injected</param> public void InjectLibrary(string libPath) { // (in?)sanity check, pretty sure this is never possible as the constructor will error - left over from how it previously was developed if (_process == null) { throw new InvalidOperationException("This injector has no associated process and thus cannot inject a library"); } if (_handle == IntPtr.Zero) { throw new InvalidOperationException("This injector does not have a valid handle to the associated process and thus cannot inject a library"); } if (!File.Exists(libPath)) { throw new FileNotFoundException(string.Format("Unable to find library {0} to inject into process {1}", libPath, _process.ProcessName), libPath); } // convenience variables string fullPath = Path.GetFullPath(libPath); string libName = Path.GetFileName(fullPath); // declare resources that need to be freed in finally IntPtr pLibRemote = IntPtr.Zero; // pointer to allocated memory of lib path string IntPtr hThread = IntPtr.Zero; // handle to thread from CreateRemoteThread IntPtr pLibFullPathUnmanaged = Marshal.StringToHGlobalUni(fullPath); // unmanaged C-String pointer try { uint sizeUni = (uint)Encoding.Unicode.GetByteCount(fullPath); // Get Handle to Kernel32.dll and pointer to LoadLibraryW IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32"); if (hKernel32 == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } IntPtr hLoadLib = Imports.GetProcAddress(hKernel32, "LoadLibraryW"); if (hLoadLib == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // allocate memory to the local process for libFullPath pLibRemote = Imports.VirtualAllocEx(_handle, IntPtr.Zero, sizeUni, AllocationType.Commit, MemoryProtection.ReadWrite); if (pLibRemote == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // write libFullPath to pLibPath int bytesWritten; if (!Imports.WriteProcessMemory(_handle, pLibRemote, pLibFullPathUnmanaged, sizeUni, out bytesWritten) || bytesWritten != (int)sizeUni) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // load dll via call to LoadLibrary using CreateRemoteThread hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, hLoadLib, pLibRemote, 0, IntPtr.Zero); if (hThread == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } if (Imports.WaitForSingleObject(hThread, (uint)ThreadWaitValue.Infinite) != (uint)ThreadWaitValue.Object0) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // get address of loaded module - this doesn't work in x64, so just iterate module list to find injected module IntPtr hLibModule;// = IntPtr.Zero; if (!Imports.GetExitCodeThread(hThread, out hLibModule)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } if (hLibModule == IntPtr.Zero) { throw new Exception("Code executed properly, but unable to get an appropriate module handle, possible Win32Exception", new Win32Exception(Marshal.GetLastWin32Error())); } // iterate modules in target process to find our newly injected module ProcessModule modFound = null; foreach (ProcessModule mod in _process.Modules) { if (mod.ModuleName == libName) { modFound = mod; break; } } if (modFound == null) { throw new Exception("Injected module could not be found within the target process!"); } injectedModules.Add(libName, new InjectedModule(modFound)); } finally { Marshal.FreeHGlobal(pLibFullPathUnmanaged); // free unmanaged string Imports.CloseHandle(hThread); // close thread from CreateRemoteThread Imports.VirtualFreeEx(_process.Handle, pLibRemote, 0, AllocationType.Release); // Free memory allocated } }