NTSTATUS RunAsTrustedInstallerThread( _In_ PVOID Parameter ) { NTSTATUS status; HANDLE threadHandle; THREAD_BASIC_INFORMATION basicInfo; if (threadHandle = PhCreateThread(0, RunAsCreateProcessThread, NULL)) { NtWaitForSingleObject(threadHandle, FALSE, NULL); status = PhGetThreadBasicInformation(threadHandle, &basicInfo); if (NT_SUCCESS(status)) { status = basicInfo.ExitStatus; } if (!NT_SUCCESS(status)) { PhShowStatus( PhMainWndHandle, L"Error creating process with TrustedInstaller privileges", basicInfo.ExitStatus, 0 ); } NtClose(threadHandle); } 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; }
NTSTATUS PhGetThreadServiceTag( _In_ HANDLE ThreadHandle, _In_opt_ HANDLE ProcessHandle, _Out_ PVOID *ServiceTag ) { NTSTATUS status; THREAD_BASIC_INFORMATION basicInfo; BOOLEAN openedProcessHandle = FALSE; if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) return status; if (!ProcessHandle) { if (!NT_SUCCESS(status = PhOpenThreadProcess( ThreadHandle, PROCESS_VM_READ, &ProcessHandle ))) return status; openedProcessHandle = TRUE; } status = NtReadVirtualMemory( ProcessHandle, PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)), ServiceTag, sizeof(PVOID), NULL ); if (openedProcessHandle) NtClose(ProcessHandle); return status; }
VOID PhpInitializeThreadMenu( _In_ PPH_EMENU Menu, _In_ HANDLE ProcessId, _In_ PPH_THREAD_ITEM *Threads, _In_ ULONG NumberOfThreads ) { PPH_EMENU_ITEM item; if (NumberOfThreads == 0) { PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); } else if (NumberOfThreads == 1) { // All menu items are enabled by default. } else { ULONG menuItemsMultiEnabled[] = { ID_THREAD_TERMINATE, ID_THREAD_SUSPEND, ID_THREAD_RESUME, ID_THREAD_COPY }; ULONG i; PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); // These menu items are capable of manipulating // multiple threads. for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++) { PhEnableEMenuItem(Menu, menuItemsMultiEnabled[i], TRUE); } } // Remove irrelevant menu items. if (WindowsVersion < WINDOWS_VISTA) { // Remove I/O priority. if (item = PhFindEMenuItem(Menu, 0, L"I/O Priority", 0)) PhDestroyEMenuItem(item); // Remove page priority. if (item = PhFindEMenuItem(Menu, 0, L"Page Priority", 0)) PhDestroyEMenuItem(item); } PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, FALSE); // Priority if (NumberOfThreads == 1) { HANDLE threadHandle; ULONG threadPriority = THREAD_PRIORITY_ERROR_RETURN; IO_PRIORITY_HINT ioPriority = -1; ULONG pagePriority = -1; ULONG id = 0; if (NT_SUCCESS(PhOpenThread( &threadHandle, ThreadQueryAccess, Threads[0]->ThreadId ))) { THREAD_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(PhGetThreadBasicInformation(threadHandle, &basicInfo))) { threadPriority = basicInfo.BasePriority; } if (WindowsVersion >= WINDOWS_VISTA) { PhGetThreadIoPriority(threadHandle, &ioPriority); PhGetThreadPagePriority(threadHandle, &pagePriority); } // Token { HANDLE tokenHandle; if (NT_SUCCESS(NtOpenThreadToken( threadHandle, TOKEN_QUERY, TRUE, &tokenHandle ))) { PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, TRUE); NtClose(tokenHandle); } } NtClose(threadHandle); } switch (threadPriority) { case THREAD_PRIORITY_TIME_CRITICAL + 1: case THREAD_PRIORITY_TIME_CRITICAL: id = ID_PRIORITY_TIMECRITICAL; break; case THREAD_PRIORITY_HIGHEST: id = ID_PRIORITY_HIGHEST; break; case THREAD_PRIORITY_ABOVE_NORMAL: id = ID_PRIORITY_ABOVENORMAL; break; case THREAD_PRIORITY_NORMAL: id = ID_PRIORITY_NORMAL; break; case THREAD_PRIORITY_BELOW_NORMAL: id = ID_PRIORITY_BELOWNORMAL; break; case THREAD_PRIORITY_LOWEST: id = ID_PRIORITY_LOWEST; break; case THREAD_PRIORITY_IDLE: case THREAD_PRIORITY_IDLE - 1: id = ID_PRIORITY_IDLE; break; } if (id != 0) { PhSetFlagsEMenuItem(Menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); } if (ioPriority != -1) { id = 0; switch (ioPriority) { case IoPriorityVeryLow: id = ID_IOPRIORITY_VERYLOW; break; case IoPriorityLow: id = ID_IOPRIORITY_LOW; break; case IoPriorityNormal: id = ID_IOPRIORITY_NORMAL; break; case IoPriorityHigh: id = ID_IOPRIORITY_HIGH; break; } if (id != 0) { PhSetFlagsEMenuItem(Menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); } } if (pagePriority != -1) { id = 0; switch (pagePriority) { case MEMORY_PRIORITY_VERY_LOW: id = ID_PAGEPRIORITY_VERYLOW; break; case MEMORY_PRIORITY_LOW: id = ID_PAGEPRIORITY_LOW; break; case MEMORY_PRIORITY_MEDIUM: id = ID_PAGEPRIORITY_MEDIUM; break; case MEMORY_PRIORITY_BELOW_NORMAL: id = ID_PAGEPRIORITY_BELOWNORMAL; break; case MEMORY_PRIORITY_NORMAL: id = ID_PAGEPRIORITY_NORMAL; break; } if (id != 0) { PhSetFlagsEMenuItem(Menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); } } } }
NTSTATUS PhpGetBestObjectName( __in HANDLE ProcessHandle, __in HANDLE Handle, __in PPH_STRING ObjectName, __in PPH_STRING TypeName, __out PPH_STRING *BestObjectName ) { NTSTATUS status; PPH_STRING bestObjectName = NULL; PPH_GET_CLIENT_ID_NAME handleGetClientIdName; if (PhEqualString2(TypeName, L"EtwRegistration", TRUE)) { if (KphIsConnected()) { ETWREG_BASIC_INFORMATION basicInfo; status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectEtwRegBasicInformation, &basicInfo, sizeof(ETWREG_BASIC_INFORMATION), NULL ); if (NT_SUCCESS(status)) { static PH_STRINGREF publishersKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\"); PPH_STRING guidString; PPH_STRING keyName; HANDLE keyHandle; PPH_STRING publisherName = NULL; guidString = PhFormatGuid(&basicInfo.Guid); // We should perform a lookup on the GUID to get the publisher name. keyName = PhConcatStringRef2(&publishersKeyName, &guidString->sr); if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &keyName->sr, 0 ))) { publisherName = PhQueryRegistryString(keyHandle, NULL); if (publisherName && publisherName->Length == 0) { PhDereferenceObject(publisherName); publisherName = NULL; } NtClose(keyHandle); } PhDereferenceObject(keyName); if (publisherName) { bestObjectName = publisherName; PhDereferenceObject(guidString); } else { bestObjectName = guidString; } } } } else if (PhEqualString2(TypeName, L"File", TRUE)) { // Convert the file name to a DOS file name. bestObjectName = PhResolveDevicePrefix(ObjectName); if (!bestObjectName) { bestObjectName = ObjectName; PhReferenceObject(ObjectName); } } else if (PhEqualString2(TypeName, L"Key", TRUE)) { bestObjectName = PhFormatNativeKeyName(ObjectName); } else if (PhEqualString2(TypeName, L"Process", TRUE)) { CLIENT_ID clientId; clientId.UniqueThread = NULL; if (KphIsConnected()) { PROCESS_BASIC_INFORMATION basicInfo; status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectProcessBasicInformation, &basicInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL ); if (!NT_SUCCESS(status)) goto CleanupExit; clientId.UniqueProcess = basicInfo.UniqueProcessId; } else { HANDLE dupHandle; PROCESS_BASIC_INFORMATION basicInfo; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, ProcessQueryAccess, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetProcessBasicInformation(dupHandle, &basicInfo); NtClose(dupHandle); if (!NT_SUCCESS(status)) goto CleanupExit; clientId.UniqueProcess = basicInfo.UniqueProcessId; } handleGetClientIdName = PhHandleGetClientIdName; if (handleGetClientIdName) bestObjectName = handleGetClientIdName(&clientId); } else if (PhEqualString2(TypeName, L"Thread", TRUE)) { CLIENT_ID clientId; if (KphIsConnected()) { THREAD_BASIC_INFORMATION basicInfo; status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectThreadBasicInformation, &basicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL ); if (!NT_SUCCESS(status)) goto CleanupExit; clientId = basicInfo.ClientId; } else { HANDLE dupHandle; THREAD_BASIC_INFORMATION basicInfo; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, ThreadQueryAccess, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetThreadBasicInformation(dupHandle, &basicInfo); NtClose(dupHandle); if (!NT_SUCCESS(status)) goto CleanupExit; clientId = basicInfo.ClientId; } handleGetClientIdName = PhHandleGetClientIdName; if (handleGetClientIdName) bestObjectName = handleGetClientIdName(&clientId); } else if (PhEqualString2(TypeName, L"TmEn", TRUE)) { HANDLE dupHandle; ENLISTMENT_BASIC_INFORMATION basicInfo; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, ENLISTMENT_QUERY_INFORMATION, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetEnlistmentBasicInformation(dupHandle, &basicInfo); NtClose(dupHandle); if (NT_SUCCESS(status)) { bestObjectName = PhFormatGuid(&basicInfo.EnlistmentId); } } else if (PhEqualString2(TypeName, L"TmRm", TRUE)) { HANDLE dupHandle; GUID guid; PPH_STRING description; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, RESOURCEMANAGER_QUERY_INFORMATION, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetResourceManagerBasicInformation( dupHandle, &guid, &description ); NtClose(dupHandle); if (NT_SUCCESS(status)) { if (!PhIsNullOrEmptyString(description)) { bestObjectName = description; } else { bestObjectName = PhFormatGuid(&guid); if (description) PhDereferenceObject(description); } } } else if (PhEqualString2(TypeName, L"TmTm", TRUE)) { HANDLE dupHandle; PPH_STRING logFileName = NULL; TRANSACTIONMANAGER_BASIC_INFORMATION basicInfo; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, TRANSACTIONMANAGER_QUERY_INFORMATION, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetTransactionManagerLogFileName( dupHandle, &logFileName ); if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(logFileName)) { bestObjectName = PhGetFileName(logFileName); PhDereferenceObject(logFileName); } else { if (logFileName) PhDereferenceObject(logFileName); status = PhGetTransactionManagerBasicInformation( dupHandle, &basicInfo ); if (NT_SUCCESS(status)) { bestObjectName = PhFormatGuid(&basicInfo.TmIdentity); } } NtClose(dupHandle); } else if (PhEqualString2(TypeName, L"TmTx", TRUE)) { HANDLE dupHandle; PPH_STRING description = NULL; TRANSACTION_BASIC_INFORMATION basicInfo; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, TRANSACTION_QUERY_INFORMATION, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetTransactionPropertiesInformation( dupHandle, NULL, NULL, &description ); if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(description)) { bestObjectName = description; } else { if (description) PhDereferenceObject(description); status = PhGetTransactionBasicInformation( dupHandle, &basicInfo ); if (NT_SUCCESS(status)) { bestObjectName = PhFormatGuid(&basicInfo.TransactionId); } } NtClose(dupHandle); } else if (PhEqualString2(TypeName, L"Token", TRUE)) { HANDLE dupHandle; PTOKEN_USER tokenUser = NULL; TOKEN_STATISTICS statistics = { 0 }; status = NtDuplicateObject( ProcessHandle, Handle, NtCurrentProcess(), &dupHandle, TOKEN_QUERY, 0, 0 ); if (!NT_SUCCESS(status)) goto CleanupExit; status = PhGetTokenUser(dupHandle, &tokenUser); PhGetTokenStatistics(dupHandle, &statistics); if (NT_SUCCESS(status)) { PPH_STRING fullName; fullName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); if (fullName) { PH_FORMAT format[3]; PhInitFormatSR(&format[0], fullName->sr); PhInitFormatS(&format[1], L": 0x"); PhInitFormatX(&format[2], statistics.AuthenticationId.LowPart); bestObjectName = PhFormat(format, 3, fullName->Length + 8 + 16); PhDereferenceObject(fullName); } PhFree(tokenUser); } NtClose(dupHandle); } CleanupExit: if (!bestObjectName) { bestObjectName = ObjectName; PhReferenceObject(ObjectName); } *BestObjectName = bestObjectName; return STATUS_SUCCESS; }
VOID PhShowHandleObjectProperties1( _In_ HWND hWnd, _In_ PPH_HANDLE_ITEM_INFO Info ) { if (PhIsNullOrEmptyString(Info->TypeName)) return; if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) || PhEqualString2(Info->TypeName, L"Mapped file", TRUE) || PhEqualString2(Info->TypeName, L"Mapped image", TRUE)) { if (Info->BestObjectName) { PhShellExecuteUserString( PhMainWndHandle, L"FileBrowseExecutable", Info->BestObjectName->Buffer, FALSE, L"Make sure the Explorer executable file is present." ); } else PhShowError(hWnd, L"Unable to open file location because the object is unnamed."); } else if (PhEqualString2(Info->TypeName, L"Key", TRUE)) { if (Info->BestObjectName) PhShellOpenKey2(hWnd, Info->BestObjectName); else PhShowError(hWnd, L"Unable to open key because the object is unnamed."); } else if (PhEqualString2(Info->TypeName, L"Process", TRUE)) { HANDLE processHandle; HANDLE processId; PPH_PROCESS_ITEM targetProcessItem; processId = NULL; if (KphIsConnected()) { if (NT_SUCCESS(PhOpenProcess( &processHandle, PROCESS_QUERY_LIMITED_INFORMATION, Info->ProcessId ))) { PROCESS_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(KphQueryInformationObject( processHandle, Info->Handle, KphObjectProcessBasicInformation, &basicInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL ))) { processId = basicInfo.UniqueProcessId; } NtClose(processHandle); } } else { HANDLE handle; PROCESS_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem( &handle, PROCESS_QUERY_LIMITED_INFORMATION, Info->ProcessId, Info->Handle ))) { if (NT_SUCCESS(PhGetProcessBasicInformation(handle, &basicInfo))) processId = basicInfo.UniqueProcessId; NtClose(handle); } } if (processId) { targetProcessItem = PhReferenceProcessItem(processId); if (targetProcessItem) { ProcessHacker_ShowProcessProperties(PhMainWndHandle, targetProcessItem); PhDereferenceObject(targetProcessItem); } else { PhShowError(hWnd, L"The process does not exist."); } } } else if (PhEqualString2(Info->TypeName, L"Section", TRUE)) { NTSTATUS status; HANDLE handle = NULL; BOOLEAN readOnly = FALSE; if (!NT_SUCCESS(status = PhpDuplicateHandleFromProcessItem( &handle, SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE, Info->ProcessId, Info->Handle ))) { status = PhpDuplicateHandleFromProcessItem( &handle, SECTION_QUERY | SECTION_MAP_READ, Info->ProcessId, Info->Handle ); readOnly = TRUE; } if (handle) { PPH_STRING sectionName = NULL; SECTION_BASIC_INFORMATION basicInfo; SIZE_T viewSize = PH_MAX_SECTION_EDIT_SIZE; PVOID viewBase = NULL; BOOLEAN tooBig = FALSE; PhGetHandleInformation(NtCurrentProcess(), handle, ULONG_MAX, NULL, NULL, NULL, §ionName); if (NT_SUCCESS(status = PhGetSectionBasicInformation(handle, &basicInfo))) { if (basicInfo.MaximumSize.QuadPart <= PH_MAX_SECTION_EDIT_SIZE) viewSize = (SIZE_T)basicInfo.MaximumSize.QuadPart; else tooBig = TRUE; status = NtMapViewOfSection( handle, NtCurrentProcess(), &viewBase, 0, 0, NULL, &viewSize, ViewShare, 0, readOnly ? PAGE_READONLY : PAGE_READWRITE ); if (status == STATUS_SECTION_PROTECTION && !readOnly) { status = NtMapViewOfSection( handle, NtCurrentProcess(), &viewBase, 0, 0, NULL, &viewSize, ViewShare, 0, PAGE_READONLY ); } if (NT_SUCCESS(status)) { PPH_SHOW_MEMORY_EDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); if (tooBig) PhShowWarning(hWnd, L"The section size is greater than 32 MB. Only the first 32 MB will be available for editing."); memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); showMemoryEditor->ProcessId = NtCurrentProcessId(); showMemoryEditor->BaseAddress = viewBase; showMemoryEditor->RegionSize = viewSize; showMemoryEditor->SelectOffset = ULONG_MAX; showMemoryEditor->SelectLength = 0; showMemoryEditor->Title = sectionName ? PhConcatStrings2(L"Section - ", sectionName->Buffer) : PhCreateString(L"Section"); showMemoryEditor->Flags = PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION; ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); } else { PhShowStatus(hWnd, L"Unable to map a view of the section.", status, 0); } } PhClearReference(§ionName); NtClose(handle); } if (!NT_SUCCESS(status)) { PhShowStatus(hWnd, L"Unable to query the section.", status, 0); } } else if (PhEqualString2(Info->TypeName, L"Thread", TRUE)) { HANDLE processHandle; CLIENT_ID clientId; PPH_PROCESS_ITEM targetProcessItem; PPH_PROCESS_PROPCONTEXT propContext; clientId.UniqueProcess = NULL; clientId.UniqueThread = NULL; if (KphIsConnected()) { if (NT_SUCCESS(PhOpenProcess( &processHandle, PROCESS_QUERY_LIMITED_INFORMATION, Info->ProcessId ))) { THREAD_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(KphQueryInformationObject( processHandle, Info->Handle, KphObjectThreadBasicInformation, &basicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL ))) { clientId = basicInfo.ClientId; } NtClose(processHandle); } } else { HANDLE handle; THREAD_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem( &handle, THREAD_QUERY_LIMITED_INFORMATION, Info->ProcessId, Info->Handle ))) { if (NT_SUCCESS(PhGetThreadBasicInformation(handle, &basicInfo))) clientId = basicInfo.ClientId; NtClose(handle); } } if (clientId.UniqueProcess) { targetProcessItem = PhReferenceProcessItem(clientId.UniqueProcess); if (targetProcessItem) { propContext = PhCreateProcessPropContext(NULL, targetProcessItem); PhDereferenceObject(targetProcessItem); PhSetSelectThreadIdProcessPropContext(propContext, clientId.UniqueThread); ProcessHacker_Invoke(PhMainWndHandle, PhpShowProcessPropContext, propContext); } else { PhShowError(hWnd, L"The process does not exist."); } } } }