2025-05-13 19:45:22 +03:00

510 lines
13 KiB
C

/*
* Process Hacker Window Explorer -
* hook procedure
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Window Explorer uses a hook procedure in order to get window procedure
* and other information that can't be retrieved using GetWindowLongPtr.
* Because WindowExplorer.dll needs to be loaded into processes other
* than Process Hacker, both ProcessHacker.exe and comctl32.dll are set as
* delay-loaded DLLs. The other DLLs that we depend on (gdi32.dll,
* kernel32.dll, ntdll.dll, user32.dll) are all guaranteed to be already
* loaded whenever WindowExplorer.dll needs to be loaded.
*/
#include "wndexp.h"
BOOLEAN WepCreateServerObjects(
VOID
);
BOOLEAN WepOpenServerObjects(
VOID
);
VOID WepCloseServerObjects(
VOID
);
VOID WepWriteClientData(
_In_ HWND hwnd
);
LRESULT CALLBACK WepCallWndProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// Shared
ULONG WeServerMessage;
HANDLE WeServerSharedSection;
PWE_HOOK_SHARED_DATA WeServerSharedData;
HANDLE WeServerSharedSectionLock;
HANDLE WeServerSharedSectionEvent;
// Server
HHOOK WeHookHandle = NULL;
// The current message ID is used to detect out-of-sync clients.
ULONG WeCurrentMessageId = 0;
// Server
VOID WeHookServerInitialization(
VOID
)
{
if (WeHookHandle)
return;
WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME);
if (!WepCreateServerObjects())
return;
WeHookHandle = SetWindowsHookEx(WH_CALLWNDPROC, WepCallWndProc, PluginInstance->DllBase, 0);
}
VOID WeHookServerUninitialization(
VOID
)
{
if (WeHookHandle)
{
UnhookWindowsHookEx(WeHookHandle);
WeHookHandle = NULL;
}
}
BOOLEAN WepCreateServerObjects(
VOID
)
{
OBJECT_ATTRIBUTES objectAttributes;
WCHAR buffer[256];
UNICODE_STRING objectName;
SECURITY_DESCRIPTOR securityDescriptor;
UCHAR saclBuffer[sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
PACL sacl;
UCHAR mandatoryLabelAceBuffer[FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
PSYSTEM_MANDATORY_LABEL_ACE mandatoryLabelAce;
PSID sid;
if (!WeServerSharedSection)
{
LARGE_INTEGER maximumSize;
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
maximumSize.QuadPart = sizeof(WE_HOOK_SHARED_DATA);
if (!NT_SUCCESS(NtCreateSection(
&WeServerSharedSection,
SECTION_ALL_ACCESS,
&objectAttributes,
&maximumSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL
)))
{
return FALSE;
}
}
if (!WeServerSharedData)
{
PVOID viewBase;
SIZE_T viewSize;
viewBase = NULL;
viewSize = sizeof(WE_HOOK_SHARED_DATA);
if (!NT_SUCCESS(NtMapViewOfSection(
WeServerSharedSection,
NtCurrentProcess(),
&viewBase,
0,
0,
NULL,
&viewSize,
ViewShare,
0,
PAGE_READWRITE
)))
{
WepCloseServerObjects();
return FALSE;
}
WeServerSharedData = viewBase;
}
if (!WeServerSharedSectionLock)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtCreateMutant(
&WeServerSharedSectionLock,
MUTANT_ALL_ACCESS,
&objectAttributes,
FALSE
)))
{
WepCloseServerObjects();
return FALSE;
}
}
if (!WeServerSharedSectionEvent)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtCreateEvent(
&WeServerSharedSectionEvent,
EVENT_ALL_ACCESS,
&objectAttributes,
NotificationEvent,
FALSE
)))
{
WepCloseServerObjects();
return FALSE;
}
}
// If mandatory labels are supported, set it to the lowest possible level.
if (WE_WindowsVersion >= WINDOWS_VISTA)
{
static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);
sacl = (PACL)saclBuffer;
RtlCreateAcl(sacl, sizeof(saclBuffer), ACL_REVISION);
mandatoryLabelAce = (PSYSTEM_MANDATORY_LABEL_ACE)mandatoryLabelAceBuffer;
mandatoryLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;
mandatoryLabelAce->Header.AceFlags = 0;
mandatoryLabelAce->Header.AceSize = sizeof(mandatoryLabelAceBuffer);
mandatoryLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;
sid = (PSID)&mandatoryLabelAce->SidStart;
RtlInitializeSid(sid, &mandatoryLabelAuthority, 1);
*RtlSubAuthoritySid(sid, 0) = SECURITY_MANDATORY_LOW_RID;
if (NT_SUCCESS(RtlAddAce(sacl, ACL_REVISION, MAXULONG32, mandatoryLabelAce, sizeof(mandatoryLabelAceBuffer))))
{
if (NT_SUCCESS(RtlSetSaclSecurityDescriptor(&securityDescriptor, TRUE, sacl, FALSE)))
{
NtSetSecurityObject(WeServerSharedSection, LABEL_SECURITY_INFORMATION, &securityDescriptor);
NtSetSecurityObject(WeServerSharedSectionLock, LABEL_SECURITY_INFORMATION, &securityDescriptor);
NtSetSecurityObject(WeServerSharedSectionEvent, LABEL_SECURITY_INFORMATION, &securityDescriptor);
}
}
}
return TRUE;
}
BOOLEAN WepOpenServerObjects(
VOID
)
{
OBJECT_ATTRIBUTES objectAttributes;
WCHAR buffer[256];
UNICODE_STRING objectName;
if (!WeServerSharedSection)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenSection(
&WeServerSharedSection,
SECTION_ALL_ACCESS,
&objectAttributes
)))
{
return FALSE;
}
}
if (!WeServerSharedData)
{
PVOID viewBase;
SIZE_T viewSize;
viewBase = NULL;
viewSize = sizeof(WE_HOOK_SHARED_DATA);
if (!NT_SUCCESS(NtMapViewOfSection(
WeServerSharedSection,
NtCurrentProcess(),
&viewBase,
0,
0,
NULL,
&viewSize,
ViewShare,
0,
PAGE_READWRITE
)))
{
WepCloseServerObjects();
return FALSE;
}
WeServerSharedData = viewBase;
}
if (!WeServerSharedSectionLock)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenMutant(
&WeServerSharedSectionLock,
MUTANT_ALL_ACCESS,
&objectAttributes
)))
{
WepCloseServerObjects();
return FALSE;
}
}
if (!WeServerSharedSectionEvent)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenEvent(
&WeServerSharedSectionEvent,
EVENT_ALL_ACCESS,
&objectAttributes
)))
{
WepCloseServerObjects();
return FALSE;
}
}
return TRUE;
}
VOID WepCloseServerObjects(
VOID
)
{
if (WeServerSharedSection)
{
NtClose(WeServerSharedSection);
WeServerSharedSection = NULL;
}
if (WeServerSharedData)
{
NtUnmapViewOfSection(NtCurrentProcess(), WeServerSharedData);
WeServerSharedData = NULL;
}
if (WeServerSharedSectionLock)
{
NtClose(WeServerSharedSectionLock);
WeServerSharedSectionLock = NULL;
}
if (WeServerSharedSectionEvent)
{
NtClose(WeServerSharedSectionEvent);
WeServerSharedSectionEvent = NULL;
}
}
BOOLEAN WeIsServerActive(
VOID
)
{
if (WepOpenServerObjects())
{
WepCloseServerObjects();
return TRUE;
}
else
{
return FALSE;
}
}
BOOLEAN WeLockServerSharedData(
_Out_ PWE_HOOK_SHARED_DATA *Data
)
{
LARGE_INTEGER timeout;
if (!WeServerSharedSectionLock)
return FALSE;
timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS;
if (NtWaitForSingleObject(WeServerSharedSectionLock, FALSE, &timeout) != WAIT_OBJECT_0)
return FALSE;
*Data = WeServerSharedData;
return TRUE;
}
VOID WeUnlockServerSharedData(
VOID
)
{
NtReleaseMutant(WeServerSharedSectionLock, NULL);
}
BOOLEAN WeSendServerRequest(
_In_ HWND hWnd
)
{
ULONG threadId;
ULONG processId;
LARGE_INTEGER timeout;
if (!WeServerSharedData || !WeServerSharedSectionEvent)
return FALSE;
threadId = GetWindowThreadProcessId(hWnd, &processId);
if (UlongToHandle(processId) == NtCurrentProcessId())
{
// We are trying to get information about the server. Call the procedure directly.
WepWriteClientData(hWnd);
return TRUE;
}
// Call the client and wait for the client to finish.
WeCurrentMessageId++;
WeServerSharedData->MessageId = WeCurrentMessageId;
NtResetEvent(WeServerSharedSectionEvent, NULL);
if (!SendNotifyMessage(hWnd, WeServerMessage, (WPARAM)NtCurrentProcessId(), WeCurrentMessageId))
return FALSE;
timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS;
if (NtWaitForSingleObject(WeServerSharedSectionEvent, FALSE, &timeout) != STATUS_WAIT_0)
return FALSE;
return TRUE;
}
// Client
VOID WeHookClientInitialization(
VOID
)
{
WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME);
}
VOID WeHookClientUninitialization(
VOID
)
{
NOTHING;
}
VOID WepWriteClientData(
_In_ HWND hwnd
)
{
WCHAR className[256];
LOGICAL isUnicode;
memset(&WeServerSharedData->c, 0, sizeof(WeServerSharedData->c));
isUnicode = IsWindowUnicode(hwnd);
if (isUnicode)
{
WeServerSharedData->c.WndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
WeServerSharedData->c.DlgProc = GetWindowLongPtrW(hwnd, DWLP_DLGPROC);
}
else
{
WeServerSharedData->c.WndProc = GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
WeServerSharedData->c.DlgProc = GetWindowLongPtrA(hwnd, DWLP_DLGPROC);
}
if (!GetClassName(hwnd, className, sizeof(className) / sizeof(WCHAR)))
className[0] = 0;
WeServerSharedData->c.ClassInfo.cbSize = sizeof(WNDCLASSEX);
GetClassInfoEx(NULL, className, &WeServerSharedData->c.ClassInfo);
if (isUnicode)
WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrW(hwnd, GCLP_WNDPROC);
else
WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrA(hwnd, GCLP_WNDPROC);
}
LRESULT CALLBACK WepCallWndProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LRESULT result;
PCWPSTRUCT info;
result = CallNextHookEx(NULL, nCode, wParam, lParam);
info = (PCWPSTRUCT)lParam;
if (info->message == WeServerMessage)
{
HANDLE serverProcessId;
ULONG messageId;
serverProcessId = (HANDLE)info->wParam;
messageId = (ULONG)info->lParam;
if (serverProcessId != NtCurrentProcessId())
{
if (WepOpenServerObjects())
{
if (WeServerSharedData->MessageId == messageId)
{
WepWriteClientData(info->hwnd);
NtSetEvent(WeServerSharedSectionEvent, NULL);
}
WepCloseServerObjects();
}
}
}
return result;
}