static NTSTATUS NTAPI TerminatorTT2( _In_ HANDLE ProcessId ) { NTSTATUS status; PVOID processes; PSYSTEM_PROCESS_INFORMATION process; ULONG i; CONTEXT context; PVOID exitProcess; exitProcess = GetExitProcessFunction(); if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) return status; process = PhFindProcessInformation(processes, ProcessId); if (!process) { PhFree(processes); return STATUS_INVALID_CID; } for (i = 0; i < process->NumberOfThreads; i++) { HANDLE threadHandle; if (NT_SUCCESS(PhOpenThread( &threadHandle, THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, process->Threads[i].ClientId.UniqueThread ))) { #ifdef _M_IX86 context.ContextFlags = CONTEXT_CONTROL; PhGetThreadContext(threadHandle, &context); context.Eip = (ULONG)exitProcess; PhSetThreadContext(threadHandle, &context); #else context.ContextFlags = CONTEXT_CONTROL; PhGetThreadContext(threadHandle, &context); context.Rip = (ULONG64)exitProcess; PhSetThreadContext(threadHandle, &context); #endif NtClose(threadHandle); } } PhFree(processes); return STATUS_SUCCESS; }
static BOOLEAN PhpWaitUntilThreadIsWaiting( _In_ HANDLE ThreadHandle ) { ULONG attempts; BOOLEAN isWaiting = FALSE; THREAD_BASIC_INFORMATION basicInfo; if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) return FALSE; for (attempts = 0; attempts < 20; attempts++) { PVOID processes; PSYSTEM_PROCESS_INFORMATION processInfo; ULONG i; PhDelayExecution(100); if (!NT_SUCCESS(PhEnumProcesses(&processes))) break; processInfo = PhFindProcessInformation(processes, basicInfo.ClientId.UniqueProcess); if (processInfo) { for (i = 0; i < processInfo->NumberOfThreads; i++) { if ( processInfo->Threads[i].ClientId.UniqueThread == basicInfo.ClientId.UniqueThread && processInfo->Threads[i].ThreadState == Waiting && (processInfo->Threads[i].WaitReason == UserRequest || processInfo->Threads[i].WaitReason == Executive) ) { isWaiting = TRUE; break; } } } PhFree(processes); if (isWaiting) break; PhDelayExecution(500); } return isWaiting; }
static NTSTATUS NTAPI TerminatorTTGeneric( _In_ HANDLE ProcessId, _In_ BOOLEAN UseKph, _In_ BOOLEAN UseKphDangerous ) { NTSTATUS status; PVOID processes; PSYSTEM_PROCESS_INFORMATION process; ULONG i; if ((UseKph || UseKphDangerous) && !KphIsConnected()) return STATUS_NOT_SUPPORTED; if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) return status; process = PhFindProcessInformation(processes, ProcessId); if (!process) { PhFree(processes); return STATUS_INVALID_CID; } for (i = 0; i < process->NumberOfThreads; i++) { HANDLE threadHandle; if (NT_SUCCESS(PhOpenThread( &threadHandle, THREAD_TERMINATE, process->Threads[i].ClientId.UniqueThread ))) { if (UseKphDangerous) KphTerminateThreadUnsafe(threadHandle, STATUS_SUCCESS); else if (UseKph) KphTerminateThread(threadHandle, STATUS_SUCCESS); else NtTerminateThread(threadHandle, STATUS_SUCCESS); NtClose(threadHandle); } } PhFree(processes); return STATUS_SUCCESS; }
BOOLEAN IsProcessSuspended( _In_ HANDLE ProcessId ) { PVOID processes; PSYSTEM_PROCESS_INFORMATION process; if (NT_SUCCESS(PhEnumProcesses(&processes))) { if (process = PhFindProcessInformation(processes, ProcessId)) return PhGetProcessIsSuspended(process); PhFree(processes); } return FALSE; }
VOID PhpThreadProviderUpdate( __in PPH_THREAD_PROVIDER ThreadProvider, __in PVOID ProcessInformation ) { PPH_THREAD_PROVIDER threadProvider = ThreadProvider; PSYSTEM_PROCESS_INFORMATION process; SYSTEM_PROCESS_INFORMATION localProcess; PSYSTEM_THREAD_INFORMATION threads; ULONG numberOfThreads; ULONG i; process = PhFindProcessInformation(ProcessInformation, threadProvider->ProcessId); if (!process) { // The process doesn't exist anymore. Pretend it does but // has no threads. process = &localProcess; process->NumberOfThreads = 0; } threads = process->Threads; numberOfThreads = process->NumberOfThreads; // System Idle Process has one thread per CPU. // They all have a TID of 0, but we can't have // multiple TIDs, so we'll assign unique TIDs. if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID) { for (i = 0; i < numberOfThreads; i++) { threads[i].ClientId.UniqueThread = (HANDLE)i; } } // Look for dead threads. { PPH_LIST threadsToRemove = NULL; ULONG enumerationKey = 0; PPH_THREAD_ITEM *threadItem; while (PhEnumHashtable(threadProvider->ThreadHashtable, (PPVOID)&threadItem, &enumerationKey)) { BOOLEAN found = FALSE; // Check if the thread still exists. for (i = 0; i < numberOfThreads; i++) { PSYSTEM_THREAD_INFORMATION thread = &threads[i]; if ((*threadItem)->ThreadId == thread->ClientId.UniqueThread) { found = TRUE; break; } } if (!found) { // Raise the thread removed event. PhInvokeCallback(&threadProvider->ThreadRemovedEvent, *threadItem); if (!threadsToRemove) threadsToRemove = PhCreateList(2); PhAddItemList(threadsToRemove, *threadItem); } } if (threadsToRemove) { PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); for (i = 0; i < threadsToRemove->Count; i++) { PhpRemoveThreadItem( threadProvider, (PPH_THREAD_ITEM)threadsToRemove->Items[i] ); } PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); PhDereferenceObject(threadsToRemove); } } // Go through the queued thread query data. { PSLIST_ENTRY entry; PPH_THREAD_QUERY_DATA data; entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead); while (entry) { data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); entry = entry->Next; if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString) { PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString); data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel; } PhSwapReference2(&data->ThreadItem->ServiceName, data->ServiceName); data->ThreadItem->JustResolved = TRUE; if (data->StartAddressString) PhDereferenceObject(data->StartAddressString); PhDereferenceObject(data->ThreadItem); PhFree(data); } } // Look for new threads and update existing ones. for (i = 0; i < numberOfThreads; i++) { PSYSTEM_THREAD_INFORMATION thread = &threads[i]; PPH_THREAD_ITEM threadItem; threadItem = PhReferenceThreadItem(threadProvider, thread->ClientId.UniqueThread); if (!threadItem) { ULONG64 cycles; PVOID startAddress = NULL; threadItem = PhCreateThreadItem(thread->ClientId.UniqueThread); threadItem->CreateTime = thread->CreateTime; threadItem->KernelTime = thread->KernelTime; threadItem->UserTime = thread->UserTime; PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); threadItem->Priority = thread->Priority; threadItem->BasePriority = thread->BasePriority; threadItem->State = (KTHREAD_STATE)thread->ThreadState; threadItem->WaitReason = thread->WaitReason; // Try to open a handle to the thread. if (!NT_SUCCESS(PhOpenThread( &threadItem->ThreadHandle, THREAD_QUERY_INFORMATION, threadItem->ThreadId ))) { PhOpenThread( &threadItem->ThreadHandle, ThreadQueryAccess, threadItem->ThreadId ); } // Get the cycle count. if (NT_SUCCESS(PhpGetThreadCycleTime( threadProvider, threadItem, &cycles ))) { PhUpdateDelta(&threadItem->CyclesDelta, cycles); } // Initialize the CPU time deltas. PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); // Try to get the start address. if (threadItem->ThreadHandle) { NtQueryInformationThread( threadItem->ThreadHandle, ThreadQuerySetWin32StartAddress, &startAddress, sizeof(PVOID), NULL ); } if (!startAddress) startAddress = thread->StartAddress; threadItem->StartAddress = (ULONG64)startAddress; // Get the Win32 priority. threadItem->PriorityWin32 = GetThreadPriority(threadItem->ThreadHandle); if (PhTestEvent(&threadProvider->SymbolsLoadedEvent)) { threadItem->StartAddressString = PhpGetThreadBasicStartAddress( threadProvider, threadItem->StartAddress, &threadItem->StartAddressResolveLevel ); } if (!threadItem->StartAddressString) { threadItem->StartAddressResolveLevel = PhsrlAddress; threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); PhPrintPointer( threadItem->StartAddressString->Buffer, (PVOID)threadItem->StartAddress ); PhTrimToNullTerminatorString(threadItem->StartAddressString); } PhpQueueThreadQuery(threadProvider, threadItem); // Is it a GUI thread? if (threadItem->ThreadHandle && KphIsConnected()) { PVOID win32Thread; if (NT_SUCCESS(KphQueryInformationThread( threadItem->ThreadHandle, KphThreadWin32Thread, &win32Thread, sizeof(PVOID), NULL ))) { threadItem->IsGuiThread = win32Thread != NULL; } } // Add the thread item to the hashtable. PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem); PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); // Raise the thread added event. PhInvokeCallback(&threadProvider->ThreadAddedEvent, threadItem); } else { BOOLEAN modified = FALSE; if (threadItem->JustResolved) modified = TRUE; threadItem->KernelTime = thread->KernelTime; threadItem->UserTime = thread->UserTime; threadItem->Priority = thread->Priority; threadItem->BasePriority = thread->BasePriority; threadItem->State = (KTHREAD_STATE)thread->ThreadState; if (threadItem->WaitReason != thread->WaitReason) { threadItem->WaitReason = thread->WaitReason; modified = TRUE; } // If the resolve level is only at address, it probably // means symbols weren't loaded the last time we // tried to get the start address. Try again. if (threadItem->StartAddressResolveLevel == PhsrlAddress) { if (PhTestEvent(&threadProvider->SymbolsLoadedEvent)) { PPH_STRING newStartAddressString; newStartAddressString = PhpGetThreadBasicStartAddress( threadProvider, threadItem->StartAddress, &threadItem->StartAddressResolveLevel ); PhSwapReference2( &threadItem->StartAddressString, newStartAddressString ); modified = TRUE; } } // If we couldn't resolve the start address to a // module+offset, use the StartAddress instead // of the Win32StartAddress and try again. // Note that we check the resolve level again // because we may have changed it in the previous // block. if ( threadItem->JustResolved && threadItem->StartAddressResolveLevel == PhsrlAddress ) { if (threadItem->StartAddress != (ULONG64)thread->StartAddress) { threadItem->StartAddress = (ULONG64)thread->StartAddress; PhpQueueThreadQuery(threadProvider, threadItem); } } // Update the context switch count. { ULONG oldDelta; oldDelta = threadItem->ContextSwitchesDelta.Delta; PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); if (threadItem->ContextSwitchesDelta.Delta != oldDelta) { modified = TRUE; } } // Update the cycle count. { ULONG64 cycles; ULONG64 oldDelta; oldDelta = threadItem->CyclesDelta.Delta; if (NT_SUCCESS(PhpGetThreadCycleTime( threadProvider, threadItem, &cycles ))) { PhUpdateDelta(&threadItem->CyclesDelta, cycles); if (threadItem->CyclesDelta.Delta != oldDelta) { modified = TRUE; } } } // Update the CPU time deltas. PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); // Update the CPU usage. // If the cycle time isn't available, we'll fall back to using the CPU time. if (PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)) { threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta; } else { threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) / (PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta); } // Update the Win32 priority. { LONG oldPriorityWin32 = threadItem->PriorityWin32; threadItem->PriorityWin32 = GetThreadPriority(threadItem->ThreadHandle); if (threadItem->PriorityWin32 != oldPriorityWin32) { modified = TRUE; } } // Update the GUI thread status. if (threadItem->ThreadHandle && KphIsConnected()) { PVOID win32Thread; if (NT_SUCCESS(KphQueryInformationThread( threadItem->ThreadHandle, KphThreadWin32Thread, &win32Thread, sizeof(PVOID), NULL ))) { BOOLEAN oldIsGuiThread = threadItem->IsGuiThread; threadItem->IsGuiThread = win32Thread != NULL; if (threadItem->IsGuiThread != oldIsGuiThread) modified = TRUE; } } threadItem->JustResolved = FALSE; if (modified) { // Raise the thread modified event. PhInvokeCallback(&threadProvider->ThreadModifiedEvent, threadItem); } PhDereferenceObject(threadItem); } } PhInvokeCallback(&threadProvider->UpdatedEvent, NULL); threadProvider->RunId++; }
__callback PPH_STRING PhStdGetClientIdName( __in PCLIENT_ID ClientId ) { static PH_QUEUED_LOCK cachedProcessesLock = PH_QUEUED_LOCK_INIT; static PVOID processes = NULL; static ULONG lastProcessesTickCount = 0; PPH_STRING name; ULONG tickCount; PSYSTEM_PROCESS_INFORMATION processInfo; // Get a new process list only if 2 seconds have passed // since the last update. tickCount = GetTickCount(); if (tickCount - lastProcessesTickCount >= 2000) { PhAcquireQueuedLockExclusive(&cachedProcessesLock); // Re-check the tick count. if (tickCount - lastProcessesTickCount >= 2000) { if (processes) { PhFree(processes); processes = NULL; } if (!NT_SUCCESS(PhEnumProcesses(&processes))) { PhReleaseQueuedLockExclusive(&cachedProcessesLock); return PhCreateString(L"(Error querying processes)"); } lastProcessesTickCount = tickCount; } PhReleaseQueuedLockExclusive(&cachedProcessesLock); } // Get a lock on the process list and get a name for the client ID. PhAcquireQueuedLockShared(&cachedProcessesLock); if (!processes) { PhReleaseQueuedLockShared(&cachedProcessesLock); return NULL; } processInfo = PhFindProcessInformation(processes, ClientId->UniqueProcess); if (ClientId->UniqueThread) { if (processInfo) { name = PhFormatString( L"%.*s (%u): %u", processInfo->ImageName.Length / 2, processInfo->ImageName.Buffer, (ULONG)ClientId->UniqueProcess, (ULONG)ClientId->UniqueThread ); } else { name = PhFormatString(L"Non-existent process (%u): %u", (ULONG)ClientId->UniqueProcess, (ULONG)ClientId->UniqueThread); } } else { if (processInfo) { name = PhFormatString( L"%.*s (%u)", processInfo->ImageName.Length / 2, processInfo->ImageName.Buffer, (ULONG)ClientId->UniqueProcess ); } else { name = PhFormatString(L"Non-existent process (%u)", (ULONG)ClientId->UniqueProcess); } } PhReleaseQueuedLockShared(&cachedProcessesLock); return name; }
static BOOLEAN PhpRunTerminatorTest( _In_ HWND WindowHandle, _In_ INT Index ) { NTSTATUS status; PTEST_ITEM testItem; PPH_PROCESS_ITEM processItem; HWND lvHandle; PVOID processes; BOOLEAN success = FALSE; LARGE_INTEGER interval; processItem = (PPH_PROCESS_ITEM)GetProp(WindowHandle, L"ProcessItem"); lvHandle = GetDlgItem(WindowHandle, IDC_TERMINATOR_LIST); if (!PhGetListViewItemParam( lvHandle, Index, &testItem )) return FALSE; if (WSTR_EQUAL(testItem->Id, L"TT4")) { if (!PhShowConfirmMessage( WindowHandle, L"run", L"the TT4 test", L"The TT4 test may cause the system to crash.", TRUE )) return FALSE; } status = testItem->TestProc(processItem->ProcessId); interval.QuadPart = -1000 * PH_TIMEOUT_MS; NtDelayExecution(FALSE, &interval); if (status == STATUS_NOT_SUPPORTED) { PPH_STRING concat; concat = PhConcatStrings2(L"(Not available) ", testItem->Description); PhSetListViewSubItem(lvHandle, Index, 1, concat->Buffer); PhDereferenceObject(concat); } if (!NT_SUCCESS(PhEnumProcesses(&processes))) return FALSE; // Check if the process exists. if (!PhFindProcessInformation(processes, processItem->ProcessId)) { PhSetListViewItemImageIndex(lvHandle, Index, TICK_INDEX); SetDlgItemText(WindowHandle, IDC_TERMINATOR_TEXT, L"The process was terminated."); success = TRUE; } else { PhSetListViewItemImageIndex(lvHandle, Index, CROSS_INDEX); } PhFree(processes); UpdateWindow(WindowHandle); return success; }