Suspending processes in Windows

I have been recently encountering quite a non-typical problem – playing Starcraft was hard due to the amount of active processes running on my operating system – including a few IDA instances, virtual machines and the most disturbing… Firefox web browser. As we all know, it’s not only about the memory being used by Firefox – the main problem is that the application tends to consume large amounts of CPU time (especially when having 150-200 opened tabs at once). When we add a very easily-heating processor, the aforementioned game might really have some problems with effectiveness.

The most intuitive solution to that problem seemed to be simply killing the firefox.exe process (no matter if it means closing it the right way or just terminating it) – the rest was no longer a problem, since it is possible to pause the Virtual Machine execution etc. The real problem appeared after the game, when I wanted to start working with the web browser – loading 150 sites back is always time-consuming, no matter how fast your connection is. When such a situation began taking place a number of times a day, I became pretty frustrated.

How one could guess by reading the post title, I finally decided to suspend the process instead of terminating it – after the time needed to make use of the processor for other purposes, I could resume the process and immediately enjoy working with it. This approach has some significant disadvantages, all of which are going to be described in detail here. The entire post has been divided into two major parts – in the first one, I will present all the (good and worse) ideas of how a remote process can be suspended, the second one will contain information about modyfing the Task Manager itself, a well-known administrative application, in order to make it possible to suspend a specified process right from its context menu. Straight to the point…

After taking a look at some Google results, it becomes clear that there are many tools providing the expected functionality – suspending particular threads/whole processes ([1],[2],[3]). One could guess that, if there is so much software offering what we need, writing our own program cannot be too hard (the system is perhaps providing some kind of interface for such operations) – and that’s exactly right ;)

The first, well documented tool in our hands is the  SuspendThread and ResumeThread function pair. As it turns out, it is possible to pause a specified thread (in particular, all of them) in a remote process’ context, if only we’re allowed to open a hThread handle with THREAD_SUSPEND_RESUME access. The CodeProject[1] solution is mainly based on this method. The article’s author decided to list all the threads present in given process, using a set of ToolHelp32 APIs[6]. More of a brutal solution could be trying to open and suspend all the possible ThreadId (which are usually reasonably small numbers). Despite this technique is working well in most cases, the following cons must be taken into account:

  • There are many multi-threaded applications, that take advantage of thread operations’ order. In case such a program would get suspended in a wrong execution moment, some unpredictable behaviour could be expected (in worst case – a simple deadlock or process crash) – it is practically very dangerous approach.
  • A race condition could happen under some specific circumstances. When half of the threads would have been already suspended, one of the upper-half threads could try to create a new one, being placed among these already handled. This would allow further program execution, resulting in unknown (depending on the application itself) behaviour.
  • Even though the process that has all of its threads suspended could be considered “inactive”, it is not really true.  It is still possible to create a remote thread in the target process’ context – such a situation could take place, for example, when CSRSS decides to create a callback routine in our console application (resulting in having the registered console handlers executed).

The above solution should be considered relatively stable and OS version independent since it makes use of actively supported APIs, that are for sure not going to be removed from any future Windows version. However, the MSDN documentation contains a small adnotation, saying that the described functions should be mainly used by debugger applications – the calling thread should have complete control over the target’s execution. This is not a very serious matter for us, but let’s think if there are any other, better ways to achieve our goal.

Despite the fact that no public SuspendProcess function, being able to entirely perform a suspend, is available to Win32 programmers, it is worth going one level deeper – some of the System Calls (and their wrappers inside ntdll.dll library) might turn out to be very handy, when the well-known and documented methods fail (or, when a public, stable solution doesn’t exist). The Windows System Call Table[10] provides a complete list of Windows syscalls, ranging from NT SP3, up to Windows Vista SP0. As one could observe, the NtSuspendProcess function has been introduced with Windows XP Sp0 and works on every single system version since then. It seems to be quite a good alternative for the “manual” solution, if we take into account that the kernel itself is responsible for disabling access to the dereferred threads and avoiding any undesirable consequences of the operation. As the Windows XP and Windows 2003 Server code can be found in the Windows Research Kernel package, we can take a look inside the function and find out what the exported symbol really does:

    if (ExAcquireRundownProtection (&Process->RundownProtect)) {

        for (Thread = PsGetNextProcessThread (Process, NULL);
             Thread != NULL;
             Thread = PsGetNextProcessThread (Process, Thread)) {

            PsSuspendThread (Thread, NULL);
        }

        ExReleaseRundownProtection (&Process->RundownProtect);

        Status = STATUS_SUCCESS;
    } else {
        Status = STATUS_PROCESS_IS_TERMINATING;
    }

    return Status;

As can be seen, the function doesn’t perform many additional actions/checks – iterating thru all the active threads, respectively uses PsSuspendThread on each. It also makes sure the process don’t get terminated while executing the “for” loop (ExAcquireRundownProtection (&Process->RundownProtect) call). The solution is significantly better than the one before – all the work is performed by the kernel itself – we don’t have to care about what happens under any certain conditions etc. On the other hand, although widely spread, making use of undocumented functions should be avoided as long as it is possible – we can’t be sure whether the API will still exist in the future system versions (however, having it removed from Windows is also very unlikely).

After a quick debriefing of the two most intuitive methods, the time has come for more interesting ideas. As we’ve probably ran out of methods directly meeting our requirments, we have to think about other Windows mechanisms that would make it possible for us to suspend something, basing on the side effects. One of such mechanisms is the Debugging Interface provided by Microsoft, making it possible to create special debugging programs in an easy and pleasant way. As you have probably observed, when a debugger attaches itself to a remote process, all the target’s threads immediately get suspended till the debugger gives a sign to let them execute. It is a well known behaviour, described in the DebugActiveProcess[7] function’s documentation. I find these functions perfect in the context of our problem – both the performance and usage is very simple from the programmer’s point of view. What is more, there is an opposite function to the suspending one – named DebugActiveProcessStop[8], making it possible to restore the original program execution by detaching the debugger. Additionally, we’re not forced to use any other API functions – it is enough to make one call for suspension and one call for resumption (in both cases, the only parameter is the destination ProcessId!).

The following code presents how easy it is to write a tiny suspend/resume application using the currently described technique:

#define _WIN32_WINNT 0x0600
#include <cstdio>
#include <windows.h>
using namespace std;

int main(int argc, char** argv)
{
  DWORD PID;
  BOOL Ret;

  if(argc!=2)
  {
    puts("Usage: suspend.exe ");
    return 1;
  }

  PID = atoi(argv[1]);
  printf("[+] DebugActiveProcess: 0x%.8x\n",(Ret=DebugActiveProcess(PID)));
  if(!Ret)
  {
    printf("[-] Function failed. LastError: 0x%.8x\n",(UINT)GetLastError());
    return 1;
  }

  printf("[+] Click ENTER to resume the process…");
  getchar();

  printf("[+] DebugActiveProcessStop: 0x%.8x\n",DebugActiveProcessStop(PID));
  return 0;
}

As shown above, the two functions are trivial to use and are suprisingly well meeting our requirements. Anyway, we have to keep in mind some of the disadvantages related to the method – for example, it is not possible to attach a genuine debugger to the process being paused till the DebugActiveProcessStop call is made. All in all, it is a minor drawback and should not be very disturbing in real life. Apart from this, when the debugging process gets killed (no matter if it closes itself or gets terminated by an external module), so will the processes being debugged. It would be a serious matter indeed, if not the presence of SetDebugKillOnExit[9] function, providing an option to change the default setting, so as the debugged processes are being detached and continue their execution instead of being terminated.

The last idea that occured to me was to use the system process called CSRSS.EXE and some of the side-effects caused by how the console window events are handled. Since the console applications have very restricted access to events, appearance and behaviour of the window they are operating on, one should take a look into the Client/Server Runtime Subsystem[11] disassembly – in particular, the \Windows\system32\winsrv.dll module, responsible for creating, destroying and handling standard messages of the consoles. My idea is based on a simple observation – when the user decides to turn the console into a different mode (for example, using the Mark option), access to the active console buffer is disabled until the normal mode is restored.

What should be noted is the fact, that this method can only be applied to:

  • Processes that actively make use of the console window – performing operations requiring access to the screen buffer
  • Local processes – this method is very hard (impossible?) to use in the context of a remote process

Even though it seems to be completely impractical, I decided to post it here to show a particular thinking scheme – if we want to achieve something in our system, we don’t necesarily need to find functions that are designed to do what we expect – taking advantage of the side-effects of how some functionalities present in the system work is often a better option for us, especially if we’re able to adjust them for our purposes.

The four above methods may (with better or worse result) be used to suspend a remote thread – it is still possible that other, good and interesting ideas exist . The current ZIP package containing a piece of Proof of Concept code for each technique can be downloaded from here (as I find new ways of process suspension, I will surely add new source files to keep it up to date with my current knowledge).

In the second part of the incoming post, I will show how to modify the TaskMgr.exe execution, so as to make it provide an embedded option of suspending a process – launching a special tool would be as uncomfortable as terminating/resuming the firefox.exe itself. I placed a few interesting addresses in the Links sections, that could shed some light on the subject in consideration – I would also like to encourage every reader to share his/her ideas in the Comments section! ;)

Links:

  1. CodeProject Win32 Process Suspend/Resume tool
  2. PsSuspend v1.06
  3. Command Line Process Viewer/Killer/Suspender
  4. SuspendThread
  5. ResumeThread
  6. Tool Help Functions
  7. DebugActiveProcess
  8. DebugActiveProcessStop
  9. DebugSetProcessKillOnExit
  10. Windows System Call Table
  11. Client/Server Runtime Subsystem
  12. Windows Research Kernel

8 thoughts on “Suspending processes in Windows”

  1. @Riddler – glad you like it ;>

    However, I have a big request for all the commenters – even though the system supports multi-language posting, there is still a problem with telling the lang versions of comments from each other. Therefore, I have to ask everyone (especially the polish readers) to post comments in English, anyway.
    Thanks in advance!

  2. @Rolf Rolles – Even if it’s not an every-day situation, yep, it takes place quite often. I don’t really like closing good articles/post entries etc, thus I keep them “in case I’ll need them in a few days” ;p

    In advance to future questions – I know what the bookmarks are, and actively use this feature ;p

  3. Nice hunting, but don’t tell me you are not aware of Process Explorer? It has suspend/resume, tons of other features and smoothly replaces task manager.

    Unfortunately, immediately after Sysinternals acquisition source codes have disappeared (with stupid explanation, to ease maintenance or something equally ridiculous), but still old versions are reachable. I don’t remember whether old version had suspend though.

    And yes, Fx is sluggish even with more than 50 tabs open. Chrome is better here, but lack of add-ons is somewhat painful.

  4. @przemoc: I am perfectly aware of Process Explorer and occasionally use it (special cases), but some old habits make it impossible for me to entirely replace TaskMgr with PE (this includes the VMs I’m performing many tests on – a great part of them lack this tool).

    And, what do you mean by reaching the old source code versions? I don’t think they would come up with a revolutionary idea of suspending processes… But worth checking anyway ;p

    When it comes to Fx, it would be more acceptable if it was only about the application itself being sluggish, but heh not when the entire OS is slowing down because of one particular program. I think I’m not gonna change it right now, after all (as you mentioned, Fx’s strenght is it’s add-on support)

Comments are closed.