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);
}