using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace DllInjector { public static class DllInjector { #region Constants public const int ERROR_UNHANDLED_EXCEPTION = -1; public const int ERROR_NOT_DOS_PROGRAM = -2; public const int ERROR_NOT_WINDOWS_PROGRAM = -3; public const int ERROR_NO_OPTIONAL_HEADER = -4; public const int ERROR_NO_IMPORT_TABLE = -5; public const int ERROR_NO_IMPORT_DIRECTORY = -6; public const int ERROR_MISMATCHED_ORDINALS = -7; public const UInt32 INVALID_HANDLE_VALUE = 0xffffffff; private const uint IMAGE_DOS_SIGNATURE = 0x5A4D; //MZ private const string IMAGE_DOS_SIGNATURE_STRING = "MZ"; // MZ private const uint IMAGE_OS2_SIGNATURE = 0x454E; // NE private const uint IMAGE_OS2_SIGNATURE_LE = 0x454C; // LE private const uint IMAGE_VXD_SIGNATURE = 0x454C; // LE private const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00 private const uint IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; private const uint IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; private enum DirectoryEntries { IMAGE_DIRECTORY_ENTRY_EXPORT = 0, // Export Directory IMAGE_DIRECTORY_ENTRY_IMPORT = 1, // Import Directory IMAGE_DIRECTORY_ENTRY_RESOURCE = 2, // Resource Directory IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3, // Exception Directory IMAGE_DIRECTORY_ENTRY_SECURITY = 4, // Security Directory IMAGE_DIRECTORY_ENTRY_BASERELOC = 5, // Base Relocation Table IMAGE_DIRECTORY_ENTRY_DEBUG = 6, // Debug Directory // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7, // (X86 usage) IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, // Architecture Specific Data IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8, // RVA of GP IMAGE_DIRECTORY_ENTRY_TLS = 9, // TLS Directory IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10, // Load Configuration Directory IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11, // Bound Import Directory in headers IMAGE_DIRECTORY_ENTRY_IAT = 12, // Import Address Table IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13, // Delay Load Import Descriptors IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14, // COM Runtime descriptor } //private enum DirectoryEntries [Flags] public enum SnapshotFlags : uint { TH32CS_SNAPHEAPLIST = 0x00000001, TH32CS_SNAPPROCESS = 0x00000002, TH32CS_SNAPTHREAD = 0x00000004, TH32CS_SNAPMODULE = 0x00000008, TH32CS_SNAPMODULE32 = 0x00000010, TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD), TH32CS_INHERIT = 0x80000000, NoHeaps = 0x40000000 } [Flags] public enum ProcessAccessFlags : uint { PROCESS_ALL_ACCESS = 0x001F0FFF, PROCESS_TERMINATE = 0x00000001, PROCESS_CREATE_THREAD = 0x00000002, PROCESS_VM_OPERATION = 0x00000008, PROCESS_VM_READ = 0x00000010, PROCESS_VM_WRITE = 0x00000020, PROCESS_DUP_HANDLE = 0x00000040, PROCESS_CREATE_PROCESS = 0x000000080, PROCESS_SET_QUOTA = 0x00000100, PROCESS_SET_INFORMATION = 0x00000200, PROCESS_QUERY_INFORMATION = 0x00000400, PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000, SYNCHRONIZE = 0x00100000, PROCESS_SUSPEND_RESUME = 0x800 } [Flags] public enum AllocationType { MEM_COMMIT = 0x1000, MEM_RESERVE = 0x2000, MEM_DECOMMIT = 0x4000, MEM_RELEASE = 0x8000, MEM_RESET = 0x80000, MEM_PHYSICAL = 0x400000, MEM_TOP_DOWN = 0x100000, MEM_RESET_UNDO = 0x1000000, MEM_WRITE_WATCH = 0x200000, MEM_LARGE_PAGES = 0x20000000 } [Flags] public enum MemoryProtection { PAGE_EXECUTE = 0x10, PAGE_EXECUTE_READ = 0x20, PAGE_EXECUTE_READWRITE = 0x40, PAGE_EXECUTE_WRITECOPY = 0x80, PAGE_NOACCESS = 0x01, PAGE_READONLY = 0x02, PAGE_READWRITE = 0x04, PAGE_WRITECOPY = 0x08, PAGE_GUARD = 0x100, PAGE_NOCACHE = 0x200, PAGE_WRITECOMBINE = 0x400, PAGE_TARGETS_INVALID = 0x40000000, PAGE_TARGETS_NO_UPDATE = 0x40000000 } [Flags] public enum FreeType { Decommit = 0x4000, Release = 0x8000, } #endregion // Constants #region Structures [StructLayout(LayoutKind.Sequential)] public struct IMAGE_DOS_HEADER { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public char[] e_magic; // Magic number public UInt16 e_cblp; // Bytes on last page of file public UInt16 e_cp; // Pages in file public UInt16 e_crlc; // Relocations public UInt16 e_cparhdr; // Size of header in paragraphs public UInt16 e_minalloc; // Minimum extra paragraphs needed public UInt16 e_maxalloc; // Maximum extra paragraphs needed public UInt16 e_ss; // Initial (relative) SS value public UInt16 e_sp; // Initial SP value public UInt16 e_csum; // Checksum public UInt16 e_ip; // Initial IP value public UInt16 e_cs; // Initial (relative) CS value public UInt16 e_lfarlc; // File address of relocation table public UInt16 e_ovno; // Overlay number [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public UInt16[] e_res1; // Reserved words public UInt16 e_oemid; // OEM identifier (for e_oeminfo) public UInt16 e_oeminfo; // OEM information; e_oemid specific [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public UInt16[] e_res2; // Reserved words public Int32 e_lfanew; // File address of new exe header public static int SizeOf { get { return Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)); } } public string e_magic_string { get { return new string(e_magic); } } public bool isValid { get { return e_magic_string == "MZ"; } } } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_DATA_DIRECTORY { public UInt32 VirtualAddress; public UInt32 Size; } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_FILE_HEADER { public UInt16 Machine; public UInt16 NumberOfSections; public UInt32 TimeDateStamp; public UInt32 PointerToSymbolTable; public UInt32 NumberOfSymbols; public UInt16 SizeOfOptionalHeader; public UInt16 Characteristics; } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_OPTIONAL_HEADER32 { public UInt16 Magic; public Byte MajorLinkerVersion; public Byte MinorLinkerVersion; public UInt32 SizeOfCode; public UInt32 SizeOfInitializedData; public UInt32 SizeOfUninitializedData; public UInt32 AddressOfEntryPoint; public UInt32 BaseOfCode; public UInt32 BaseOfData; public UInt32 ImageBase; public UInt32 SectionAlignment; public UInt32 FileAlignment; public UInt16 MajorOperatingSystemVersion; public UInt16 MinorOperatingSystemVersion; public UInt16 MajorImageVersion; public UInt16 MinorImageVersion; public UInt16 MajorSubsystemVersion; public UInt16 MinorSubsystemVersion; public UInt32 Win32VersionValue; public UInt32 SizeOfImage; public UInt32 SizeOfHeaders; public UInt32 CheckSum; public UInt16 Subsystem; public UInt16 DllCharacteristics; public UInt32 SizeOfStackReserve; public UInt32 SizeOfStackCommit; public UInt32 SizeOfHeapReserve; public UInt32 SizeOfHeapCommit; public UInt32 LoaderFlags; public UInt32 NumberOfRvaAndSizes; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public IMAGE_DATA_DIRECTORY[] DataDirectory; } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_OPTIONAL_HEADER64 { public UInt16 Magic; public Byte MajorLinkerVersion; public Byte MinorLinkerVersion; public UInt32 SizeOfCode; public UInt32 SizeOfInitializedData; public UInt32 SizeOfUninitializedData; public UInt32 AddressOfEntryPoint; public UInt32 BaseOfCode; public UInt64 ImageBase; public UInt32 SectionAlignment; public UInt32 FileAlignment; public UInt16 MajorOperatingSystemVersion; public UInt16 MinorOperatingSystemVersion; public UInt16 MajorImageVersion; public UInt16 MinorImageVersion; public UInt16 MajorSubsystemVersion; public UInt16 MinorSubsystemVersion; public UInt32 Win32VersionValue; public UInt32 SizeOfImage; public UInt32 SizeOfHeaders; public UInt32 CheckSum; public UInt16 Subsystem; public UInt16 DllCharacteristics; public UInt64 SizeOfStackReserve; public UInt64 SizeOfStackCommit; public UInt64 SizeOfHeapReserve; public UInt64 SizeOfHeapCommit; public UInt32 LoaderFlags; public UInt32 NumberOfRvaAndSizes; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public IMAGE_DATA_DIRECTORY[] DataDirectory; } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_NT_HEADERS32 { public UInt32 Signature; public IMAGE_FILE_HEADER FileHeader; public IMAGE_OPTIONAL_HEADER32 OptionalHeader32; public static int SizeOf = Marshal.SizeOf(typeof(IMAGE_NT_HEADERS32)); } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_NT_HEADERS64 { public static int SizeOf = Marshal.SizeOf(typeof(IMAGE_NT_HEADERS64)); public UInt32 Signature; public IMAGE_FILE_HEADER FileHeader; public IMAGE_OPTIONAL_HEADER64 OptionalHeader64; } [StructLayout(LayoutKind.Sequential)] public struct IMAGE_EXPORT_DIRECTORY { public UInt32 Characteristics; public UInt32 TimeDateStamp; public UInt16 MajorVersion; public UInt16 MinorVersion; public UInt32 Name; public UInt32 Base; public UInt32 NumberOfFunctions; public UInt32 NumberOfNames; public UInt32 AddressOfFunctions; // RVA from base of image public UInt32 AddressOfNames; // RVA from base of image public UInt32 AddressOfNameOrdinals; // RVA from base of image public static int SizeOf = Marshal.SizeOf(typeof(IMAGE_EXPORT_DIRECTORY)); } public struct MODULEENTRY32 { //http://pastebin.com/BzD1jdmH private const int MAX_PATH = 255; internal uint dwSize; internal uint th32ModuleID; internal uint th32ProcessID; internal uint GlblcntUsage; internal uint ProccntUsage; internal IntPtr modBaseAddr; internal uint modBaseSize; internal IntPtr hModule; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)] internal string szModule; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 5)] internal string szExePath; } #endregion // Structures #region DllImports [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, out IMAGE_DOS_HEADER lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, out IMAGE_NT_HEADERS32 lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, out IMAGE_NT_HEADERS64 lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, out IMAGE_EXPORT_DIRECTORY lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, [Out] ushort[] lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool ReadProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, [Out] uint[] lpBuffer, int nSize, IntPtr lpNumberOfBytesRead ); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle( IntPtr hObject ); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateToolhelp32Snapshot( SnapshotFlags dwFlags, uint th32ProcessID ); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool Module32First( IntPtr hSnapshot, ref MODULEENTRY32 lpme ); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool Module32Next( IntPtr hSnapshot, ref MODULEENTRY32 lpme ); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr OpenProcess( ProcessAccessFlags processAccess, bool bInheritHandle, uint processId ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern IntPtr VirtualAllocEx( IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect ); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern bool VirtualFreeEx( IntPtr hProcess, IntPtr lpAddress, int dwSize, FreeType dwFreeType ); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool WriteProcessMemory( IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateRemoteThread( IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId ); [DllImport("kernel32.dll", SetLastError = true)] public static extern UInt32 WaitForSingleObject( IntPtr hHandle, UInt32 dwMilliseconds ); #endregion // DllImports /// /// Given a ProccesID, this routine will return the base address of the module specified by moduleName. /// /// /// /// /// Returns NULL on failure. public static IntPtr? GetProcessModuleHandle(uint processID, string moduleName, out int errorCode) { errorCode = 0; IntPtr hSnapShot = IntPtr.Zero; moduleName = moduleName.ToLower(); /// Process/Module names are not case sensitive. try { /// Getting snapshot of current running processes so we can search through thier loaded modules. hSnapShot = CreateToolhelp32Snapshot(SnapshotFlags.TH32CS_SNAPMODULE | SnapshotFlags.TH32CS_SNAPMODULE32, processID); if ((uint)hSnapShot == INVALID_HANDLE_VALUE) { errorCode = Marshal.GetLastWin32Error(); return null; } /// Creating space to hold our MODULEENTRY32 structure MODULEENTRY32 mod = new MODULEENTRY32() { dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32)) }; /// Retrieving the first module out of our snap shot. if (!Module32First(hSnapShot, ref mod)) { errorCode = Marshal.GetLastWin32Error(); return null; } do { if (mod.szModule.ToLower() == moduleName) { return mod.modBaseAddr; } } while (Module32Next(hSnapShot, ref mod)); /// Did not find the module in the specified process. return IntPtr.Zero; } catch { errorCode = ERROR_UNHANDLED_EXCEPTION; return null; } finally { if (hSnapShot != IntPtr.Zero) { CloseHandle(hSnapShot); } } } public static IntPtr? GetProcessProcAddress(IntPtr hProcess, uint processID, string moduleName, string procName, out int errorCode) { errorCode = 0; try { /// Get handle to the Kernel32.dll library thats located inside the process specified by ProcessID IntPtr? ret = GetProcessModuleHandle((uint)processID, "Kernel32.dll", out errorCode); if (ret == null) { return null; } IntPtr hKernel32 = (IntPtr)ret; /// Retrieving the dos header of our Kernel32 library module inside of the process indicated by hProcess IMAGE_DOS_HEADER dos_header; if (!ReadProcessMemory(hProcess, hKernel32, out dos_header, IMAGE_DOS_HEADER.SizeOf, IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } /// checking to make sure this is a DOS program if (dos_header.e_magic_string != IMAGE_DOS_SIGNATURE_STRING) { errorCode = ERROR_NOT_DOS_PROGRAM; return null; } //parse nt header IntPtr nt_header_ptr = new IntPtr(dos_header.e_lfanew + hKernel32.ToInt32()); IMAGE_DATA_DIRECTORY[] DataDirectory; if (IntPtr.Size == 4) { /// this is block is for 32-bit Architectures. IMAGE_NT_HEADERS32 nt_header; if (!ReadProcessMemory(hProcess, nt_header_ptr, out nt_header, IMAGE_NT_HEADERS32.SizeOf, IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } /// Checking to make sure this is a windows program if (nt_header.Signature != IMAGE_NT_SIGNATURE) { errorCode = ERROR_NOT_WINDOWS_PROGRAM; return null; } //optional header (pretty much not optional) if (nt_header.OptionalHeader32.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { errorCode = ERROR_NO_OPTIONAL_HEADER; return null; } DataDirectory = nt_header.OptionalHeader32.DataDirectory; } else { /// this is block is for 64-bit Architectures. IMAGE_NT_HEADERS64 nt_header; if (!ReadProcessMemory(hProcess, nt_header_ptr, out nt_header, IMAGE_NT_HEADERS64.SizeOf, IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } /// Checking to make sure this is a windows program if (nt_header.Signature != IMAGE_NT_SIGNATURE) { errorCode = ERROR_NOT_WINDOWS_PROGRAM; return null; } //optional header (pretty much not optional) if (nt_header.OptionalHeader64.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { errorCode = ERROR_NO_OPTIONAL_HEADER; return null; } DataDirectory = nt_header.OptionalHeader64.DataDirectory; } IMAGE_DATA_DIRECTORY EntryExport = DataDirectory[(int)DirectoryEntries.IMAGE_DIRECTORY_ENTRY_EXPORT]; if (EntryExport.Size == 0) { errorCode = ERROR_NO_IMPORT_TABLE; return null; //no import table } if (EntryExport.VirtualAddress == 0) { errorCode = ERROR_NO_IMPORT_DIRECTORY; return null; //no import directory } IntPtr pExports_ptr = new IntPtr(EntryExport.VirtualAddress + hKernel32.ToInt32()); IMAGE_EXPORT_DIRECTORY pExports; if (!ReadProcessMemory(hProcess, pExports_ptr, out pExports, IMAGE_EXPORT_DIRECTORY.SizeOf, IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } IntPtr functions_ptr = new IntPtr(hKernel32.ToInt32() + pExports.AddressOfFunctions); IntPtr ordinals_ptr = new IntPtr(hKernel32.ToInt32() + pExports.AddressOfNameOrdinals); IntPtr names_ptr = new IntPtr(hKernel32.ToInt32() + pExports.AddressOfNames); uint[] functions = new uint[pExports.NumberOfFunctions]; if (!ReadProcessMemory(hProcess, functions_ptr, functions, (int)pExports.NumberOfFunctions * sizeof(uint), IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } ushort[] ordinals = new ushort[pExports.NumberOfNames]; if (!ReadProcessMemory(hProcess, ordinals_ptr, ordinals, (int)pExports.NumberOfNames * sizeof(ushort), IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } uint[] names = new uint[pExports.NumberOfNames]; if (!ReadProcessMemory(hProcess, names_ptr, names, (int)pExports.NumberOfNames * sizeof(uint), IntPtr.Zero)) { errorCode = Marshal.GetLastWin32Error(); return null; } for (uint i = 0; i < ordinals.Length; i++) { uint ord = ordinals[i]; if (i >= pExports.NumberOfNames || ord >= pExports.NumberOfFunctions) { errorCode = ERROR_MISMATCHED_ORDINALS; return null; // Mismatched ordinals } if (functions[ord] < EntryExport.VirtualAddress || functions[ord] >= EntryExport.VirtualAddress + EntryExport.Size) { IntPtr name_ptr = new IntPtr(hKernel32.ToInt32() + names[i]); if (name_ptr != IntPtr.Zero) { byte[] name_buf = new byte[procName.Length + 1]; // +1 for terminating null '\0' if (!ReadProcessMemory(hProcess, name_ptr, name_buf, name_buf.Length, IntPtr.Zero)) { continue; } if (name_buf[name_buf.Length - 1] == 0) //check for partial name that does not end with terminating zero { string name = Encoding.ASCII.GetString(name_buf, 0, name_buf.Length - 1); //NB! buf length - 1 if (name == procName) { IntPtr pFunctionAddress = new IntPtr(hKernel32.ToInt32() + functions[ord]); return pFunctionAddress; } } } } } return IntPtr.Zero; } catch { errorCode = ERROR_UNHANDLED_EXCEPTION; return null; } } public static bool InjectDll(uint processID, string dllPath, out int errorCode, uint DllExitWaitTime = 5000) { errorCode = 0; IntPtr hProcess = IntPtr.Zero; IntPtr hDllPathArg = IntPtr.Zero; IntPtr hRemoteThread = IntPtr.Zero; try { /// Get handle to the process identified by processID hProcess = OpenProcess(ProcessAccessFlags.PROCESS_ALL_ACCESS, false, processID); /// Error checking if (hProcess == IntPtr.Zero) { errorCode = Marshal.GetLastWin32Error(); return false; } /// Get Address of the LoadLibrary routine withint the process identified by processID IntPtr? ret = GetProcessProcAddress(hProcess, processID, "Kernel32.dll", "LoadLibraryA", out errorCode); if (ret == null) { return false; } IntPtr hLoadLibrary = (IntPtr)ret; /// Allocate some memory in the remote process to store the dllPath string argument. hDllPathArg = VirtualAllocEx( hProcess, IntPtr.Zero, (uint)(dllPath.Length + 1), AllocationType.MEM_COMMIT, MemoryProtection.PAGE_READWRITE ); /// Error checking if (hDllPathArg == IntPtr.Zero) { errorCode = Marshal.GetLastWin32Error(); return false; } // write dll file path argument into remote process's memory space IntPtr bytesWritten; bool isSucceeded = WriteProcessMemory( hProcess, hDllPathArg, ASCIIEncoding.ASCII.GetBytes(dllPath), dllPath.Length + 1, out bytesWritten ); /// Error checking if (!isSucceeded) { errorCode = Marshal.GetLastWin32Error(); return false; } // invoke the LoadLibrary method in the remote process. IntPtr dwThreadId; hRemoteThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, hLoadLibrary, hDllPathArg, 0, out dwThreadId); /// Error checking if (hRemoteThread == IntPtr.Zero) { errorCode = Marshal.GetLastWin32Error(); return false; } /// Waiting for thread to exit. if (DllExitWaitTime > 0) { uint result = WaitForSingleObject(hRemoteThread, DllExitWaitTime); } return true; } catch { errorCode = ERROR_UNHANDLED_EXCEPTION; return false; } finally { bool retBool; if (hProcess != IntPtr.Zero) { if (hDllPathArg != IntPtr.Zero) { retBool = VirtualFreeEx(hProcess, hDllPathArg, 0, FreeType.Release); } retBool = CloseHandle(hProcess); } if (hRemoteThread != IntPtr.Zero) { retBool = CloseHandle(hRemoteThread); } } } } }