public override void GetObjectData(SerializationInfo info, StreamingContext context) { int targetIndex = 0; Object[] invocationList = _invocationList as Object[]; if (invocationList == null) { MethodInfo method = Method; // A MethodInfo object can be a RuntimeMethodInfo, a RefEmit method (MethodBuilder, etc), or a DynamicMethod // One can only create delegates on RuntimeMethodInfo and DynamicMethod. // If it is not a RuntimeMethodInfo (must be a DynamicMethod) or if it is an unmanaged function pointer, throw if (!(method is RuntimeMethodInfo) || IsUnmanagedFunctionPtr()) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidDelegateType")); } // We can't deal with secure delegates either. if (!InvocationListLogicallyNull() && !_invocationCount.IsNull() && !_methodPtrAux.IsNull()) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidDelegateType")); } DelegateSerializationHolder.GetDelegateSerializationInfo(info, this.GetType(), Target, method, targetIndex); } else { DelegateSerializationHolder.DelegateEntry nextDe = null; int invocationCount = (int)_invocationCount; for (int i = invocationCount; --i >= 0;) { MulticastDelegate d = (MulticastDelegate)invocationList[i]; MethodInfo method = d.Method; // If it is not a RuntimeMethodInfo (must be a DynamicMethod) or if it is an unmanaged function pointer, skip if (!(method is RuntimeMethodInfo) || IsUnmanagedFunctionPtr()) { continue; } // We can't deal with secure delegates either. if (!d.InvocationListLogicallyNull() && !d._invocationCount.IsNull() && !d._methodPtrAux.IsNull()) { continue; } DelegateSerializationHolder.DelegateEntry de = DelegateSerializationHolder.GetDelegateSerializationInfo(info, d.GetType(), d.Target, method, targetIndex++); if (nextDe != null) { nextDe.Entry = de; } nextDe = de; } // if nothing was serialized it is a delegate over a DynamicMethod, so just throw if (nextDe == null) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidDelegateType")); } } }
public override void GetObjectData(SerializationInfo info, StreamingContext context) { int targetIndex = 0; Object[] invocationList = _invocationList as Object[]; if (invocationList == null) { MethodInfo method = Method; // if it is a delegate over a DynamicMethod or an unmanaged function pointer, throw if (method is System.Reflection.Emit.DynamicMethod || method is System.Reflection.Emit.DynamicMethod.RTDynamicMethod || IsUnmanagedFunctionPtr()) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidDelegateType")); } // We can't deal with secure delegates either. if (_invocationList != null && !_invocationCount.IsNull()) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidDelegateType")); } DelegateSerializationHolder.GetDelegateSerializationInfo(info, this.GetType(), Target, method, targetIndex); } else { DelegateSerializationHolder.DelegateEntry nextDe = null; int invocationCount = (int)_invocationCount; for (int i = invocationCount; --i >= 0;) { MulticastDelegate d = (MulticastDelegate)invocationList[i]; MethodInfo method = d.Method; if (method is System.Reflection.Emit.DynamicMethod || method is System.Reflection.Emit.DynamicMethod.RTDynamicMethod || IsUnmanagedFunctionPtr()) { continue; } // We can't deal with secure delegates either. if (d._invocationList != null && !d._invocationCount.IsNull()) { continue; } DelegateSerializationHolder.DelegateEntry de = DelegateSerializationHolder.GetDelegateSerializationInfo(info, d.GetType(), d.Target, method, targetIndex++); if (nextDe != null) { nextDe.Entry = de; } nextDe = de; } // if nothing was serialized it is a delegate over a DynamicMethod, so just throw if (nextDe == null) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidDelegateType")); } } }
public override IntPtr[] InjectAll(string[] dllPaths, IntPtr hProcess) { ClearErrors(); if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentOutOfRangeException("hProcess", "Invalid process handle specified."); try { // Use the optimized assembly "multiload" stub to load all the dlls in one go. IntPtr pModules = IntPtr.Zero; IntPtr pStub = CreateMultiLoadStub(dllPaths, hProcess, out pModules); IntPtr[] modules = null; if (!pStub.IsNull()) { try { // Run the stub uint threadval = WinAPI.RunThread(hProcess, pStub, 0, 10000); if (threadval != uint.MaxValue) { // Read the module handle buffer into memory byte[] rawHandles = WinAPI.ReadRemoteMemory(hProcess, pModules, (uint)dllPaths.Length << 2); if (rawHandles != null) { // convert the raw binary data into usable module handles. modules = new IntPtr[dllPaths.Length]; for (int i = 0; i < modules.Length; i++) modules[i] = new IntPtr(BitConverter.ToInt32(rawHandles, i << 2)); } else { throw new InvalidOperationException("Unable to read from the remote process."); } } else { throw new Exception("Error occurred while executing remote thread."); } } finally { // cleanup the memory WinAPI.VirtualFreeEx(hProcess, pModules, 0, 0x8000); WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); } } return modules; } catch (Exception e) { SetLastError(e); return null; } }
/// <summary> /// Get a handle used to make a call into the VM pointing to this domain /// </summary> internal AppDomainHandle GetNativeHandle() { // This should never happen under normal circumstances. However, there ar ways to create an // uninitialized object through remoting, etc. if (_pDomain.IsNull()) { throw new InvalidOperationException(SR.Argument_InvalidHandle); } return(new AppDomainHandle(_pDomain)); }
internal void RegisterWithHost() { if (HasHost()) { IntPtr punkAppDomainManager = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { punkAppDomainManager = Marshal.GetIUnknownForObject(this); RegisterWithHost(punkAppDomainManager); } finally { if (!punkAppDomainManager.IsNull()) { Marshal.Release(punkAppDomainManager); } } } }
// Core injection method that actually does all the work. public override IntPtr Inject(string dllPath, IntPtr hProcess) { ClearErrors(); if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentOutOfRangeException("hProcess", "Invalid process handle specified."); try { IntPtr hModule = IntPtr.Zero; // Find the LoadLibraryW function address in the remote process IntPtr fnLoadLibraryW = WinAPI.GetProcAddress(WinAPI.GetModuleHandleA("kernel32.dll"), "LoadLibraryW"); if (fnLoadLibraryW.IsNull()) throw new Exception("Unable to locate the LoadLibraryW entry point"); // Create a wchar_t * in the remote process which points to the unicode version of the dll path. IntPtr pLib = WinAPI.CreateRemotePointer(hProcess, Encoding.Unicode.GetBytes(dllPath + "\0"), 0x04); if (pLib.IsNull()) throw new InvalidOperationException("Failed to allocate memory in the remote process"); try { // Call LoadLibraryW in the remote process by using CreateRemoteThread. uint hMod = WinAPI.RunThread(hProcess, fnLoadLibraryW, (uint)pLib.ToInt32(), 10000); if (hMod == uint.MaxValue) throw new Exception("Error occurred when calling function in the remote process"); else if (hMod == 0) throw new Exception("Failed to load module into remote process. Error code: " + WinAPI.GetLastErrorEx(hProcess).ToString()); else hModule = Win32Ptr.Create(hMod); } finally { // Cleanup in all cases. WinAPI.VirtualFreeEx(hProcess, pLib, 0, 0x8000); } return hModule; } catch (Exception e) { SetLastError(e); return IntPtr.Zero; } }
internal void RegisterWithHost() { if (HasHost()) { IntPtr zero = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { zero = Marshal.GetIUnknownForObject(this); RegisterWithHost(zero); } finally { if (!zero.IsNull()) { Marshal.Release(zero); } } } }
public override bool Unload(IntPtr hModule, IntPtr hProcess) { ClearErrors(); if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentOutOfRangeException("hProcess", "Invalid process handle specified."); if (hModule.IsNull()) throw new ArgumentNullException("hModule", "Invalid module handle"); try { bool[] results = UnloadAll(new IntPtr[] { hModule }, hProcess); return results != null && results.Length > 0 ? results[0] : false; } catch (Exception e) { SetLastError(e); return false; } }
internal void RegisterWithHost() { if (!AppDomainManager.HasHost()) { return; } IntPtr num = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { num = Marshal.GetIUnknownForObject((object)this); AppDomainManager.RegisterWithHost(num); } finally { if (!num.IsNull()) { Marshal.Release(num); } } }
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; } }
public static IntPtr ReadRemotePointer(IntPtr hProcess, IntPtr pData) { IntPtr ptr = IntPtr.Zero; if (!hProcess.IsNull() && !pData.IsNull()) { byte[] mem = null; if ((mem = ReadRemoteMemory(hProcess, pData, (uint)IntPtr.Size)) != null) ptr = new IntPtr(BitConverter.ToInt32(mem, 0)); } return ptr; }
// 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; }
public override bool[] UnloadAll(IntPtr[] hModules, IntPtr hProcess) { // No fancy optimized method here, UnloadAll simply represents a series of direct calls to Unload for each // module. Pretty simple stuff. ClearErrors(); if (hModules == null) throw new ArgumentNullException("hModules", "Parameter cannot be null."); if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentOutOfRangeException("hProcess", "Invalid process handle specified."); try { var results = new bool[hModules.Length]; for (int i = 0; i < hModules.Length; i++) results[i] = Unload(hModules[i], hProcess); return results; } catch (Exception e) { SetLastError(e); return null; } }
protected virtual IntPtr CreateMultiLoadStub(string[] paths, IntPtr hProcess, out IntPtr pModuleBuffer, uint nullmodule = 0) { // This function creates a multi-loading stub which essentially iterates a list of required modules and writes the results // of the LoadLibraryA / GetModuleHandleA call to a preallocated buffer (out IntPtr pModuleBuffer) in the remote process. pModuleBuffer = IntPtr.Zero; IntPtr pStub = IntPtr.Zero; try { // get function addresses. IntPtr hKernel32 = WinAPI.GetModuleHandleA("kernel32.dll"); IntPtr fnLoadLibraryA = WinAPI.GetProcAddress(hKernel32, "LoadLibraryA"); IntPtr fnGetModuleHandleA = WinAPI.GetProcAddress(hKernel32, "GetModuleHandleA"); // sanity check if (fnLoadLibraryA.IsNull() || fnGetModuleHandleA.IsNull()) throw new Exception("Unable to find necessary function entry points in the remote process"); // Create the necessary remote buffers and values for the assembler call pModuleBuffer = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)paths.Length << 2, 0x1000 | 0x2000, 0x04); IntPtr pLibs = WinAPI.CreateRemotePointer(hProcess, System.Text.Encoding.ASCII.GetBytes(string.Join("\0", paths) + "\0"), 0x04); if (pModuleBuffer.IsNull() || pLibs.IsNull()) throw new InvalidOperationException("Unable to allocate memory in the remote process"); try { uint nbytes = 0; byte[] nullset = new byte[paths.Length << 2]; for (int i = 0; i < nullset.Length >> 2; i++) BitConverter.GetBytes(nullmodule).CopyTo(nullset, i << 2); WinAPI.WriteProcessMemory(hProcess, pModuleBuffer, nullset, nullset.Length, out nbytes); var stub = (byte[])MULTILOAD_STUB.Clone(); pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)stub.Length, 0x1000 | 0x2000, 0x40); if (pStub.IsNull()) throw new InvalidOperationException("Unable to allocate memory in the remote process"); BitConverter.GetBytes(pLibs.ToInt32()).CopyTo(stub, 0x07); BitConverter.GetBytes(paths.Length).CopyTo(stub, 0x0F); BitConverter.GetBytes(pModuleBuffer.ToInt32()).CopyTo(stub, 0x18); BitConverter.GetBytes(fnGetModuleHandleA.Subtract(pStub.Add(0x38)).ToInt32()).CopyTo(stub, 0x34); BitConverter.GetBytes(fnLoadLibraryA.Subtract(pStub.Add(0x45)).ToInt32()).CopyTo(stub, 0x41); if (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nbytes) || nbytes != (uint)stub.Length) throw new Exception("Error creating the remote function stub."); return pStub; } finally // Don't actually handle the exception, just clean up some of the allocated memory. { WinAPI.VirtualFreeEx(hProcess, pModuleBuffer, 0, 0x8000); WinAPI.VirtualFreeEx(hProcess, pLibs, 0, 0x8000); if (!pStub.IsNull()) WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); pModuleBuffer = IntPtr.Zero; } } catch (Exception e) { SetLastError(e); return IntPtr.Zero; } }
public override IntPtr[] InjectAll(string[] dllPaths, IntPtr hProcess) { ClearErrors(); try { if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentException("Invalid process handle.", "hProcess"); int processId = WinAPI.GetProcessId(hProcess); if (processId == 0) throw new ArgumentException("Provided handle doesn't have sufficient permissions to inject", "hProcess"); Process target = Process.GetProcessById(processId); if (target.Threads.Count == 0) throw new Exception("Target process has no targetable threads to hijack."); //open a handle to the remote thread to allow for thread operations. ProcessThread thread = SelectOptimalThread(target); IntPtr hThread = WinAPI.OpenThread(0x001A, false, thread.Id); if (hThread.IsNull() || hThread.Compare(-1)) throw new Exception("Unable to obtain a handle for the remote thread."); IntPtr pModules = IntPtr.Zero; IntPtr pRedirect = IntPtr.Zero; // use the generic multiload stub to load the paths. // call this stub from the REDIRECT_STUB. IntPtr pStub = CreateMultiLoadStub(dllPaths, hProcess, out pModules, 1); IntPtr[] modules = null; if (!pStub.IsNull()) { if (WinAPI.SuspendThread(hThread) == uint.MaxValue) throw new Exception("Unable to suspend the remote thread"); //enter a new try/catch block to ensure the suspended thread is resumed, no matter if we fail somewhere else. try { uint nbytes = 0; WinAPI.CONTEXT ctx = default(WinAPI.CONTEXT); ctx.ContextFlags = 0x10001U; // CONTEXT_CONTROL flag. So that we get back the EIP value of the suspended thread. if (!WinAPI.GetThreadContext(hThread, ref ctx)) throw new InvalidOperationException("Cannot get the remote thread's context"); byte[] stub = REDIRECT_STUB; IntPtr pAlloc = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)stub.Length, 0x1000 | 0x2000, 0x40); if (pAlloc.IsNull()) throw new InvalidOperationException("Unable to allocate memory in the remote process."); //patch the EIP value and the Stub address for the redirection stub before commiting it to the remote process. BitConverter.GetBytes(pStub.Subtract(pAlloc.Add(7)).ToInt32()).CopyTo(stub, 3); BitConverter.GetBytes((uint)(ctx.Eip - pAlloc.Add(stub.Length).ToInt32())).CopyTo(stub, stub.Length - 4); if (!WinAPI.WriteProcessMemory(hProcess, pAlloc, stub, stub.Length, out nbytes) || nbytes != (uint)stub.Length) throw new InvalidOperationException("Unable to write stub to the remote process."); ctx.Eip = (uint)pAlloc.ToInt32(); // Set the entry point for the thread to the redirection stub and resume the thread. WinAPI.SetThreadContext(hThread, ref ctx); } catch (Exception e) { SetLastError(e); modules = null; WinAPI.VirtualFreeEx(hProcess, pModules, 0, 0x8000); WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); WinAPI.VirtualFreeEx(hProcess, pRedirect, 0, 0x8000); } WinAPI.ResumeThread(hThread); if (GetLastError() == null) { System.Threading.Thread.Sleep(100); modules = new IntPtr[dllPaths.Length]; byte[] rawHandles = WinAPI.ReadRemoteMemory(hProcess, pModules, (uint)dllPaths.Length << 2); if (rawHandles != null) { for (int i = 0; i < modules.Length; i++) modules[i] = Win32Ptr.Create(BitConverter.ToInt32(rawHandles, i << 2)); } } // deliberately didn't clean up the remote memory here. Unfortunately there's no solid way // to ensure the function stub has been scheduled by the operating system. It may not even happen for // ages, or something else may block the thread. When the stub eventually is executes and returns, the reset // of the stub needs to still be there in order for the function to successfully return, otherwise the process just crashes // and we lose the distinct possibility that the injection was successful. WinAPI.CloseHandle(hThread); } return modules; } catch (Exception e) { SetLastError(e); return null; } }
[System.Security.SecuritySafeCritical] // auto-generated public override bool Equals(Object obj) { if (obj == null || !InternalEqualTypes(this, obj)) { return(false); } Delegate d = (Delegate)obj; // do an optimistic check first. This is hopefully cheap enough to be worth if (_target == d._target && _methodPtr == d._methodPtr && _methodPtrAux == d._methodPtrAux) { return(true); } // even though the fields were not all equals the delegates may still match // When target carries the delegate itself the 2 targets (delegates) may be different instances // but the delegates are logically the same // It may also happen that the method pointer was not jitted when creating one delegate and jitted in the other // if that's the case the delegates may still be equals but we need to make a more complicated check if (_methodPtrAux.IsNull()) { if (!d._methodPtrAux.IsNull()) { return(false); // different delegate kind } // they are both closed over the first arg if (_target != d._target) { return(false); } // fall through method handle check } else { if (d._methodPtrAux.IsNull()) { return(false); // different delegate kind } // Ignore the target as it will be the delegate instance, though it may be a different one /* * if (_methodPtr != d._methodPtr) * return false; */ if (_methodPtrAux == d._methodPtrAux) { return(true); } // fall through method handle check } // method ptrs don't match, go down long path // if (_methodBase == null || d._methodBase == null || !(_methodBase is MethodInfo) || !(d._methodBase is MethodInfo)) { return(Delegate.InternalEqualMethodHandles(this, d)); } else { return(_methodBase.Equals(d._methodBase)); } }
/** * Find the entry point of a loaded module * based on its Base Address. Reverses the PE * structure to find the entry point */ private static uint FindEntryPoint(IntPtr hProcess, IntPtr hModule) { if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentException("Invalid process handle.", "hProcess"); if (hModule.IsNull()) throw new ArgumentException("Invalid module handle.", "hModule"); byte[] bDosHeader = WinAPI.ReadRemoteMemory(hProcess, hModule, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))); if (bDosHeader != null) { ushort e_magic = BitConverter.ToUInt16(bDosHeader, 0); uint e_lfanew = BitConverter.ToUInt32(bDosHeader, 0x3C); if (e_magic == 23117) { byte[] bNtHeader = WinAPI.ReadRemoteMemory(hProcess, hModule.Add(e_lfanew), (uint)Marshal.SizeOf(typeof(IMAGE_NT_HEADER32))); if (bNtHeader != null && BitConverter.ToUInt32(bNtHeader, 0) == 17744) { IMAGE_NT_HEADER32 ntHd = default(IMAGE_NT_HEADER32); using (var buffer = new UnmanagedBuffer(256)) if (buffer.Translate<IMAGE_NT_HEADER32>(bNtHeader, out ntHd)) return ntHd.OptionalHeader.AddressOfEntryPoint; } } } return 0; }