Was hunting around an old machine, and found a collection of old code nuggets.

One that jumped out was a little win32 script which was an experiment in terminating processes on the system.

In windows land, many applications that are worried enough about “unauthorised” processes killing them, tend to at least hook the system calls needed, like TerminateProcess.

Back when I last looked at this a couple of years ago, surprisingly few of these apps bothered with guarding from TerminateJobObject, which bypasses NtTerminateProcess, and calls into the kernel via NtTerminateJobObject. Not a big deal, since your app isn’t part of any job set? Except that AssignProcessToJobObject lets pretty much anyone do that whenever they like.

import win32api
import win32job
import win32con

from win32api import OpenProcess, CloseHandle
from win32job import CreateJobObject, TerminateJobObject, AssignProcessToJobObject
from win32con import PROCESS_TERMINATE, PROCESS_SET_QUOTA


def kill_via_job(pid):
    """ Terminates a process by killing its associated Job.

    Adds the given process to a new Job object.  This will fail if the process
    is already a member of another Job.
    """
    target_process = OpenProcess(PROCESS_TERMINATE | PROCESS_SET_QUOTA, False, pid)
    job = CreateJobObject(None, "job_to_kill_pid_{0}".format(pid))
    try:
        AssignProcessToJobObject(job, target_process)
        TerminateJobObject(job, 0)
    finally:
        CloseHandle(target_process)
        CloseHandle(job)


if __name__ == "__main__":
    # we're being run from the command line...
    # eg. "C:\>python jobkill.py 1234"
    import sys
    pid = int(sys.argv[1])
    print "Killing PID {0}".format(pid)
    kill_via_job(pid)
    print "Done."

This is easy to defeat. Just hook the extra (Nt)TerminateJobObject functions. But it always spun me out how often this still worked. Probably a moral in there somewhere.


Comments

comments powered by Disqus