Exemple #1
0
VOID PhpExecuteCallbackForAllPlugins(
    _In_ PH_PLUGIN_CALLBACK Callback,
    _In_ BOOLEAN StartupParameters
    )
{
    PPH_AVL_LINKS links;

    for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links))
    {
        PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links);
        PPH_LIST parameters = NULL;

        // Find relevant startup parameters for this plugin.
        if (StartupParameters && PhStartupParameters.PluginParameters)
        {
            ULONG i;

            for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++)
            {
                PPH_STRING string = PhStartupParameters.PluginParameters->Items[i];
                PH_STRINGREF pluginName;
                PH_STRINGREF parameter;

                if (PhSplitStringRefAtChar(&string->sr, ':', &pluginName, &parameter) &&
                    PhEqualStringRef(&pluginName, &plugin->Name, FALSE) &&
                    parameter.Length != 0)
                {
                    if (!parameters)
                        parameters = PhCreateList(3);

                    PhAddItemList(parameters, PhCreateString2(&parameter));
                }
            }
        }

        PhInvokeCallback(PhGetPluginCallback(plugin, Callback), parameters);

        if (parameters)
        {
            PhDereferenceObjects(parameters->Items, parameters->Count);
            PhDereferenceObject(parameters);
        }
    }
}
BOOLEAN ProcessTreeFilterCallback(
    _In_ PPH_TREENEW_NODE Node,
    _In_opt_ PVOID Context
    )
{
    PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node;

    if (PhIsNullOrEmptyString(SearchboxText))
        return TRUE;

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->ProcessName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->ProcessName->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->FileName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->FileName->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->CommandLine))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->CommandLine->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.CompanyName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.CompanyName->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.FileDescription))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.FileDescription->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.FileVersion))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.FileVersion->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.ProductName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.ProductName->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->UserName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->UserName->sr))
            return TRUE;
    }

    if (processNode->ProcessItem->IntegrityString)
    {
        if (WordMatchStringZ(processNode->ProcessItem->IntegrityString))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->JobName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->JobName->sr))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->VerifySignerName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->VerifySignerName->sr))
            return TRUE;
    }

    if (processNode->ProcessItem->ProcessIdString[0])
    {
        if (WordMatchStringZ(processNode->ProcessItem->ProcessIdString))
            return TRUE;
    }

    if (processNode->ProcessItem->ParentProcessIdString[0])
    {
        if (WordMatchStringZ(processNode->ProcessItem->ParentProcessIdString))
            return TRUE;
    }

    if (processNode->ProcessItem->SessionIdString[0])
    {
        if (WordMatchStringZ(processNode->ProcessItem->SessionIdString))
            return TRUE;
    }

    if (!PhIsNullOrEmptyString(processNode->ProcessItem->PackageFullName))
    {
        if (WordMatchStringRef(&processNode->ProcessItem->PackageFullName->sr))
            return TRUE;
    }

    if (WordMatchStringZ(PhGetProcessPriorityClassString(processNode->ProcessItem->PriorityClass)))
    {
        return TRUE;
    }

    if (processNode->ProcessItem->VerifyResult != VrUnknown)
    {
        switch (processNode->ProcessItem->VerifyResult)
        {
        case VrNoSignature:
            if (WordMatchStringZ(L"NoSignature"))
                return TRUE;
            break;
        case VrTrusted:
            if (WordMatchStringZ(L"Trusted"))
                return TRUE;
            break;
        case VrExpired:
            if (WordMatchStringZ(L"Expired"))
                return TRUE;
            break;
        case VrRevoked:
            if (WordMatchStringZ(L"Revoked"))
                return TRUE;
            break;
        case VrDistrust:
            if (WordMatchStringZ(L"Distrust"))
                return TRUE;
            break;
        case VrSecuritySettings:
            if (WordMatchStringZ(L"SecuritySettings"))
                return TRUE;
            break;
        case VrBadSignature:
            if (WordMatchStringZ(L"BadSignature"))
                return TRUE;
            break;
        default:
            if (WordMatchStringZ(L"Unknown"))
                return TRUE;
            break;
        }
    }

    if (processNode->ProcessItem->ElevationType != TokenElevationTypeDefault)
    {
        switch (processNode->ProcessItem->ElevationType)
        {
        case TokenElevationTypeLimited:
            if (WordMatchStringZ(L"Limited"))
                return TRUE;
            break;
        case TokenElevationTypeFull:
            if (WordMatchStringZ(L"Full"))
                return TRUE;
            break;
        default:
            if (WordMatchStringZ(L"Unknown"))
                return TRUE;
            break;
        }
    }

    if (WordMatchStringZ(L"IsBeingDebugged") && processNode->ProcessItem->IsBeingDebugged)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsDotNet") && processNode->ProcessItem->IsDotNet)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsElevated") && processNode->ProcessItem->IsElevated)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsInJob") && processNode->ProcessItem->IsInJob)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsInSignificantJob") && processNode->ProcessItem->IsInSignificantJob)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsPacked") && processNode->ProcessItem->IsPacked)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsSuspended") && processNode->ProcessItem->IsSuspended)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsWow64") && processNode->ProcessItem->IsWow64)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsImmersive") && processNode->ProcessItem->IsImmersive)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsProtectedProcess") && processNode->ProcessItem->IsProtectedProcess)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsSecureProcess") && processNode->ProcessItem->IsSecureProcess)
    {
        return TRUE;
    }

    if (WordMatchStringZ(L"IsPicoProcess") && processNode->ProcessItem->IsSubsystemProcess)
    {
        return TRUE;
    }

    if (processNode->ProcessItem->ServiceList && processNode->ProcessItem->ServiceList->Count)
    {
        ULONG enumerationKey = 0;
        PPH_SERVICE_ITEM serviceItem;
        PPH_LIST serviceList;
        ULONG i;
        BOOLEAN matched = FALSE;

        // Copy the service list so we can search it.
        serviceList = PhCreateList(processNode->ProcessItem->ServiceList->Count);

        PhAcquireQueuedLockShared(&processNode->ProcessItem->ServiceListLock);

        while (PhEnumPointerList(
            processNode->ProcessItem->ServiceList,
            &enumerationKey,
            &serviceItem
            ))
        {
            PhReferenceObject(serviceItem);
            PhAddItemList(serviceList, serviceItem);
        }

        PhReleaseQueuedLockShared(&processNode->ProcessItem->ServiceListLock);

        for (i = 0; i < serviceList->Count; i++)
        {
            PPH_STRING serviceFileName = NULL;
            PPH_STRING serviceBinaryPath = NULL;

            serviceItem = serviceList->Items[i];

            if (!PhIsNullOrEmptyString(serviceItem->Name))
            {
                if (WordMatchStringRef(&serviceItem->Name->sr))
                {
                    matched = TRUE;
                    break;
                }
            }

            if (!PhIsNullOrEmptyString(serviceItem->DisplayName))
            {
                if (WordMatchStringRef(&serviceItem->DisplayName->sr))
                {
                    matched = TRUE;
                    break;
                }
            }

            if (serviceItem->ProcessId)
            {
                if (WordMatchStringZ(serviceItem->ProcessIdString))
                {
                    matched = TRUE;
                    break;
                }
            }

            if (NT_SUCCESS(QueryServiceFileName(
                &serviceItem->Name->sr,
                &serviceFileName,
                &serviceBinaryPath
                )))
            {
                if (serviceFileName)
                {
                    if (WordMatchStringRef(&serviceFileName->sr))
                    {
                        matched = TRUE;
                    }

                    PhDereferenceObject(serviceFileName);
                }

                if (serviceBinaryPath)
                {
                    if (WordMatchStringRef(&serviceBinaryPath->sr))
                    {
                        matched = TRUE;
                    }

                    PhDereferenceObject(serviceBinaryPath);
                }

                if (matched)
                    break;
            }
        }

        PhDereferenceObjects(serviceList->Items, serviceList->Count);
        PhDereferenceObject(serviceList);

        if (matched)
            return TRUE;
    }

    return FALSE;
}
Exemple #3
0
INT_PTR CALLBACK PhpProcessThreadsDlgProc(
    _In_ HWND hwndDlg,
    _In_ UINT uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    )
{
    LPPROPSHEETPAGE propSheetPage;
    PPH_PROCESS_PROPPAGECONTEXT propPageContext;
    PPH_PROCESS_ITEM processItem;
    PPH_THREADS_CONTEXT threadsContext;
    HWND tnHandle;

    if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
        &propSheetPage, &propPageContext, &processItem))
    {
        threadsContext = (PPH_THREADS_CONTEXT)propPageContext->Context;

        if (threadsContext)
            tnHandle = threadsContext->ListContext.TreeNewHandle;
    }
    else
    {
        return FALSE;
    }

    switch (uMsg)
    {
    case WM_INITDIALOG:
        {
            threadsContext = propPageContext->Context =
                PhAllocate(PhEmGetObjectSize(EmThreadsContextType, sizeof(PH_THREADS_CONTEXT)));

            // The thread provider has a special registration mechanism.
            threadsContext->Provider = PhCreateThreadProvider(
                processItem->ProcessId
                );
            PhRegisterCallback(
                &threadsContext->Provider->ThreadAddedEvent,
                ThreadAddedHandler,
                threadsContext,
                &threadsContext->AddedEventRegistration
                );
            PhRegisterCallback(
                &threadsContext->Provider->ThreadModifiedEvent,
                ThreadModifiedHandler,
                threadsContext,
                &threadsContext->ModifiedEventRegistration
                );
            PhRegisterCallback(
                &threadsContext->Provider->ThreadRemovedEvent,
                ThreadRemovedHandler,
                threadsContext,
                &threadsContext->RemovedEventRegistration
                );
            PhRegisterCallback(
                &threadsContext->Provider->UpdatedEvent,
                ThreadsUpdatedHandler,
                threadsContext,
                &threadsContext->UpdatedEventRegistration
                );
            PhRegisterCallback(
                &threadsContext->Provider->LoadingStateChangedEvent,
                ThreadsLoadingStateChangedHandler,
                threadsContext,
                &threadsContext->LoadingStateChangedEventRegistration
                );
            threadsContext->WindowHandle = hwndDlg;

            // Initialize the list.
            tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
            BringWindowToTop(tnHandle);
            PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext);
            TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0);
            PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100);

            // Use Cycles instead of Context Switches on Vista and above, but only when we can
            // open the process, since cycle time information requires sufficient access to the
            // threads.
            if (WINDOWS_HAS_CYCLE_TIME)
            {
                HANDLE processHandle;
                PROCESS_EXTENDED_BASIC_INFORMATION extendedBasicInfo;

                // We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since
                // the latter can be used when opening audiodg.exe even though we can't access its threads using
                // THREAD_QUERY_LIMITED_INFORMATION.

                if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)
                {
                    threadsContext->ListContext.UseCycleTime = TRUE;
                }
                else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId)))
                {
                    threadsContext->ListContext.UseCycleTime = TRUE;
                    NtClose(processHandle);
                }
                else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId)))
                {
                    threadsContext->ListContext.UseCycleTime = TRUE;

                    // We can't use cycle time for protected processes (without KProcessHacker).
                    if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &extendedBasicInfo)) && extendedBasicInfo.IsProtectedProcess)
                    {
                        threadsContext->ListContext.UseCycleTime = FALSE;
                    }

                    NtClose(processHandle);
                }
            }

            if (processItem->ServiceList && processItem->ServiceList->Count != 0 && WINDOWS_HAS_SERVICE_TAGS)
                threadsContext->ListContext.HasServices = TRUE;

            PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectCreate);

            if (PhPluginsEnabled)
            {
                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;

                treeNewInfo.TreeNewHandle = tnHandle;
                treeNewInfo.CmData = &threadsContext->ListContext.Cm;
                treeNewInfo.SystemContext = threadsContext;
                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing), &treeNewInfo);
            }

            PhLoadSettingsThreadList(&threadsContext->ListContext);

            PhThreadProviderInitialUpdate(threadsContext->Provider);
            PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);

            SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER)));
        }
        break;
    case WM_DESTROY:
        {
            PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete);

            PhUnregisterCallback(
                &threadsContext->Provider->ThreadAddedEvent,
                &threadsContext->AddedEventRegistration
                );
            PhUnregisterCallback(
                &threadsContext->Provider->ThreadModifiedEvent,
                &threadsContext->ModifiedEventRegistration
                );
            PhUnregisterCallback(
                &threadsContext->Provider->ThreadRemovedEvent,
                &threadsContext->RemovedEventRegistration
                );
            PhUnregisterCallback(
                &threadsContext->Provider->UpdatedEvent,
                &threadsContext->UpdatedEventRegistration
                );
            PhUnregisterCallback(
                &threadsContext->Provider->LoadingStateChangedEvent,
                &threadsContext->LoadingStateChangedEventRegistration
                );
            PhUnregisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);
            PhSetTerminatingThreadProvider(threadsContext->Provider);
            PhDereferenceObject(threadsContext->Provider);
            PhDeleteProviderEventQueue(&threadsContext->EventQueue);

            if (PhPluginsEnabled)
            {
                PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;

                treeNewInfo.TreeNewHandle = tnHandle;
                treeNewInfo.CmData = &threadsContext->ListContext.Cm;
                PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing), &treeNewInfo);
            }

            PhSaveSettingsThreadList(&threadsContext->ListContext);
            PhDeleteThreadList(&threadsContext->ListContext);

            PhFree(threadsContext);

            PhpPropPageDlgProcDestroy(hwndDlg);
        }
        break;
    case WM_SHOWWINDOW:
        {
            if (!propPageContext->LayoutInitialized)
            {
                PPH_LAYOUT_ITEM dialogItem;

                dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
                    PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
                    dialogItem, PH_ANCHOR_ALL);

#define ADD_BL_ITEM(Id) \
    PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, Id), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM)

                // Thread details area
                {
                    ULONG id;

                    for (id = IDC_STATICBL1; id <= IDC_STATICBL11; id++)
                        ADD_BL_ITEM(id);

                    // Not in sequence
                    ADD_BL_ITEM(IDC_STATICBL12);
                }

                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE),
                    dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
                PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE),
                    dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
                ADD_BL_ITEM(IDC_STARTED);
                ADD_BL_ITEM(IDC_KERNELTIME);
                ADD_BL_ITEM(IDC_USERTIME);
                ADD_BL_ITEM(IDC_CONTEXTSWITCHES);
                ADD_BL_ITEM(IDC_CYCLES);
                ADD_BL_ITEM(IDC_STATE);
                ADD_BL_ITEM(IDC_PRIORITY);
                ADD_BL_ITEM(IDC_BASEPRIORITY);
                ADD_BL_ITEM(IDC_IOPRIORITY);
                ADD_BL_ITEM(IDC_PAGEPRIORITY);
                ADD_BL_ITEM(IDC_IDEALPROCESSOR);

                PhDoPropPageLayout(hwndDlg);

                propPageContext->LayoutInitialized = TRUE;
            }
        }
        break;
    case WM_COMMAND:
        {
            INT id = LOWORD(wParam);

            switch (id)
            {
            case ID_SHOWCONTEXTMENU:
                {
                    PhShowThreadContextMenu(hwndDlg, processItem, threadsContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
                }
                break;
            case ID_THREAD_INSPECT:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem)
                    {
                        PhReferenceObject(threadsContext->Provider);
                        PhShowThreadStackDialog(
                            hwndDlg,
                            threadsContext->Provider->ProcessId,
                            threadItem->ThreadId,
                            threadsContext->Provider
                            );
                        PhDereferenceObject(threadsContext->Provider);
                    }
                }
                break;
            case ID_THREAD_TERMINATE:
                {
                    PPH_THREAD_ITEM *threads;
                    ULONG numberOfThreads;

                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
                    PhReferenceObjects(threads, numberOfThreads);

                    if (PhUiTerminateThreads(hwndDlg, threads, numberOfThreads))
                        PhDeselectAllThreadNodes(&threadsContext->ListContext);

                    PhDereferenceObjects(threads, numberOfThreads);
                    PhFree(threads);
                }
                break;
            case ID_THREAD_SUSPEND:
                {
                    PPH_THREAD_ITEM *threads;
                    ULONG numberOfThreads;

                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
                    PhReferenceObjects(threads, numberOfThreads);
                    PhUiSuspendThreads(hwndDlg, threads, numberOfThreads);
                    PhDereferenceObjects(threads, numberOfThreads);
                    PhFree(threads);
                }
                break;
            case ID_THREAD_RESUME:
                {
                    PPH_THREAD_ITEM *threads;
                    ULONG numberOfThreads;

                    PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
                    PhReferenceObjects(threads, numberOfThreads);
                    PhUiResumeThreads(hwndDlg, threads, numberOfThreads);
                    PhDereferenceObjects(threads, numberOfThreads);
                    PhFree(threads);
                }
                break;
            case ID_THREAD_AFFINITY:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem)
                    {
                        PhReferenceObject(threadItem);
                        PhShowProcessAffinityDialog(hwndDlg, NULL, threadItem);
                        PhDereferenceObject(threadItem);
                    }
                }
                break;
            case ID_THREAD_PERMISSIONS:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
                    PH_STD_OBJECT_SECURITY stdObjectSecurity;
                    PPH_ACCESS_ENTRY accessEntries;
                    ULONG numberOfAccessEntries;

                    if (threadItem)
                    {
                        stdObjectSecurity.OpenObject = PhpThreadPermissionsOpenThread;
                        stdObjectSecurity.ObjectType = L"Thread";
                        stdObjectSecurity.Context = threadItem->ThreadId;

                        if (PhGetAccessEntries(L"Thread", &accessEntries, &numberOfAccessEntries))
                        {
                            PhEditSecurity(
                                hwndDlg,
                                PhaFormatString(L"Thread %u", HandleToUlong(threadItem->ThreadId))->Buffer,
                                PhStdGetObjectSecurity,
                                PhStdSetObjectSecurity,
                                &stdObjectSecurity,
                                accessEntries,
                                numberOfAccessEntries
                                );
                            PhFree(accessEntries);
                        }
                    }
                }
                break;
            case ID_THREAD_TOKEN:
                {
                    NTSTATUS status;
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
                    HANDLE threadHandle;

                    if (threadItem)
                    {
                        if (NT_SUCCESS(status = PhOpenThread(
                            &threadHandle,
                            ThreadQueryAccess,
                            threadItem->ThreadId
                            )))
                        {
                            PhShowTokenProperties(
                                hwndDlg,
                                PhpOpenThreadTokenObject,
                                (PVOID)threadHandle,
                                NULL
                                );

                            NtClose(threadHandle);
                        }
                        else
                        {
                            PhShowStatus(hwndDlg, L"Unable to open the thread", status, 0);
                        }
                    }
                }
                break;
            case ID_ANALYZE_WAIT:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem)
                    {
                        PhReferenceObject(threadsContext->Provider->SymbolProvider);
                        PhUiAnalyzeWaitThread(
                            hwndDlg,
                            processItem->ProcessId,
                            threadItem->ThreadId,
                            threadsContext->Provider->SymbolProvider
                            );
                        PhDereferenceObject(threadsContext->Provider->SymbolProvider);
                    }
                }
                break;
            case ID_PRIORITY_TIMECRITICAL:
            case ID_PRIORITY_HIGHEST:
            case ID_PRIORITY_ABOVENORMAL:
            case ID_PRIORITY_NORMAL:
            case ID_PRIORITY_BELOWNORMAL:
            case ID_PRIORITY_LOWEST:
            case ID_PRIORITY_IDLE:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem)
                    {
                        ULONG threadPriorityWin32;

                        switch (id)
                        {
                        case ID_PRIORITY_TIMECRITICAL:
                            threadPriorityWin32 = THREAD_PRIORITY_TIME_CRITICAL;
                            break;
                        case ID_PRIORITY_HIGHEST:
                            threadPriorityWin32 = THREAD_PRIORITY_HIGHEST;
                            break;
                        case ID_PRIORITY_ABOVENORMAL:
                            threadPriorityWin32 = THREAD_PRIORITY_ABOVE_NORMAL;
                            break;
                        case ID_PRIORITY_NORMAL:
                            threadPriorityWin32 = THREAD_PRIORITY_NORMAL;
                            break;
                        case ID_PRIORITY_BELOWNORMAL:
                            threadPriorityWin32 = THREAD_PRIORITY_BELOW_NORMAL;
                            break;
                        case ID_PRIORITY_LOWEST:
                            threadPriorityWin32 = THREAD_PRIORITY_LOWEST;
                            break;
                        case ID_PRIORITY_IDLE:
                            threadPriorityWin32 = THREAD_PRIORITY_IDLE;
                            break;
                        }

                        PhReferenceObject(threadItem);
                        PhUiSetPriorityThread(hwndDlg, threadItem, threadPriorityWin32);
                        PhDereferenceObject(threadItem);
                    }
                }
                break;
            case ID_IOPRIORITY_VERYLOW:
            case ID_IOPRIORITY_LOW:
            case ID_IOPRIORITY_NORMAL:
            case ID_IOPRIORITY_HIGH:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem)
                    {
                        IO_PRIORITY_HINT ioPriority;

                        switch (id)
                        {
                        case ID_IOPRIORITY_VERYLOW:
                            ioPriority = IoPriorityVeryLow;
                            break;
                        case ID_IOPRIORITY_LOW:
                            ioPriority = IoPriorityLow;
                            break;
                        case ID_IOPRIORITY_NORMAL:
                            ioPriority = IoPriorityNormal;
                            break;
                        case ID_IOPRIORITY_HIGH:
                            ioPriority = IoPriorityHigh;
                            break;
                        }

                        PhReferenceObject(threadItem);
                        PhUiSetIoPriorityThread(hwndDlg, threadItem, ioPriority);
                        PhDereferenceObject(threadItem);
                    }
                }
                break;
            case ID_PAGEPRIORITY_VERYLOW:
            case ID_PAGEPRIORITY_LOW:
            case ID_PAGEPRIORITY_MEDIUM:
            case ID_PAGEPRIORITY_BELOWNORMAL:
            case ID_PAGEPRIORITY_NORMAL:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem)
                    {
                        ULONG pagePriority;

                        switch (id)
                        {
                            case ID_PAGEPRIORITY_VERYLOW:
                                pagePriority = MEMORY_PRIORITY_VERY_LOW;
                                break;
                            case ID_PAGEPRIORITY_LOW:
                                pagePriority = MEMORY_PRIORITY_LOW;
                                break;
                            case ID_PAGEPRIORITY_MEDIUM:
                                pagePriority = MEMORY_PRIORITY_MEDIUM;
                                break;
                            case ID_PAGEPRIORITY_BELOWNORMAL:
                                pagePriority = MEMORY_PRIORITY_BELOW_NORMAL;
                                break;
                            case ID_PAGEPRIORITY_NORMAL:
                                pagePriority = MEMORY_PRIORITY_NORMAL;
                                break;
                        }

                        PhReferenceObject(threadItem);
                        PhUiSetPagePriorityThread(hwndDlg, threadItem, pagePriority);
                        PhDereferenceObject(threadItem);
                    }
                }
                break;
            case ID_THREAD_COPY:
                {
                    PPH_STRING text;

                    text = PhGetTreeNewText(tnHandle, 0);
                    PhSetClipboardString(tnHandle, &text->sr);
                    PhDereferenceObject(text);
                }
                break;
            case IDC_OPENSTARTMODULE:
                {
                    PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);

                    if (threadItem && threadItem->StartAddressFileName)
                    {
                        PhShellExploreFile(hwndDlg, threadItem->StartAddressFileName->Buffer);
                    }
                }
                break;
            }
        }
        break;
    case WM_NOTIFY:
        {
            LPNMHDR header = (LPNMHDR)lParam;

            switch (header->code)
            {
            case PSN_SETACTIVE:
                break;
            case PSN_KILLACTIVE:
                // Can't disable, it screws up the deltas.
                break;
            }
        }
        break;
    case WM_PH_THREADS_UPDATED:
        {
            ULONG upToRunId = (ULONG)wParam;
            BOOLEAN firstRun = !!lParam;
            PPH_PROVIDER_EVENT events;
            ULONG count;
            ULONG i;

            events = PhFlushProviderEventQueue(&threadsContext->EventQueue, upToRunId, &count);

            if (events)
            {
                TreeNew_SetRedraw(tnHandle, FALSE);

                for (i = 0; i < count; i++)
                {
                    PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]);
                    PPH_THREAD_ITEM threadItem = PH_PROVIDER_EVENT_OBJECT(events[i]);

                    switch (type)
                    {
                    case ProviderAddedEvent:
                        PhAddThreadNode(&threadsContext->ListContext, threadItem, firstRun);
                        PhDereferenceObject(threadItem);
                        break;
                    case ProviderModifiedEvent:
                        PhUpdateThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));
                        break;
                    case ProviderRemovedEvent:
                        PhRemoveThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));
                        break;
                    }
                }

                PhFree(events);
            }

            PhTickThreadNodes(&threadsContext->ListContext);

            if (count != 0)
                TreeNew_SetRedraw(tnHandle, TRUE);

            if (propPageContext->PropContext->SelectThreadId)
            {
                PPH_THREAD_NODE threadNode;

                if (threadNode = PhFindThreadNode(&threadsContext->ListContext, propPageContext->PropContext->SelectThreadId))
                {
                    if (threadNode->Node.Visible)
                    {
                        TreeNew_SetFocusNode(tnHandle, &threadNode->Node);
                        TreeNew_SetMarkNode(tnHandle, &threadNode->Node);
                        TreeNew_SelectRange(tnHandle, threadNode->Node.Index, threadNode->Node.Index);
                        TreeNew_EnsureVisible(tnHandle, &threadNode->Node);
                    }
                }

                propPageContext->PropContext->SelectThreadId = NULL;
            }

            PhpUpdateThreadDetails(hwndDlg, threadsContext, FALSE);
        }
        break;
    case WM_PH_THREAD_SELECTION_CHANGED:
        {
            PhpUpdateThreadDetails(hwndDlg, threadsContext, TRUE);
        }
        break;
    }

    return FALSE;
}
PPH_STRING PhGetProcessTooltipText(
    __in PPH_PROCESS_ITEM Process
    )
{
    PH_STRING_BUILDER stringBuilder;
    PPH_STRING tempString;

    PhInitializeStringBuilder(&stringBuilder, 200);

    // Command line

    if (Process->CommandLine)
    {
        PhAppendStringBuilder(&stringBuilder, Process->CommandLine);
        PhAppendCharStringBuilder(&stringBuilder, '\n');
    }

    // File information

    tempString = PhFormatImageVersionInfo(
        Process->FileName,
        &Process->VersionInfo,
        L"    ",
        0
        );

    if (!PhIsNullOrEmptyString(tempString))
    {
        PhAppendStringBuilder2(&stringBuilder, L"File:\n");
        PhAppendStringBuilder(&stringBuilder, tempString);
        PhAppendCharStringBuilder(&stringBuilder, '\n');
    }

    if (tempString)
        PhDereferenceObject(tempString);

    // Known command line information

    if (Process->CommandLine && Process->QueryHandle)
    {
        PH_KNOWN_PROCESS_TYPE knownProcessType;
        PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine;

        if (NT_SUCCESS(PhGetProcessKnownType(
            Process->QueryHandle,
            &knownProcessType
            )) && PhaGetProcessKnownCommandLine(
            Process->CommandLine,
            knownProcessType,
            &knownCommandLine
            ))
        {
            switch (knownProcessType & KnownProcessTypeMask)
            {
            case ServiceHostProcessType:
                PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n    ");
                PhAppendStringBuilder(&stringBuilder, knownCommandLine.ServiceHost.GroupName);
                PhAppendCharStringBuilder(&stringBuilder, '\n');
                break;
            case RunDllAsAppProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;

                    if (PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.RunDllAsApp.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.RunDllAsApp.FileName,
                            &versionInfo,
                            L"    ",
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n");
                            PhAppendStringBuilder(&stringBuilder, tempString);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            case ComSurrogateProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;
                    PPH_STRING guidString;

                    PhAppendStringBuilder2(&stringBuilder, L"COM target:\n");

                    if (knownCommandLine.ComSurrogate.Name)
                    {
                        PhAppendStringBuilder2(&stringBuilder, L"    ");
                        PhAppendStringBuilder(&stringBuilder, knownCommandLine.ComSurrogate.Name);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid))
                    {
                        PhAppendStringBuilder2(&stringBuilder, L"    ");
                        PhAppendStringBuilder(&stringBuilder, guidString);
                        PhDereferenceObject(guidString);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.ComSurrogate.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.ComSurrogate.FileName,
                            &versionInfo,
                            L"    ",
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n");
                            PhAppendStringBuilder(&stringBuilder, tempString);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            }
        }
    }

    // Services

    if (Process->ServiceList && Process->ServiceList->Count != 0)
    {
        ULONG enumerationKey = 0;
        PPH_SERVICE_ITEM serviceItem;
        PPH_LIST serviceList;
        ULONG i;

        // Copy the service list into our own list so we can sort it.

        serviceList = PhCreateList(Process->ServiceList->Count);

        PhAcquireQueuedLockShared(&Process->ServiceListLock);

        while (PhEnumPointerList(
            Process->ServiceList,
            &enumerationKey,
            &serviceItem
            ))
        {
            PhReferenceObject(serviceItem);
            PhAddItemList(serviceList, serviceItem);
        }

        PhReleaseQueuedLockShared(&Process->ServiceListLock);

        qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare);

        PhAppendStringBuilder2(&stringBuilder, L"Services:\n");

        // Add the services.
        for (i = 0; i < serviceList->Count; i++)
        {
            serviceItem = serviceList->Items[i];

            PhAppendStringBuilder2(&stringBuilder, L"    ");
            PhAppendStringBuilder(&stringBuilder, serviceItem->Name);
            PhAppendStringBuilder2(&stringBuilder, L" (");
            PhAppendStringBuilder(&stringBuilder, serviceItem->DisplayName);
            PhAppendStringBuilder2(&stringBuilder, L")\n");
        }

        PhDereferenceObjects(serviceList->Items, serviceList->Count);
        PhDereferenceObject(serviceList);
    }

    // Tasks
    if (PhEqualString2(Process->ProcessName, L"taskeng.exe", TRUE) ||
        PhEqualString2(Process->ProcessName, L"taskhost.exe", TRUE))
    {
        PH_STRING_BUILDER tasks;

        PhInitializeStringBuilder(&tasks, 40);

        PhpFillRunningTasks(Process, &tasks);

        if (tasks.String->Length != 0)
        {
            PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n");
            PhAppendStringBuilder(&stringBuilder, tasks.String);
        }

        PhDeleteStringBuilder(&tasks);
    }

    // Plugin
    if (PhPluginsEnabled)
    {
        PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText;

        getTooltipText.Parameter = Process;
        getTooltipText.StringBuilder = &stringBuilder;

        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText);
    }

    // Notes

    {
        PH_STRING_BUILDER notes;

        PhInitializeStringBuilder(&notes, 40);

        if (Process->FileName)
        {
            if (Process->VerifyResult == VrTrusted)
            {
                if (!PhIsNullOrEmptyString(Process->VerifySignerName))
                    PhAppendFormatStringBuilder(&notes, L"    Signer: %s\n", Process->VerifySignerName->Buffer);
                else
                    PhAppendStringBuilder2(&notes, L"    Signed.\n");
            }
            else if (Process->VerifyResult == VrUnknown)
            {
                // Nothing
            }
            else if (Process->VerifyResult != VrNoSignature)
            {
                PhAppendStringBuilder2(&notes, L"    Signature invalid.\n");
            }
        }

        if (Process->IsPacked)
        {
            PhAppendFormatStringBuilder(
                &notes,
                L"    Image is probably packed (%u imports over %u modules).\n",
                Process->ImportFunctions,
                Process->ImportModules
                );
        }

        if (Process->ConsoleHostProcessId)
        {
            CLIENT_ID clientId;
            PPH_STRING clientIdString;

            clientId.UniqueProcess = Process->ConsoleHostProcessId;
            clientId.UniqueThread = NULL;

            clientIdString = PhGetClientIdName(&clientId);
            PhAppendFormatStringBuilder(&notes, L"    Console host: %s\n", clientIdString->Buffer);
            PhDereferenceObject(clientIdString);
        }

        if (Process->IsDotNet)
            PhAppendStringBuilder2(&notes, L"    Process is managed (.NET).\n");
        if (Process->IsElevated)
            PhAppendStringBuilder2(&notes, L"    Process is elevated.\n");
        if (Process->IsInJob)
            PhAppendStringBuilder2(&notes, L"    Process is in a job.\n");
        if (Process->IsPosix)
            PhAppendStringBuilder2(&notes, L"    Process is POSIX.\n");
        if (Process->IsWow64)
            PhAppendStringBuilder2(&notes, L"    Process is 32-bit (WOW64).\n");

        if (notes.String->Length != 0)
        {
            PhAppendStringBuilder2(&stringBuilder, L"Notes:\n");
            PhAppendStringBuilder(&stringBuilder, notes.String);
        }

        PhDeleteStringBuilder(&notes);
    }

    // Remove the trailing newline.
    if (stringBuilder.String->Length != 0)
        PhRemoveStringBuilder(&stringBuilder, stringBuilder.String->Length / 2 - 1, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}
INT_PTR CALLBACK EspServiceOtherDlgProc(
    _In_ HWND hwndDlg,
    _In_ UINT uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    )
{
    PSERVICE_OTHER_CONTEXT context;

    if (uMsg == WM_INITDIALOG)
    {
        context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT));
        memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT));

        SetProp(hwndDlg, L"Context", (HANDLE)context);
    }
    else
    {
        context = (PSERVICE_OTHER_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;
            HWND privilegesLv;

            context->ServiceItem = serviceItem;

            context->PrivilegesLv = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
            PhSetListViewStyle(privilegesLv, FALSE, TRUE);
            PhSetControlTheme(privilegesLv, L"explorer");
            PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 140, L"Name");
            PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 220, L"Display Name");
            PhSetExtendedListView(privilegesLv);

            context->PrivilegeList = PhCreateList(32);

            if (context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER)
            {
                // Drivers don't support required privileges.
                EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
            }

            EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE);

            PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_SIDTYPE),
                EspServiceSidTypeStrings, sizeof(EspServiceSidTypeStrings) / sizeof(PWSTR));
            PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION),
                EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR));

            if (WindowsVersion < WINDOWS_8_1)
                EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE);

            SetDlgItemText(hwndDlg, IDC_SERVICESID,
                PhGetStringOrDefault(PH_AUTO(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A"));

            status = EspLoadOtherInfo(hwndDlg, context);

            if (!NT_SUCCESS(status))
            {
                PhShowWarning(hwndDlg, L"Unable to query service information: %s",
                    ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
            }

            context->Ready = TRUE;
        }
        break;
    case WM_DESTROY:
        {
            if (context->PrivilegeList)
            {
                PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count);
                PhDereferenceObject(context->PrivilegeList);
            }

            PhFree(context);
        }
        break;
    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDC_ADD:
                {
                    NTSTATUS status;
                    LSA_HANDLE policyHandle;
                    LSA_ENUMERATION_HANDLE enumContext;
                    PPOLICY_PRIVILEGE_DEFINITION buffer;
                    ULONG count;
                    ULONG i;
                    PPH_LIST choices;
                    PPH_STRING selectedChoice = NULL;

                    choices = PH_AUTO(PhCreateList(100));

                    if (!NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL)))
                    {
                        PhShowStatus(hwndDlg, L"Unable to open LSA policy", status, 0);
                        break;
                    }

                    enumContext = 0;

                    while (TRUE)
                    {
                        status = LsaEnumeratePrivileges(
                            policyHandle,
                            &enumContext,
                            &buffer,
                            0x100,
                            &count
                            );

                        if (status == STATUS_NO_MORE_ENTRIES)
                            break;
                        if (!NT_SUCCESS(status))
                            break;

                        for (i = 0; i < count; i++)
                        {
                            PhAddItemList(choices, PhaCreateStringEx(buffer[i].Name.Buffer, buffer[i].Name.Length)->Buffer);
                        }

                        LsaFreeMemory(buffer);
                    }

                    LsaClose(policyHandle);

                    qsort(choices->Items, choices->Count, sizeof(PWSTR), PrivilegeNameCompareFunction);

                    while (PhaChoiceDialog(
                        hwndDlg,
                        L"Add privilege",
                        L"Select a privilege to add:",
                        (PWSTR *)choices->Items,
                        choices->Count,
                        NULL,
                        PH_CHOICE_DIALOG_CHOICE,
                        &selectedChoice,
                        NULL,
                        NULL
                        ))
                    {
                        BOOLEAN found = FALSE;
                        PPH_STRING privilegeString;
                        INT lvItemIndex;
                        PPH_STRING displayName;

                        // Check for duplicates.
                        for (i = 0; i < context->PrivilegeList->Count; i++)
                        {
                            if (PhEqualString(context->PrivilegeList->Items[i], selectedChoice, FALSE))
                            {
                                found = TRUE;
                                break;
                            }
                        }

                        if (found)
                        {
                            if (PhShowMessage(
                                hwndDlg,
                                MB_OKCANCEL | MB_ICONERROR,
                                L"The selected privilege has already been added."
                                ) == IDOK)
                            {
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }

                        PhSetReference(&privilegeString, selectedChoice);
                        PhAddItemList(context->PrivilegeList, privilegeString);

                        lvItemIndex = PhAddListViewItem(context->PrivilegesLv, MAXINT, privilegeString->Buffer, privilegeString);

                        if (PhLookupPrivilegeDisplayName(&privilegeString->sr, &displayName))
                        {
                            PhSetListViewSubItem(context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
                            PhDereferenceObject(displayName);
                        }

                        ExtendedListView_SortItems(context->PrivilegesLv);

                        context->Dirty = TRUE;
                        context->RequiredPrivilegesValid = TRUE;

                        break;
                    }
                }
                break;
            case IDC_REMOVE:
                {
                    INT lvItemIndex;
                    PPH_STRING privilegeString;
                    ULONG index;

                    lvItemIndex = ListView_GetNextItem(context->PrivilegesLv, -1, LVNI_SELECTED);

                    if (lvItemIndex != -1 && PhGetListViewItemParam(context->PrivilegesLv, lvItemIndex, (PVOID *)&privilegeString))
                    {
                        index = PhFindItemList(context->PrivilegeList, privilegeString);

                        if (index != -1)
                        {
                            PhDereferenceObject(privilegeString);
                            PhRemoveItemList(context->PrivilegeList, index);
                            PhRemoveListViewItem(context->PrivilegesLv, lvItemIndex);

                            context->Dirty = TRUE;
                            context->RequiredPrivilegesValid = TRUE;
                        }
                    }
                }
                break;
            }

            switch (HIWORD(wParam))
            {
            case EN_CHANGE:
            case CBN_SELCHANGE:
                {
                    if (context->Ready)
                    {
                        context->Dirty = TRUE;

                        switch (LOWORD(wParam))
                        {
                        case IDC_PRESHUTDOWNTIMEOUT:
                            context->PreshutdownTimeoutValid = TRUE;
                            break;
                        case IDC_SIDTYPE:
                            context->SidTypeValid = TRUE;
                            break;
                        case IDC_PROTECTION:
                            context->LaunchProtectedValid = TRUE;
                            break;
                        }
                    }
                }
                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:
                {
                    SC_HANDLE serviceHandle = NULL;
                    ULONG win32Result = 0;
                    BOOLEAN connectedToPhSvc = FALSE;
                    PPH_STRING launchProtectedString;
                    ULONG launchProtected;

                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);

                    launchProtectedString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_PROTECTION)));
                    launchProtected = EspGetServiceLaunchProtectedInteger(launchProtectedString->Buffer);

                    if (context->LaunchProtectedValid && launchProtected != 0 && launchProtected != context->OriginalLaunchProtected)
                    {
                        if (PhShowMessage(
                            hwndDlg,
                            MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2,
                            L"Setting service protection will prevent the service from being controlled, modified, or deleted. Do you want to continue?"
                            ) == IDNO)
                        {
                            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
                            return TRUE;
                        }
                    }

                    if (context->Dirty)
                    {
                        SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
                        SERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
                        SERVICE_SID_INFO sidInfo;
                        SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;

                        if (!(serviceHandle = PhOpenService(context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG)))
                        {
                            win32Result = GetLastError();

                            if (win32Result == ERROR_ACCESS_DENIED && !PhElevated)
                            {
                                // Elevate using phsvc.
                                if (PhUiConnectToPhSvc(hwndDlg, FALSE))
                                {
                                    win32Result = 0;
                                    connectedToPhSvc = TRUE;
                                }
                                else
                                {
                                    // User cancelled elevation.
                                    win32Result = ERROR_CANCELLED;
                                    goto Done;
                                }
                            }
                            else
                            {
                                goto Done;
                            }
                        }

                        if (context->PreshutdownTimeoutValid)
                        {
                            preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE);

                            if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
                                SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo))
                            {
                                win32Result = GetLastError();
                            }
                        }

                        if (context->RequiredPrivilegesValid)
                        {
                            PH_STRING_BUILDER sb;
                            ULONG i;

                            PhInitializeStringBuilder(&sb, 100);

                            for (i = 0; i < context->PrivilegeList->Count; i++)
                            {
                                PhAppendStringBuilder(&sb, &((PPH_STRING)context->PrivilegeList->Items[i])->sr);
                                PhAppendCharStringBuilder(&sb, 0);
                            }

                            requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer;

                            if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
                                SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo))
                            {
                                win32Result = GetLastError();
                            }

                            PhDeleteStringBuilder(&sb);
                        }

                        if (context->SidTypeValid)
                        {
                            PPH_STRING sidTypeString;

                            sidTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE)));
                            sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer);

                            if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
                                SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo))
                            {
                                win32Result = GetLastError();
                            }
                        }

                        if (context->LaunchProtectedValid)
                        {
                            launchProtectedInfo.dwLaunchProtected = launchProtected;

                            if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
                                SERVICE_CONFIG_LAUNCH_PROTECTED, &launchProtectedInfo))
                            {
                                // For now, ignore errors here.
                                // win32Result = GetLastError();
                            }
                        }

Done:
                        if (connectedToPhSvc)
                            PhUiDisconnectFromPhSvc();
                        if (serviceHandle)
                            CloseServiceHandle(serviceHandle);

                        if (win32Result != 0)
                        {
                            if (win32Result == ERROR_CANCELLED || PhShowMessage(
                                hwndDlg,
                                MB_ICONERROR | MB_RETRYCANCEL,
                                L"Unable to change service information: %s",
                                ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer
                                ) == IDRETRY)
                            {
                                SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
                            }
                        }
                    }

                    return TRUE;
                }
                break;
            case LVN_ITEMCHANGED:
                {
                    if (header->hwndFrom == context->PrivilegesLv)
                    {
                        EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), ListView_GetSelectedCount(context->PrivilegesLv) == 1);
                    }
                }
                break;
            }
        }
        break;
    }

    return FALSE;
}
Exemple #6
0
PPH_STRING PhGetProcessTooltipText(
    _In_ PPH_PROCESS_ITEM Process,
    _Out_opt_ PULONG ValidToTickCount
    )
{
    PH_STRING_BUILDER stringBuilder;
    ULONG validForMs = 60 * 60 * 1000; // 1 hour
    PPH_STRING tempString;
    PH_KNOWN_PROCESS_TYPE knownProcessType = UnknownProcessType;

    PhInitializeStringBuilder(&stringBuilder, 200);

    // Command line

    if (Process->CommandLine)
    {
        tempString = PhEllipsisString(Process->CommandLine, 100 * 10);

        // This is necessary because the tooltip control seems to use some kind of O(n^9999) word-wrapping
        // algorithm.
        PhpAppendStringWithLineBreaks(&stringBuilder, &tempString->sr, 100, NULL);
        PhAppendCharStringBuilder(&stringBuilder, '\n');

        PhDereferenceObject(tempString);
    }

    // File information

    tempString = PhFormatImageVersionInfo(
        Process->FileName,
        &Process->VersionInfo,
        &StandardIndent,
        0
        );

    if (!PhIsNullOrEmptyString(tempString))
    {
        PhAppendStringBuilder2(&stringBuilder, L"File:\n");
        PhAppendStringBuilder(&stringBuilder, &tempString->sr);
        PhAppendCharStringBuilder(&stringBuilder, '\n');
    }

    if (tempString)
        PhDereferenceObject(tempString);

    // Known command line information

    if (Process->QueryHandle)
        PhGetProcessKnownType(Process->QueryHandle, &knownProcessType);

    if (Process->CommandLine && Process->QueryHandle)
    {
        PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine;

        if (knownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine(
            Process->CommandLine,
            knownProcessType,
            &knownCommandLine
            ))
        {
            switch (knownProcessType & KnownProcessTypeMask)
            {
            case ServiceHostProcessType:
                PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n    ");
                PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ServiceHost.GroupName->sr);
                PhAppendCharStringBuilder(&stringBuilder, '\n');
                break;
            case RunDllAsAppProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;

                    if (PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.RunDllAsApp.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.RunDllAsApp.FileName,
                            &versionInfo,
                            &StandardIndent,
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n");
                            PhAppendStringBuilder(&stringBuilder, &tempString->sr);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            case ComSurrogateProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;
                    PPH_STRING guidString;

                    PhAppendStringBuilder2(&stringBuilder, L"COM target:\n");

                    if (knownCommandLine.ComSurrogate.Name)
                    {
                        PhAppendStringBuilder(&stringBuilder, &StandardIndent);
                        PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ComSurrogate.Name->sr);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid))
                    {
                        PhAppendStringBuilder(&stringBuilder, &StandardIndent);
                        PhAppendStringBuilder(&stringBuilder, &guidString->sr);
                        PhDereferenceObject(guidString);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.ComSurrogate.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.ComSurrogate.FileName,
                            &versionInfo,
                            &StandardIndent,
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n");
                            PhAppendStringBuilder(&stringBuilder, &tempString->sr);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            }
        }
    }

    // Services

    if (Process->ServiceList && Process->ServiceList->Count != 0)
    {
        ULONG enumerationKey = 0;
        PPH_SERVICE_ITEM serviceItem;
        PPH_LIST serviceList;
        ULONG i;

        // Copy the service list into our own list so we can sort it.

        serviceList = PhCreateList(Process->ServiceList->Count);

        PhAcquireQueuedLockShared(&Process->ServiceListLock);

        while (PhEnumPointerList(
            Process->ServiceList,
            &enumerationKey,
            &serviceItem
            ))
        {
            PhReferenceObject(serviceItem);
            PhAddItemList(serviceList, serviceItem);
        }

        PhReleaseQueuedLockShared(&Process->ServiceListLock);

        qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare);

        PhAppendStringBuilder2(&stringBuilder, L"Services:\n");

        // Add the services.
        for (i = 0; i < serviceList->Count; i++)
        {
            serviceItem = serviceList->Items[i];

            PhAppendStringBuilder(&stringBuilder, &StandardIndent);
            PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr);
            PhAppendStringBuilder2(&stringBuilder, L" (");
            PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr);
            PhAppendStringBuilder2(&stringBuilder, L")\n");
        }

        PhDereferenceObjects(serviceList->Items, serviceList->Count);
        PhDereferenceObject(serviceList);
    }

    // Tasks, Drivers
    switch (knownProcessType & KnownProcessTypeMask)
    {
    case TaskHostProcessType:
        {
            PH_STRING_BUILDER tasks;

            PhInitializeStringBuilder(&tasks, 40);

            PhpFillRunningTasks(Process, &tasks);

            if (tasks.String->Length != 0)
            {
                PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n");
                PhAppendStringBuilder(&stringBuilder, &tasks.String->sr);
            }

            PhDeleteStringBuilder(&tasks);
        }
        break;
    case UmdfHostProcessType:
        {
            PH_STRING_BUILDER drivers;

            PhInitializeStringBuilder(&drivers, 40);

            PhpFillUmdfDrivers(Process, &drivers);

            if (drivers.String->Length != 0)
            {
                PhAppendStringBuilder2(&stringBuilder, L"Drivers:\n");
                PhAppendStringBuilder(&stringBuilder, &drivers.String->sr);
            }

            PhDeleteStringBuilder(&drivers);

            validForMs = 10 * 1000; // 10 seconds
        }
        break;
    }

    // Plugin
    if (PhPluginsEnabled)
    {
        PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText;

        getTooltipText.Parameter = Process;
        getTooltipText.StringBuilder = &stringBuilder;
        getTooltipText.ValidForMs = validForMs;

        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText);
        validForMs = getTooltipText.ValidForMs;
    }

    // Notes

    {
        PH_STRING_BUILDER notes;

        PhInitializeStringBuilder(&notes, 40);

        if (Process->FileName)
        {
            if (Process->VerifyResult == VrTrusted)
            {
                if (!PhIsNullOrEmptyString(Process->VerifySignerName))
                    PhAppendFormatStringBuilder(&notes, L"    Signer: %s\n", Process->VerifySignerName->Buffer);
                else
                    PhAppendStringBuilder2(&notes, L"    Signed.\n");
            }
            else if (Process->VerifyResult == VrUnknown)
            {
                // Nothing
            }
            else if (Process->VerifyResult != VrNoSignature)
            {
                PhAppendStringBuilder2(&notes, L"    Signature invalid.\n");
            }
        }

        if (Process->IsPacked)
        {
            PhAppendFormatStringBuilder(
                &notes,
                L"    Image is probably packed (%u imports over %u modules).\n",
                Process->ImportFunctions,
                Process->ImportModules
                );
        }

        if ((ULONG_PTR)Process->ConsoleHostProcessId & ~3)
        {
            CLIENT_ID clientId;
            PWSTR description = L"Console host";
            PPH_STRING clientIdString;

            clientId.UniqueProcess = (HANDLE)((ULONG_PTR)Process->ConsoleHostProcessId & ~3);
            clientId.UniqueThread = NULL;

            if ((ULONG_PTR)Process->ConsoleHostProcessId & 2)
                description = L"Console application";

            clientIdString = PhGetClientIdName(&clientId);
            PhAppendFormatStringBuilder(&notes, L"    %s: %s\n", description, clientIdString->Buffer);
            PhDereferenceObject(clientIdString);
        }

        if (Process->PackageFullName)
        {
            PhAppendFormatStringBuilder(&notes, L"    Package name: %s\n", Process->PackageFullName->Buffer);
        }

        if (Process->IsDotNet)
            PhAppendStringBuilder2(&notes, L"    Process is managed (.NET).\n");
        if (Process->IsElevated)
            PhAppendStringBuilder2(&notes, L"    Process is elevated.\n");
        if (Process->IsImmersive)
            PhAppendStringBuilder2(&notes, L"    Process is a Modern UI app.\n");
        if (Process->IsInJob)
            PhAppendStringBuilder2(&notes, L"    Process is in a job.\n");
        if (Process->IsPosix)
            PhAppendStringBuilder2(&notes, L"    Process is POSIX.\n");
        if (Process->IsWow64)
            PhAppendStringBuilder2(&notes, L"    Process is 32-bit (WOW64).\n");

        if (notes.String->Length != 0)
        {
            PhAppendStringBuilder2(&stringBuilder, L"Notes:\n");
            PhAppendStringBuilder(&stringBuilder, &notes.String->sr);
        }

        PhDeleteStringBuilder(&notes);
    }

    if (ValidToTickCount)
        *ValidToTickCount = GetTickCount() + validForMs;

    // Remove the trailing newline.
    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}