VOID NTAPI MainMenuInitializingCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; PPH_EMENU_ITEM systemMenu; PPH_EMENU_ITEM bootMenuItem; if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) return; if (!(systemMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"System", 0))) { PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menuInfo->Menu, systemMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&System", NULL), -1); } PhInsertEMenuItem(systemMenu, bootMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, BOOT_ENTRIES_MENUITEM, L"Firm&ware Table", NULL), -1); if (!PhGetOwnTokenAttributes().Elevated) { bootMenuItem->Flags |= PH_EMENU_DISABLED; } }
PPH_LIST DiskDriveQueryMountPointHandles( _In_ ULONG DeviceNumber ) { ULONG driveMask; PPH_LIST deviceList; WCHAR deviceNameBuffer[7] = L"\\\\.\\?:"; driveMask = DiskDriveQueryDeviceMap(); deviceList = PhCreateList(2); // NOTE: This isn't the best way of doing this but it works. for (INT i = 0; i < 0x1A; i++) { if (driveMask & (0x1 << i)) { HANDLE deviceHandle; deviceNameBuffer[4] = (WCHAR)('A' + i); if (NT_SUCCESS(PhCreateFileWin32( &deviceHandle, deviceNameBuffer, PhGetOwnTokenAttributes().Elevated ? FILE_GENERIC_READ : FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { ULONG deviceNumber = ULONG_MAX; // Note: Do not initialize to zero. DEVICE_TYPE deviceType = 0; if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber( deviceHandle, &deviceNumber, &deviceType ))) { // BUG: Device numbers are re-used on seperate device controllers and this // causes drive letters to be assigned to disks at those same indexes. // For now, just filter CD_ROM devices but we may need to be a lot more strict and // only allow devices of type FILE_DEVICE_DISK to be scanned for mount points. if (deviceNumber == DeviceNumber && deviceType != FILE_DEVICE_CD_ROM) { PDISK_HANDLE_ENTRY entry = PhAllocate(sizeof(DISK_HANDLE_ENTRY)); memset(entry, 0, sizeof(DISK_HANDLE_ENTRY)); entry->DeviceLetter = deviceNameBuffer[4]; entry->DeviceHandle = deviceHandle; PhAddItemList(deviceList, entry); } } } } } return deviceList; }
HRESULT CALLBACK FinalTaskDialogCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ LONG_PTR dwRefData ) { PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; switch (uMsg) { case TDN_NAVIGATED: { if (!PhGetOwnTokenAttributes().Elevated) { SendMessage(hwndDlg, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); } } break; case TDN_BUTTON_CLICKED: { if ((INT)wParam == IDRETRY) { ShowAvailableDialog(context); return S_FALSE; } } break; } return S_OK; }
VOID EtEtwMonitorInitialization( VOID ) { if (PhGetOwnTokenAttributes().Elevated && PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR)) { EtStartEtwSession(); if (EtEtwEnabled) EtpEtwMonitorThreadHandle = PhCreateThread(0, EtpEtwMonitorThreadStart, NULL); } }
VOID NTAPI MainMenuInitializingCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; PPH_EMENU_ITEM liveDumpMenu; if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) return; PhInsertEMenuItem(menuInfo->Menu, liveDumpMenu = PhPluginCreateEMenuItem(PluginInstance, 0, PLUGIN_MENU_ITEM, L"&Live kernel dump...", NULL), -1); if (WindowsVersion < WINDOWS_8_1 || !PhGetOwnTokenAttributes().Elevated) { liveDumpMenu->Flags |= PH_EMENU_DISABLED; } }
VOID PhpAdvancedPageLoad( _In_ HWND hwndDlg ) { HWND changeButton; SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); SetDlgItemCheckForSetting(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); if (WindowsVersion >= WINDOWS_7) SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); if (PhGetIntegerSetting(L"SampleCountAutomatic")) EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); // Replace Task Manager changeButton = GetDlgItem(hwndDlg, IDC_CHANGE); if (PhGetOwnTokenAttributes().Elevated) { ShowWindow(changeButton, SW_HIDE); } else { SendMessage(changeButton, BCM_SETSHIELD, 0, TRUE); } { HANDLE taskmgrKeyHandle = NULL; ULONG disposition; BOOLEAN success = FALSE; BOOLEAN alreadyReplaced = FALSE; // See if we can write to the key. if (NT_SUCCESS(PhCreateKey( &taskmgrKeyHandle, KEY_READ | KEY_WRITE, PH_KEY_LOCAL_MACHINE, &TaskMgrImageOptionsKeyName, 0, 0, &disposition ))) { success = TRUE; } if (taskmgrKeyHandle || NT_SUCCESS(PhOpenKey( &taskmgrKeyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &TaskMgrImageOptionsKeyName, 0 ))) { PhClearReference(&OldTaskMgrDebugger); if (OldTaskMgrDebugger = PhQueryRegistryString(taskmgrKeyHandle, L"Debugger")) { alreadyReplaced = PathMatchesPh(OldTaskMgrDebugger); } NtClose(taskmgrKeyHandle); } if (!success) EnableWindow(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), FALSE); OldReplaceTaskMgr = alreadyReplaced; Button_SetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), alreadyReplaced ? BST_CHECKED : BST_UNCHECKED); } }
/** * Starts a program as another user. * * \param hWnd A handle to the parent window. * \param Program The command line of the program to start. * \param UserName The user to start the program as. The user * name should be specified as: domain\\name. This parameter * can be NULL if \a ProcessIdWithToken is specified. * \param Password The password for the specified user. If there * is no password, specify an empty string. This parameter * can be NULL if \a ProcessIdWithToken is specified. * \param LogonType The logon type for the specified user. This * parameter can be 0 if \a ProcessIdWithToken is specified. * \param ProcessIdWithToken The ID of a process from which * to duplicate the token. * \param SessionId The ID of the session to run the program * under. * \param DesktopName The window station and desktop to run the * program under. * \param UseLinkedToken Uses the linked token if possible. * * \retval STATUS_CANCELLED The user cancelled the operation. * * \remarks This function will cause another instance of * Process Hacker to be executed if the current security context * does not have sufficient system access. This is done * through a UAC elevation prompt. */ NTSTATUS PhExecuteRunAsCommand2( _In_ HWND hWnd, _In_ PWSTR Program, _In_opt_ PWSTR UserName, _In_opt_ PWSTR Password, _In_opt_ ULONG LogonType, _In_opt_ HANDLE ProcessIdWithToken, _In_ ULONG SessionId, _In_ PWSTR DesktopName, _In_ BOOLEAN UseLinkedToken ) { NTSTATUS status = STATUS_SUCCESS; PH_RUNAS_SERVICE_PARAMETERS parameters; WCHAR serviceName[32]; PPH_STRING portName; UNICODE_STRING portNameUs; memset(¶meters, 0, sizeof(PH_RUNAS_SERVICE_PARAMETERS)); parameters.ProcessId = HandleToUlong(ProcessIdWithToken); parameters.UserName = UserName; parameters.Password = Password; parameters.LogonType = LogonType; parameters.SessionId = SessionId; parameters.CommandLine = Program; parameters.DesktopName = DesktopName; parameters.UseLinkedToken = UseLinkedToken; // Try to use an existing instance of the service if possible. if (RunAsOldServiceName[0] != 0) { PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsOldServiceName); PhStringRefToUnicodeString(&portName->sr, &portNameUs); if (NT_SUCCESS(PhSvcConnectToServer(&portNameUs, 0))) { parameters.ServiceName = RunAsOldServiceName; status = PhSvcCallInvokeRunAsService(¶meters); PhSvcDisconnectFromServer(); PhDereferenceObject(portName); PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); return status; } PhDereferenceObject(portName); PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); } // An existing instance was not available. Proceed normally. memcpy(serviceName, L"ProcessHacker", 13 * sizeof(WCHAR)); PhGenerateRandomAlphaString(&serviceName[13], 16); PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); memcpy(RunAsOldServiceName, serviceName, sizeof(serviceName)); PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); parameters.ServiceName = serviceName; if (PhGetOwnTokenAttributes().Elevated) { status = PhExecuteRunAsCommand(¶meters); } else { if (PhUiConnectToPhSvc(hWnd, FALSE)) { status = PhSvcCallExecuteRunAsCommand(¶meters); PhUiDisconnectFromPhSvc(); } else { status = STATUS_CANCELLED; } } return status; }
HRESULT CALLBACK FinalTaskDialogCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ LONG_PTR dwRefData ) { PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; switch (uMsg) { case TDN_NAVIGATED: { if (!PhGetOwnTokenAttributes().Elevated) { SendMessage(hwndDlg, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); } } break; case TDN_BUTTON_CLICKED: { if ((INT)wParam == IDRETRY) { ShowCheckingForUpdatesDialog(context); return S_FALSE; } if ((INT)wParam == IDYES) { SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; if (PhIsNullOrEmptyString(context->SetupFilePath)) break; info.lpFile = context->SetupFilePath->Buffer; info.lpVerb = PhGetOwnTokenAttributes().Elevated ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); if (!ShellExecuteEx(&info)) { // Install failed, cancel the shutdown. ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); // Set button text for next action //Button_SetText(GetDlgItem(hwndDlg, IDOK), L"Retry"); return S_FALSE; } else { ProcessHacker_Destroy(PhMainWndHandle); } } } break; case TDN_HYPERLINK_CLICKED: { TaskDialogLinkClicked(context); } break; } return S_OK; }
VOID ToolbarLoadSettings( VOID ) { RebarLoadSettings(); if (ToolStatusConfig.ToolBarEnabled && ToolBarHandle) { INT index = 0; INT buttonCount = 0; buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); for (index = 0; index < buttonCount; index++) { TBBUTTONINFO buttonInfo = { sizeof(TBBUTTONINFO), TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_STATE }; // Get settings for first button if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) break; // Skip separator buttons if (buttonInfo.fsStyle == BTNS_SEP) continue; // Add the button text buttonInfo.dwMask |= TBIF_TEXT; buttonInfo.pszText = ToolbarGetText(buttonInfo.idCommand); switch (DisplayStyle) { case TOOLBAR_DISPLAY_STYLE_IMAGEONLY: buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; break; case TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT: { switch (buttonInfo.idCommand) { case PHAPP_ID_VIEW_REFRESH: case PHAPP_ID_HACKER_OPTIONS: case PHAPP_ID_HACKER_FINDHANDLESORDLLS: case PHAPP_ID_VIEW_SYSTEMINFORMATION: buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; break; default: buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; break; } } break; case TOOLBAR_DISPLAY_STYLE_ALLTEXT: buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; break; } switch (buttonInfo.idCommand) { case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: { if (PhGetOwnTokenAttributes().Elevated) { buttonInfo.fsState &= ~TBSTATE_ENABLED; } } break; case PHAPP_ID_VIEW_ALWAYSONTOP: { // Set the pressed state if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) { buttonInfo.fsState |= TBSTATE_PRESSED; } } break; case TIDC_POWERMENUDROPDOWN: { buttonInfo.fsStyle |= BTNS_WHOLEDROPDOWN; } break; } // Set updated button info SendMessage(ToolBarHandle, TB_SETBUTTONINFO, index, (LPARAM)&buttonInfo); } // Resize the toolbar SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); } if (ToolStatusConfig.ToolBarEnabled && RebarHandle && ToolBarHandle) { UINT index; REBARBANDINFO rebarBandInfo = { sizeof(REBARBANDINFO), RBBIM_IDEALSIZE }; if ((index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_TOOLBAR, 0)) != UINT_MAX) { // Get settings for Rebar band. if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo)) { SIZE idealWidth = { 0, 0 }; // Reset the cxIdeal for the Chevron if (SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth)) { rebarBandInfo.cxIdeal = (UINT)idealWidth.cx; SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); } } } } // Invoke the LayoutPaddingCallback. SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); }
INT WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ INT nCmdShow ) { LONG result; #ifdef DEBUG PHP_BASE_THREAD_DBG dbg; #endif HANDLE currentTokenHandle; CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); #ifndef DEBUG SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #endif PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress; if (!NT_SUCCESS(PhInitializePhLib())) return 1; if (!PhInitializeAppSystem()) return 1; PhInitializeCommonControls(); currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; if (currentTokenHandle) { PTOKEN_USER tokenUser; if (NT_SUCCESS(PhGetTokenUser(currentTokenHandle, &tokenUser))) { PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); PhFree(tokenUser); } } PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); // There has been a report of the above call failing. if (!PhLocalSystemName) PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); PhApplicationFileName = PhGetApplicationFileName(); PhApplicationDirectory = PhGetApplicationDirectory(); // Just in case if (!PhApplicationFileName) PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); if (!PhApplicationDirectory) PhApplicationDirectory = PhReferenceEmptyString(); PhpProcessStartupParameters(); PhSettingsInitialization(); PhpEnablePrivileges(); if (PhStartupParameters.RunAsServiceMode) { RtlExitUserProcess(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode)); } PhpInitializeSettings(); // Activate a previous instance if required. if (PhGetIntegerSetting(L"AllowOnlyOneInstance") && !PhStartupParameters.NewInstance && !PhStartupParameters.ShowOptions && !PhStartupParameters.CommandMode && !PhStartupParameters.PhSvc) { PhActivatePreviousInstance(); } if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhStartupParameters.CommandMode && !PhIsExecutingInWow64()) PhInitializeKph(); if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction) { NTSTATUS status; status = PhCommandModeStart(); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) { PhShowStatus(NULL, L"Unable to execute the command", status, 0); } RtlExitUserProcess(status); } #ifdef DEBUG dbg.ClientId = NtCurrentTeb()->ClientId; dbg.StartAddress = wWinMain; dbg.Parameter = NULL; InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); #endif PhInitializeAutoPool(&BaseAutoPool); PhEmInitialization(); PhGuiSupportInitialization(); PhTreeNewInitialization(); PhGraphControlInitialization(); PhHexEditInitialization(); PhColorBoxInitialization(); PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); if (PhStartupParameters.ShowOptions) { // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. PhShowOptionsDialog(PhStartupParameters.WindowHandle); RtlExitUserProcess(STATUS_SUCCESS); } #ifndef DEBUG if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc) { PhShowWarning( NULL, L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " L"Most features will not work correctly.\n\n" L"Please run the 64-bit version of Process Hacker instead." ); } #endif PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins; if (PhPluginsEnabled) { PhPluginsInitialization(); PhLoadPlugins(); } if (PhStartupParameters.PhSvc) { MSG message; // Turn the feedback cursor off. PostMessage(NULL, WM_NULL, 0, 0); GetMessage(&message, NULL, 0, 0); RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL)); } // Create a mutant for the installer. { HANDLE mutantHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHacker2Mutant"); InitializeObjectAttributes( &oa, &mutantName, 0, NULL, NULL ); NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); } // Set priority. { PROCESS_PRIORITY_CLASS priorityClass; priorityClass.Foreground = FALSE; priorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; if (PhStartupParameters.PriorityClass != 0) priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass; NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); } if (!PhMainWndInitialization(nCmdShow)) { PhShowError(NULL, L"Unable to initialize the main window."); return 1; } PhDrainAutoPool(&BaseAutoPool); result = PhMainMessageLoop(); RtlExitUserProcess(result); }
VOID PhpProcessStartupParameters( VOID ) { static PH_COMMAND_LINE_OPTION options[] = { { PH_ARG_SETTINGS, L"settings", MandatoryArgumentType }, { PH_ARG_NOSETTINGS, L"nosettings", NoArgumentType }, { PH_ARG_SHOWVISIBLE, L"v", NoArgumentType }, { PH_ARG_SHOWHIDDEN, L"hide", NoArgumentType }, { PH_ARG_COMMANDMODE, L"c", NoArgumentType }, { PH_ARG_COMMANDTYPE, L"ctype", MandatoryArgumentType }, { PH_ARG_COMMANDOBJECT, L"cobject", MandatoryArgumentType }, { PH_ARG_COMMANDACTION, L"caction", MandatoryArgumentType }, { PH_ARG_COMMANDVALUE, L"cvalue", MandatoryArgumentType }, { PH_ARG_RUNASSERVICEMODE, L"ras", MandatoryArgumentType }, { PH_ARG_NOKPH, L"nokph", NoArgumentType }, { PH_ARG_INSTALLKPH, L"installkph", NoArgumentType }, { PH_ARG_UNINSTALLKPH, L"uninstallkph", NoArgumentType }, { PH_ARG_DEBUG, L"debug", NoArgumentType }, { PH_ARG_HWND, L"hwnd", MandatoryArgumentType }, { PH_ARG_POINT, L"point", MandatoryArgumentType }, { PH_ARG_SHOWOPTIONS, L"showoptions", NoArgumentType }, { PH_ARG_PHSVC, L"phsvc", NoArgumentType }, { PH_ARG_NOPLUGINS, L"noplugins", NoArgumentType }, { PH_ARG_NEWINSTANCE, L"newinstance", NoArgumentType }, { PH_ARG_ELEVATE, L"elevate", NoArgumentType }, { PH_ARG_SILENT, L"s", NoArgumentType }, { PH_ARG_HELP, L"help", NoArgumentType }, { PH_ARG_SELECTPID, L"selectpid", MandatoryArgumentType }, { PH_ARG_PRIORITY, L"priority", MandatoryArgumentType }, { PH_ARG_PLUGIN, L"plugin", MandatoryArgumentType }, { PH_ARG_SELECTTAB, L"selecttab", MandatoryArgumentType }, { PH_ARG_SYSINFO, L"sysinfo", OptionalArgumentType } }; PH_STRINGREF commandLine; PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); memset(&PhStartupParameters, 0, sizeof(PH_STARTUP_PARAMETERS)); if (!PhParseCommandLine( &commandLine, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART, PhpCommandLineOptionCallback, NULL ) || PhStartupParameters.Help) { PhShowInformation( NULL, L"Command line options:\n\n" L"-c\n" L"-ctype command-type\n" L"-cobject command-object\n" L"-caction command-action\n" L"-cvalue command-value\n" L"-debug\n" L"-elevate\n" L"-help\n" L"-hide\n" L"-installkph\n" L"-newinstance\n" L"-nokph\n" L"-noplugins\n" L"-nosettings\n" L"-plugin pluginname:value\n" L"-priority r|h|n|l\n" L"-s\n" L"-selectpid pid-to-select\n" L"-selecttab name-of-tab-to-select\n" L"-settings filename\n" L"-sysinfo [section-name]\n" L"-uninstallkph\n" L"-v\n" ); if (PhStartupParameters.Help) RtlExitUserProcess(STATUS_SUCCESS); } if (PhStartupParameters.InstallKph) { NTSTATUS status; PPH_STRING kprocesshackerFileName; KPH_PARAMETERS parameters; kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); parameters.SecurityLevel = KphSecuritySignatureCheck; parameters.CreateDynamicConfiguration = TRUE; status = KphInstallEx(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) PhShowStatus(NULL, L"Unable to install KProcessHacker", status, 0); RtlExitUserProcess(status); } if (PhStartupParameters.UninstallKph) { NTSTATUS status; status = KphUninstall(KPH_DEVICE_SHORT_NAME); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) PhShowStatus(NULL, L"Unable to uninstall KProcessHacker", status, 0); RtlExitUserProcess(status); } if (PhStartupParameters.Elevate && !PhGetOwnTokenAttributes().Elevated) { PhShellProcessHacker( NULL, NULL, SW_SHOW, PH_SHELL_EXECUTE_ADMIN, PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS, 0, NULL ); RtlExitUserProcess(STATUS_SUCCESS); } if (PhStartupParameters.Debug) { // The symbol provider won't work if this is chosen. PhShowDebugConsole(); } }
static _Callback_ NTSTATUS PhpSetServiceSecurity( _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ SECURITY_INFORMATION SecurityInformation, _In_opt_ PVOID Context ) { NTSTATUS status; PPH_STD_OBJECT_SECURITY stdObjectSecurity; stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; status = PhStdSetObjectSecurity(SecurityDescriptor, SecurityInformation, Context); if ((status == STATUS_ACCESS_DENIED || status == NTSTATUS_FROM_WIN32(ERROR_ACCESS_DENIED)) && !PhGetOwnTokenAttributes().Elevated) { // Elevate using phsvc. if (PhUiConnectToPhSvc(NULL, FALSE)) { status = PhSvcCallSetServiceSecurity( ((PPH_SERVICE_ITEM)stdObjectSecurity->Context)->Name->Buffer, SecurityInformation, SecurityDescriptor ); PhUiDisconnectFromPhSvc(); } } return status; }
INT_PTR CALLBACK PhpServiceGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam; PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; ULONG startType; ULONG errorControl; PPH_STRING serviceDll; // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); SetDlgItemText(hwndDlg, IDC_DESCRIPTION, serviceItem->DisplayName->Buffer); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), PhGetServiceTypeString(serviceItem->Type), FALSE); startType = serviceItem->StartType; errorControl = serviceItem->ErrorControl; serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG); if (serviceHandle) { LPQUERY_SERVICE_CONFIG config; PPH_STRING description; BOOLEAN delayedStart; if (config = PhGetServiceConfig(serviceHandle)) { SetDlgItemText(hwndDlg, IDC_GROUP, config->lpLoadOrderGroup); SetDlgItemText(hwndDlg, IDC_BINARYPATH, config->lpBinaryPathName); SetDlgItemText(hwndDlg, IDC_USERACCOUNT, config->lpServiceStartName); if (startType != config->dwStartType || errorControl != config->dwErrorControl) { startType = config->dwStartType; errorControl = config->dwErrorControl; PhMarkNeedsConfigUpdateServiceItem(serviceItem); } PhFree(config); } if (description = PhGetServiceDescription(serviceHandle)) { SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description->Buffer); PhDereferenceObject(description); } if ( WindowsVersion >= WINDOWS_VISTA && PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart) ) { context->OldDelayedStart = delayedStart; if (delayedStart) Button_SetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), BST_CHECKED); } CloseServiceHandle(serviceHandle); } PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhGetServiceStartTypeString(startType), FALSE); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhGetServiceErrorControlString(errorControl), FALSE); SetDlgItemText(hwndDlg, IDC_PASSWORD, L"password"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); if (NT_SUCCESS(PhGetServiceDllParameter(&serviceItem->Name->sr, &serviceDll))) { SetDlgItemText(hwndDlg, IDC_SERVICEDLL, serviceDll->Buffer); PhDereferenceObject(serviceDll); } else { SetDlgItemText(hwndDlg, IDC_SERVICEDLL, L"N/A"); } PhpRefreshControls(hwndDlg); context->Ready = TRUE; } break; case WM_DESTROY: { RemoveProp(hwndDlg, PhMakeContextAtom()); } break; case WM_COMMAND: { PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); switch (LOWORD(wParam)) { case IDCANCEL: { // Workaround for property sheet + multiline edit: http://support.microsoft.com/kb/130765 SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam); } break; case IDC_PASSWORD: { if (HIWORD(wParam) == EN_CHANGE) { Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_CHECKED); } } break; case IDC_DELAYEDSTART: { context->Dirty = TRUE; } break; case IDC_BROWSE: { static PH_FILETYPE_FILTER filters[] = { { L"Executable files (*.exe;*.sys)", L"*.exe;*.sys" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; PPH_STRING commandLine; PPH_STRING fileName; fileDialog = PhCreateOpenFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); commandLine = PhaGetDlgItemText(hwndDlg, IDC_BINARYPATH); if (context->ServiceItem->Type & SERVICE_WIN32) { PH_STRINGREF dummyFileName; PH_STRINGREF dummyArguments; if (!PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName)) fileName = NULL; if (!fileName) PhSwapReference(&fileName, commandLine); } else { fileName = PhGetFileName(commandLine); } PhSetFileDialogFileName(fileDialog, fileName->Buffer); PhDereferenceObject(fileName); if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PhGetFileDialogFileName(fileDialog); SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); PhDereferenceObject(fileName); } PhFreeFileDialog(fileDialog); } break; } switch (HIWORD(wParam)) { case EN_CHANGE: case CBN_SELCHANGE: { PhpRefreshControls(hwndDlg); if (context->Ready) context->Dirty = TRUE; } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_QUERYINITIALFOCUS: { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_STARTTYPE)); } return TRUE; case PSN_KILLACTIVE: { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); } return TRUE; case PSN_APPLY: { NTSTATUS status; PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; PPH_STRING newServiceTypeString; PPH_STRING newServiceStartTypeString; PPH_STRING newServiceErrorControlString; ULONG newServiceType; ULONG newServiceStartType; ULONG newServiceErrorControl; PPH_STRING newServiceGroup; PPH_STRING newServiceBinaryPath; PPH_STRING newServiceUserAccount; PPH_STRING newServicePassword; SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); if (!context->Dirty) { return TRUE; } newServiceTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE))); newServiceStartTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE))); newServiceErrorControlString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL))); newServiceType = PhGetServiceTypeInteger(newServiceTypeString->Buffer); newServiceStartType = PhGetServiceStartTypeInteger(newServiceStartTypeString->Buffer); newServiceErrorControl = PhGetServiceErrorControlInteger(newServiceErrorControlString->Buffer); newServiceGroup = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_GROUP))); newServiceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); newServiceUserAccount = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_USERACCOUNT))); if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK)) == BST_CHECKED) { newServicePassword = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); } else { newServicePassword = NULL; } if (newServiceType == SERVICE_KERNEL_DRIVER && newServiceUserAccount->Length == 0) { newServiceUserAccount = NULL; } serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_CHANGE_CONFIG); if (serviceHandle) { if (ChangeServiceConfig( serviceHandle, newServiceType, newServiceStartType, newServiceErrorControl, newServiceBinaryPath->Buffer, newServiceGroup->Buffer, NULL, NULL, PhGetString(newServiceUserAccount), PhGetString(newServicePassword), NULL )) { if (WindowsVersion >= WINDOWS_VISTA) { BOOLEAN newDelayedStart; newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; if (newDelayedStart != context->OldDelayedStart) { PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart); } } PhMarkNeedsConfigUpdateServiceItem(serviceItem); CloseServiceHandle(serviceHandle); } else { CloseServiceHandle(serviceHandle); goto ErrorCase; } } else { if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) { // Elevate using phsvc. if (PhUiConnectToPhSvc(hwndDlg, FALSE)) { if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig( serviceItem->Name->Buffer, newServiceType, newServiceStartType, newServiceErrorControl, newServiceBinaryPath->Buffer, newServiceGroup->Buffer, NULL, NULL, PhGetString(newServiceUserAccount), PhGetString(newServicePassword), NULL ))) { if (WindowsVersion >= WINDOWS_VISTA) { BOOLEAN newDelayedStart; newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; if (newDelayedStart != context->OldDelayedStart) { SERVICE_DELAYED_AUTO_START_INFO info; info.fDelayedAutostart = newDelayedStart; PhSvcCallChangeServiceConfig2( serviceItem->Name->Buffer, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &info ); } } PhMarkNeedsConfigUpdateServiceItem(serviceItem); } PhUiDisconnectFromPhSvc(); if (!NT_SUCCESS(status)) { SetLastError(PhNtStatusToDosError(status)); goto ErrorCase; } } else { // User cancelled elevation. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } } else { goto ErrorCase; } } goto Cleanup; ErrorCase: if (PhShowMessage( hwndDlg, MB_ICONERROR | MB_RETRYCANCEL, L"Unable to change service configuration: %s", PH_AUTO_T(PH_STRING, PhGetWin32Message(GetLastError()))->Buffer ) == IDRETRY) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } Cleanup: if (newServicePassword) { RtlSecureZeroMemory(newServicePassword->Buffer, newServicePassword->Length); PhDereferenceObject(newServicePassword); } } return TRUE; } } break; } return FALSE; }
INT_PTR CALLBACK EspServiceRecoveryDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { PSERVICE_RECOVERY_CONTEXT context; if (uMsg == WM_INITDIALOG) { context = PhAllocate(sizeof(SERVICE_RECOVERY_CONTEXT)); memset(context, 0, sizeof(SERVICE_RECOVERY_CONTEXT)); SetProp(hwndDlg, L"Context", (HANDLE)context); } else { context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); if (uMsg == WM_DESTROY) RemoveProp(hwndDlg, L"Context"); } if (!context) return FALSE; switch (uMsg) { case WM_INITDIALOG: { NTSTATUS status; LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; context->ServiceItem = serviceItem; EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); status = EspLoadRecoveryInfo(hwndDlg, context); if (status == STATUS_SOME_NOT_MAPPED) { if (context->NumberOfActions > 3) { PhShowWarning( hwndDlg, L"The service has %lu failure actions configured, but this program only supports editing 3. " L"If you save the recovery information using this program, the additional failure actions will be lost.", context->NumberOfActions ); } } else if (!NT_SUCCESS(status)) { SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); if (WindowsVersion >= WINDOWS_VISTA) { context->EnableFlagCheckBox = TRUE; EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); } PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s", ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); } EspFixControls(hwndDlg, context); context->Ready = TRUE; } break; case WM_DESTROY: { PhClearReference(&context->RebootMessage); PhFree(context); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_FIRSTFAILURE: case IDC_SECONDFAILURE: case IDC_SUBSEQUENTFAILURES: { if (HIWORD(wParam) == CBN_SELCHANGE) { EspFixControls(hwndDlg, context); } } break; case IDC_RESTARTCOMPUTEROPTIONS: { DialogBoxParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_RESTARTCOMP), hwndDlg, RestartComputerDlgProc, (LPARAM)context ); } break; case IDC_BROWSE: { static PH_FILETYPE_FILTER filters[] = { { L"Executable files (*.exe;*.cmd;*.bat)", L"*.exe;*.cmd;*.bat" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; PPH_STRING fileName; fileDialog = PhCreateOpenFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); fileName = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM); PhSetFileDialogFileName(fileDialog, fileName->Buffer); if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer); } PhFreeFileDialog(fileDialog); } break; case IDC_ENABLEFORERRORSTOPS: { context->Dirty = TRUE; } break; } switch (HIWORD(wParam)) { case EN_CHANGE: case CBN_SELCHANGE: { if (context->Ready) context->Dirty = TRUE; } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_KILLACTIVE: { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); } return TRUE; case PSN_APPLY: { NTSTATUS status; PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; ULONG restartServiceAfter; SERVICE_FAILURE_ACTIONS failureActions; SC_ACTION actions[3]; ULONG i; BOOLEAN enableRestart = FALSE; SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); if (!context->Dirty) { return TRUE; } // Build the failure actions structure. failureActions.dwResetPeriod = GetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, NULL, FALSE) * 60 * 60 * 24; failureActions.lpRebootMsg = PhGetStringOrEmpty(context->RebootMessage); failureActions.lpCommand = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM)->Buffer; failureActions.cActions = 3; failureActions.lpsaActions = actions; actions[0].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); actions[2].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); restartServiceAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, NULL, FALSE) * 1000 * 60; for (i = 0; i < 3; i++) { switch (actions[i].Type) { case SC_ACTION_RESTART: actions[i].Delay = restartServiceAfter; enableRestart = TRUE; break; case SC_ACTION_REBOOT: actions[i].Delay = context->RebootAfter; break; case SC_ACTION_RUN_COMMAND: actions[i].Delay = 0; break; } } // Try to save the changes. serviceHandle = PhOpenService( serviceItem->Name->Buffer, SERVICE_CHANGE_CONFIG | (enableRestart ? SERVICE_START : 0) // SC_ACTION_RESTART requires SERVICE_START ); if (serviceHandle) { if (ChangeServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, &failureActions )) { if (context->EnableFlagCheckBox) { SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; failureActionsFlag.fFailureActionsOnNonCrashFailures = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED; ChangeServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, &failureActionsFlag ); } CloseServiceHandle(serviceHandle); } else { CloseServiceHandle(serviceHandle); goto ErrorCase; } } else { if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) { // Elevate using phsvc. if (PhUiConnectToPhSvc(hwndDlg, FALSE)) { if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2( serviceItem->Name->Buffer, SERVICE_CONFIG_FAILURE_ACTIONS, &failureActions ))) { if (context->EnableFlagCheckBox) { SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; failureActionsFlag.fFailureActionsOnNonCrashFailures = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED; PhSvcCallChangeServiceConfig2( serviceItem->Name->Buffer, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, &failureActionsFlag ); } } PhUiDisconnectFromPhSvc(); if (!NT_SUCCESS(status)) { SetLastError(PhNtStatusToDosError(status)); goto ErrorCase; } } else { // User cancelled elevation. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } } else { goto ErrorCase; } } return TRUE; ErrorCase: if (PhShowMessage( hwndDlg, MB_ICONERROR | MB_RETRYCANCEL, L"Unable to change service recovery information: %s", ((PPH_STRING)PH_AUTO(PhGetWin32Message(GetLastError())))->Buffer ) == IDRETRY) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } } return TRUE; } } break; } return FALSE; }