Windows 挂起进程
阅读原文时间:2023年07月09日阅读:1

A thread can suspend and resume the execution of another thread. While a thread is suspended, it is not scheduled for time on the processor.

If a thread is created in a suspended state (with the CREATE_SUSPENDED flag), it does not begin to execute until another thread calls the ResumeThread function with a handle to the suspended thread. This can be useful for initializing the thread's state before it begins to execute. Suspending a thread at creation can be useful for one-time synchronization, because this ensures that the suspended thread will execute the starting point of its code when you call ResumeThread.

The SuspendThread function is not intended to be used for thread synchronization because it does not control the point in the code at which the thread's execution is suspended. This function is primarily designed for use by debuggers.

A thread can temporarily yield its execution for a specified interval by calling the Sleep or SleepEx functions This is useful particularly in cases where the thread responds to user interaction, because it can delay execution long enough to allow users to observe the results of their actions. During the sleep interval, the thread is not scheduled for time on the processor.

The SwitchToThread function is similar to Sleep and SleepEx, except that you cannot specify the interval. SwitchToThread allows the thread to give up its time slice.

https://docs.microsoft.com/zh-cn/windows/win32/procthread/suspending-thread-execution

两个 API 函数

SuspendThread

Wow64SuspendThread

How to suspend/resume a process in Windows?

You can't do it from the command line, you have to write some code (I assume you're not just looking for an utility otherwise Super User may be a better place to ask). I also assume your application has all the required permissions to do it (examples are without any error checking).

First get all the threads of a given process then call the SuspendThread function to stop each one (and ResumeThread to resume). It works but some applications may crash or hung because a thread may be stopped in any point and the order of suspend/resume is unpredictable (for example this may cause a dead lock). For a single threaded application this may not be an issue.

void suspend(DWORD processId)
{
    HANDLE hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

    THREADENTRY32 threadEntry;
    threadEntry.dwSize = sizeof(THREADENTRY32);

    Thread32First(hThreadSnapshot, &threadEntry);

    do
    {
        if (threadEntry.th32OwnerProcessID == processId)
        {
            HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE,
                threadEntry.th32ThreadID);

            SuspendThread(hThread);
            CloseHandle(hThread);
        }
    } while (Thread32Next(hThreadSnapshot, &threadEntry));

    CloseHandle(hThreadSnapshot);
}

Please note that this function is even too much naive, to resume threads you should skip threads that was suspended and it's easy to cause a dead-lock because of suspend/resume order. For single threaded applications it's prolix but it works.

Starting from Windows XP there is the NtSuspendProcess but it's undocumented. Read this post for a code example (reference for undocumented functions: news://comp.os.ms-windows.programmer.win32).

typedef LONG (NTAPI *NtSuspendProcess)(IN HANDLE ProcessHandle);

void suspend(DWORD processId)
{
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId));

    NtSuspendProcess pfnNtSuspendProcess = (NtSuspendProcess)GetProcAddress(
        GetModuleHandle("ntdll"), "NtSuspendProcess");

    pfnNtSuspendProcess(processHandle);
    CloseHandle(processHandle);
}

To suspend a program is what usually a debugger does, to do it you can use the DebugActiveProcess function. It'll suspend the process execution (with all threads all together). To resume you may use DebugActiveProcessStop.

This function lets you stop a process (given its Process ID), syntax is very simple: just pass the ID of the process you want to stop et-voila. If you'll make a command line application you'll need to keep its instance running to keep the process suspended (or it'll be terminated). See the Remarks section on MSDN for details.

void suspend(DWORD processId)
{
    DebugActiveProcess(processId);
}

As I said Windows command line has not any utility to do that but you can invoke a Windows API function from PowerShell. First install Invoke-WindowsApi script then you can write this:

Invoke-WindowsApi "kernel32" ([bool]) "DebugActiveProcess" @([int]) @(process_id_here)

Of course if you need it often you can make an alias for that.