mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
45adf6df86
* fixed buffer overflow in PhpShowTokenAdvancedProperties * added PhpGenericPropertyPageHeader * added job advanced property sheet git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2950 21ef857c-d57f-4fe0-8362-d861dc6d29cd
483 lines
16 KiB
C
483 lines
16 KiB
C
/*
|
|
* Process Hacker -
|
|
* job properties
|
|
*
|
|
* 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>
|
|
|
|
typedef struct _JOB_PAGE_CONTEXT
|
|
{
|
|
PPH_OPEN_OBJECT OpenObject;
|
|
PVOID Context;
|
|
DLGPROC HookProc;
|
|
} JOB_PAGE_CONTEXT, *PJOB_PAGE_CONTEXT;
|
|
|
|
INT CALLBACK PhpJobPropPageProc(
|
|
__in HWND hwnd,
|
|
__in UINT uMsg,
|
|
__in LPPROPSHEETPAGE ppsp
|
|
);
|
|
|
|
INT_PTR CALLBACK PhpJobPageProc(
|
|
__in HWND hwndDlg,
|
|
__in UINT uMsg,
|
|
__in WPARAM wParam,
|
|
__in LPARAM lParam
|
|
);
|
|
|
|
VOID PhpShowJobAdvancedProperties(
|
|
__in HWND ParentWindowHandle,
|
|
__in PJOB_PAGE_CONTEXT Context
|
|
);
|
|
|
|
INT_PTR CALLBACK PhpJobStatisticsPageProc(
|
|
__in HWND hwndDlg,
|
|
__in UINT uMsg,
|
|
__in WPARAM wParam,
|
|
__in LPARAM lParam
|
|
);
|
|
|
|
VOID PhShowJobProperties(
|
|
__in HWND ParentWindowHandle,
|
|
__in PPH_OPEN_OBJECT OpenObject,
|
|
__in PVOID Context,
|
|
__in_opt PWSTR Title
|
|
)
|
|
{
|
|
PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
|
|
HPROPSHEETPAGE pages[1];
|
|
|
|
propSheetHeader.dwFlags =
|
|
PSH_NOAPPLYNOW |
|
|
PSH_NOCONTEXTHELP |
|
|
PSH_PROPTITLE;
|
|
propSheetHeader.hwndParent = ParentWindowHandle;
|
|
propSheetHeader.pszCaption = Title ? Title : L"Job";
|
|
propSheetHeader.nPages = 1;
|
|
propSheetHeader.nStartPage = 0;
|
|
propSheetHeader.phpage = pages;
|
|
|
|
pages[0] = PhCreateJobPage(OpenObject, Context, NULL);
|
|
|
|
PropertySheet(&propSheetHeader);
|
|
}
|
|
|
|
HPROPSHEETPAGE PhCreateJobPage(
|
|
__in PPH_OPEN_OBJECT OpenObject,
|
|
__in PVOID Context,
|
|
__in_opt DLGPROC HookProc
|
|
)
|
|
{
|
|
HPROPSHEETPAGE propSheetPageHandle;
|
|
PROPSHEETPAGE propSheetPage;
|
|
PJOB_PAGE_CONTEXT jobPageContext;
|
|
|
|
if (!NT_SUCCESS(PhCreateAlloc(&jobPageContext, sizeof(JOB_PAGE_CONTEXT))))
|
|
return NULL;
|
|
|
|
memset(jobPageContext, 0, sizeof(JOB_PAGE_CONTEXT));
|
|
jobPageContext->OpenObject = OpenObject;
|
|
jobPageContext->Context = Context;
|
|
jobPageContext->HookProc = HookProc;
|
|
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.dwFlags = PSP_USECALLBACK;
|
|
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJJOB);
|
|
propSheetPage.pfnDlgProc = PhpJobPageProc;
|
|
propSheetPage.lParam = (LPARAM)jobPageContext;
|
|
propSheetPage.pfnCallback = PhpJobPropPageProc;
|
|
|
|
propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);
|
|
// CreatePropertySheetPage would have sent PSPCB_ADDREF (below),
|
|
// which would have added a reference.
|
|
PhDereferenceObject(jobPageContext);
|
|
|
|
return propSheetPageHandle;
|
|
}
|
|
|
|
INT CALLBACK PhpJobPropPageProc(
|
|
__in HWND hwnd,
|
|
__in UINT uMsg,
|
|
__in LPPROPSHEETPAGE ppsp
|
|
)
|
|
{
|
|
PJOB_PAGE_CONTEXT jobPageContext;
|
|
|
|
jobPageContext = (PJOB_PAGE_CONTEXT)ppsp->lParam;
|
|
|
|
if (uMsg == PSPCB_ADDREF)
|
|
{
|
|
PhReferenceObject(jobPageContext);
|
|
}
|
|
else if (uMsg == PSPCB_RELEASE)
|
|
{
|
|
PhDereferenceObject(jobPageContext);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
FORCEINLINE PJOB_PAGE_CONTEXT PhpJobPageHeader(
|
|
__in HWND hwndDlg,
|
|
__in UINT uMsg,
|
|
__in WPARAM wParam,
|
|
__in LPARAM lParam
|
|
)
|
|
{
|
|
return (PJOB_PAGE_CONTEXT)PhpGenericPropertyPageHeader(
|
|
hwndDlg, uMsg, wParam, lParam, L"JobPageContext");
|
|
}
|
|
|
|
static PhpAddLimit(
|
|
__in HWND Handle,
|
|
__in PWSTR Name,
|
|
__in PWSTR Value
|
|
)
|
|
{
|
|
INT lvItemIndex;
|
|
|
|
lvItemIndex = PhAddListViewItem(Handle, MAXINT, Name, NULL);
|
|
PhSetListViewSubItem(Handle, lvItemIndex, 1, Value);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpJobPageProc(
|
|
__in HWND hwndDlg,
|
|
__in UINT uMsg,
|
|
__in WPARAM wParam,
|
|
__in LPARAM lParam
|
|
)
|
|
{
|
|
PJOB_PAGE_CONTEXT jobPageContext;
|
|
|
|
jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam);
|
|
|
|
if (!jobPageContext)
|
|
return FALSE;
|
|
|
|
if (jobPageContext->HookProc)
|
|
{
|
|
if (jobPageContext->HookProc(hwndDlg, uMsg, wParam, lParam))
|
|
return TRUE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HANDLE jobHandle;
|
|
HWND processesLv;
|
|
HWND limitsLv;
|
|
|
|
processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES);
|
|
limitsLv = GetDlgItem(hwndDlg, IDC_LIMITS);
|
|
PhSetListViewStyle(processesLv, FALSE, TRUE);
|
|
PhSetListViewStyle(limitsLv, FALSE, TRUE);
|
|
PhSetControlTheme(processesLv, L"explorer");
|
|
PhSetControlTheme(limitsLv, L"explorer");
|
|
|
|
PhAddListViewColumn(processesLv, 0, 0, 0, LVCFMT_LEFT, 240, L"Name");
|
|
|
|
PhAddListViewColumn(limitsLv, 0, 0, 0, LVCFMT_LEFT, 120, L"Name");
|
|
PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L"Value");
|
|
|
|
SetDlgItemText(hwndDlg, IDC_NAME, L"Unknown");
|
|
|
|
if (NT_SUCCESS(jobPageContext->OpenObject(
|
|
&jobHandle,
|
|
JOB_OBJECT_QUERY,
|
|
jobPageContext->Context
|
|
)))
|
|
{
|
|
PPH_STRING jobObjectName = NULL;
|
|
PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;
|
|
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits;
|
|
JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiRestrictions;
|
|
|
|
// Name
|
|
|
|
PhGetHandleInformation(
|
|
NtCurrentProcess(),
|
|
jobHandle,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&jobObjectName
|
|
);
|
|
PHA_DEREFERENCE(jobObjectName);
|
|
|
|
if (jobObjectName->Length == 0)
|
|
jobObjectName = NULL;
|
|
|
|
SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L"(unnamed job)"));
|
|
|
|
// Processes
|
|
|
|
if (NT_SUCCESS(PhGetJobProcessIdList(jobHandle, &processIdList)))
|
|
{
|
|
ULONG i;
|
|
CLIENT_ID clientId;
|
|
PPH_STRING name;
|
|
|
|
clientId.UniqueThread = NULL;
|
|
|
|
for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++)
|
|
{
|
|
clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i];
|
|
name = PHA_DEREFERENCE(PhGetClientIdName(&clientId));
|
|
|
|
PhAddListViewItem(processesLv, MAXINT, PhGetString(name), NULL);
|
|
}
|
|
|
|
PhFree(processIdList);
|
|
}
|
|
|
|
// Limits
|
|
|
|
if (NT_SUCCESS(PhGetJobExtendedLimits(jobHandle, &extendedLimits)))
|
|
{
|
|
ULONG flags = extendedLimits.BasicLimitInformation.LimitFlags;
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS)
|
|
{
|
|
WCHAR value[PH_INT32_STR_LEN_1];
|
|
PhPrintUInt32(value, extendedLimits.BasicLimitInformation.ActiveProcessLimit);
|
|
PhpAddLimit(limitsLv, L"Active Processes", value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_AFFINITY)
|
|
{
|
|
WCHAR value[PH_PTR_STR_LEN_1];
|
|
PhPrintPointer(value, (PVOID)extendedLimits.BasicLimitInformation.Affinity);
|
|
PhpAddLimit(limitsLv, L"Affinity", value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)
|
|
{
|
|
PhpAddLimit(limitsLv, L"Breakaway OK", L"Enabled");
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION)
|
|
{
|
|
PhpAddLimit(limitsLv, L"Die on Unhandled Exception", L"Enabled");
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_JOB_MEMORY)
|
|
{
|
|
PPH_STRING value = PhFormatSize(extendedLimits.JobMemoryLimit, -1);
|
|
PhpAddLimit(limitsLv, L"Job Memory", value->Buffer);
|
|
PhDereferenceObject(value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_JOB_TIME)
|
|
{
|
|
WCHAR value[PH_TIMESPAN_STR_LEN_1];
|
|
PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart,
|
|
PH_TIMESPAN_DHMS);
|
|
PhpAddLimit(limitsLv, L"Job Time", value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)
|
|
{
|
|
PhpAddLimit(limitsLv, L"Kill on Job Close", L"Enabled");
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_PRIORITY_CLASS)
|
|
{
|
|
PhpAddLimit(limitsLv, L"Priority Class",
|
|
PhGetProcessPriorityClassWin32String(extendedLimits.BasicLimitInformation.PriorityClass));
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_PROCESS_MEMORY)
|
|
{
|
|
PPH_STRING value = PhFormatSize(extendedLimits.ProcessMemoryLimit, -1);
|
|
PhpAddLimit(limitsLv, L"Process Memory", value->Buffer);
|
|
PhDereferenceObject(value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_PROCESS_TIME)
|
|
{
|
|
WCHAR value[PH_TIMESPAN_STR_LEN_1];
|
|
PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart,
|
|
PH_TIMESPAN_DHMS);
|
|
PhpAddLimit(limitsLv, L"Process Time", value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS)
|
|
{
|
|
WCHAR value[PH_INT32_STR_LEN_1];
|
|
PhPrintUInt32(value, extendedLimits.BasicLimitInformation.SchedulingClass);
|
|
PhpAddLimit(limitsLv, L"Scheduling Class", value);
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
|
|
{
|
|
PhpAddLimit(limitsLv, L"Silent Breakaway OK", L"Enabled");
|
|
}
|
|
|
|
if (flags & JOB_OBJECT_LIMIT_WORKINGSET)
|
|
{
|
|
PPH_STRING value;
|
|
|
|
value = PhFormatSize(extendedLimits.BasicLimitInformation.MinimumWorkingSetSize, -1);
|
|
PhpAddLimit(limitsLv, L"Working Set Minimum", value->Buffer);
|
|
PhDereferenceObject(value);
|
|
|
|
value = PhFormatSize(extendedLimits.BasicLimitInformation.MaximumWorkingSetSize, -1);
|
|
PhpAddLimit(limitsLv, L"Working Set Maximum", value->Buffer);
|
|
PhDereferenceObject(value);
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(PhGetJobBasicUiRestrictions(jobHandle, &basicUiRestrictions)))
|
|
{
|
|
ULONG flags = basicUiRestrictions.UIRestrictionsClass;
|
|
|
|
if (flags & JOB_OBJECT_UILIMIT_DESKTOP)
|
|
PhpAddLimit(limitsLv, L"Desktop", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_DISPLAYSETTINGS)
|
|
PhpAddLimit(limitsLv, L"Display Settings", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_EXITWINDOWS)
|
|
PhpAddLimit(limitsLv, L"Exit Windows", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_GLOBALATOMS)
|
|
PhpAddLimit(limitsLv, L"Global Atoms", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_HANDLES)
|
|
PhpAddLimit(limitsLv, L"Handles", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_READCLIPBOARD)
|
|
PhpAddLimit(limitsLv, L"Read Clipboard", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS)
|
|
PhpAddLimit(limitsLv, L"System Parameters", L"Limited");
|
|
if (flags & JOB_OBJECT_UILIMIT_WRITECLIPBOARD)
|
|
PhpAddLimit(limitsLv, L"Write Clipboard", L"Limited");
|
|
}
|
|
|
|
NtClose(jobHandle);
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_TERMINATE:
|
|
{
|
|
if (PhShowConfirmMessage(
|
|
hwndDlg,
|
|
L"terminate",
|
|
L"the job",
|
|
L"Terminating a job will terminate all processes assigned to it.",
|
|
TRUE
|
|
))
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE jobHandle;
|
|
|
|
if (NT_SUCCESS(status = jobPageContext->OpenObject(
|
|
&jobHandle,
|
|
JOB_OBJECT_TERMINATE,
|
|
jobPageContext->Context
|
|
)))
|
|
{
|
|
status = NtTerminateJobObject(jobHandle, STATUS_SUCCESS);
|
|
NtClose(jobHandle);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status))
|
|
PhShowStatus(hwndDlg, L"Unable to terminate the job", status, 0);
|
|
}
|
|
}
|
|
break;
|
|
case IDC_ADVANCED:
|
|
{
|
|
PhpShowJobAdvancedProperties(hwndDlg, jobPageContext);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID PhpShowJobAdvancedProperties(
|
|
__in HWND ParentWindowHandle,
|
|
__in PJOB_PAGE_CONTEXT Context
|
|
)
|
|
{
|
|
PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
|
|
HPROPSHEETPAGE pages[2];
|
|
PROPSHEETPAGE statisticsPage;
|
|
PH_STD_OBJECT_SECURITY stdObjectSecurity;
|
|
PPH_ACCESS_ENTRY accessEntries;
|
|
ULONG numberOfAccessEntries;
|
|
|
|
propSheetHeader.dwFlags =
|
|
PSH_NOAPPLYNOW |
|
|
PSH_NOCONTEXTHELP |
|
|
PSH_PROPTITLE;
|
|
propSheetHeader.hwndParent = ParentWindowHandle;
|
|
propSheetHeader.pszCaption = L"Job";
|
|
propSheetHeader.nPages = 2;
|
|
propSheetHeader.nStartPage = 0;
|
|
propSheetHeader.phpage = pages;
|
|
|
|
// General
|
|
|
|
memset(&statisticsPage, 0, sizeof(PROPSHEETPAGE));
|
|
statisticsPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
statisticsPage.pszTemplate = MAKEINTRESOURCE(IDD_JOBSTATISTICS);
|
|
statisticsPage.pfnDlgProc = PhpJobStatisticsPageProc;
|
|
statisticsPage.lParam = (LPARAM)Context;
|
|
pages[0] = CreatePropertySheetPage(&statisticsPage);
|
|
|
|
// Security
|
|
|
|
stdObjectSecurity.OpenObject = Context->OpenObject;
|
|
stdObjectSecurity.ObjectType = L"Job";
|
|
stdObjectSecurity.Context = Context->Context;
|
|
|
|
if (PhGetAccessEntries(L"Job", &accessEntries, &numberOfAccessEntries))
|
|
{
|
|
pages[1] = PhCreateSecurityPage(
|
|
L"Job",
|
|
PhStdGetObjectSecurity,
|
|
PhStdSetObjectSecurity,
|
|
&stdObjectSecurity,
|
|
accessEntries,
|
|
numberOfAccessEntries
|
|
);
|
|
PhFree(accessEntries);
|
|
}
|
|
|
|
PropertySheet(&propSheetHeader);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpJobStatisticsPageProc(
|
|
__in HWND hwndDlg,
|
|
__in UINT uMsg,
|
|
__in WPARAM wParam,
|
|
__in LPARAM lParam
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|