protected override void WndProc(ref Message m) { if (m.Msg == WM_RPC_MESSAGE) { byte[] messageData = null; UInt32 messageID = 0; if ((m.WParam != IntPtr.Zero) && (m.LParam != IntPtr.Zero)) { using (var region = RemoteMemoryRegion.Existing(_Process, m.WParam, (uint)m.LParam.ToInt64())) messageData = ReadRemoteData(region, out messageID); } Future <byte[]> fResult; Monitor.Enter(_AwaitingResponses); if (_AwaitingResponses.TryGetValue(messageID, out fResult)) { _AwaitingResponses.Remove(messageID); Monitor.Exit(_AwaitingResponses); fResult.SetResult(messageData, null); } else { Debug.Assert(messageID == 0); Monitor.Exit(_AwaitingResponses); _Messages.Enqueue(messageData); } } else { base.WndProc(ref m); } }
protected RemoteMemoryRegion GetFunctionRegion(string moduleName, string functionName, byte[] replacementBytes) { var address = GetFunctionAddress(moduleName, functionName); return(RemoteMemoryRegion.Existing( Process, address, (uint)replacementBytes.Length )); }
protected unsafe byte[] ReadRemoteData(RemoteMemoryRegion region, out UInt32 messageId) { using (var handle = region.OpenHandle(ProcessAccessFlags.VMRead)) { messageId = BitConverter.ToUInt32( region.ReadBytes(handle, 0, 4), 0 ); return(region.ReadBytes(handle, 4, region.Size - 4)); } }
public static RemoteMemoryRegion Allocate(Process process, SafeProcessHandle handle, UInt32 size) { var result = new RemoteMemoryRegion { Process = process, Size = size }; result.Address = Win32.VirtualAllocEx( handle.DangerousGetHandle(), IntPtr.Zero, size, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ReadWrite ); if (result.Address == IntPtr.Zero) { var error = Win32.GetLastError(); throw new Exception(String.Format("Allocation failed: Error {0:x8}", error)); } return result; }
public static RemoteMemoryRegion Allocate(Process process, SafeProcessHandle handle, UInt32 size) { var result = new RemoteMemoryRegion { Process = process, Size = size }; result.Address = Win32.VirtualAllocEx( handle.DangerousGetHandle(), IntPtr.Zero, size, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ReadWrite ); if (result.Address == IntPtr.Zero) { var error = Win32.GetLastError(); throw new Exception(String.Format("Allocation failed: Error {0:x8}", error)); } return(result); }
public unsafe void Send(byte[] message) { if (_Process == null) { throw new Exception("No remote process"); } if (RemoteThreadId == 0) { throw new Exception("No remote thread"); } using (var handle = Win32.OpenProcessHandle(ProcessAccessFlags.VMWrite | ProcessAccessFlags.VMOperation, false, _Process.Id)) { RemoteMemoryRegion region; UInt32 regionSize = (UInt32)message.Length; // leaked on purpose region = RemoteMemoryRegion.Allocate( _Process, handle, regionSize ); fixed(byte *pData = message) { try { region.Write(handle, 0, regionSize, pData); } catch { try { region.Dispose(); } catch { } throw; } } if (!Win32.PostThreadMessage(RemoteThreadId, WM_RPC_MESSAGE, region.Address, region.Size)) { var error = Win32.GetLastError(); region.Dispose(); throw new Exception(String.Format("Error posting thread message: {0:x8}", error)); } } }
public static unsafe RemoteMemoryRegion Inject( Process process, PortableExecutable executable, IntPtr payloadArgument, Future <Int32> threadResultFuture, Future <UInt32> threadIdFuture ) { RemoteMemoryRegion region = null; using (var handle = Win32.OpenProcessHandle( ProcessAccessFlags.VMRead | ProcessAccessFlags.VMWrite | ProcessAccessFlags.VMOperation | ProcessAccessFlags.CreateThread | ProcessAccessFlags.QueryInformation, false, process.Id )) try { region = RemoteMemoryRegion.Allocate( process, handle, executable.OptionalHeader.SizeOfImage ); region.Protect(handle, 0, region.Size, MemoryProtection.ReadWrite); var baseAddress = (UInt32)region.Address.ToInt64(); executable.Rebase(baseAddress); executable.ResolveImports(); foreach (var section in executable.Sections.Values) { // 0-byte remote memory read/write/protect operations will fail with an error. if (section.Size <= 0) { continue; fixed(byte *data = section.RawData) { region.Write( handle, section.VirtualAddress, section.Size, data ); // Why the f**k isn't this a flags-style enumeration? Sigh, classic windows. MemoryProtection protection = MemoryProtection.ReadOnly; if ((section.Characteristics & PortableExecutable.SectionCharacteristics.MemExecute) == PortableExecutable.SectionCharacteristics.MemExecute) { protection = MemoryProtection.ExecuteRead; } else if ((section.Characteristics & PortableExecutable.SectionCharacteristics.MemWrite) == PortableExecutable.SectionCharacteristics.MemWrite) { protection = MemoryProtection.ReadWrite; } region.Protect( handle, section.VirtualAddress, section.Size, protection ); } } UInt32 threadId = 0; UInt32 creationFlags = 0x0; IntPtr remoteThreadHandle = Win32.CreateRemoteThread( handle.DangerousGetHandle(), IntPtr.Zero, 0, baseAddress + executable.OptionalHeader.AddressOfEntryPoint, payloadArgument, creationFlags, out threadId ); if (remoteThreadHandle == IntPtr.Zero) { var error = Win32.GetLastError(); throw new Exception(String.Format("Thread start failed: Error {0:x8}", error)); } threadIdFuture.Complete(threadId); var threadHandle = new ThreadWaitHandle(new SafeWaitHandle(remoteThreadHandle, true)); ThreadPool.RegisterWaitForSingleObject(threadHandle, (s, e) => { Int32 exitCode; Win32.GetExitCodeThread(handle.DangerousGetHandle(), out exitCode); threadResultFuture.Complete(exitCode); threadHandle.Close(); }, null, -1, true); var theResult = region; region = null; return(theResult); } finally { if (region != null) { bool exited = true; try { exited = process.HasExited; } catch { } if (!exited) region.Dispose(); } } }
protected unsafe byte[] ReadRemoteData(RemoteMemoryRegion region, out UInt32 messageId) { using (var handle = region.OpenHandle(ProcessAccessFlags.VMRead)) { messageId = BitConverter.ToUInt32( region.ReadBytes(handle, 0, 4), 0 ); return region.ReadBytes(handle, 4, region.Size - 4); } }