/** * Initializes a work queue. * * \param WorkQueue A work queue object. * \param MinimumThreads The suggested minimum number of threads to keep alive, even * when there is no work to be performed. * \param MaximumThreads The suggested maximum number of threads to create. * \param NoWorkTimeout The number of milliseconds after which threads without work * will terminate. */ VOID PhInitializeWorkQueue( __out PPH_WORK_QUEUE WorkQueue, __in ULONG MinimumThreads, __in ULONG MaximumThreads, __in ULONG NoWorkTimeout ) { PhInitializeRundownProtection(&WorkQueue->RundownProtect); WorkQueue->Terminating = FALSE; InitializeListHead(&WorkQueue->QueueListHead); PhInitializeQueuedLock(&WorkQueue->QueueLock); WorkQueue->MinimumThreads = MinimumThreads; WorkQueue->MaximumThreads = MaximumThreads; WorkQueue->NoWorkTimeout = NoWorkTimeout; PhInitializeQueuedLock(&WorkQueue->StateLock); NtCreateSemaphore(&WorkQueue->SemaphoreHandle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG); WorkQueue->CurrentThreads = 0; WorkQueue->BusyThreads = 0; #ifdef DEBUG PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); InsertTailList(&PhDbgWorkQueueListHead, &WorkQueue->DbgListEntry); PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); #endif }
/** * Initializes a work queue. * * \param WorkQueue A work queue object. * \param MinimumThreads The suggested minimum number of threads to keep alive, even * when there is no work to be performed. * \param MaximumThreads The suggested maximum number of threads to create. * \param NoWorkTimeout The number of milliseconds after which threads without work * will terminate. */ VOID PhInitializeWorkQueue( _Out_ PPH_WORK_QUEUE WorkQueue, _In_ ULONG MinimumThreads, _In_ ULONG MaximumThreads, _In_ ULONG NoWorkTimeout ) { PhInitializeRundownProtection(&WorkQueue->RundownProtect); WorkQueue->Terminating = FALSE; InitializeListHead(&WorkQueue->QueueListHead); PhInitializeQueuedLock(&WorkQueue->QueueLock); PhInitializeQueuedLock(&WorkQueue->QueueEmptyCondition); WorkQueue->MinimumThreads = MinimumThreads; WorkQueue->MaximumThreads = MaximumThreads; WorkQueue->NoWorkTimeout = NoWorkTimeout; PhInitializeQueuedLock(&WorkQueue->StateLock); WorkQueue->SemaphoreHandle = NULL; WorkQueue->CurrentThreads = 0; WorkQueue->BusyCount = 0; #ifdef DEBUG PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); PhAddItemList(PhDbgWorkQueueList, WorkQueue); PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); #endif }
VOID PerformNetworkAction( __in HWND hWnd, __in ULONG Action, __in PPH_IP_ADDRESS Address ) { NETWORK_OUTPUT_CONTEXT context = { 0 }; context.Action = Action; context.Address = *Address; PhInitializeQueuedLock(&context.WindowHandleLock); PhInitializeStringBuilder(&context.ReceivedString, PAGE_SIZE); DialogBoxParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_OUTPUT), NULL, NetworkOutputDlgProc, (LPARAM)&context ); if (context.ThreadHandle) { // Wait for our thread to exit since it uses the context structure. NtWaitForSingleObject(context.ThreadHandle, FALSE, NULL); NtClose(context.ThreadHandle); } PhDeleteStringBuilder(&context.ReceivedString); }
VOID EtInitializeNetworkBlock( __out PET_NETWORK_BLOCK Block, __in PPH_NETWORK_ITEM NetworkItem ) { memset(Block, 0, sizeof(ET_NETWORK_BLOCK)); Block->NetworkItem = NetworkItem; PhInitializeQueuedLock(&Block->TextCacheLock); InsertTailList(&EtNetworkBlockListHead, &Block->ListEntry); }
VOID EtInitializeProcessBlock( __out PET_PROCESS_BLOCK Block, __in PPH_PROCESS_ITEM ProcessItem ) { memset(Block, 0, sizeof(ET_PROCESS_BLOCK)); Block->ProcessItem = ProcessItem; PhInitializeQueuedLock(&Block->TextCacheLock); InsertTailList(&EtProcessBlockListHead, &Block->ListEntry); }
PPH_THREAD_PROVIDER PhCreateThreadProvider( _In_ HANDLE ProcessId ) { PPH_THREAD_PROVIDER threadProvider; threadProvider = PhCreateObject( PhEmGetObjectSize(EmThreadProviderType, sizeof(PH_THREAD_PROVIDER)), PhThreadProviderType ); memset(threadProvider, 0, sizeof(PH_THREAD_PROVIDER)); threadProvider->ThreadHashtable = PhCreateHashtable( sizeof(PPH_THREAD_ITEM), PhpThreadHashtableEqualFunction, PhpThreadHashtableHashFunction, 20 ); PhInitializeFastLock(&threadProvider->ThreadHashtableLock); PhInitializeCallback(&threadProvider->ThreadAddedEvent); PhInitializeCallback(&threadProvider->ThreadModifiedEvent); PhInitializeCallback(&threadProvider->ThreadRemovedEvent); PhInitializeCallback(&threadProvider->UpdatedEvent); PhInitializeCallback(&threadProvider->LoadingStateChangedEvent); threadProvider->ProcessId = ProcessId; threadProvider->SymbolProvider = PhCreateSymbolProvider(ProcessId); if (threadProvider->SymbolProvider) { if (threadProvider->SymbolProvider->IsRealHandle) threadProvider->ProcessHandle = threadProvider->SymbolProvider->ProcessHandle; } RtlInitializeSListHead(&threadProvider->QueryListHead); PhInitializeQueuedLock(&threadProvider->LoadSymbolsLock); threadProvider->RunId = 1; threadProvider->SymbolsLoadedRunId = 0; // Force symbols to be loaded the first time we try to resolve an address PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectCreate); return threadProvider; }
PPH_HANDLE_PROVIDER PhCreateHandleProvider( __in HANDLE ProcessId ) { PPH_HANDLE_PROVIDER handleProvider; if (!NT_SUCCESS(PhCreateObject( &handleProvider, sizeof(PH_HANDLE_PROVIDER), 0, PhHandleProviderType ))) return NULL; handleProvider->HandleHashSetSize = 128; handleProvider->HandleHashSet = PhCreateHashSet(handleProvider->HandleHashSetSize); handleProvider->HandleHashSetCount = 0; PhInitializeQueuedLock(&handleProvider->HandleHashSetLock); PhInitializeCallback(&handleProvider->HandleAddedEvent); PhInitializeCallback(&handleProvider->HandleModifiedEvent); PhInitializeCallback(&handleProvider->HandleRemovedEvent); PhInitializeCallback(&handleProvider->UpdatedEvent); handleProvider->ProcessId = ProcessId; handleProvider->ProcessHandle = NULL; PhOpenProcess( &handleProvider->ProcessHandle, PROCESS_DUP_HANDLE, ProcessId ); handleProvider->TempListHashtable = PhCreateSimpleHashtable(20); return handleProvider; }
PPH_HANDLE_PROVIDER PhCreateHandleProvider( _In_ HANDLE ProcessId ) { PPH_HANDLE_PROVIDER handleProvider; handleProvider = PhCreateObject( PhEmGetObjectSize(EmHandleProviderType, sizeof(PH_HANDLE_PROVIDER)), PhHandleProviderType ); handleProvider->HandleHashSetSize = 128; handleProvider->HandleHashSet = PhCreateHashSet(handleProvider->HandleHashSetSize); handleProvider->HandleHashSetCount = 0; PhInitializeQueuedLock(&handleProvider->HandleHashSetLock); PhInitializeCallback(&handleProvider->HandleAddedEvent); PhInitializeCallback(&handleProvider->HandleModifiedEvent); PhInitializeCallback(&handleProvider->HandleRemovedEvent); PhInitializeCallback(&handleProvider->UpdatedEvent); handleProvider->ProcessId = ProcessId; handleProvider->ProcessHandle = NULL; handleProvider->RunStatus = PhOpenProcess( &handleProvider->ProcessHandle, PROCESS_DUP_HANDLE, ProcessId ); handleProvider->TempListHashtable = PhCreateSimpleHashtable(20); PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectCreate); return handleProvider; }
PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( _In_opt_ HANDLE ProcessId ) { PPH_SYMBOL_PROVIDER symbolProvider; if (!NT_SUCCESS(PhCreateObject( &symbolProvider, sizeof(PH_SYMBOL_PROVIDER), 0, PhSymbolProviderType ))) return NULL; InitializeListHead(&symbolProvider->ModulesListHead); PhInitializeQueuedLock(&symbolProvider->ModulesListLock); PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction); PhInitializeCallback(&symbolProvider->EventCallback); if (ProcessId) { static ACCESS_MASK accesses[] = { STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, MAXIMUM_ALLOWED }; ULONG i; symbolProvider->IsRealHandle = FALSE; // Try to open the process with many different accesses. // This handle will be re-used when walking stacks, and doing // various other things. for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) { if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId))) { symbolProvider->IsRealHandle = TRUE; break; } } } else { symbolProvider->IsRealHandle = FALSE; } if (!symbolProvider->IsRealHandle) { HANDLE fakeHandle; // Just generate a fake handle. fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4); // Add one to make sure it isn't divisible // by 4 (so it can't be mistaken for a real // handle). fakeHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1); symbolProvider->ProcessHandle = fakeHandle; } symbolProvider->IsRegistered = FALSE; #ifdef PH_SYMBOL_PROVIDER_DELAY_INIT PhInitializeInitOnce(&symbolProvider->InitOnce); #else PhpRegisterSymbolProvider(symbolProvider); #endif return symbolProvider; }
VOID PhShowThreadStackDialog( _In_ HWND ParentWindowHandle, _In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ PPH_SYMBOL_PROVIDER SymbolProvider ) { NTSTATUS status; THREAD_STACK_CONTEXT threadStackContext; HANDLE threadHandle = NULL; // If the user is trying to view a system thread stack // but KProcessHacker is not loaded, show an error message. if (ProcessId == SYSTEM_PROCESS_ID && !KphIsConnected()) { PhShowError(ParentWindowHandle, KPH_ERROR_MESSAGE); return; } memset(&threadStackContext, 0, sizeof(THREAD_STACK_CONTEXT)); threadStackContext.ProcessId = ProcessId; threadStackContext.ThreadId = ThreadId; threadStackContext.SymbolProvider = SymbolProvider; if (!NT_SUCCESS(status = PhOpenThread( &threadHandle, THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, ThreadId ))) { if (KphIsConnected()) { status = PhOpenThread( &threadHandle, ThreadQueryAccess, ThreadId ); } } if (!NT_SUCCESS(status)) { PhShowStatus(ParentWindowHandle, L"Unable to open the thread", status, 0); return; } threadStackContext.ThreadHandle = threadHandle; threadStackContext.List = PhCreateList(10); threadStackContext.NewList = PhCreateList(10); PhInitializeQueuedLock(&threadStackContext.StatusLock); DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_THRDSTACK), ParentWindowHandle, PhpThreadStackDlgProc, (LPARAM)&threadStackContext ); PhSwapReference(&threadStackContext.StatusMessage, NULL); PhDereferenceObject(threadStackContext.NewList); PhDereferenceObject(threadStackContext.List); if (threadStackContext.ThreadHandle) NtClose(threadStackContext.ThreadHandle); }
INT_PTR CALLBACK EtpWsWatchDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { PWS_WATCH_CONTEXT context; if (uMsg == WM_INITDIALOG) { context = (PWS_WATCH_CONTEXT)lParam; SetProp(hwndDlg, L"Context", (HANDLE)context); } else { context = (PWS_WATCH_CONTEXT)GetProp(hwndDlg, L"Context"); if (uMsg == WM_DESTROY) RemoveProp(hwndDlg, L"Context"); } if (!context) return FALSE; switch (uMsg) { case WM_INITDIALOG: { HWND lvHandle; PhCenterWindow(hwndDlg, GetParent(hwndDlg)); context->WindowHandle = hwndDlg; context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 340, L"Instruction"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Count"); PhSetExtendedListView(lvHandle); ExtendedListView_SetSort(lvHandle, 1, DescendingSortOrder); context->Hashtable = PhCreateSimpleHashtable(64); context->BufferSize = 0x2000; context->Buffer = PhAllocate(context->BufferSize); PhInitializeQueuedLock(&context->ResultListLock); context->SymbolProvider = PhCreateSymbolProvider(context->ProcessItem->ProcessId); PhLoadSymbolProviderOptions(context->SymbolProvider); if (!context->SymbolProvider || !context->SymbolProvider->IsRealHandle) { PhShowError(hwndDlg, L"Unable to open the process."); EndDialog(hwndDlg, IDCANCEL); break; } context->ProcessHandle = context->SymbolProvider->ProcessHandle; // Load symbols for both process and kernel modules. context->LoadingSymbolsForProcessId = context->ProcessItem->ProcessId; PhEnumGenericModules( NULL, context->ProcessHandle, 0, EnumGenericModulesCallback, context ); context->LoadingSymbolsForProcessId = SYSTEM_PROCESS_ID; PhEnumGenericModules( SYSTEM_PROCESS_ID, NULL, 0, EnumGenericModulesCallback, context ); context->Enabled = EtpUpdateWsWatch(hwndDlg, context); if (context->Enabled) { // WS Watch is already enabled for the process. Enable updating. EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE); ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW); SetTimer(hwndDlg, 1, 1000, NULL); } else { // WS Watch has not yet been enabled for the process. } } break; case WM_DESTROY: { context->Destroying = TRUE; PhDereferenceObject(context->Hashtable); if (context->Buffer) { PhFree(context->Buffer); context->Buffer = NULL; } } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hwndDlg, IDOK); break; case IDC_ENABLE: { NTSTATUS status; HANDLE processHandle; if (NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_SET_INFORMATION, context->ProcessItem->ProcessId ))) { status = NtSetInformationProcess( processHandle, ProcessWorkingSetWatchEx, NULL, 0 ); NtClose(processHandle); } if (NT_SUCCESS(status)) { EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE); ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW); SetTimer(hwndDlg, 1, 1000, NULL); } else { PhShowStatus(hwndDlg, L"Unable to enable WS watch", status, 0); } } break; } } break; case WM_NOTIFY: { PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); } break; case WM_TIMER: { switch (wParam) { case 1: { EtpUpdateWsWatch(hwndDlg, context); } break; } } break; } return FALSE; }