NTSTATUS PhSvcApiPortInitialization( _In_ PUNICODE_STRING PortName ) { static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; PSECURITY_DESCRIPTOR securityDescriptor; ULONG sdAllocationLength; UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; PSID administratorsSid; PACL dacl; ULONG i; // Create the API port. administratorsSid = (PSID)administratorsSidBuffer; RtlInitializeSid(administratorsSid, &ntAuthority, 2); *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + (ULONG)sizeof(ACL) + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(administratorsSid) + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(&PhSeEveryoneSid); securityDescriptor = PhAllocate(sdAllocationLength); dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); RtlAddAccessAllowedAce(dacl, ACL_REVISION, PORT_ALL_ACCESS, administratorsSid); RtlAddAccessAllowedAce(dacl, ACL_REVISION, PORT_CONNECT, &PhSeEveryoneSid); RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); InitializeObjectAttributes( &objectAttributes, PortName, OBJ_CASE_INSENSITIVE, NULL, securityDescriptor ); status = NtCreatePort( &PhSvcApiPortHandle, &objectAttributes, sizeof(PHSVC_API_CONNECTINFO), PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG), 0 ); PhFree(securityDescriptor); if (!NT_SUCCESS(status)) return status; // Start the API threads. PhSvcApiThreadContextTlsIndex = TlsAlloc(); for (i = 0; i < 2; i++) { PhCreateThread2(PhSvcApiRequestThreadStart, NULL); } return status; }
NTSTATUS PhSvcApiRequestThreadStart( _In_ PVOID Parameter ) { PH_AUTO_POOL autoPool; NTSTATUS status; PHSVC_THREAD_CONTEXT threadContext; HANDLE portHandle; PVOID portContext; SIZE_T messageSize; PPORT_MESSAGE receiveMessage; PPORT_MESSAGE replyMessage; CSHORT messageType; PPHSVC_CLIENT client; PPHSVC_API_PAYLOAD payload; PhInitializeAutoPool(&autoPool); threadContext.CurrentClient = NULL; threadContext.OldClient = NULL; TlsSetValue(PhSvcApiThreadContextTlsIndex, &threadContext); portHandle = PhSvcApiPortHandle; messageSize = PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG); receiveMessage = PhAllocate(messageSize); replyMessage = NULL; while (TRUE) { status = NtReplyWaitReceivePort( portHandle, &portContext, replyMessage, receiveMessage ); portHandle = PhSvcApiPortHandle; replyMessage = NULL; if (!NT_SUCCESS(status)) { // Client probably died. continue; } messageType = receiveMessage->u2.s2.Type; if (messageType == LPC_CONNECTION_REQUEST) { PhSvcHandleConnectionRequest(receiveMessage); continue; } if (!portContext) continue; client = portContext; threadContext.CurrentClient = client; PhWaitForEvent(&client->ReadyEvent, NULL); if (messageType == LPC_REQUEST) { if (PhIsExecutingInWow64()) payload = &((PPHSVC_API_MSG64)receiveMessage)->p; else payload = &((PPHSVC_API_MSG)receiveMessage)->p; PhSvcDispatchApiCall(client, payload, &portHandle); replyMessage = receiveMessage; } else if (messageType == LPC_PORT_CLOSED) { PhDereferenceObject(client); if (_InterlockedDecrement(&PhSvcApiNumberOfClients) == 0) { NtSetEvent(PhSvcTimeoutStandbyEventHandle, NULL); } } assert(!threadContext.OldClient); PhDrainAutoPool(&autoPool); } PhDeleteAutoPool(&autoPool); }
VOID PhSvcHandleConnectionRequest( _In_ PPORT_MESSAGE PortMessage ) { NTSTATUS status; PPHSVC_API_MSG message; PPHSVC_API_MSG64 message64; CLIENT_ID clientId; PPHSVC_CLIENT client; HANDLE portHandle; REMOTE_PORT_VIEW clientView; REMOTE_PORT_VIEW64 clientView64; PREMOTE_PORT_VIEW actualClientView; message = (PPHSVC_API_MSG)PortMessage; message64 = (PPHSVC_API_MSG64)PortMessage; if (PhIsExecutingInWow64()) { clientId.UniqueProcess = (HANDLE)message64->h.ClientId.UniqueProcess; clientId.UniqueThread = (HANDLE)message64->h.ClientId.UniqueThread; } else { PPH_STRING referenceFileName; PPH_STRING remoteFileName; clientId = message->h.ClientId; // Make sure that the remote process is Process Hacker itself and not some other program. referenceFileName = NULL; PhGetProcessImageFileNameByProcessId(NtCurrentProcessId(), &referenceFileName); PH_AUTO(referenceFileName); remoteFileName = NULL; PhGetProcessImageFileNameByProcessId(clientId.UniqueProcess, &remoteFileName); PH_AUTO(remoteFileName); if (!referenceFileName || !remoteFileName || !PhEqualString(referenceFileName, remoteFileName, TRUE)) { NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL); return; } } client = PhSvcCreateClient(&clientId); if (!client) { NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL); return; } if (PhIsExecutingInWow64()) { message64->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId()); clientView64.Length = sizeof(REMOTE_PORT_VIEW64); clientView64.ViewSize = 0; clientView64.ViewBase = 0; actualClientView = (PREMOTE_PORT_VIEW)&clientView64; } else { message->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId()); clientView.Length = sizeof(REMOTE_PORT_VIEW); clientView.ViewSize = 0; clientView.ViewBase = NULL; actualClientView = &clientView; } status = NtAcceptConnectPort( &portHandle, client, PortMessage, TRUE, NULL, actualClientView ); if (!NT_SUCCESS(status)) { PhDereferenceObject(client); return; } // IMPORTANT: Since Vista, NtCompleteConnectPort does not do anything and simply returns STATUS_SUCCESS. // We will call it anyway (for completeness), but we need to use an event to ensure that other threads don't try // to process requests before we have finished setting up the client object. client->PortHandle = portHandle; if (PhIsExecutingInWow64()) { client->ClientViewBase = (PVOID)clientView64.ViewBase; client->ClientViewLimit = PTR_ADD_OFFSET(clientView64.ViewBase, clientView64.ViewSize); } else { client->ClientViewBase = clientView.ViewBase; client->ClientViewLimit = PTR_ADD_OFFSET(clientView.ViewBase, clientView.ViewSize); } NtCompleteConnectPort(portHandle); PhSetEvent(&client->ReadyEvent); if (_InterlockedIncrement(&PhSvcApiNumberOfClients) == 1) { NtSetEvent(PhSvcTimeoutCancelEventHandle, NULL); } }
INT WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ INT nCmdShow ) { LONG result; #ifdef DEBUG PHP_BASE_THREAD_DBG dbg; #endif CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); #ifndef DEBUG SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #endif PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress; if (!NT_SUCCESS(PhInitializePhLib())) return 1; if (!PhInitializeAppSystem()) return 1; PhInitializeCommonControls(); if (PhCurrentTokenQueryHandle) { PTOKEN_USER tokenUser; if (NT_SUCCESS(PhGetTokenUser(PhCurrentTokenQueryHandle, &tokenUser))) { PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); PhFree(tokenUser); } } PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); // There has been a report of the above call failing. if (!PhLocalSystemName) PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); PhApplicationFileName = PhGetApplicationFileName(); PhApplicationDirectory = PhGetApplicationDirectory(); // Just in case if (!PhApplicationFileName) PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); if (!PhApplicationDirectory) PhApplicationDirectory = PhReferenceEmptyString(); PhpProcessStartupParameters(); PhSettingsInitialization(); PhpEnablePrivileges(); if (PhStartupParameters.RunAsServiceMode) { RtlExitUserProcess(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode)); } PhpInitializeSettings(); // Activate a previous instance if required. if (PhGetIntegerSetting(L"AllowOnlyOneInstance") && !PhStartupParameters.NewInstance && !PhStartupParameters.ShowOptions && !PhStartupParameters.CommandMode && !PhStartupParameters.PhSvc) { PhActivatePreviousInstance(); } if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhIsExecutingInWow64()) PhInitializeKph(); if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction) { NTSTATUS status; status = PhCommandModeStart(); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) { PhShowStatus(NULL, L"Unable to execute the command", status, 0); } RtlExitUserProcess(status); } #ifdef DEBUG dbg.ClientId = NtCurrentTeb()->ClientId; dbg.StartAddress = wWinMain; dbg.Parameter = NULL; InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); #endif PhInitializeAutoPool(&BaseAutoPool); PhEmInitialization(); PhGuiSupportInitialization(); PhTreeNewInitialization(); PhGraphControlInitialization(); PhHexEditInitialization(); PhColorBoxInitialization(); PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); if (PhStartupParameters.ShowOptions) { // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. PhShowOptionsDialog(PhStartupParameters.WindowHandle); RtlExitUserProcess(STATUS_SUCCESS); } #ifndef DEBUG if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc) { PhShowWarning( NULL, L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " L"Most features will not work correctly.\n\n" L"Please run the 64-bit version of Process Hacker instead." ); } #endif PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins; if (PhPluginsEnabled) { PhPluginsInitialization(); PhLoadPlugins(); } if (PhStartupParameters.PhSvc) { MSG message; // Turn the feedback cursor off. PostMessage(NULL, WM_NULL, 0, 0); GetMessage(&message, NULL, 0, 0); RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL)); } // Create a mutant for the installer. { HANDLE mutantHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHacker2Mutant"); InitializeObjectAttributes( &oa, &mutantName, 0, NULL, NULL ); NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); } // Set priority. { PROCESS_PRIORITY_CLASS priorityClass; priorityClass.Foreground = FALSE; priorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; if (PhStartupParameters.PriorityClass != 0) priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass; NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); } if (!PhMainWndInitialization(nCmdShow)) { PhShowError(NULL, L"Unable to initialize the main window."); return 1; } PhDrainAutoPool(&BaseAutoPool); result = PhMainMessageLoop(); RtlExitUserProcess(result); }