510 lines
13 KiB
C
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;
|
|
}
|