private static extern bool VirtualFreeEx(SafeMemoryHandle hProcess, IntPtr lpAddress, UIntPtr dwSize, FreeType dwFreeType);
private static extern IntPtr VirtualAllocEx(SafeMemoryHandle hProcess, IntPtr lpAddress, UIntPtr dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
/// <summary> /// Calls the specified export with the specified args. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="exportName">Name of the export.</param> /// <param name="parameter">The argument.</param> /// <param name="callWithParameter"> /// if set to <c>true</c>, the specified export will be called with the specified /// parameter. /// </param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">exportName</exception> /// <exception cref="BlueRainException"> /// Couldn't resolve export named with name + exportName + in remotely injected /// library. /// </exception> /// <exception cref="InjectionException"> /// WaitForSingleObject returned an unexpected value while waiting for the /// remote thread to be created for export call. /// </exception> public IntPtr Call <T>(string exportName, T parameter, bool callWithParameter = false) where T : struct { // The idea behind this method's quite simple. We can only call an __stdcall export with one parameter, // any subsequent arguments would require injecting a stub to push the args to the stack. // We don't support that as of yet - we'll resort to allocating and calling the export with a single parameter for now. if (string.IsNullOrEmpty(exportName)) { throw new ArgumentNullException(nameof(exportName)); } var exportPtr = GetExportPointer(exportName); if (exportPtr == IntPtr.Zero) { throw new BlueRainException("Couldn't resolve export named with name " + exportName + " in remotely injected library."); } var kernel32Handle = UnsafeNativeMethods.GetModuleHandle(UnsafeNativeMethods.Kernel32); uint exitCode; SafeMemoryHandle threadHandle = null; AllocatedMemory alloc = null; try { if (callWithParameter) { var size = Marshal.SizeOf(parameter); alloc = _memory.Allocate((UIntPtr)size); alloc.Write(IntPtr.Zero, parameter); } threadHandle = UnsafeNativeMethods.CreateRemoteThread(kernel32Handle.DangerousGetHandle(), IntPtr.Zero, 0, exportPtr, alloc?.Address ?? IntPtr.Zero, 0x0, IntPtr.Zero); if (UnsafeNativeMethods.WaitForSingleObject(threadHandle.DangerousGetHandle(), uint.MaxValue) != 0x0) { throw new InjectionException( "WaitForSingleObject returned an unexpected value while waiting for the remote thread to be created for export call."); } UnsafeNativeMethods.GetExitCodeThread(threadHandle.DangerousGetHandle(), out exitCode); } finally { if (kernel32Handle != null && !kernel32Handle.IsClosed) { kernel32Handle.Close(); } if (threadHandle != null && !threadHandle.IsClosed) { threadHandle.Close(); } // Make sure we free the chunk for the args. alloc?.Dispose(); } return((IntPtr)exitCode); }
private static extern bool VirtualProtectEx( SafeMemoryHandle hProcess, IntPtr lpAddress, IntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
private static extern bool WriteProcessMemory( SafeMemoryHandle hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out int lpNumberOfBytesWritten);
private static extern unsafe bool ReadProcessMemory( SafeMemoryHandle hProcess, IntPtr lpBaseAddress, byte *lpBuffer, int dwSize, out int lpNumberOfBytesRead);
protected static extern uint SuspendThread(SafeMemoryHandle hThread);
private InjectedModule InjectLibraryExternal(string libraryPath) { // Injecting remotely consists of a few steps: // 1. GetProcAddress on kernel32 to get a pointer to LoadLibraryW // 2. Allocate chunk of memory to write the path to our library to // 3. CreateRemoteThread that calls LoadLibraryW and pass it a pointer to our chunk // 4. Get thread's exit code // 5. ???? // 6. Profit var memory = _memory as ExternalProcessMemory; // Realistically won't happen, but code analysis complains about it being null. if (memory == null) { throw new InvalidOperationException("A valid memory instance is required for InjectLibraryExternal!"); } if (memory.ProcessHandle.IsInvalid) { throw new InvalidOperationException("Can not inject library with an invalid ProcessHandle in ExternalProcessMemory!"); } var path = Path.GetFullPath(libraryPath); var libraryFileName = Path.GetFileName(libraryPath); ProcessModule ourModule; SafeMemoryHandle threadHandle = null; SafeMemoryHandle kernel32Handle = null; try { kernel32Handle = UnsafeNativeMethods.GetModuleHandle(UnsafeNativeMethods.Kernel32); var loadLibraryPtr = UnsafeNativeMethods.GetProcAddress(kernel32Handle.DangerousGetHandle(), "LoadLibraryW"); if (loadLibraryPtr == IntPtr.Zero) { throw new InjectionException("Couldn't obtain handle to LoadLibraryW in remote process!"); } var pathBytes = Encoding.Unicode.GetBytes(path); using (var alloc = memory.Allocate((UIntPtr)pathBytes.Length)) { alloc.WriteBytes(IntPtr.Zero, pathBytes); threadHandle = UnsafeNativeMethods.CreateRemoteThread(memory.ProcessHandle.DangerousGetHandle(), IntPtr.Zero, 0x0, loadLibraryPtr, alloc.Address, 0, IntPtr.Zero); if (threadHandle.IsInvalid) { throw new InjectionException( "Couldn't obtain a handle to the remotely created thread for module injection!"); } } // ThreadWaitValue.Infinite = 0xFFFFFFFF = uint.MaxValue - Object0 = 0x0 if (UnsafeNativeMethods.WaitForSingleObject(threadHandle.DangerousGetHandle(), uint.MaxValue) != 0x0) { throw new InjectionException( "WaitForSingleObject returned an unexpected value while waiting for the remote thread to be created for module injection."); } uint exitCode; if (!UnsafeNativeMethods.GetExitCodeThread(threadHandle.DangerousGetHandle(), out exitCode)) { throw new InjectionException("Couldn't obtain exit code for LoadLibraryW thread in remote process!"); } // Let's make sure our module is actually present in the remote process now (assuming it's doing nothing special to hide itself..) var moduleHandle = UnsafeNativeMethods.GetModuleHandle(libraryFileName); if (moduleHandle.IsInvalid) { throw new InjectionException( "Couldn't obtain module handle to remotely injected library after LoadLibraryW!"); } ourModule = memory.Process.Modules.Cast <ProcessModule>() .FirstOrDefault(m => m.BaseAddress == moduleHandle.DangerousGetHandle()); } finally { if (threadHandle != null && !threadHandle.IsClosed) { threadHandle.Close(); } if (kernel32Handle != null && !kernel32Handle.IsClosed) { kernel32Handle.Close(); } } // We can safely do this - if something went wrong we wouldn't be here. var module = new InjectedModule(ourModule, _memory); _injectedModules.Add(path, module); return(module); }