NTSTATUS PhpThreadQueryWorker( __in PVOID Parameter ) { PPH_THREAD_QUERY_DATA data = (PPH_THREAD_QUERY_DATA)Parameter; LONG newSymbolsLoading; newSymbolsLoading = _InterlockedIncrement(&data->ThreadProvider->SymbolsLoading); if (newSymbolsLoading == 1) PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)TRUE); // We can't resolve the start address until symbols have // been loaded. PhWaitForEvent(&data->ThreadProvider->SymbolsLoadedEvent, NULL); data->StartAddressString = PhGetSymbolFromAddress( data->ThreadProvider->SymbolProvider, data->ThreadItem->StartAddress, &data->StartAddressResolveLevel, &data->ThreadItem->StartAddressFileName, NULL, NULL ); newSymbolsLoading = _InterlockedDecrement(&data->ThreadProvider->SymbolsLoading); if (newSymbolsLoading == 0) PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)FALSE); // Get the service tag, and the service name. if ( WINDOWS_HAS_SERVICE_TAGS && data->ThreadProvider->SymbolProvider->IsRealHandle && data->ThreadItem->ThreadHandle ) { PVOID serviceTag; if (NT_SUCCESS(PhGetThreadServiceTag( data->ThreadItem->ThreadHandle, data->ThreadProvider->ProcessHandle, &serviceTag ))) { data->ServiceName = PhGetServiceNameFromTag( data->ThreadProvider->ProcessId, serviceTag ); } } RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry); PhDereferenceObject(data->ThreadProvider); return STATUS_SUCCESS; }
static BOOLEAN NTAPI PhpWalkThreadStackCallback( _In_ PPH_THREAD_STACK_FRAME StackFrame, _In_opt_ PVOID Context ) { PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)Context; PPH_STRING symbol; PTHREAD_STACK_ITEM item; if (threadStackContext->StopWalk) return FALSE; PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); PhMoveReference(&threadStackContext->StatusMessage, PhFormatString(L"Processing frame %u...", threadStackContext->NewList->Count)); PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_STATUS_UPDATE, 0, 0); symbol = PhGetSymbolFromAddress( threadStackContext->SymbolProvider, (ULONG64)StackFrame->PcAddress, NULL, NULL, NULL, NULL ); if (symbol && (StackFrame->Flags & PH_THREAD_STACK_FRAME_I386) && !(StackFrame->Flags & PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT)) { PhMoveReference(&symbol, PhConcatStrings2(symbol->Buffer, L" (No unwind info)")); } item = PhAllocate(sizeof(THREAD_STACK_ITEM)); item->StackFrame = *StackFrame; item->Index = threadStackContext->NewList->Count; if (PhPluginsEnabled) { PH_PLUGIN_THREAD_STACK_CONTROL control; control.Type = PluginThreadStackResolveSymbol; control.UniqueKey = threadStackContext; control.u.ResolveSymbol.StackFrame = StackFrame; control.u.ResolveSymbol.Symbol = symbol; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); symbol = control.u.ResolveSymbol.Symbol; } item->Symbol = symbol; PhAddItemList(threadStackContext->NewList, item); return TRUE; }
static NTSTATUS EtpSymbolLookupFunction( _In_ PVOID Parameter ) { PSYMBOL_LOOKUP_RESULT result; result = Parameter; // Don't bother looking up the symbol if the window has already closed. if (result->Context->Destroying) { EtpDereferenceWsWatchContext(result->Context); PhFree(result); return STATUS_SUCCESS; } result->Symbol = PhGetSymbolFromAddress( result->Context->SymbolProvider, (ULONG64)result->Address, NULL, NULL, NULL, NULL ); // Fail if we don't have a symbol. if (!result->Symbol) { EtpDereferenceWsWatchContext(result->Context); PhFree(result); return STATUS_SUCCESS; } PhAcquireQueuedLockExclusive(&result->Context->ResultListLock); PushEntryList(&result->Context->ResultListHead, &result->ListEntry); PhReleaseQueuedLockExclusive(&result->Context->ResultListLock); EtpDereferenceWsWatchContext(result->Context); return STATUS_SUCCESS; }
static INT_PTR CALLBACK PhpNetworkStackDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { PNETWORK_STACK_CONTEXT networkStackContext; HWND lvHandle; PPH_LAYOUT_MANAGER layoutManager; PVOID address; ULONG i; PhCenterWindow(hwndDlg, GetParent(hwndDlg)); networkStackContext = (PNETWORK_STACK_CONTEXT)lParam; SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)networkStackContext); lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Name"); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); networkStackContext->ListViewHandle = lvHandle; layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); PhInitializeLayoutManager(layoutManager, hwndDlg); SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); PhAddLayoutItem(layoutManager, lvHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); if (MinimumSize.left == -1) { RECT rect; rect.left = 0; rect.top = 0; rect.right = 190; rect.bottom = 120; MapDialogRect(hwndDlg, &rect); MinimumSize = rect; MinimumSize.left = 0; } for (i = 0; i < PH_NETWORK_OWNER_INFO_SIZE; i++) { PPH_STRING name; address = *(PVOID *)&networkStackContext->NetworkItem->OwnerInfo[i]; if ((ULONG_PTR)address < PAGE_SIZE) // stop at an invalid address break; name = PhGetSymbolFromAddress( networkStackContext->SymbolProvider, (ULONG64)address, NULL, NULL, NULL, NULL ); PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); PhDereferenceObject(name); } } break; case WM_DESTROY: { PPH_LAYOUT_MANAGER layoutManager; PNETWORK_STACK_CONTEXT networkStackContext; layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); PhDeleteLayoutManager(layoutManager); PhFree(layoutManager); networkStackContext = (PNETWORK_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); RemoveProp(hwndDlg, PhMakeContextAtom()); RemoveProp(hwndDlg, L"LayoutManager"); } break; case WM_COMMAND: { INT id = LOWORD(wParam); switch (id) { case IDCANCEL: // Esc and X button to close case IDOK: EndDialog(hwndDlg, IDOK); break; } } break; case WM_SIZE: { PPH_LAYOUT_MANAGER layoutManager; layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); PhLayoutManagerLayout(layoutManager); } break; case WM_SIZING: { PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); } break; } return FALSE; }
NTSTATUS PhpThreadQueryWorker( _In_ PVOID Parameter ) { PPH_THREAD_QUERY_DATA data = (PPH_THREAD_QUERY_DATA)Parameter; LONG newSymbolsLoading; if (data->ThreadProvider->Terminating) goto Done; newSymbolsLoading = _InterlockedIncrement(&data->ThreadProvider->SymbolsLoading); if (newSymbolsLoading == 1) PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)TRUE); if (data->ThreadProvider->SymbolsLoadedRunId == 0) PhLoadSymbolsThreadProvider(data->ThreadProvider); data->StartAddressString = PhGetSymbolFromAddress( data->ThreadProvider->SymbolProvider, data->ThreadItem->StartAddress, &data->StartAddressResolveLevel, &data->ThreadItem->StartAddressFileName, NULL, NULL ); if (data->StartAddressResolveLevel == PhsrlAddress && data->ThreadProvider->SymbolsLoadedRunId < data->RunId) { // The process may have loaded new modules, so load symbols for those and try again. PhLoadSymbolsThreadProvider(data->ThreadProvider); PhClearReference(&data->StartAddressString); PhClearReference(&data->ThreadItem->StartAddressFileName); data->StartAddressString = PhGetSymbolFromAddress( data->ThreadProvider->SymbolProvider, data->ThreadItem->StartAddress, &data->StartAddressResolveLevel, &data->ThreadItem->StartAddressFileName, NULL, NULL ); } newSymbolsLoading = _InterlockedDecrement(&data->ThreadProvider->SymbolsLoading); if (newSymbolsLoading == 0) PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)FALSE); // Check if the process has services - we'll need to know before getting service tag/name // information. if (WINDOWS_HAS_SERVICE_TAGS && !data->ThreadProvider->HasServicesKnown) { PPH_PROCESS_ITEM processItem; if (processItem = PhReferenceProcessItem(data->ThreadProvider->ProcessId)) { data->ThreadProvider->HasServices = processItem->ServiceList && processItem->ServiceList->Count != 0; PhDereferenceObject(processItem); } data->ThreadProvider->HasServicesKnown = TRUE; } // Get the service tag, and the service name. if (WINDOWS_HAS_SERVICE_TAGS && data->ThreadProvider->SymbolProvider->IsRealHandle && data->ThreadItem->ThreadHandle) { PVOID serviceTag; if (NT_SUCCESS(PhGetThreadServiceTag( data->ThreadItem->ThreadHandle, data->ThreadProvider->ProcessHandle, &serviceTag ))) { data->ServiceName = PhGetServiceNameFromTag( data->ThreadProvider->ProcessId, serviceTag ); } } Done: RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry); PhDereferenceObject(data->ThreadProvider); return STATUS_SUCCESS; }
INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( __in HWND hwndDlg, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam; HANDLE workerFactoryHandle; if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&workerFactoryHandle, WORKER_FACTORY_QUERY_INFORMATION, context))) { WORKER_FACTORY_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(NtQueryInformationWorkerFactory( workerFactoryHandle, WorkerFactoryBasicInformation, &basicInfo, sizeof(WORKER_FACTORY_BASIC_INFORMATION), NULL ))) { PPH_SYMBOL_PROVIDER symbolProvider; PPH_STRING symbol = NULL; symbolProvider = PhCreateSymbolProvider(basicInfo.ProcessId); PhLoadSymbolProviderOptions(symbolProvider); if (symbolProvider->IsRealHandle) { PhEnumGenericModules(basicInfo.ProcessId, symbolProvider->ProcessHandle, 0, EnumGenericModulesCallback, symbolProvider); symbol = PhGetSymbolFromAddress(symbolProvider, (ULONG64)basicInfo.StartRoutine, NULL, NULL, NULL, NULL); } PhDereferenceObject(symbolProvider); if (symbol) { SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, PhaFormatString(L"Worker Thread Start: %s", symbol->Buffer)->Buffer); PhDereferenceObject(symbol); } else { SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, PhaFormatString(L"Worker Thread Start: 0x%Ix", basicInfo.StartRoutine)->Buffer); } SetDlgItemText(hwndDlg, IDC_WORKERTHREADCONTEXT, PhaFormatString(L"Worker Thread Context: 0x%Ix", basicInfo.StartParameter)->Buffer); } NtClose(workerFactoryHandle); } } break; } return FALSE; }
static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( _In_ PPH_THREAD_STACK_FRAME StackFrame, _In_opt_ PVOID Context ) { PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context; PPH_STRING name; name = PhGetSymbolFromAddress( context->SymbolProvider, (ULONG64)StackFrame->PcAddress, NULL, NULL, NULL, NULL ); if (!name) return TRUE; context->Found = TRUE; #define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE) #define NT_FUNC_MATCH(Name) ( \ PhStartsWithString2(name, L"ntdll.dll!Nt" L##Name, TRUE) || \ PhStartsWithString2(name, L"ntdll.dll!Zw" L##Name, TRUE) \ ) if (!name) { // Dummy } else if (FUNC_MATCH("kernel32.dll!Sleep")) { PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is sleeping. Timeout: %lu milliseconds.", PtrToUlong(StackFrame->Params[0]) ); } else if (NT_FUNC_MATCH("DelayExecution")) { BOOLEAN alertable = !!StackFrame->Params[0]; PVOID timeoutAddress = StackFrame->Params[1]; LARGE_INTEGER timeout; if (NT_SUCCESS(NtReadVirtualMemory( context->ProcessHandle, timeoutAddress, &timeout, sizeof(LARGE_INTEGER), NULL ))) { if (timeout.QuadPart < 0) { PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is sleeping. Timeout: %I64u milliseconds.", -timeout.QuadPart / PH_TIMEOUT_MS ); } else { // TODO } } else { PhAppendStringBuilder2( &context->StringBuilder, L"Thread is sleeping." ); } } else if (NT_FUNC_MATCH("DeviceIoControlFile")) { HANDLE handle = (HANDLE)StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for an I/O control request:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("FsControlFile")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for a FS control request:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("QueryObject")) { HANDLE handle = StackFrame->Params[0]; // Use the KiFastSystemCall args if the handle we have is wrong. if ((ULONG_PTR)handle % 4 != 0 || !handle) handle = context->PrevParams[1]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is querying an object:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("ReadFile") || NT_FUNC_MATCH("WriteFile")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for file I/O:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("RemoveIoCompletion")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for an I/O completion port:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( NT_FUNC_MATCH("ReplyWaitReceivePort") || NT_FUNC_MATCH("RequestWaitReplyPort") || NT_FUNC_MATCH("AlpcSendWaitReceivePort") ) { HANDLE handle = StackFrame->Params[0]; PPH_STRING alpcInfo; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for an ALPC port:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId)) { PhAppendStringBuilder2( &context->StringBuilder, L"\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &alpcInfo->sr ); } } else if ( NT_FUNC_MATCH("SetHighWaitLowEventPair") || NT_FUNC_MATCH("SetLowWaitHighEventPair") || NT_FUNC_MATCH("WaitHighEventPair") || NT_FUNC_MATCH("WaitLowEventPair") ) { HANDLE handle = StackFrame->Params[0]; if ((ULONG_PTR)handle % 4 != 0 || !handle) handle = context->PrevParams[1]; PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is waiting (%s) for an event pair:\r\n", name->Buffer ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( FUNC_MATCH("user32.dll!NtUserGetMessage") || FUNC_MATCH("user32.dll!NtUserWaitMessage") ) { PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for a USER message.\r\n" ); } else if (FUNC_MATCH("user32.dll!NtUserMessageCall")) { PPH_STRING receiverString; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is sending a USER message:\r\n" ); receiverString = PhpaGetSendMessageReceiver(context->ThreadId); if (receiverString) { PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr); PhAppendStringBuilder2(&context->StringBuilder, L"\r\n"); } else { PhAppendStringBuilder2(&context->StringBuilder, L"Unknown.\r\n"); } } else if (NT_FUNC_MATCH("WaitForDebugEvent")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for a debug event:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( NT_FUNC_MATCH("WaitForKeyedEvent") || NT_FUNC_MATCH("ReleaseKeyedEvent") ) { HANDLE handle = StackFrame->Params[0]; PVOID key = StackFrame->Params[1]; PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is waiting (%s) for a keyed event (key 0x%Ix):\r\n", name->Buffer, key ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( NT_FUNC_MATCH("WaitForMultipleObjects") || FUNC_MATCH("kernel32.dll!WaitForMultipleObjects") ) { ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]); PVOID addressOfHandles = StackFrame->Params[1]; WAIT_TYPE waitType = (WAIT_TYPE)StackFrame->Params[2]; BOOLEAN alertable = !!StackFrame->Params[3]; if (numberOfHandles > MAXIMUM_WAIT_OBJECTS) { numberOfHandles = PtrToUlong(context->PrevParams[1]); addressOfHandles = context->PrevParams[2]; waitType = (WAIT_TYPE)context->PrevParams[3]; alertable = FALSE; } PhpGetWfmoInformation( context->ProcessHandle, TRUE, // on x64 this function is only called for WOW64 processes numberOfHandles, addressOfHandles, waitType, alertable, &context->StringBuilder ); } else if ( NT_FUNC_MATCH("WaitForSingleObject") || FUNC_MATCH("kernel32.dll!WaitForSingleObject") ) { HANDLE handle = StackFrame->Params[0]; BOOLEAN alertable = !!StackFrame->Params[1]; if ((ULONG_PTR)handle % 4 != 0 || !handle) { handle = context->PrevParams[1]; alertable = !!context->PrevParams[2]; } PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is waiting (%s) for:\r\n", alertable ? L"alertable" : L"non-alertable" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("WaitForWorkViaWorkerFactory")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for work from a worker factory:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else { context->Found = FALSE; } PhDereferenceObject(name); memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params)); return !context->Found; }