diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index 56beef8a3..2bc9a24f4 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -2,6 +2,8 @@ Process Hacker 1.3.6.6 * NEW/IMPROVED: + * "Terminate process" now uses a special kernel-mode method to bypass + almost all anti-termination methods * Basic support for Windows 7 in Process Hacker and KProcessHacker * Proper symbol support with dbghelp.dll * Private, Shared and Shareable Working Set columns diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys index 73541c6e6..2429a09f4 100644 Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ diff --git a/trunk/KProcessHacker/include/kph.h b/trunk/KProcessHacker/include/kph.h index 447b1dfdf..c768021b8 100644 --- a/trunk/KProcessHacker/include/kph.h +++ b/trunk/KProcessHacker/include/kph.h @@ -20,8 +20,8 @@ * along with Process Hacker. If not, see . */ -#ifndef _KPH_NT_H -#define _KPH_NT_H +#ifndef _KPH_H +#define _KPH_H #include "kprocesshacker.h" #include "debug.h" @@ -31,10 +31,24 @@ #include "ps.h" #include "zw.h" -extern _PsGetProcessJob PsGetProcessJob; -extern _PsSuspendProcess PsSuspendProcess; -extern _PsResumeProcess PsResumeProcess; -extern _MmCopyVirtualMemory MmCopyVirtualMemory; +#ifdef EXT +#undef EXT +#endif + +#ifdef _KPH_PRIVATE +#define EXT +#define EQNULL = NULL +#else +#define EXT extern +#define EQNULL +#endif + +EXT _MmCopyVirtualMemory MmCopyVirtualMemory EQNULL; +EXT _NtClose __NtClose EQNULL; +EXT _PsGetProcessJob PsGetProcessJob EQNULL; +EXT _PsResumeProcess PsResumeProcess EQNULL; +EXT _PsSuspendProcess PsSuspendProcess EQNULL; +EXT _PsTerminateProcess __PsTerminateProcess EQNULL; typedef struct _KPH_ATTACH_STATE { @@ -191,7 +205,7 @@ NTSTATUS KphWriteVirtualMemory( /* OB */ -NTSTATUS KphObDuplicateObject( +NTSTATUS ObDuplicateObject( PEPROCESS SourceProcess, PEPROCESS TargetProcess, HANDLE SourceHandle, @@ -202,12 +216,18 @@ NTSTATUS KphObDuplicateObject( KPROCESSOR_MODE AccessMode ); -PHANDLE_TABLE KphObReferenceProcessHandleTable( +PHANDLE_TABLE ObReferenceProcessHandleTable( PEPROCESS Process ); -VOID KphObDereferenceProcessHandleTable( +VOID ObDereferenceProcessHandleTable( PEPROCESS Process ); +/* PS */ +NTSTATUS PsTerminateProcess( + PEPROCESS Process, + NTSTATUS ExitStatus + ); + #endif \ No newline at end of file diff --git a/trunk/KProcessHacker/include/ps.h b/trunk/KProcessHacker/include/ps.h index 802e31bec..a16871222 100644 --- a/trunk/KProcessHacker/include/ps.h +++ b/trunk/KProcessHacker/include/ps.h @@ -69,6 +69,11 @@ typedef NTSTATUS (NTAPI *_PsSuspendProcess)( PEPROCESS Process ); +typedef NTSTATUS (__fastcall *_PsTerminateProcess)( + PEPROCESS Process, + NTSTATUS ExitStatus + ); + /* STRUCTS */ typedef struct _KEXECUTE_OPTIONS diff --git a/trunk/KProcessHacker/include/version.h b/trunk/KProcessHacker/include/version.h index e6f91a500..f67479fcc 100644 --- a/trunk/KProcessHacker/include/version.h +++ b/trunk/KProcessHacker/include/version.h @@ -25,16 +25,20 @@ #include "kprocesshacker.h" -#define WINDOWS_XP '0051' -#define WINDOWS_SERVER_2003 '0052' -#define WINDOWS_VISTA '0060' -#define WINDOWS_7 '0061' +#define WINDOWS_XP 51 +#define WINDOWS_SERVER_2003 52 +#define WINDOWS_VISTA 60 +#define WINDOWS_7 61 #define KVOFF(object, offset) ((PCHAR)(object) + offset) NTSTATUS KvInit(); -#ifdef KPH_VERSION_PRIVATE +#ifdef EXT +#undef EXT +#endif + +#ifdef _VERSION_PRIVATE #define EXT #else #define EXT extern @@ -46,7 +50,7 @@ EXT ACCESS_MASK ProcessAllAccess; EXT ACCESS_MASK ThreadAllAccess; /* Offsets */ -/* +/* Structures * Et: ETHREAD * Ep: EPROCESS * Ot: OBJECT_TYPE @@ -62,4 +66,9 @@ EXT ULONG OffEpProtectedProcessBit; EXT ULONG OffEpRundownProtect; EXT ULONG OffOtiGenericMapping; +/* Functions + * These are all offsets from NtClose. + */ +EXT ULONG OffPsTerminateProcess; + #endif diff --git a/trunk/KProcessHacker/include/zw.h b/trunk/KProcessHacker/include/zw.h index 6107e9fce..6937f5c5a 100644 --- a/trunk/KProcessHacker/include/zw.h +++ b/trunk/KProcessHacker/include/zw.h @@ -54,6 +54,19 @@ #define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ 0x1F) +typedef struct _SYSTEM_MODULE_INFORMATION +{ + ULONG Reserved[2]; + PVOID Base; + ULONG Size; + ULONG Flags; + USHORT Index; + USHORT Unknown; + USHORT LoadCount; + USHORT ModuleNameOffset; + CHAR ImageName[256]; +} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; + NTSTATUS NTAPI ZwOpenProcessToken( HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, @@ -67,4 +80,8 @@ NTSTATUS NTAPI ZwSetInformationProcess( ULONG ProcessInformationLength ); +typedef NTSTATUS (NTAPI *_NtClose)( + HANDLE Handle + ); + #endif diff --git a/trunk/KProcessHacker/kph.c b/trunk/KProcessHacker/kph.c index f8f685e1d..60c16dac8 100644 --- a/trunk/KProcessHacker/kph.c +++ b/trunk/KProcessHacker/kph.c @@ -20,12 +20,10 @@ * along with Process Hacker. If not, see . */ +#define _KPH_PRIVATE #include "include/kph.h" -_PsGetProcessJob PsGetProcessJob = NULL; -_PsSuspendProcess PsSuspendProcess = NULL; -_PsResumeProcess PsResumeProcess = NULL; -_MmCopyVirtualMemory MmCopyVirtualMemory = NULL; +static char StandardPrologue[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec }; PVOID GetSystemRoutineAddress(WCHAR *Name) { @@ -50,11 +48,30 @@ NTSTATUS KphNtInit() { NTSTATUS status = STATUS_SUCCESS; + __NtClose = GetSystemRoutineAddress(L"NtClose"); + + /* NtClose is used as a reference point for any addresses + dependent on where the kernel is loaded. */ + if (!__NtClose) + return STATUS_NOT_SUPPORTED; + MmCopyVirtualMemory = GetSystemRoutineAddress(L"MmCopyVirtualMemory"); PsGetProcessJob = GetSystemRoutineAddress(L"PsGetProcessJob"); PsResumeProcess = GetSystemRoutineAddress(L"PsResumeProcess"); PsSuspendProcess = GetSystemRoutineAddress(L"PsSuspendProcess"); + /* Initialize function pointers */ + if (OffPsTerminateProcess) + { + __PsTerminateProcess = (_PsTerminateProcess)((ULONG)__NtClose + OffPsTerminateProcess); + dprintf("PsTerminateProcess: 0x%08x\n", __PsTerminateProcess); + if (memcmp(__PsTerminateProcess, StandardPrologue, 5) != 0) + { + __PsTerminateProcess = NULL; + dprintf("PsTerminateProcess failed memory check\n"); + } + } + return status; } diff --git a/trunk/KProcessHacker/mm.c b/trunk/KProcessHacker/mm.c index 9b1333711..f9bc18ed6 100644 --- a/trunk/KProcessHacker/mm.c +++ b/trunk/KProcessHacker/mm.c @@ -36,7 +36,7 @@ NTSTATUS KphReadVirtualMemory( PEPROCESS processObject; ULONG returnLength = 0; - if (MmCopyVirtualMemory == NULL) + if (!MmCopyVirtualMemory) return STATUS_NOT_SUPPORTED; if (AccessMode != KernelMode) @@ -107,7 +107,7 @@ NTSTATUS KphWriteVirtualMemory( PEPROCESS processObject; ULONG returnLength = 0; - if (MmCopyVirtualMemory == NULL) + if (!MmCopyVirtualMemory) return STATUS_NOT_SUPPORTED; if (AccessMode != KernelMode) diff --git a/trunk/KProcessHacker/ob.c b/trunk/KProcessHacker/ob.c index b3ca21b58..5fbc27787 100644 --- a/trunk/KProcessHacker/ob.c +++ b/trunk/KProcessHacker/ob.c @@ -81,7 +81,7 @@ NTSTATUS KphDuplicateObject( } /* Call the internal function */ - status = KphObDuplicateObject( + status = ObDuplicateObject( sourceProcess, targetProcess, SourceHandle, @@ -121,7 +121,7 @@ BOOLEAN KphEnumProcessHandleTable( BOOLEAN result = FALSE; PHANDLE_TABLE handleTable = NULL; - handleTable = KphObReferenceProcessHandleTable(Process); + handleTable = ObReferenceProcessHandleTable(Process); if (!handleTable) return FALSE; @@ -131,18 +131,18 @@ BOOLEAN KphEnumProcessHandleTable( EnumHandleProcedure, Context, Handle); - KphObDereferenceProcessHandleTable(Process); + ObDereferenceProcessHandleTable(Process); return result; } -VOID KphObDereferenceProcessHandleTable( +VOID ObDereferenceProcessHandleTable( PEPROCESS Process ) { ExReleaseRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect)); } -NTSTATUS KphObDuplicateObject( +NTSTATUS ObDuplicateObject( PEPROCESS SourceProcess, PEPROCESS TargetProcess, HANDLE SourceHandle, @@ -257,7 +257,7 @@ OpenObjectEnd: return status; } -PHANDLE_TABLE KphObReferenceProcessHandleTable( +PHANDLE_TABLE ObReferenceProcessHandleTable( PEPROCESS Process ) { diff --git a/trunk/KProcessHacker/ps.c b/trunk/KProcessHacker/ps.c index 2fd851b14..1dcab66a2 100644 --- a/trunk/KProcessHacker/ps.c +++ b/trunk/KProcessHacker/ps.c @@ -419,7 +419,7 @@ NTSTATUS KphResumeProcess( NTSTATUS status = STATUS_SUCCESS; PEPROCESS processObject; - if (PsResumeProcess == NULL) + if (!PsResumeProcess) return STATUS_NOT_SUPPORTED; status = ObReferenceObjectByHandle( @@ -472,7 +472,7 @@ NTSTATUS KphSuspendProcess( NTSTATUS status = STATUS_SUCCESS; PEPROCESS processObject; - if (PsSuspendProcess == NULL) + if (!PsSuspendProcess) return STATUS_NOT_SUPPORTED; status = ObReferenceObjectByHandle( @@ -515,22 +515,73 @@ NTSTATUS KphTerminateProcess( return status; /* Can't terminate ourself. Get user-mode to do it. */ - if (PsGetProcessId(processObject) == PsGetCurrentProcessId()) + if (processObject == PsGetCurrentProcess()) { ObDereferenceObject(processObject); return STATUS_DISK_FULL; } - /* We have to open it again because ZwTerminateProcess only accepts kernel handles. */ - clientId.UniqueThread = 0; - clientId.UniqueProcess = PsGetProcessId(processObject); - status = KphOpenProcess(&newProcessHandle, 0x1, &objectAttributes, &clientId, KernelMode); - ObDereferenceObject(processObject); - - if (NT_SUCCESS(status)) + if (__PsTerminateProcess) { - status = ZwTerminateProcess(newProcessHandle, ExitStatus); - ZwClose(newProcessHandle); + status = PsTerminateProcess(processObject, ExitStatus); + } + else + { + /* We have to open it again because ZwTerminateProcess only accepts kernel handles. */ + clientId.UniqueThread = 0; + clientId.UniqueProcess = PsGetProcessId(processObject); + status = KphOpenProcess(&newProcessHandle, 0x1, &objectAttributes, &clientId, KernelMode); + ObDereferenceObject(processObject); + + if (NT_SUCCESS(status)) + { + status = ZwTerminateProcess(newProcessHandle, ExitStatus); + ZwClose(newProcessHandle); + } + } + + return status; +} + +NTSTATUS PsTerminateProcess( + PEPROCESS Process, + NTSTATUS ExitStatus + ) +{ + PVOID psTerminateProcess = __PsTerminateProcess; + NTSTATUS status; + + if (!psTerminateProcess) + return STATUS_NOT_SUPPORTED; + + if (WindowsVersion == WINDOWS_XP) + { + /* PsTerminateProcess on XP is stdcall */ + __asm + { + push [ExitStatus] + push [Process] + call [psTerminateProcess] + mov [status], eax + } + } + else if ( + WindowsVersion == WINDOWS_VISTA || + WindowsVersion == WINDOWS_7 + ) + { + /* PsTerminateProcess on Vista and above is thiscall */ + __asm + { + push [ExitStatus] + mov ecx, [Process] + call [psTerminateProcess] + mov [status], eax + } + } + else + { + return STATUS_NOT_SUPPORTED; } return status; diff --git a/trunk/KProcessHacker/version.c b/trunk/KProcessHacker/version.c index 48f92c6bc..a7b990aef 100644 --- a/trunk/KProcessHacker/version.c +++ b/trunk/KProcessHacker/version.c @@ -20,10 +20,15 @@ * along with Process Hacker. If not, see . */ -#define KPH_VERSION_PRIVATE +#define _VERSION_PRIVATE #include "include/version.h" #include "include/debug.h" +/* The following offsets took me a long time to work out, so + please do not steal them. If you want to use them, please + license your project under the GNU GPL (although you are + not legally required to). + */ NTSTATUS KvInit() { NTSTATUS status = STATUS_SUCCESS; @@ -58,15 +63,26 @@ NTSTATUS KvInit() /* Windows XP SP0 and 1 are not supported */ if (servicePack == 0) + { return STATUS_NOT_SUPPORTED; + } else if (servicePack == 1) + { return STATUS_NOT_SUPPORTED; + } else if (servicePack == 2) - ; + { + /* Seems to be OK for both ntkrnlpa and ntkrpamp */ + OffPsTerminateProcess = 0x16576; + } else if (servicePack == 3) - ; + { + OffPsTerminateProcess = 0x1676c; + } else + { return STATUS_NOT_SUPPORTED; + } dprintf("Initialized version-specific data for Windows XP SP%d\n", servicePack); } @@ -97,12 +113,13 @@ NTSTATUS KvInit() if (servicePack == 0) { OffOtiGenericMapping = 0x60 + 0xc; + OffPsTerminateProcess = 0x29b83; } /* SP1 */ else if (servicePack == 1) { - /* They got rid of the Mutex (an ERESOURCE) */ - OffOtiGenericMapping = 0x28 + 0xc; + OffOtiGenericMapping = 0x28 + 0xc; /* They got rid of the Mutex (an ERESOURCE) */ + OffPsTerminateProcess = 0x7768a; } else { @@ -129,9 +146,15 @@ NTSTATUS KvInit() /* SP0 */ if (servicePack == 0) - ; + { + /* In Windows 7 PsTerminateProcess is before + NtClose, so we have a negative number here. */ + OffPsTerminateProcess = 0xfff80dc2; + } else + { return STATUS_NOT_SUPPORTED; + } dprintf("Initialized version-specific data for Windows 7 SP%d\n", servicePack); }