Process and Job Objects

Just like we mentioned in The Main Thread Problem, some questions do not have direct answer just because they are invalid by definition.

Today, the invalid question would be:

How do I kill a process tree in Windows?

Unfortunately, the question is invalid, since Windows by design doesn't keep a tree of process creation relationship. Each process does have a parent process ID (except for the Windows Session Manager SMSS.exe), however this information is not going to change when the parent process got terminated.

To verify this, simply run tlist.exe -t and see the rootless processes, at least the following processes don't have a parent on my Win7 machine:

csrss.exe (536)
  conhost.exe (6036) CicMarshalWnd
  conhost.exe (8432) CicMarshalWnd
winlogon.exe (672)
explorer.exe (5640) Program Manager

Now back to the question, probably the intention was to kill all processes spawned from or forked by a certain process. If this is the case, Job Object might help. But please be cautious:

  1. It is possible to use CreateProcess with CREATE_BREAKAWAY_FROM_JOB.
  2. One process can be assigned to only one job.
  3. Job objects cannot be nested.

2 and 3 are subject to change in the near future.

Another option I could think of is to hook process creations and maintain our own data structure.

This could be done in either user mode or kernel mode, one possible approach could be:

 #include <ddk/ntddk.h>

extern "C" DDKAPI NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath);
static DDKAPI VOID CreateProcessNotifyRoutine(HANDLE hPPID, HANDLE hPID, BOOLEAN bCreate);
static DDKAPI VOID DriverUnload(PDRIVER_OBJECT pDriverObject);

DDKAPI NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
  NTSTATUS retval;
  pDriverObject->DriverUnload = DriverUnload;
  retval = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, FALSE);
  return retval;
}

DDKAPI VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
  PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, TRUE);
}

DDKAPI VOID CreateProcessNotifyRoutine(HANDLE hPPID, HANDLE hPID, BOOLEAN bCreate)
{
  DbgPrint("%s(PPID=%u, PID=%u)", bCreate ? "CreateProcess" : "TerminateProcess", hPPID, hPID);
}

I wouldn't recommend the driver way for several reasons:

  1. Modern Windows doesn't allow you to install an unsigned driver module.
  2. Antivirus software may complain since they are making use of similar approaches.
  3. It's easier to crash the whole system if you pay less attention (e.g. the sample code itself has a bug of race condition during unload, I'll leave this as a pop quiz to our readers).