/// <summary> /// Converts an handle into a <see cref="ProcessThread"/> object assuming this is a thread handle. /// </summary> /// <param name="threadHandle">A valid handle to an opened thread.</param> /// <returns>A <see cref="ProcessThread"/> object from the specified handle.</returns> public static ProcessThread HandleToThread(SafeMemoryHandle threadHandle) { // Search the thread by iterating the processes list foreach (var process in Process.GetProcesses()) { var ret = process.Threads.Cast<ProcessThread>().FirstOrDefault(t => t.Id == HandleToThreadId(threadHandle)); if (ret != null) return ret; } // If no thread was found, throws a exception like the First() function with no element throw new InvalidOperationException("Sequence contains no matching element"); }
/// <summary> /// Releases a region of memory within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">A handle to a process.</param> /// <param name="address">A pointer to the starting address of the region of memory to be freed.</param> public static void Free(SafeMemoryHandle processHandle, IntPtr address) { // Check if the handles are valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); HandleManipulator.ValidateAsArgument(address, "address"); // Free the memory if (!NativeMethods.VirtualFreeEx(processHandle, address, 0, MemoryReleaseFlags.Release)) { // If the memory wasn't correctly freed, throws an exception throw new Win32Exception(string.Format("The memory page 0x{0} cannot be freed.", address.ToString("X"))); } }
/// <summary> /// Converts an handle into a process id assuming this is a process handle. /// </summary> /// <param name="processHandle">A valid handle to an opened process.</param> /// <returns>A process id from the specified handle.</returns> public static int HandleToProcessId(SafeMemoryHandle processHandle) { // Check if the handle is valid ValidateAsArgument(processHandle, "processHandle"); // Find the process id var ret = NativeMethods.GetProcessId(processHandle); // If the process id is valid if (ret != 0) return ret; // Else the function failed, throws an exception throw new Win32Exception("Couldn't find the process id of the specified handle."); }
/// <summary> /// Reserves a region of memory within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">The handle to a process.</param> /// <param name="size">The size of the region of memory to allocate, in bytes.</param> /// <param name="protectionFlags">The memory protection for the region of pages to be allocated.</param> /// <param name="allocationFlags">The type of memory allocation.</param> /// <returns>The base address of the allocated region.</returns> public static IntPtr Allocate(SafeMemoryHandle processHandle, int size, MemoryProtectionFlags protectionFlags = MemoryProtectionFlags.ExecuteReadWrite, MemoryAllocationFlags allocationFlags = MemoryAllocationFlags.Commit) { // Check if the handle is valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); // Allocate a memory page var ret = NativeMethods.VirtualAllocEx(processHandle, IntPtr.Zero, size, allocationFlags, protectionFlags); // Check whether the memory page is valid if (ret != IntPtr.Zero) return ret; // If the pointer isn't valid, throws an exception throw new Win32Exception(string.Format("Couldn't allocate memory of {0} byte(s).", size)); }
/// <summary> /// Retrieves the context of the specified thread. /// </summary> /// <param name="threadHandle">A handle to the thread whose context is to be retrieved.</param> /// <param name="contextFlags">Determines which registers are returned or set.</param> /// <returns>A <see cref="ThreadContext"/> structure that receives the appropriate context of the specified thread.</returns> public static ThreadContext GetThreadContext(SafeMemoryHandle threadHandle, ThreadContextFlags contextFlags = ThreadContextFlags.Full) { // Check if the handle is valid HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle"); // Allocate a thread context structure var context = new ThreadContext {ContextFlags = contextFlags}; // Set the context flag // Get the thread context if (NativeMethods.GetThreadContext(threadHandle, ref context)) return context; // Else couldn't get the thread context, throws an exception throw new Win32Exception("Couldn't get the thread context."); }
/// <summary> /// Creates a thread that runs in the virtual address space of another process. /// </summary> /// <param name="processHandle">A handle to the process in which the thread is to be created.</param> /// <param name="startAddress">A pointer to the application-defined function to be executed by the thread and represents the starting address of the thread in the remote process.</param> /// <param name="parameter">A pointer to a variable to be passed to the thread function.</param> /// <param name="creationFlags">The flags that control the creation of the thread.</param> /// <returns>A handle to the new thread.</returns> public static SafeMemoryHandle CreateRemoteThread(SafeMemoryHandle processHandle, IntPtr startAddress, IntPtr parameter, ThreadCreationFlags creationFlags = ThreadCreationFlags.Run) { // Check if the handles are valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); HandleManipulator.ValidateAsArgument(startAddress, "startAddress"); // Create the remote thread int threadId; var ret = NativeMethods.CreateRemoteThread(processHandle, IntPtr.Zero, 0, startAddress, parameter, creationFlags, out threadId); // If the thread is created if (!ret.IsClosed && !ret.IsInvalid) return ret; // Else couldn't create thread, throws an exception throw new Win32Exception(string.Format("Couldn't create the thread at 0x{0}.", startAddress.ToString("X"))); }
/// <summary> /// Retrieves the termination status of the specified thread. /// </summary> /// <param name="threadHandle">A handle to the thread.</param> /// <returns> /// Nullable type: the return value is A pointer to a variable to receive the thread termination status or /// <code>null</code> if it is running. /// </returns> public static IntPtr? GetExitCodeThread(SafeMemoryHandle threadHandle) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(threadHandle, "threadHandle"); // Create the variable storing the output exit code IntPtr exitCode; // Get the exit code of the thread if (!NativeMethods.GetExitCodeThread(threadHandle, out exitCode)) throw new Win32Exception("Couldn't get the exit code of the thread."); // If the thread is still active if (exitCode == new IntPtr(259)) return null; return exitCode; }
/// <summary> /// Changes the protection on a region of committed pages in the virtual address space of a specified process. /// </summary> /// <param name="processHandle">A handle to the process whose memory protection is to be changed.</param> /// <param name="address"> /// A pointer to the base address of the region of pages whose access protection attributes are to be /// changed. /// </param> /// <param name="size">The size of the region whose access protection attributes are changed, in bytes.</param> /// <param name="protection">The memory protection option.</param> /// <returns>The old protection of the region in a <see cref="Native.MemoryBasicInformation" /> structure.</returns> public static MemoryProtectionFlags ChangeProtection(SafeMemoryHandle processHandle, IntPtr address, int size, MemoryProtectionFlags protection) { // Check if the handles are valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); HandleManipulator.ValidateAsArgument(address, "address"); // Create the variable storing the old protection of the memory page MemoryProtectionFlags oldProtection; // Change the protection in the target process if (NativeMethods.VirtualProtectEx(processHandle, address, size, protection, out oldProtection)) { // Return the old protection return oldProtection; } // Else the protection couldn't be changed, throws an exception throw new Win32Exception(string.Format("Couldn't change the protection of the memory at 0x{0} of {1} byte(s) to {2}.", address.ToString("X"), size, protection)); }
/// <summary> /// Performs a pattern scan. /// </summary> /// <param name="processHandle">The process the <see cref="ProcessModule" /> containing the data resides in.</param> /// <param name="processModule">The <see cref="ProcessModule" /> that contains the pattern data resides in.</param> /// <param name="data">The array of bytes containing the data to search for matches in.</param> /// <param name="mask"> /// The mask that defines the byte pattern we are searching for. /// <example> /// <code> /// var bytes = new byte[]{55,45,00,00,55} ; /// var mask = "xx??x"; /// </code> /// </example> /// </param> /// <param name="offsetToAdd">The offset to add to the offset result found from the pattern.</param> /// <param name="reBase">If the address should be rebased to this Instance's base address.</param> /// <param name="wildCardChar"> /// [Optinal] The 'wild card' defines the <see cref="char" /> value that the mask uses to differentiate /// between pattern data that is relevant, and pattern data that should be ignored. The default value is 'x'. /// </param> /// <param name="pattern">The byte array that contains the pattern of bytes we're looking for.</param> /// <returns>A new <see cref="PatternScanResult" /> instance.</returns> public static PatternScanResult Find(SafeMemoryHandle processHandle, ProcessModule processModule, byte[] data, byte[] pattern, string mask, int offsetToAdd, bool reBase, char wildCardChar = 'x') { for (var offset = 0; offset < data.Length; offset++) { if (mask.Where((m, b) => m == 'x' && pattern[b] != data[b + offset]).Any()) continue; var found = MemoryCore.Read<IntPtr>(processHandle, processModule.BaseAddress + offset + offsetToAdd); var result = new PatternScanResult { OriginalAddress = found, Address = reBase ? found : found.Subtract(processModule.BaseAddress), Offset = (IntPtr) offset }; return result; } // If this is reached, the pattern was not found. throw new Exception("The pattern scan for the pattern mask: " + "[" + mask + "]" + " was not found."); }
/// <summary> /// Waits an infinite amount of time for the specified object to become signaled. /// </summary> /// <param name="handle">A handle to the object.</param> /// <returns>If the function succeeds, the return value indicates the event that caused the function to return.</returns> public static WaitValues WaitForSingleObject(SafeMemoryHandle handle) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(handle, "handle"); // Wait for single object var ret = NativeMethods.WaitForSingleObject(handle, 0xFFFFFFFF); // If the function failed if (ret == WaitValues.Failed) throw new Win32Exception("The WaitForSingleObject function call failed."); return ret; }
/// <summary> /// Waits until the specified object is in the signaled state or the time-out interval elapses. /// </summary> /// <param name="handle">A handle to the object.</param> /// <param name="timeout"> /// The time-out interval. If this parameter is NULL, the function does not enter a wait state if the /// object is not signaled; it always returns immediately. /// </param> /// <returns>Indicates the <see cref="WaitValues" /> event that caused the function to return.</returns> public static WaitValues WaitForSingleObject(SafeMemoryHandle handle, TimeSpan? timeout) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(handle, "handle"); // Wait for single object var ret = NativeMethods.WaitForSingleObject(handle, timeout.HasValue ? Convert.ToUInt32(timeout.Value.TotalMilliseconds) : 0); // If the function failed if (ret == WaitValues.Failed) throw new Win32Exception("The WaitForSingleObject function call failed."); return ret; }
/// <summary> /// Terminates a thread. /// </summary> /// <param name="threadHandle">A handle to the thread to be terminated.</param> /// <param name="exitCode">The exit code for the thread.</param> public static void TerminateThread(SafeMemoryHandle threadHandle, int exitCode) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(threadHandle, "threadHandle"); // Terminate the thread var ret = NativeMethods.TerminateThread(threadHandle, exitCode); // If the function failed if (!ret) throw new Win32Exception("Couldn't terminate the thread."); }
public static extern bool SetThreadContext(SafeMemoryHandle hThread, [MarshalAs(UnmanagedType.Struct)] ref ThreadContext lpContext);
public static extern uint SuspendThread(SafeMemoryHandle hThread);
/// <summary> /// Finds the Process Environment Block address of a specified process. /// </summary> /// <param name="processHandle">A handle of the process.</param> /// <returns>A <see cref="IntPtr"/> pointer of the PEB.</returns> public static IntPtr FindPeb(SafeMemoryHandle processHandle) { return(MemoryCore.NtQueryInformationProcess(processHandle).PebBaseAddress); }
public static extern bool TerminateThread(SafeMemoryHandle hThread, int dwExitCode);
public static extern IntPtr VirtualAllocEx(SafeMemoryHandle hProcess, IntPtr lpAddress, int dwSize, MemoryAllocationFlags flAllocationType, MemoryProtectionFlags flProtect);
/// <summary> /// Converts an handle into a <see cref="Process"/> object assuming this is a process handle. /// </summary> /// <param name="processHandle">A valid handle to an opened process.</param> /// <returns>A <see cref="Process"/> object from the specified handle.</returns> public static Process HandleToProcess(SafeMemoryHandle processHandle) { // Search the process by iterating the processes list return Process.GetProcesses().First(p => p.Id == HandleToProcessId(processHandle)); }
/// <summary> /// Validates an handle to fit correctly as argument. /// </summary> /// <param name="handle">A handle to validate.</param> /// <param name="argumentName">The name of the argument that represents the handle in its original function.</param> public static void ValidateAsArgument(SafeMemoryHandle handle, string argumentName) { // Check if the handle is not null if (handle == null) throw new ArgumentNullException(argumentName); // Check if the handle is valid if(handle.IsClosed || handle.IsInvalid) throw new ArgumentException("The handle is not valid or closed.", argumentName); }
/// <summary> /// Retrieves information about a range of pages within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">A handle to the process whose memory information is queried.</param> /// <param name="baseAddress">A pointer to the base address of the region of pages to be queried.</param> /// <returns>A <see cref="Native.MemoryBasicInformation"/> structures in which information about the specified page range is returned.</returns> public static MemoryBasicInformation Query(SafeMemoryHandle processHandle, IntPtr baseAddress) { // Allocate the structure to store information of memory MemoryBasicInformation memoryInfo; // Query the memory region if(NativeMethods.VirtualQueryEx(processHandle, baseAddress, out memoryInfo, MarshalType<MemoryBasicInformation>.Size) != 0) return memoryInfo; // Else the information couldn't be got throw new Win32Exception(string.Format("Couldn't query information about the memory region 0x{0}", baseAddress.ToString("X"))); }
/// <summary> /// Finds the Process Environment Block address of a specified process. /// </summary> /// <param name="processHandle">A handle of the process.</param> /// <returns>A <see cref="IntPtr"/> pointer of the PEB.</returns> public static IntPtr FindPeb(SafeMemoryHandle processHandle) { return MemoryCore.NtQueryInformationProcess(processHandle).PebBaseAddress; }
/// <summary> /// Writes data to an area of memory in a specified process. /// </summary> /// <param name="processHandle">A handle to the process memory to be modified.</param> /// <param name="address">A pointer to the base address in the specified process to which data is written.</param> /// <param name="byteArray">A buffer that contains data to be written in the address space of the specified process.</param> /// <returns>The number of bytes written.</returns> public static int WriteBytes(SafeMemoryHandle processHandle, IntPtr address, byte[] byteArray) { // Check if the handles are valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); HandleManipulator.ValidateAsArgument(address, "address"); // Create the variable storing the number of bytes written int nbBytesWritten; // Write the data to the target process if (NativeMethods.WriteProcessMemory(processHandle, address, byteArray, byteArray.Length, out nbBytesWritten)) { // Check whether the length of the data written is equal to the inital array if (nbBytesWritten == byteArray.Length) return nbBytesWritten; } // Else the data couldn't be written, throws an exception throw new Win32Exception(string.Format("Couldn't write {0} bytes to 0x{1}", byteArray.Length, address.ToString("X"))); }
/// <summary> /// Finds the Thread Environment Block address of a specified thread. /// </summary> /// <param name="threadHandle">A handle of the thread.</param> /// <returns>A <see cref="IntPtr"/> pointer of the TEB.</returns> public static IntPtr FindTeb(SafeMemoryHandle threadHandle) { return ThreadCore.NtQueryInformationThread(threadHandle).TebBaseAdress; }
public static extern bool VirtualFreeEx(SafeMemoryHandle hProcess, IntPtr lpAddress, int dwSize, MemoryReleaseFlags dwFreeType);
/// <summary> /// Reads an array of bytes in the memory form the target process. /// </summary> /// <param name="processHandle">A handle to the process with memory that is being read.</param> /// <param name="address">A pointer to the base address in the specified process from which to read.</param> /// <param name="size">The number of bytes to be read from the specified process.</param> /// <returns>The collection of read bytes.</returns> public static byte[] ReadBytes(SafeMemoryHandle processHandle, IntPtr address, int size) { // Check if the handles are valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); HandleManipulator.ValidateAsArgument(address, "address"); // Allocate the buffer var buffer = new byte[size]; int nbBytesRead; // Read the data from the target process if (NativeMethods.ReadProcessMemory(processHandle, address, buffer, size, out nbBytesRead) && size == nbBytesRead) return buffer; // Else the data couldn't be read, throws an exception throw new Win32Exception(string.Format("Couldn't read {0} byte(s) from 0x{1}.", size, address.ToString("X"))); }
/// <summary> /// Retrieves a descriptor table entry for the specified selector and thread. /// </summary> /// <param name="threadHandle">A handle to the thread containing the specified selector.</param> /// <param name="selector">The global or local selector value to look up in the thread's descriptor tables.</param> /// <returns>A pointer to an <see cref="LdtEntry" /> structure that receives a copy of the descriptor table entry.</returns> public static LdtEntry GetThreadSelectorEntry(SafeMemoryHandle threadHandle, uint selector) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(threadHandle, "threadHandle"); // Get the selector entry LdtEntry entry; if (NativeMethods.GetThreadSelectorEntry(threadHandle, selector, out entry)) return entry; // Else couldn't get the selector entry, throws an exception throw new Win32Exception($"Couldn't get the selector entry for this selector: {selector}."); }
/// <summary> /// Retrieves information about a range of pages within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">A handle to the process whose memory information is queried.</param> /// <param name="addressFrom">A pointer to the starting address of the region of pages to be queried.</param> /// <param name="addressTo">A pointer to the ending address of the region of pages to be queried.</param> /// <returns>A collection of <see cref="Native.MemoryBasicInformation"/> structures.</returns> public static IEnumerable<MemoryBasicInformation> Query(SafeMemoryHandle processHandle, IntPtr addressFrom, IntPtr addressTo) { // Check if the handle is valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); // Convert the addresses to Int64 var numberFrom = addressFrom.ToInt64(); var numberTo = addressTo.ToInt64(); // The first address must be lower than the second if (numberFrom >= numberTo) throw new ArgumentException("The starting address must be lower than the ending address.", "addressFrom"); // Create the variable storing the result of the call of VirtualQueryEx int ret; // Enumerate the memory pages do { // Allocate the structure to store information of memory MemoryBasicInformation memoryInfo; // Get the next memory page ret = NativeMethods.VirtualQueryEx(processHandle, new IntPtr(numberFrom), out memoryInfo, MarshalType<MemoryBasicInformation>.Size); // Increment the starting address with the size of the page numberFrom += memoryInfo.RegionSize; // Return the memory page if(memoryInfo.State != MemoryStateFlags.Free) yield return memoryInfo; } while (numberFrom < numberTo && ret != 0); }
/// <summary> /// Retrieves information about the specified thread. /// </summary> /// <param name="threadHandle">A handle to the thread to query.</param> /// <returns>A <see cref="ThreadBasicInformation" /> structure containg thread information.</returns> public static ThreadBasicInformation NtQueryInformationThread(SafeMemoryHandle threadHandle) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(threadHandle, "threadHandle"); // Create a structure to store thread info var info = new ThreadBasicInformation(); // Get the thread info var ret = NativeMethods.NtQueryInformationThread(threadHandle, 0, ref info, MarshalType<ThreadBasicInformation>.Size, IntPtr.Zero); // If the function succeeded if (ret == 0) return info; // Else, couldn't get the thread info, throws an exception throw new ApplicationException($"Couldn't get the information from the thread, error code '{ret}'."); }
/// <summary> /// Sets the context for the specified thread. /// </summary> /// <param name="threadHandle">A handle to the thread whose context is to be set.</param> /// <param name="context"> /// A pointer to a <see cref="ThreadContext" /> structure that contains the context to be set in the /// specified thread. /// </param> public static void SetThreadContext(SafeMemoryHandle threadHandle, ThreadContext context) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(threadHandle, "threadHandle"); // Set the thread context if (!NativeMethods.SetThreadContext(threadHandle, ref context)) throw new Win32Exception("Couldn't set the thread context."); }
/// <summary> /// Suspends the specified thread. /// </summary> /// <param name="threadHandle">A handle to the thread that is to be suspended.</param> /// <returns>The thread's previous suspend count.</returns> public static uint SuspendThread(SafeMemoryHandle threadHandle) { // Check if the handle is valid HandleManipulationHelper.ValidateAsArgument(threadHandle, "threadHandle"); // Suspend the thread var ret = NativeMethods.SuspendThread(threadHandle); // If the function failed if (ret == uint.MaxValue) throw new Win32Exception("Couldn't suspend the thread."); return ret; }
/// <summary> /// etrieves information about the specified process. /// </summary> /// <param name="processHandle">A handle to the process to query.</param> /// <returns>A <see cref="ProcessBasicInformation"/> structure containg process information.</returns> public static ProcessBasicInformation NtQueryInformationProcess(SafeMemoryHandle processHandle) { // Check if the handle is valid HandleManipulator.ValidateAsArgument(processHandle, "processHandle"); // Create a structure to store process info var info = new ProcessBasicInformation(); // Get the process info var ret = NativeMethods.NtQueryInformationProcess(processHandle, ProcessInformationClass.ProcessBasicInformation, ref info, info.Size, IntPtr.Zero); // If the function succeeded if (ret == 0) return info; // Else, couldn't get the process info, throws an exception throw new ApplicationException(string.Format("Couldn't get the information from the process, error code '{0}'.", ret)); }
/// <summary> /// Finds the Thread Environment Block address of a specified thread. /// </summary> /// <param name="threadHandle">A handle of the thread.</param> /// <returns>A <see cref="IntPtr" /> pointer of the TEB.</returns> public static IntPtr FindTeb(SafeMemoryHandle threadHandle) { return(ThreadCore.NtQueryInformationThread(threadHandle).TebBaseAdress); }