Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

561 lines
18 KiB

/****************************** Module Header ******************************\
* Module Name: srvhook.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Server side of hook calls and callbacks.
*
* 05-09-91 ScottLu Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
LRESULT fnHkINLPCBTCREATESTRUCT(UINT msg, WPARAM wParam, LPCBT_CREATEWND pcbt,
PROC xpfnProc, BOOL bAnsi);
/***************************************************************************\
* xxxHkCallHook
*
* This is the server-side stub that calls to the client to call the actual
* hook function.
*
* History:
* 05-09-91 ScottLu Rewrote to make all hooks work client/server!
* 01-28-91 DavidPe Created.
\***************************************************************************/
LRESULT xxxHkCallHook(
PHOOK phk,
int nCode,
WPARAM wParam,
LPARAM lParam)
{
LRESULT nRet;
PROC pfnHk, pfnHookProc;
PPFNCLIENT ppfnClient;
PCWPSTRUCTEX pcwp;
PCWPRETSTRUCTEX pcwpret;
PCLIENTINFO pci;
ULONG_PTR dwHookData;
ULONG_PTR dwFlags;
struct tagSMS *psms;
#ifdef LATER
/*
* WindowsBug 246329
* The code was supposed to prevent the backdoor
* for the surprise foreground change.
* However, the implementation below locks the
* entire system, preventing the legit, expected
* foreground change too. It's obvious on MP systems.
* E.g. in the case global hooks such as
* GETMESSAGEHOOK are installed, the chances are
* pretty high.
* For this time being, instead of making the lock
* per process or per thread, we decided to simply
* disable the foreground lock during the hook
* callback.
*/
TL tlSFWLock;
BOOL fLockForeground;
#endif
DbgValidateHooks(phk, phk->iHook);
/*
* Only low level hooks are allowed in the RIT context.
* Also asssert that the hook is not destroyed
*/
#ifdef REDIRECTION
UserAssert((PtiCurrent() != gptiRit)
|| (phk->iHook == WH_MOUSE_LL)
|| (phk->iHook == WH_KEYBOARD_LL)
|| (phk->iHook == WH_HITTEST));
#else
UserAssert((PtiCurrent() != gptiRit)
|| (phk->iHook == WH_MOUSE_LL)
|| (phk->iHook == WH_KEYBOARD_LL));
#endif // REDIRECTION
/*
* While we're still inside the critical section make sure the
* hook hasn't been 'freed'. If so just return 0.
*/
if (phk->offPfn != 0) {
pfnHookProc = PFNHOOK(phk);
} else {
return 0;
}
ppfnClient = (phk->flags & HF_ANSI) ? &gpsi->apfnClientA :
&gpsi->apfnClientW;
#ifdef LATER // per 246329
/*
* LATER5.0 GerardoB. This might generate some hate reactions but I'm
* not sure we want people hooking just to steal the foreground.
* Prevent hookprocs from other processes from switching the foreground
*/
fLockForeground = (GETPTI(phk)->ppi != PpiCurrent());
if (fLockForeground) {
ThreadLockSFWLockCount(&tlSFWLock);
}
#endif
switch(phk->iHook) {
case WH_CALLWNDPROC:
case WH_CALLWNDPROCRET:
if (phk->iHook == WH_CALLWNDPROC) {
pcwp = (PCWPSTRUCTEX)lParam;
psms = pcwp->psmsSender;
} else {
pcwpret = (PCWPRETSTRUCTEX)lParam;
psms = pcwpret->psmsSender;
}
/*
* If the sender has died or timed out, don't call the
* hook because any memory the message points to may be invalid.
*/
if (psms != NULL && (psms->flags & (SMF_SENDERDIED | SMF_REPLY))) {
nRet = 0;
break;
}
/*
* This is the hardest of the hooks because we need to thunk through
* the message hooks in order to deal with synchronously sent messages
* that point to structures - to get the structures passed across
* alright, etc.
*
* This will call a special client-side routine that'll rebundle the
* arguments and call the hook in the right format.
*
* Currently, the message thunk callbacks to the client-side don't take
* enough parameters to pass wParam (which == fInterThread send msg).
* To do this, call one of two functions.
*/
pci = GetClientInfo();
if (phk->iHook == WH_CALLWNDPROC) {
pfnHk = ppfnClient->pfnHkINLPCWPSTRUCT;
} else {
pfnHk = ppfnClient->pfnHkINLPCWPRETSTRUCT;
try {
pci->dwHookData = pcwpret->lResult;
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
nRet = 0;
break;
}
}
/*
* Save current hook state.
*/
try {
dwFlags = pci->CI_flags & CI_INTERTHREAD_HOOK;
dwHookData = pci->dwHookData;
if (wParam) {
pci->CI_flags |= CI_INTERTHREAD_HOOK;
} else {
pci->CI_flags &= ~CI_INTERTHREAD_HOOK;
}
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
nRet = 0;
break;
}
if (phk->iHook == WH_CALLWNDPROC) {
nRet = ScSendMessageSMS(
PW(pcwp->hwnd),
pcwp->message,
pcwp->wParam,
pcwp->lParam,
(ULONG_PTR)pfnHookProc, pfnHk,
(phk->flags & HF_ANSI) ?
(SCMS_FLAGS_ANSI|SCMS_FLAGS_INONLY) :
SCMS_FLAGS_INONLY,
psms);
} else {
nRet = ScSendMessageSMS(
PW(pcwpret->hwnd),
pcwpret->message,
pcwpret->wParam,
pcwpret->lParam,
(ULONG_PTR)pfnHookProc, pfnHk,
(phk->flags & HF_ANSI) ?
(SCMS_FLAGS_ANSI|SCMS_FLAGS_INONLY) :
SCMS_FLAGS_INONLY,
psms);
}
/*
* Restore previous hook state.
*/
try {
pci->CI_flags ^= ((pci->CI_flags ^ dwFlags) & CI_INTERTHREAD_HOOK);
pci->dwHookData = dwHookData;
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
nRet = 0;
}
break;
case WH_CBT:
/*
* There are many different types of CBT hooks!
*/
switch(nCode) {
case HCBT_CLICKSKIPPED:
goto MouseHook;
break;
case HCBT_CREATEWND:
/*
* This hook type points to a CREATESTRUCT, so we need to
* be fancy with it's thunking, because a CREATESTRUCT contains
* a pointer to CREATEPARAMS which can be anything... so
* funnel this through our message thunks.
*/
nRet = fnHkINLPCBTCREATESTRUCT(
MAKELONG((WORD)nCode, (WORD)phk->iHook),
wParam,
(LPCBT_CREATEWND)lParam,
pfnHookProc,
(phk->flags & HF_ANSI) ? TRUE : FALSE);
break;
#ifdef REDIRECTION
case HCBT_GETCURSORPOS:
/*
* This hook type points to a POINT structure, so it's pretty
* simple.
*/
nRet = fnHkINLPPOINT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPPOINT)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook);
break;
#endif // REDIRECTION
case HCBT_MOVESIZE:
/*
* This hook type points to a RECT structure, so it's pretty
* simple.
*/
nRet = fnHkINLPRECT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPRECT)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook);
break;
case HCBT_ACTIVATE:
/*
* This hook type points to a CBTACTIVATESTRUCT
*/
nRet = fnHkINLPCBTACTIVATESTRUCT(MAKELONG((UINT)nCode,
(UINT)phk->iHook), wParam, (LPCBTACTIVATESTRUCT)lParam,
(ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
break;
default:
/*
* The rest of the cbt hooks are all dword parameters.
*/
nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook, &phk->flags);
break;
}
break;
case WH_FOREGROUNDIDLE:
/*
* These are dword parameters and are therefore real easy.
*
*/
nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook, &phk->flags);
break;
case WH_SHELL:
if (nCode == HSHELL_GETMINRECT) {
/*
* This hook type points to a RECT structure, so it's pretty
* simple.
*/
nRet = fnHkINLPRECT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPRECT)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook);
break;
}
/*
* Otherwise fall through to the simple case of DWORD below
*/
case WH_KEYBOARD:
/*
* These are dword parameters and are therefore real easy.
*/
nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook, &phk->flags);
break;
case WH_MSGFILTER:
case WH_SYSMSGFILTER:
case WH_GETMESSAGE:
/*
* These take an lpMsg as their last parameter. Since these are
* exclusively posted parameters, and since nowhere on the server
* do we post a message with a pointer to some other structure in
* it, the lpMsg structure contents can all be treated verbatim.
*/
nRet = fnHkINLPMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPMSG)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook,
(phk->flags & HF_ANSI) ? TRUE : FALSE, &phk->flags);
break;
case WH_JOURNALPLAYBACK:
#ifdef HOOKBATCH
/*
* If this hook has cached playback info then we need to grab
* the info out of the cache.
*/
if (phk->cEventMessages) {
if (nCode == HC_GETNEXT) {
LPEVENTMSG pEventMsg;
pEventMsg = (LPEVENTMSG)lParam;
if (phk->flags & HF_NEEDHC_SKIP)
phk->iCurrentEvent++;
if (phk->iCurrentEvent < phk->cEventMessages) {
*pEventMsg = phk->aEventCache[phk->iCurrentEvent];
} else {
/*
* Free the cache set if it is still around
*/
if (phk->aEventCache) {
UserFreePool(phk->aEventCache);
phk->aEventCache = NULL;
}
phk->cEventMessages = 0;
phk->iCurrentEvent = 0;
goto MakeClientJournalPlaybackCall;
}
/*
* Return the time and zero the batched time so if we sleep
* this time we won't sleep again next time
*/
nRet = pEventMsg->time;
if (nRet)
phk->aEventCache[phk->iCurrentEvent].time = 0;
} else if (nCode == HC_SKIP) {
phk->iCurrentEvent++;
nRet = 0;
}
} else {
#endif // HOOKBATCH
/*
* In order to avoid a client/server transition for HC_SKIP we
* piggy-back it on top of the next journal playback event and
* send it from there.
*/
// MakeClientJournalPlaybackCall:
nRet = fnHkOPTINLPEVENTMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
(WPARAM)PtoHq(phk), (LPEVENTMSG)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook);
#ifdef HOOKBATCH
}
/*
* Determine if we received a cached set of events if so then store
* them away off of the hook.
* paramL will be the number of events.
* paramH will be the array of events.
*/
if ((nCode == HC_GETNEXT) && (((LPEVENTMSG)lParam)->message == 0x12341234)) {
NTSTATUS Status;
LPEVENTMSG pEventMsg = (LPEVENTMSG)lParam;
/*
* We should not be getting another cached set if we aren't
* done with the first set
*/
UserAssert((phk->cEventMessages == 0) ||
(phk->cEventMessages >= phk->iCurrentEvent));
UserAssert((pEventMsg->paramL < 500) && (pEventMsg->paramL > 1));
/*
* Free the last cache set if it is still around
*/
if (phk->aEventCache) {
UserFreePool(phk->aEventCache);
phk->aEventCache = NULL;
}
if (phk->aEventCache = LocalAlloc(LPTR,
pEventMsg->paramL*sizeof(EVENTMSG))) {
PETHREAD Thread = PsGetCurrentThread();
Status = ZwReadVirtualMemory(Thread->Process->ProcessHandle,
(PVOID)pEventMsg->paramH, phk->aEventCache,
pEventMsg->paramL*sizeof(EVENTMSG), NULL);
if (NT_SUCCESS(Status)) {
phk->cEventMessages = pEventMsg->paramL;
phk->iCurrentEvent = 0;
/*
* Fill in the real EventMsg for this message
*/
*pEventMsg = phk->aEventCache[0];
phk->aEventCache[0].time = 0;
}
} else {
phk->cEventMessages = 0;
phk->iCurrentEvent = 0;
}
}
#endif // HOOKBATCH
phk->flags &= ~HF_NEEDHC_SKIP;
break;
case WH_JOURNALRECORD:
nRet = fnHkOPTINLPEVENTMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPEVENTMSG)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook);
break;
case WH_DEBUG:
/*
* This takes an lpDebugHookStruct.
*/
nRet = fnHkINLPDEBUGHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPDEBUGHOOKINFO)lParam, (ULONG_PTR)pfnHookProc,
ppfnClient->pfnDispatchHook);
break;
case WH_KEYBOARD_LL:
/*
* This takes an lpKbdHookStruct.
*/
nRet = fnHkINLPKBDLLHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPKBDLLHOOKSTRUCT)lParam,
(ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
break;
case WH_MOUSE_LL:
/*
* This takes an lpMsllHookStruct.
*/
nRet = fnHkINLPMSLLHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPMSLLHOOKSTRUCT)lParam,
(ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
break;
case WH_MOUSE:
/*
* This takes an lpMouseHookStructEx.
*/
MouseHook:
nRet = fnHkINLPMOUSEHOOKSTRUCTEX(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPMOUSEHOOKSTRUCTEX)lParam,
(ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook, &phk->flags);
break;
#ifdef REDIRECTION
case WH_HITTEST:
/*
* This takes an lpHTHookStruct.
*/
nRet = fnHkINLPHTHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
wParam, (LPHTHOOKSTRUCT)lParam,
(ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
break;
#endif // REDIRECTION
}
#ifdef LATER // per 246329
if (fLockForeground) {
ThreadUnlockSFWLockCount(&tlSFWLock);
}
#endif
return nRet;
}
/***************************************************************************\
* fnHkINLPCWPEXSTRUCT
*
* This gets thunked through the message thunks, so it has the format
* of a c/s message thunk call.
*
* 05-09-91 ScottLu Created.
\***************************************************************************/
LRESULT fnHkINLPCWPEXSTRUCT(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
ULONG_PTR xParam)
{
CWPSTRUCTEX cwp;
PCLIENTINFO pci = GetClientInfo();
BOOL bInterThread;
UNREFERENCED_PARAMETER(xParam);
cwp.hwnd = HW(pwnd);
cwp.message = message;
cwp.wParam = wParam;
cwp.lParam = lParam;
cwp.psmsSender = NULL;
try {
bInterThread = (pci->CI_flags & CI_INTERTHREAD_HOOK) != 0;
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
return 0;
}
return xxxCallNextHookEx(HC_ACTION, bInterThread, (LPARAM)&cwp);
}
LRESULT fnHkINLPCWPRETEXSTRUCT(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
ULONG_PTR xParam)
{
CWPRETSTRUCTEX cwp;
PCLIENTINFO pci = GetClientInfo();
BOOL bInterThread;
UNREFERENCED_PARAMETER(xParam);
cwp.hwnd = HW(pwnd);
cwp.message = message;
cwp.wParam = wParam;
cwp.lParam = lParam;
cwp.psmsSender = NULL;
try {
cwp.lResult = pci->dwHookData;
bInterThread = (pci->CI_flags & CI_INTERTHREAD_HOOK) != 0;
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
return 0;
}
return xxxCallNextHookEx(HC_ACTION, bInterThread, (LPARAM)&cwp);
}