/// <summary> /// Creates a thread that runs in the remote process. /// </summary> /// <param name="address"> /// 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="isStarted">Sets if the thread must be started just after being created.</param> /// <returns>A new instance of the <see cref="RemoteThread"/> class.</returns> public RemoteThread Create(IntPtr address, bool isStarted = true) { // Create the thread var ret = ThreadCore.NtQueryInformationThread( ThreadCore.CreateRemoteThread(MemorySharp.Handle, address, IntPtr.Zero, ThreadCreationFlags.Suspended)); // Get the native thread previously created // Loop until the native thread is retrieved ProcessThread nativeThread; do { nativeThread = MemorySharp.Threads.NativeThreads.FirstOrDefault(t => t.Id == ret.ClientIdStruct.UniqueThread.ToInt64()); } while (nativeThread == null); // Wrap the native thread in an object of the library var result = new RemoteThread(MemorySharp, nativeThread); // If the thread must be started if (isStarted) { result.Resume(); } return(result); }
/// <summary> /// Terminates the thread. /// </summary> /// <param name="exitCode">The exit code of the thread to close.</param> public void Terminate(int exitCode = 0) { if (IsAlive) { ThreadCore.TerminateThread(Handle, exitCode); } }
/// <summary> /// Sets the context of the thread. /// If the thread is not already suspended, performs a <see cref="Suspend" /> and <see cref="Resume" /> call on the thread. /// </summary> /// <typeparam name="TContext">The type of the context to set. /// The type must be unmanaged, so it can be fixed while the native call is done. /// The performance is increased if the structure is blittable, which is the case for the structures /// provided with the library.</typeparam> /// <param name="context">An instance of the structure where the context is set to.</param> /// <exception cref="ThreadStateException">The context cannot be set because the thread #{Id} is terminated.</exception> /// <exception cref="Win32Exception">The context cannot be set to the thread.</exception> public void SetContext <TContext>(ref TContext context) where TContext : unmanaged { // Check if the thread is alive if (!IsAlive) { throw new ThreadStateException($"The context cannot be set because the thread #{Id} is terminated."); } // Check if the thread is already suspended var isSuspended = IsSuspended; try { // Suspend the thread if it wasn't if (!isSuspended) { Suspend(); } // Set the context ThreadCore.SetThreadContext(Handle, ref context); } finally { // Resume the thread if it wasn't suspended if (!isSuspended) { Resume(); } } }
/// <summary> /// Creates a thread that runs in the remote process. /// </summary> /// <param name="address"> /// 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 variable to be passed to the thread function.</param> /// <param name="isStarted">Sets if the thread must be started just after being created.</param> /// <returns>A new instance of the <see cref="RemoteThread"/> class.</returns> public RemoteThread Create(IntPtr address, dynamic parameter, bool isStarted = true) { // Marshal the parameter var marshalledParameter = MarshalValue.Marshal(MemorySharp, parameter); //Create the thread var ret = ThreadCore.NtQueryInformationThread( ThreadCore.CreateRemoteThread(MemorySharp.Handle, address, marshalledParameter.Reference, ThreadCreationFlags.Suspended)); // Get the native thread previously created // Loop until the native thread is retrieved ProcessThread nativeThread; do { nativeThread = MemorySharp.Threads.NativeThreads.FirstOrDefault(t => ret.ClientIdStruct.UniqueThread.IsEqual(t.Id)); } while (nativeThread == null); // Find the managed object corresponding to this thread var result = new RemoteThread(MemorySharp, nativeThread, marshalledParameter); // If the thread must be started if (isStarted) { result.Resume(); } return(result); }
/// <summary> /// Gets the termination status of the thread. /// </summary> public T GetExitCode <T>() { // Get the exit code of the thread (can be nullable) var ret = ThreadCore.GetExitCodeThread(Handle); // Return the exit code or the default value of T if there's no exit code return(ret.HasValue ? MarshalType <T> .PtrToObject(MemorySharp, ret.Value) : default(T)); }
/// <summary> /// Either suspends the thread, or if the thread is already suspended, has no effect. /// </summary> /// <returns>A new instance of the <see cref="FrozenThread"/> class. If this object is disposed, the thread is resumed.</returns> public FrozenThread Suspend() { if (IsAlive) { ThreadCore.SuspendThread(Handle); return(new FrozenThread(this)); } return(null); }
/// <summary> /// Initializes a new instance of the <see cref="RemoteThread"/> class. /// </summary> /// <param name="memorySharp">The reference of the <see cref="Library.MemorySharp.MemorySharp"/> object.</param> /// <param name="thread">The native <see cref="ProcessThread"/> object.</param> internal RemoteThread(MemorySharp memorySharp, ProcessThread thread) { // Save the parameters MemorySharp = memorySharp; Native = thread; // Save the thread id Id = thread.Id; // Open the thread Handle = ThreadCore.OpenThread(ThreadAccessFlags.AllAccess, Id); // Initialize the TEB lazy loader _teb = new Lazy <ManagedTeb>(() => new ManagedTeb(memorySharp, this)); }
/// <summary> /// Resumes a thread that has been suspended. /// </summary> public void Resume() { // Check if the thread is still alive if (!IsAlive) { return; } // Start the thread ThreadCore.ResumeThread(Handle); // Start a task to clean the memory used by the parameter if we created the thread if (_parameter != null && !_parameterCleaner.IsCompleted) { _parameterCleaner.Start(); } }
/// <summary> /// Gets the linear address of a specified segment. /// </summary> /// <param name="segment">The segment to get.</param> /// <param name="context">The context.</param> /// <returns>A <see cref="IntPtr" /> pointer corresponding to the linear address of the segment.</returns> /// <exception cref="InvalidEnumArgumentException">segment</exception> public IntPtr GetRealSegmentAddress(SegmentRegisters segment, ref ThreadContext32 context) { // Get a selector entry for the segment LdtEntry entry; switch (segment) { case SegmentRegisters.Cs: entry = ThreadCore.GetThreadSelectorEntry(Handle, context.SegCs); break; case SegmentRegisters.Ds: entry = ThreadCore.GetThreadSelectorEntry(Handle, context.SegDs); break; case SegmentRegisters.Es: entry = ThreadCore.GetThreadSelectorEntry(Handle, context.SegEs); break; case SegmentRegisters.Fs: entry = ThreadCore.GetThreadSelectorEntry(Handle, context.SegFs); break; case SegmentRegisters.Gs: entry = ThreadCore.GetThreadSelectorEntry(Handle, context.SegGs); break; case SegmentRegisters.Ss: entry = ThreadCore.GetThreadSelectorEntry(Handle, context.SegSs); break; default: throw new InvalidEnumArgumentException(nameof(segment), (int)segment, typeof(SegmentRegisters)); } // Compute the linear address return(new IntPtr(entry.BaseLow | (entry.BaseMid << 16) | (entry.BaseHi << 24))); }
/// <summary> /// Blocks the calling thread until a thread terminates or the specified time elapses. /// </summary> /// <param name="time">The timeout.</param> /// <returns>The return value is a flag that indicates if the thread terminated or if the time elapsed.</returns> public WaitValues Join(TimeSpan time) { return(ThreadCore.WaitForSingleObject(Handle, time)); }
/// <summary> /// Blocks the calling thread until the thread terminates. /// </summary> public void Join() { ThreadCore.WaitForSingleObject(Handle); }