Files
mirror-processhacker/2.x/trunk/ProcessHacker/actions.c
T
wj32 5de79e9750 * added more native defs
* added reverse-engineered SYSTEM_PROCESS_IMAGE_NAME_INFORMATION
* now can get the file name of any process, under any account and without KProcessHacker, on Vista and above

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2995 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2010-03-30 07:49:52 +00:00

1494 lines
34 KiB
C

/*
* Process Hacker -
* UI actions
*
* Copyright (C) 2010 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include <phapp.h>
#include <settings.h>
#include <kph.h>
static PWSTR DangerousProcesses[] =
{
L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe",
L"services.exe", L"smss.exe", L"wininit.exe", L"winlogon.exe"
};
/**
* Determines if a process is a system process.
*
* \param ProcessId The PID of the process to check.
*/
static BOOLEAN PhpIsDangerousProcess(
__in HANDLE ProcessId
)
{
NTSTATUS status;
HANDLE processHandle;
PPH_STRING fileName;
PPH_STRING systemDirectory;
ULONG i;
if (ProcessId == SYSTEM_PROCESS_ID)
return TRUE;
if (WindowsVersion >= WINDOWS_VISTA)
{
status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName);
}
else
{
if (!NT_SUCCESS(status = PhOpenProcess(
&processHandle,
ProcessQueryAccess,
ProcessId
)))
return FALSE;
status = PhGetProcessImageFileName(processHandle, &fileName);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
return FALSE;
PhaDereferenceObject(fileName);
fileName = PHA_DEREFERENCE(PhGetFileName(fileName));
systemDirectory = PHA_DEREFERENCE(PhGetSystemDirectory());
for (i = 0; i < sizeof(DangerousProcesses) / sizeof(PWSTR); i++)
{
PPH_STRING fullName;
fullName = PhaConcatStrings(3, systemDirectory->Buffer, L"\\", DangerousProcesses[i]);
if (PhStringEquals(fileName, fullName, TRUE))
return TRUE;
}
return FALSE;
}
/**
* Checks if the user wants to proceed with an operation.
*
* \param hWnd A handle to the parent window.
* \param Verb A verb describing the action.
* \param Message A message containing additional information
* about the action.
* \param WarnOnlyIfDangerous TRUE to skip the confirmation
* dialog if none of the processes are system processes,
* FALSE to always show the confirmation dialog.
* \param Processes An array of pointers to process items.
* \param NumberOfProcesses The number of process items.
*
* \return TRUE if the user wants to proceed with the operation,
* otherwise FALSE.
*/
static BOOLEAN PhpShowContinueMessageProcesses(
__in HWND hWnd,
__in PWSTR Verb,
__in_opt PWSTR Message,
__in BOOLEAN WarnOnlyIfDangerous,
__in PPH_PROCESS_ITEM *Processes,
__in ULONG NumberOfProcesses
)
{
PWSTR object;
ULONG i;
BOOLEAN dangerous = FALSE;
BOOLEAN cont = FALSE;
if (NumberOfProcesses == 0)
return FALSE;
for (i = 0; i < NumberOfProcesses; i++)
{
if (PhpIsDangerousProcess(Processes[i]->ProcessId))
{
dangerous = TRUE;
break;
}
}
if (WarnOnlyIfDangerous && !dangerous)
return TRUE;
if (PhGetIntegerSetting(L"EnableWarnings"))
{
if (NumberOfProcesses == 1)
{
object = Processes[0]->ProcessName->Buffer;
}
else if (NumberOfProcesses == 2)
{
object = PhaConcatStrings(
3,
Processes[0]->ProcessName->Buffer,
L" and ",
Processes[1]->ProcessName->Buffer
)->Buffer;
}
else
{
object = L"the selected processes";
}
if (!dangerous)
{
cont = PhShowConfirmMessage(
hWnd,
Verb,
object,
Message,
FALSE
);
}
else
{
cont = PhShowConfirmMessage(
hWnd,
Verb,
object,
PhaConcatStrings(
3,
L"You are about to ",
Verb,
L" one or more system processes."
)->Buffer,
TRUE
);
}
}
else
{
cont = TRUE;
}
return cont;
}
/**
* Shows an error message to the user and checks
* if the user wants to continue.
*
* \param hWnd A handle to the parent window.
* \param Verb A verb describing the action which
* resulted in an error.
* \param Process The process item which the action
* was performed on.
* \param Status A NT status value representing the
* error.
* \param Win32Result A Win32 error code representing
* the error.
*
* \return TRUE if the user wants to continue, otherwise
* FALSE. The result is typically only useful when
* executing an action on multiple processes.
*/
static BOOLEAN PhpShowErrorProcess(
__in HWND hWnd,
__in PWSTR Verb,
__in PPH_PROCESS_ITEM Process,
__in NTSTATUS Status,
__in_opt ULONG Win32Result
)
{
if (
Process->ProcessId != DPCS_PROCESS_ID &&
Process->ProcessId != INTERRUPTS_PROCESS_ID
)
{
return PhShowContinueStatus(
hWnd,
PhaFormatString(
L"Unable to %s %s (PID %u)",
Verb,
Process->ProcessName->Buffer,
(ULONG)Process->ProcessId
)->Buffer,
Status,
Win32Result
);
}
else
{
return PhShowContinueStatus(
hWnd,
PhaFormatString(
L"Unable to %s %s",
Verb,
Process->ProcessName->Buffer
)->Buffer,
Status,
Win32Result
);
}
}
BOOLEAN PhUiTerminateProcesses(
__in HWND hWnd,
__in PPH_PROCESS_ITEM *Processes,
__in ULONG NumberOfProcesses
)
{
BOOLEAN success = TRUE;
ULONG i;
if (!PhpShowContinueMessageProcesses(
hWnd,
L"terminate",
L"Terminating a process will cause unsaved data to be lost.",
FALSE,
Processes,
NumberOfProcesses
))
return FALSE;
for (i = 0; i < NumberOfProcesses; i++)
{
NTSTATUS status;
HANDLE processHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_TERMINATE,
Processes[i]->ProcessId
)))
{
status = PhTerminateProcess(processHandle, STATUS_SUCCESS);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiSuspendProcesses(
__in HWND hWnd,
__in PPH_PROCESS_ITEM *Processes,
__in ULONG NumberOfProcesses
)
{
BOOLEAN success = TRUE;
ULONG i;
if (!PhpShowContinueMessageProcesses(
hWnd,
L"suspend",
NULL,
TRUE,
Processes,
NumberOfProcesses
))
return FALSE;
for (i = 0; i < NumberOfProcesses; i++)
{
NTSTATUS status;
HANDLE processHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_SUSPEND_RESUME,
Processes[i]->ProcessId
)))
{
status = PhSuspendProcess(processHandle);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiResumeProcesses(
__in HWND hWnd,
__in PPH_PROCESS_ITEM *Processes,
__in ULONG NumberOfProcesses
)
{
BOOLEAN success = TRUE;
ULONG i;
if (!PhpShowContinueMessageProcesses(
hWnd,
L"resume",
NULL,
TRUE,
Processes,
NumberOfProcesses
))
return FALSE;
for (i = 0; i < NumberOfProcesses; i++)
{
NTSTATUS status;
HANDLE processHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_SUSPEND_RESUME,
Processes[i]->ProcessId
)))
{
status = PhResumeProcess(processHandle);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiRestartProcess(
__in HWND hWnd,
__in PPH_PROCESS_ITEM Process
)
{
NTSTATUS status;
BOOLEAN cont = FALSE;
HANDLE processHandle = NULL;
BOOLEAN isPosix;
PPH_STRING commandLine;
PPH_STRING currentDirectory;
if (PhGetIntegerSetting(L"EnableWarnings"))
{
cont = PhShowConfirmMessage(
hWnd,
L"restart",
Process->ProcessName->Buffer,
L"The process will be restarted with the same command line and "
L"working directory, but if it is running under a different user it "
L"will be restarted under the current user.",
TRUE
);
}
else
{
cont = TRUE;
}
if (!cont)
return FALSE;
// Open the process and get the command line and current directory.
if (!NT_SUCCESS(status = PhOpenProcess(
&processHandle,
ProcessQueryAccess | PROCESS_VM_READ,
Process->ProcessId
)))
goto ErrorExit;
if (!NT_SUCCESS(status = PhGetProcessIsPosix(processHandle, &isPosix)))
goto ErrorExit;
if (isPosix)
{
PhShowError(hWnd, L"POSIX processes cannot be restarted.");
goto ErrorExit;
}
if (!NT_SUCCESS(status = PhGetProcessCommandLine(
processHandle,
&commandLine
)))
goto ErrorExit;
PhaDereferenceObject(commandLine);
if (!NT_SUCCESS(status = PhGetProcessPebString(
processHandle,
PhpoCurrentDirectory,
&currentDirectory
)))
goto ErrorExit;
PhaDereferenceObject(currentDirectory);
NtClose(processHandle);
processHandle = NULL;
// Open the process and terminate it.
if (!NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_TERMINATE,
Process->ProcessId
)))
goto ErrorExit;
if (!NT_SUCCESS(status = PhTerminateProcess(
processHandle,
STATUS_SUCCESS
)))
goto ErrorExit;
NtClose(processHandle);
processHandle = NULL;
// Start the process.
status = PhCreateProcessWin32(
PhGetString(Process->FileName), // we didn't wait for S1 processing
commandLine->Buffer, // string may be modified, but it's OK in this case
NULL,
currentDirectory->Buffer,
0,
NULL,
NULL,
NULL
);
ErrorExit:
if (processHandle)
NtClose(processHandle);
if (!NT_SUCCESS(status))
{
PhpShowErrorProcess(hWnd, L"restart", Process, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiReduceWorkingSetProcesses(
__in HWND hWnd,
__in PPH_PROCESS_ITEM *Processes,
__in ULONG NumberOfProcesses
)
{
BOOLEAN success = TRUE;
ULONG i;
for (i = 0; i < NumberOfProcesses; i++)
{
NTSTATUS status;
ULONG win32Result = 0;
HANDLE processHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_SET_QUOTA,
Processes[i]->ProcessId
)))
{
if (!SetProcessWorkingSetSize(processHandle, -1, -1))
win32Result = GetLastError();
NtClose(processHandle);
}
if (!NT_SUCCESS(status) || win32Result)
{
success = FALSE;
if (!PhpShowErrorProcess(hWnd, L"reduce the working set of", Processes[i], status, win32Result))
break;
}
}
return success;
}
BOOLEAN PhUiSetVirtualizationProcess(
__in HWND hWnd,
__in PPH_PROCESS_ITEM Process,
__in BOOLEAN Enable
)
{
NTSTATUS status;
BOOLEAN cont = FALSE;
HANDLE processHandle;
HANDLE tokenHandle;
if (PhGetIntegerSetting(L"EnableWarnings"))
{
cont = PhShowConfirmMessage(
hWnd,
L"set",
L"virtualization for the process",
L"Enabling or disabling virtualization for a process may "
L"alter its functionality and produce undesirable effects.",
FALSE
);
}
else
{
cont = TRUE;
}
if (!cont)
return FALSE;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
ProcessQueryAccess,
Process->ProcessId
)))
{
if (NT_SUCCESS(status = PhOpenProcessToken(
&tokenHandle,
TOKEN_WRITE,
processHandle
)))
{
status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable);
NtClose(tokenHandle);
}
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
PhpShowErrorProcess(hWnd, L"set virtualization for", Process, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiDetachFromDebuggerProcess(
__in HWND hWnd,
__in PPH_PROCESS_ITEM Process
)
{
NTSTATUS status;
HANDLE processHandle;
HANDLE debugObjectHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME,
Process->ProcessId
)))
{
if (NT_SUCCESS(status = PhGetProcessDebugObject(
processHandle,
&debugObjectHandle
)))
{
ULONG flags;
// Disable kill-on-close.
flags = 0;
status = NtSetInformationDebugObject(
debugObjectHandle,
DebugObjectFlags,
&flags,
sizeof(ULONG),
NULL
);
status = NtRemoveProcessDebug(processHandle, debugObjectHandle);
NtClose(debugObjectHandle);
}
NtClose(processHandle);
}
if (status == STATUS_PORT_NOT_SET)
{
PhShowInformation(hWnd, L"The process is not being debugged.");
return FALSE;
}
if (!NT_SUCCESS(status))
{
PhpShowErrorProcess(hWnd, L"detach debugger from", Process, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiInjectDllProcess(
__in HWND hWnd,
__in PPH_PROCESS_ITEM Process
)
{
static PH_FILETYPE_FILTER filters[] =
{
{ L"DLL files (*.dll)", L"*.dll" },
{ L"All files (*.*)", L"*.*" }
};
NTSTATUS status;
PVOID fileDialog;
PPH_STRING fileName;
HANDLE processHandle;
fileDialog = PhCreateOpenFileDialog();
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
if (!PhShowFileDialog(hWnd, fileDialog))
{
PhFreeFileDialog(fileDialog);
return FALSE;
}
fileName = PHA_DEREFERENCE(PhGetFileDialogFileName(fileDialog));
PhFreeFileDialog(fileDialog);
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE,
Process->ProcessId
)))
{
status = PhInjectDllProcess(
processHandle,
fileName->Buffer,
5000
);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
PhpShowErrorProcess(hWnd, L"inject the DLL into", Process, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiSetIoPriorityProcess(
__in HWND hWnd,
__in PPH_PROCESS_ITEM Process,
__in ULONG IoPriority
)
{
NTSTATUS status;
HANDLE processHandle;
if (!PhKphHandle)
{
PhShowError(hWnd, KPH_ERROR_MESSAGE);
return FALSE;
}
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_SET_INFORMATION,
Process->ProcessId
)))
{
status = PhSetProcessIoPriority(processHandle, IoPriority);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
PhpShowErrorProcess(hWnd, L"set the I/O priority of", Process, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiSetPriorityProcess(
__in HWND hWnd,
__in PPH_PROCESS_ITEM Process,
__in ULONG PriorityClassWin32
)
{
NTSTATUS status;
ULONG win32Result = 0;
HANDLE processHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_SET_INFORMATION,
Process->ProcessId
)))
{
if (!SetPriorityClass(processHandle, PriorityClassWin32))
win32Result = GetLastError();
NtClose(processHandle);
}
if (!NT_SUCCESS(status) || win32Result)
{
PhpShowErrorProcess(hWnd, L"set the priority of", Process, status, 0);
return FALSE;
}
return TRUE;
}
static VOID PhpShowErrorService(
__in HWND hWnd,
__in PWSTR Verb,
__in PPH_SERVICE_ITEM Service,
__in NTSTATUS Status,
__in_opt ULONG Win32Result
)
{
PhShowStatus(
hWnd,
PhaFormatString(
L"Unable to %s %s",
Verb,
Service->Name->Buffer
)->Buffer,
Status,
Win32Result
);
}
BOOLEAN PhUiStartService(
__in HWND hWnd,
__in PPH_SERVICE_ITEM Service
)
{
SC_HANDLE serviceHandle;
BOOLEAN success = FALSE;
serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_START);
if (serviceHandle)
{
if (StartService(serviceHandle, 0, NULL))
success = TRUE;
CloseServiceHandle(serviceHandle);
}
if (!success)
PhpShowErrorService(hWnd, L"start", Service, 0, GetLastError());
return success;
}
BOOLEAN PhUiContinueService(
__in HWND hWnd,
__in PPH_SERVICE_ITEM Service
)
{
SC_HANDLE serviceHandle;
BOOLEAN success = FALSE;
serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
if (serviceHandle)
{
SERVICE_STATUS serviceStatus;
if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
success = TRUE;
CloseServiceHandle(serviceHandle);
}
if (!success)
PhpShowErrorService(hWnd, L"continue", Service, 0, GetLastError());
return success;
}
BOOLEAN PhUiPauseService(
__in HWND hWnd,
__in PPH_SERVICE_ITEM Service
)
{
SC_HANDLE serviceHandle;
BOOLEAN success = FALSE;
serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
if (serviceHandle)
{
SERVICE_STATUS serviceStatus;
if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
success = TRUE;
CloseServiceHandle(serviceHandle);
}
if (!success)
PhpShowErrorService(hWnd, L"pause", Service, 0, GetLastError());
return success;
}
BOOLEAN PhUiStopService(
__in HWND hWnd,
__in PPH_SERVICE_ITEM Service
)
{
SC_HANDLE serviceHandle;
BOOLEAN success = FALSE;
serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_STOP);
if (serviceHandle)
{
SERVICE_STATUS serviceStatus;
if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
success = TRUE;
CloseServiceHandle(serviceHandle);
}
if (!success)
PhpShowErrorService(hWnd, L"stop", Service, 0, GetLastError());
return success;
}
BOOLEAN PhUiDeleteService(
__in HWND hWnd,
__in PPH_SERVICE_ITEM Service
)
{
SC_HANDLE serviceHandle;
BOOLEAN success = FALSE;
// Warnings cannot be disabled for service deletion.
if (!PhShowConfirmMessage(
hWnd,
L"delete",
Service->Name->Buffer,
L"Deleting a service can prevent the system from starting "
L"or functioning properly.",
TRUE
))
return FALSE;
serviceHandle = PhOpenService(Service->Name->Buffer, DELETE);
if (serviceHandle)
{
if (DeleteService(serviceHandle))
success = TRUE;
CloseServiceHandle(serviceHandle);
}
if (!success)
PhpShowErrorService(hWnd, L"delete", Service, 0, GetLastError());
return success;
}
static BOOLEAN PhpShowContinueMessageThreads(
__in HWND hWnd,
__in PWSTR Verb,
__in PWSTR Message,
__in BOOLEAN Warning,
__in PPH_THREAD_ITEM *Threads,
__in ULONG NumberOfThreads
)
{
PWSTR object;
BOOLEAN cont = FALSE;
if (NumberOfThreads == 0)
return FALSE;
if (PhGetIntegerSetting(L"EnableWarnings"))
{
if (NumberOfThreads == 1)
{
object = L"the selected thread";
}
else
{
object = L"the selected threads";
}
cont = PhShowConfirmMessage(
hWnd,
Verb,
object,
Message,
Warning
);
}
else
{
cont = TRUE;
}
return cont;
}
static BOOLEAN PhpShowErrorThread(
__in HWND hWnd,
__in PWSTR Verb,
__in PPH_THREAD_ITEM Thread,
__in NTSTATUS Status,
__in_opt ULONG Win32Result
)
{
return PhShowContinueStatus(
hWnd,
PhaFormatString(
L"Unable to %s thread %u",
Verb,
(ULONG)Thread->ThreadId
)->Buffer,
Status,
Win32Result
);
}
BOOLEAN PhUiTerminateThreads(
__in HWND hWnd,
__in PPH_THREAD_ITEM *Threads,
__in ULONG NumberOfThreads
)
{
BOOLEAN success = TRUE;
ULONG i;
if (!PhpShowContinueMessageThreads(
hWnd,
L"terminate",
L"Terminating a thread may cause the process to stop working.",
FALSE,
Threads,
NumberOfThreads
))
return FALSE;
for (i = 0; i < NumberOfThreads; i++)
{
NTSTATUS status;
HANDLE threadHandle;
if (NT_SUCCESS(status = PhOpenThread(
&threadHandle,
THREAD_TERMINATE,
Threads[i]->ThreadId
)))
{
status = PhTerminateThread(threadHandle, STATUS_SUCCESS);
NtClose(threadHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiForceTerminateThreads(
__in HWND hWnd,
__in HANDLE ProcessId,
__in PPH_THREAD_ITEM *Threads,
__in ULONG NumberOfThreads
)
{
BOOLEAN success = TRUE;
ULONG i;
if (!PhKphHandle)
{
PhShowError(hWnd, KPH_ERROR_MESSAGE);
return FALSE;
}
if (ProcessId != SYSTEM_PROCESS_ID)
{
if (!PhpShowContinueMessageThreads(
hWnd,
L"force terminate",
L"Forcibly terminating threads may cause the system to crash or become unstable.",
TRUE,
Threads,
NumberOfThreads
))
return FALSE;
}
else
{
if (!PhpShowContinueMessageThreads(
hWnd,
L"terminate",
L"Forcibly terminating system threads may cause the system to crash or become unstable.",
TRUE,
Threads,
NumberOfThreads
))
return FALSE;
}
for (i = 0; i < NumberOfThreads; i++)
{
NTSTATUS status;
HANDLE threadHandle;
if (NT_SUCCESS(status = PhOpenThread(
&threadHandle,
THREAD_TERMINATE,
Threads[i]->ThreadId
)))
{
status = KphDangerousTerminateThread(PhKphHandle, threadHandle, STATUS_SUCCESS);
NtClose(threadHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiSuspendThreads(
__in HWND hWnd,
__in PPH_THREAD_ITEM *Threads,
__in ULONG NumberOfThreads
)
{
BOOLEAN success = TRUE;
ULONG i;
for (i = 0; i < NumberOfThreads; i++)
{
NTSTATUS status;
HANDLE threadHandle;
if (NT_SUCCESS(status = PhOpenThread(
&threadHandle,
THREAD_SUSPEND_RESUME,
Threads[i]->ThreadId
)))
{
status = PhSuspendThread(threadHandle, NULL);
NtClose(threadHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiResumeThreads(
__in HWND hWnd,
__in PPH_THREAD_ITEM *Threads,
__in ULONG NumberOfThreads
)
{
BOOLEAN success = TRUE;
ULONG i;
for (i = 0; i < NumberOfThreads; i++)
{
NTSTATUS status;
HANDLE threadHandle;
if (NT_SUCCESS(status = PhOpenThread(
&threadHandle,
THREAD_SUSPEND_RESUME,
Threads[i]->ThreadId
)))
{
status = PhResumeThread(threadHandle, NULL);
NtClose(threadHandle);
}
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0))
break;
}
}
return success;
}
BOOLEAN PhUiSetPriorityThread(
__in HWND hWnd,
__in PPH_THREAD_ITEM Thread,
__in ULONG ThreadPriorityWin32
)
{
NTSTATUS status;
ULONG win32Result = 0;
HANDLE threadHandle;
if (NT_SUCCESS(status = PhOpenThread(
&threadHandle,
ThreadSetAccess,
Thread->ThreadId
)))
{
if (!SetThreadPriority(threadHandle, ThreadPriorityWin32))
win32Result = GetLastError();
NtClose(threadHandle);
}
if (!NT_SUCCESS(status) || win32Result)
{
PhpShowErrorThread(hWnd, L"set the priority of", Thread, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiSetIoPriorityThread(
__in HWND hWnd,
__in PPH_THREAD_ITEM Thread,
__in ULONG IoPriority
)
{
NTSTATUS status;
HANDLE threadHandle;
if (!PhKphHandle)
{
PhShowError(hWnd, KPH_ERROR_MESSAGE);
return FALSE;
}
if (NT_SUCCESS(status = PhOpenThread(
&threadHandle,
ThreadSetAccess,
Thread->ThreadId
)))
{
status = PhSetThreadIoPriority(threadHandle, IoPriority);
NtClose(threadHandle);
}
if (!NT_SUCCESS(status))
{
PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
return FALSE;
}
return TRUE;
}
BOOLEAN PhUiUnloadModule(
__in HWND hWnd,
__in HANDLE ProcessId,
__in PPH_MODULE_ITEM Module
)
{
NTSTATUS status;
BOOLEAN cont = FALSE;
HANDLE processHandle;
if (PhGetIntegerSetting(L"EnableWarnings"))
{
cont = PhShowConfirmMessage(
hWnd,
L"unload",
Module->Name->Buffer,
ProcessId != SYSTEM_PROCESS_ID ?
L"Unloading a module may cause the process to crash." :
L"Unloading a driver may cause system instability.",
TRUE
);
}
else
{
cont = TRUE;
}
if (!cont)
return FALSE;
if (ProcessId != SYSTEM_PROCESS_ID)
{
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_READ | PROCESS_VM_WRITE,
ProcessId
)))
{
status = PhUnloadDllProcess(
processHandle,
Module->BaseAddress,
5000
);
NtClose(processHandle);
}
if (status == STATUS_DLL_NOT_FOUND)
{
#ifdef _M_IX86
PhShowError(hWnd, L"Unable to find the module to unload. This may be "
L"due to an attempt to unload a mapped file.");
#else
PhShowError(hWnd, L"Unable to find the module to unload. This may be "
L"due to an attempt to unload a mapped file or a 32-bit module.");
#endif
return FALSE;
}
if (!NT_SUCCESS(status))
{
PhShowStatus(
hWnd,
PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
status,
0
);
return FALSE;
}
}
else
{
status = PhUnloadDriver(Module->BaseAddress, Module->Name->Buffer);
if (!NT_SUCCESS(status))
{
PhShowStatus(
hWnd,
PhaConcatStrings(
3,
L"Unable to unload ",
Module->Name->Buffer,
L". Make sure Process Hacker is running with "
L"administrative privileges. Error"
)->Buffer,
status,
0
);
return FALSE;
}
}
return TRUE;
}
static BOOLEAN PhpShowErrorHandle(
__in HWND hWnd,
__in PWSTR Verb,
__in PPH_HANDLE_ITEM Handle,
__in NTSTATUS Status,
__in_opt ULONG Win32Result
)
{
if (!PhIsStringNullOrEmpty(Handle->BestObjectName))
{
return PhShowContinueStatus(
hWnd,
PhaFormatString(
L"Unable to %s handle \"%s\" (0x%Ix)",
Verb,
Handle->BestObjectName->Buffer,
(ULONG)Handle->Handle
)->Buffer,
Status,
Win32Result
);
}
else
{
return PhShowContinueStatus(
hWnd,
PhaFormatString(
L"Unable to %s handle 0x%Ix",
Verb,
(ULONG)Handle->Handle
)->Buffer,
Status,
Win32Result
);
}
}
BOOLEAN PhUiCloseHandles(
__in HWND hWnd,
__in HANDLE ProcessId,
__in PPH_HANDLE_ITEM *Handles,
__in ULONG NumberOfHandles,
__in BOOLEAN Warn
)
{
NTSTATUS status;
BOOLEAN cont = FALSE;
BOOLEAN success = TRUE;
HANDLE processHandle;
if (NumberOfHandles == 0)
return FALSE;
if (Warn && PhGetIntegerSetting(L"EnableWarnings"))
{
cont = PhShowConfirmMessage(
hWnd,
L"close",
NumberOfHandles == 1 ? L"the selected handle" : L"the selected handles",
L"Closing handles may cause system instability and data corruption.",
FALSE
);
}
else
{
cont = TRUE;
}
if (!cont)
return FALSE;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_DUP_HANDLE,
ProcessId
)))
{
ULONG i;
for (i = 0; i < NumberOfHandles; i++)
{
status = PhDuplicateObject(
processHandle,
Handles[i]->Handle,
NULL,
NULL,
0,
0,
DUPLICATE_CLOSE_SOURCE
);
if (!NT_SUCCESS(status))
{
success = FALSE;
if (!PhpShowErrorHandle(
hWnd,
L"close",
Handles[i],
status,
0
))
break;
}
}
NtClose(processHandle);
}
else
{
PhShowStatus(hWnd, L"Unable to open the process", status, 0);
return FALSE;
}
return success;
}
BOOLEAN PhUiSetAttributesHandle(
__in HWND hWnd,
__in HANDLE ProcessId,
__in PPH_HANDLE_ITEM Handle,
__in ULONG Attributes
)
{
NTSTATUS status;
HANDLE processHandle;
if (!PhKphHandle)
{
PhShowError(hWnd, KPH_ERROR_MESSAGE);
return FALSE;
}
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
ProcessQueryAccess,
ProcessId
)))
{
status = KphSetHandleAttributes(
PhKphHandle,
processHandle,
Handle->Handle,
Attributes
);
NtClose(processHandle);
}
if (!NT_SUCCESS(status))
{
PhpShowErrorHandle(hWnd, L"set attributes of", Handle, status, 0);
return FALSE;
}
return TRUE;
}