public override bool Unload(IntPtr hModule, IntPtr hProcess) { // Unloading a manually mapped file is fairly straightforward. There is no need to call FreeLibrary or anything // because the file was never actually injected using LoadLibrary and doesn't need to clear any PEB entries etc. // basically just call the Entry Point again with DLL_PROCESS_DETACH flag and not-null for the lpReserved parameter // and then VirtualFree the remote memory. ClearErrors(); if (hModule.IsNull()) { throw new ArgumentNullException("hModule", "Invalid module handle"); } if (hProcess.IsNull() || hProcess.Compare(-1)) { throw new ArgumentException("Invalid process handle.", "hProcess"); } IntPtr pStub = IntPtr.Zero; uint nBytes = 0; try { uint entry = FindEntryPoint(hProcess, hModule); if (entry != 0) { var stub = (byte[])DLLMAIN_STUB.Clone(); BitConverter.GetBytes(hModule.ToInt32()).CopyTo(stub, 0x0B); BitConverter.GetBytes((uint)0).CopyTo(stub, 0x06); BitConverter.GetBytes((uint)1000).CopyTo(stub, 0x01); pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLMAIN_STUB.Length, 0x1000 | 0x2000, 0x40); if (pStub.IsNull() || (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nBytes) || nBytes != (uint)stub.Length)) { throw new InvalidOperationException("Unable to write stub to the remote process."); } IntPtr hStubThread = WinAPI.CreateRemoteThread(hProcess, 0, 0, pStub, (uint)hModule.Add(entry).ToInt32(), 0, 0); if (WinAPI.WaitForSingleObject(hStubThread, 5000) == 0x0L) { WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); WinAPI.CloseHandle(hStubThread); return(WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000)); } return(false); } else { return(WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000)); } } catch (Exception e) { SetLastError(e); return(false); } }
// Most efficient version, this will be the work horse. private static IntPtr MapModule(PortableExecutable image, IntPtr hProcess, bool preserveHeaders = false) { if (hProcess.IsNull() || hProcess.Compare(-1)) { throw new ArgumentException("Invalid process handle.", "hProcess"); } if (image == null) { throw new ArgumentException("Cannot map a non-existant PE Image.", "image"); } int processId = WinAPI.GetProcessId(hProcess); if (processId == 0) { throw new ArgumentException("Provided handle doesn't have sufficient permissions to inject", "hProcess"); } IntPtr hModule = IntPtr.Zero; IntPtr pStub = IntPtr.Zero; uint nBytes = 0; try { //allocate memory for the image to load into the remote process. hModule = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, image.NTHeader.OptionalHeader.SizeOfImage, 0x1000 | 0x2000, 0x04); if (hModule.IsNull()) { throw new InvalidOperationException("Unable to allocate memory in the remote process."); } PatchRelocations(image, hModule); LoadDependencies(image, hProcess, processId); PatchImports(image, hProcess, processId); if (preserveHeaders) { long szHeader = (image.DOSHeader.e_lfanew + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) + sizeof(uint) + image.NTHeader.FileHeader.SizeOfOptionalHeader); byte[] header = new byte[szHeader]; if (image.Read(0, SeekOrigin.Begin, header)) { WinAPI.WriteProcessMemory(hProcess, hModule, header, header.Length, out nBytes); } } MapSections(image, hProcess, hModule); // some modules don't have an entry point and are purely libraries, mapping them and keeping the handle is just fine // an unlikely scenario with forced injection, but you never know. if (image.NTHeader.OptionalHeader.AddressOfEntryPoint > 0) { var stub = (byte[])DLLMAIN_STUB.Clone(); BitConverter.GetBytes(hModule.ToInt32()).CopyTo(stub, 0x0B); pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLMAIN_STUB.Length, 0x1000 | 0x2000, 0x40); if (pStub.IsNull() || (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nBytes) || nBytes != (uint)stub.Length)) { throw new InvalidOperationException("Unable to write stub to the remote process."); } IntPtr hStubThread = WinAPI.CreateRemoteThread(hProcess, 0, 0, pStub, (uint)(hModule.Add(image.NTHeader.OptionalHeader.AddressOfEntryPoint).ToInt32()), 0, 0); if (WinAPI.WaitForSingleObject(hStubThread, 5000) == 0x0L) { WinAPI.GetExitCodeThread(hStubThread, out nBytes); if (nBytes == 0) { WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); throw new Exception("Entry method of module reported a failure " + Marshal.GetLastWin32Error().ToString()); } WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); WinAPI.CloseHandle(hStubThread); } } } catch (Exception e) { if (!hModule.IsNull()) { WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); } if (!pStub.IsNull()) { WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); } hModule = IntPtr.Zero; throw e; } return(hModule); }