NTSTATUS PhpGetCsrHandleProcessId( _Inout_ PPH_CSR_HANDLE_INFO Handle ) { NTSTATUS status; PROCESS_BASIC_INFORMATION processBasicInfo; THREAD_BASIC_INFORMATION threadBasicInfo; Handle->IsThreadHandle = FALSE; Handle->ProcessId = NULL; // Assume the handle is a process handle, and get the // process ID. status = KphQueryInformationObject( Handle->CsrProcessHandle, Handle->Handle, KphObjectProcessBasicInformation, &processBasicInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL ); if (NT_SUCCESS(status)) { Handle->ProcessId = processBasicInfo.UniqueProcessId; } else { // We failed to get the process ID. Assume the handle // is a thread handle, and get the process ID. status = KphQueryInformationObject( Handle->CsrProcessHandle, Handle->Handle, KphObjectThreadBasicInformation, &threadBasicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL ); if (NT_SUCCESS(status)) { Handle->ProcessId = threadBasicInfo.ClientId.UniqueProcess; Handle->IsThreadHandle = TRUE; } } return status; }
NTSTATUS PhpGetObjectName( __in HANDLE ProcessHandle, __in HANDLE Handle, __out PPH_STRING *ObjectName ) { NTSTATUS status; POBJECT_NAME_INFORMATION buffer; ULONG bufferSize; ULONG attempts = 8; bufferSize = 0x200; buffer = PhAllocate(bufferSize); // A loop is needed because the I/O subsystem likes to give us the wrong return lengths... do { if (KphIsConnected()) { status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectNameInformation, buffer, bufferSize, &bufferSize ); } else { status = NtQueryObject( Handle, ObjectNameInformation, buffer, bufferSize, &bufferSize ); } if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_BUFFER_TOO_SMALL) { PhFree(buffer); buffer = PhAllocate(bufferSize); } else { break; } } while (--attempts); if (NT_SUCCESS(status)) { *ObjectName = PhCreateStringEx(buffer->Name.Buffer, buffer->Name.Length); } PhFree(buffer); return status; }
NTSTATUS PhpGetObjectBasicInformation( __in HANDLE ProcessHandle, __in HANDLE Handle, __out POBJECT_BASIC_INFORMATION BasicInformation ) { NTSTATUS status; if (KphIsConnected()) { status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectBasicInformation, BasicInformation, sizeof(OBJECT_BASIC_INFORMATION), NULL ); if (NT_SUCCESS(status)) { // The object was referenced in KProcessHacker, so // we need to subtract 1 from the pointer count. BasicInformation->PointerCount -= 1; } } else { status = NtQueryObject( Handle, ObjectBasicInformation, BasicInformation, sizeof(OBJECT_BASIC_INFORMATION), NULL ); if (NT_SUCCESS(status)) { // The object was referenced in NtQueryObject and // a handle was opened to the object. We need to // subtract 1 from the pointer count, then subtract // 1 from both counts. BasicInformation->HandleCount -= 1; BasicInformation->PointerCount -= 2; } } return status; }
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; }
NTSTATUS PhpGetObjectTypeName( __in HANDLE ProcessHandle, __in HANDLE Handle, __in ULONG ObjectTypeNumber, __out PPH_STRING *TypeName ) { NTSTATUS status = STATUS_SUCCESS; PPH_STRING typeName = NULL; // If the cache contains the object type name, use it. Otherwise, // query the type name. if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) typeName = PhObjectTypeNames[ObjectTypeNumber]; if (typeName) { PhReferenceObject(typeName); } else { POBJECT_TYPE_INFORMATION buffer; ULONG returnLength = 0; PPH_STRING oldTypeName; // Get the needed buffer size. if (KphIsConnected()) { status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectTypeInformation, NULL, 0, &returnLength ); } else { status = NtQueryObject( Handle, ObjectTypeInformation, NULL, 0, &returnLength ); } if (returnLength == 0) return status; buffer = PhAllocate(returnLength); if (KphIsConnected()) { status = KphQueryInformationObject( ProcessHandle, Handle, KphObjectTypeInformation, buffer, returnLength, &returnLength ); } else { status = NtQueryObject( Handle, ObjectTypeInformation, buffer, returnLength, &returnLength ); } if (!NT_SUCCESS(status)) { PhFree(buffer); return status; } // Create a copy of the type name. typeName = PhCreateStringEx(buffer->TypeName.Buffer, buffer->TypeName.Length); if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) { // Try to store the type name in the cache. oldTypeName = _InterlockedCompareExchangePointer( &PhObjectTypeNames[ObjectTypeNumber], typeName, NULL ); // Add a reference if we stored the type name // successfully. if (!oldTypeName) PhReferenceObject(typeName); } PhFree(buffer); } // At this point typeName should contain a type name // with one additional reference. *TypeName = typeName; return status; }
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."); } } } }