mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
KphTerminateProcess now uses PsTerminateProcess where possible; if the wrong address is found it should not BSOD the system because the first 5 bytes are checked against the known standard function prologue.
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1099 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -20,8 +20,8 @@
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -69,6 +69,11 @@ typedef NTSTATUS (NTAPI *_PsSuspendProcess)(
|
||||
PEPROCESS Process
|
||||
);
|
||||
|
||||
typedef NTSTATUS (__fastcall *_PsTerminateProcess)(
|
||||
PEPROCESS Process,
|
||||
NTSTATUS ExitStatus
|
||||
);
|
||||
|
||||
/* STRUCTS */
|
||||
|
||||
typedef struct _KEXECUTE_OPTIONS
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,12 +20,10 @@
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
{
|
||||
|
||||
+63
-12
@@ -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;
|
||||
|
||||
@@ -20,10 +20,15 @@
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user