TerminateProcess or NtTerminateProcess
Everyone knows about TerminateProcess. You simply open a handle to the target process and call TerminateProcess. In case TerminateProcess is hooked, you can call the equivalent Native API function NtTerminateProcess.
For this method you will have to find the address of ExitProcess within the target process. It is usually the same as ExitProcess for your process, so you can use GetModuleHandle and GetProcAddress. You can then create a thread inside the target process which executes ExitProcess, killing the target process.
NtQuerySystemInformation or toolhelp32, TerminateThread or NtTerminateThread
Simply loop through the threads of the target process and terminate each one using TerminateThread. If it’s hooked, call NtTerminateThread.
NtQuerySystemInformation or toolhelp32, SetThreadContext
Loop through the threads of the target process and set their contexts using SetThreadContext; modify their contexts so that eip points to ExitProcess.
Loop from 0 to 4096 and call DuplicateHandle with Options = 1, leaving TargetProcess and TargetProcessHandle null. This will close most, if not all handles opened by the target process. This method works best for complex applications like security software – it doesn’t crash Notepad, for example.
CreateJobObject, AssignProcessToJobObject, TerminateJobObject (and their Native API equivalents)
Create a job object using CreateJobObject, assign the target process to it using AssignProcessToJobObject, and terminate it using TerminateJobObject. This only works if the process is not already associated with a job object. This technique works well if NtAssignProcessToJobObject and NtTerminateJobObject are not hooked because NtTerminateJobObject calls PsTerminateProcess directly.
NtCreateDebugObject, NtDebugActiveProcess, CloseHandle
People usually implement this technique by using DebugActiveProcess and then exiting the current process. They do this because they don’t know how DebugActiveProcess works. Behind the scenes kernel32 is calling ntdll which calls NtDebugActiveProcess with an already-created debug object. You don’t have to exit the current process for the debuggee to get killed; you just need to close the debug object. When it is closed, the kernel will kill the debuggee using PsTerminateProcess.
To implement this technique, you can create a debug object using NtCreateDebugObject (specifying the kill-on-close flag), debug the process using NtDebugActiveProcess (the process handle needs PROCESS_SUSPEND_RESUME access), and close the handle to the debug object using CloseHandle. Here are the definitions:
#define DEBUG_OBJECT_READEVENT 0x1 #define DEBUG_OBJECT_PROCESSASSIGN 0x2 #define DEBUG_OBJECT_SETINFORMATION 0x4 #define DEBUG_OBJECT_QUERYINFORMATION 0x8 #define DEBUG_OBJECT_KILLONCLOSE 0x1 NTSTATUS NTAPI NtCreateDebugObject( PHANDLE DebugObjectHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG Flags ); NTSTATUS NTAPI NtDebugActiveProcess( HANDLE ProcessHandle, HANDLE DebugObjectHandle );
Loop through the memory regions of the target process using VirtualQueryEx and set their protections to PAGE_NOACCESS. The program will crash as soon as it context-switches into user-mode code because it will be unable to read any code from memory.
Loop through the memory regions of the target process and write random data to it using WriteProcessMemory.
Call VirtualAllocEx in a loop until you can’t reserve any more memory in the target process. It will crash when it is unable to allocate any more memory.
PsTerminateProcess is an internal kernel-mode function which is not exported by ntoskrnl. You will need to locate it by scanning kernel-mode memory for a specific signature, which I will not post here. WARNING: On XP you should locate PspTerminateProcess instead, which is stdcall. On Vista PsTerminateProcess is thiscall (first argument goes in ecx), so you will need some hand-coded assembly.
typedef NTSTATUS (*_PsTerminateProcess)( PEPROCESS Process, NTSTATUS ExitStatus );
This function is not exported either. WARNING: On XP, there are two arguments. On Vista, there are three.
/* XP */ typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer51)( PETHREAD Thread, NTSTATUS ExitStatus ); /* Vista */ typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer60)( PETHREAD Thread, NTSTATUS ExitStatus, BOOLEAN DirectTerminate );
A note about process handles
Before you get started on these methods, you will need to know the ways of getting a handle to the victim process. Surely, the only way to do this is by calling OpenProcess/NtOpenProcess, right? Wrong. If you can’t get a handle with the right access because of a hooked function (such as with security software), you can open the target process with SYNCHRONIZE access (or whatever access you think will be granted) and call DuplicateHandle to get new access rights. This won’t always work though because security software vendors are starting to hook ZwDuplicateObject to prevent this.
On Windows Vista there are two Native API functions named NtGetNextProcess and NtGetNextThread. Almost no one knows about this and almost no one hooks these two functions. Here are their definitions:
NTSTATUS NTAPI NtGetNextProcess( HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, ULONG Flags, PHANDLE NewProcessHandle ); NTSTATUS NTAPI NtGetNextThread( HANDLE ProcessHandle, HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, ULONG Flags, PHANDLE NewThreadHandle );