PHOOK zzzSetWindowsHookEx( HANDLE hmod, PUNICODE_STRING pstrLib, PTHREADINFO ptiThread, int nFilterType, PROC pfnFilterProc, DWORD dwFlags) { ACCESS_MASK amDesired; PHOOK phkNew; TL tlphkNew; PHOOK *pphkStart; PTHREADINFO ptiCurrent;
/* * Check to see if filter type is valid. */ if ((nFilterType < WH_MIN) || (nFilterType > WH_MAX)) { RIPERR0(ERROR_INVALID_HOOK_FILTER, RIP_VERBOSE, ""); return NULL; }
/* * Check to see if filter proc is valid. */ if (pfnFilterProc == NULL) { RIPERR0(ERROR_INVALID_FILTER_PROC, RIP_VERBOSE, ""); return NULL; }
ptiCurrent = PtiCurrent();
if (ptiThread == NULL) { /* * Is the app trying to set a global hook without a library? * If so return an error. */ if (hmod == NULL) { RIPERR0(ERROR_HOOK_NEEDS_HMOD, RIP_VERBOSE, ""); return NULL; } } else { /* * Is the app trying to set a local hook that is global-only? * If so return an error. */ if (!(abHookFlags[nFilterType + 1] & HKF_TASK)) { RIPERR0(ERROR_GLOBAL_ONLY_HOOK, RIP_VERBOSE, ""); return NULL; }
/* * Can't hook outside our own desktop. */ if (ptiThread->rpdesk != ptiCurrent->rpdesk) { RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied to desktop in zzzSetWindowsHookEx - can't hook other desktops");
return NULL; }
if (ptiCurrent->ppi != ptiThread->ppi) { /* * Is the app trying to set hook in another process without a library? * If so return an error. */ if (hmod == NULL) { RIPERR0(ERROR_HOOK_NEEDS_HMOD, RIP_VERBOSE, ""); return NULL; }
/* * Is the app hooking another user without access? * If so return an error. Note that this check is done * for global hooks every time the hook is called. */ if ((!RtlEqualLuid(&ptiThread->ppi->luidSession, &ptiCurrent->ppi->luidSession)) && !(ptiThread->TIF_flags & TIF_ALLOWOTHERACCOUNTHOOK)) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied to other user in zzzSetWindowsHookEx");
return NULL; }
if ((ptiThread->TIF_flags & (TIF_CSRSSTHREAD | TIF_SYSTEMTHREAD)) && !(abHookFlags[nFilterType + 1] & HKF_INTERSENDABLE)) {
/* * Can't hook console or GUI system thread if inter-thread * calling isn't implemented for this hook type. */ RIPERR1(ERROR_HOOK_TYPE_NOT_ALLOWED, RIP_WARNING, "nFilterType (%ld) not allowed in zzzSetWindowsHookEx", nFilterType);
return NULL; } } }
/* * Check if this thread has access to hook its desktop. */ switch( nFilterType ) { case WH_JOURNALRECORD: amDesired = DESKTOP_JOURNALRECORD; break;
case WH_JOURNALPLAYBACK: amDesired = DESKTOP_JOURNALPLAYBACK; break;
default: amDesired = DESKTOP_HOOKCONTROL; break; }
if (!RtlAreAllAccessesGranted(ptiCurrent->amdesk, amDesired)) { RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied to desktop in zzzSetWindowsHookEx");
return NULL; }
if (amDesired != DESKTOP_HOOKCONTROL && (ptiCurrent->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)) { RIPERR0(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION, RIP_WARNING, "Journal hooks invalid on a desktop belonging to a non-interactive WindowStation.");
return NULL; }
#if 0 /* * Is this a journal hook? */ if (abHookFlags[nFilterType + 1] & HKF_JOURNAL) { /* * Is a journal hook of this type already installed? * If so it's an error. * If this code is enabled, use PhkFirstGlobalValid instead * of checking phkStart directly */ if (ptiCurrent->pDeskInfo->asphkStart[nFilterType + 1] != NULL) { RIPERR0(ERROR_JOURNAL_HOOK_SET, RIP_VERBOSE, ""); return NULL; } } #endif
/* * Allocate the new HOOK structure. */ phkNew = (PHOOK)HMAllocObject(ptiCurrent, ptiCurrent->rpdesk, TYPE_HOOK, sizeof(HOOK)); if (phkNew == NULL) { return NULL; }
/* * If a DLL is required for this hook, register the library with * the library management routines so we can assure it's loaded * into all the processes necessary. */ phkNew->ihmod = -1; if (hmod != NULL) {
#if defined(WX86)
phkNew->flags |= (dwFlags & HF_WX86KNOWNDLL);
#endif
phkNew->ihmod = GetHmodTableIndex(pstrLib);
if (phkNew->ihmod == -1) { RIPERR0(ERROR_MOD_NOT_FOUND, RIP_VERBOSE, ""); HMFreeObject((PVOID)phkNew); return NULL; }
/* * Add a dependency on this module - meaning, increment a count * that simply counts the number of hooks set into this module. */ if (phkNew->ihmod >= 0) { AddHmodDependency(phkNew->ihmod); } }
/* * Depending on whether we're setting a global or local hook, * get the start of the appropriate linked-list of HOOKs. Also * set the HF_GLOBAL flag if it's a global hook. */ if (ptiThread != NULL) { pphkStart = &ptiThread->aphkStart[nFilterType + 1];
/* * Set the WHF_* in the THREADINFO so we know it's hooked. */ ptiThread->fsHooks |= WHF_FROM_WH(nFilterType);
/* * Set the flags in the thread's TEB */ if (ptiThread->pClientInfo) { BOOL fAttached;
/* * If the thread being hooked is in another process, attach * to that process so that we can access its ClientInfo. */ if (ptiThread->ppi != ptiCurrent->ppi) { KeAttachProcess(&ptiThread->ppi->Process->Pcb); fAttached = TRUE; } else fAttached = FALSE;
ptiThread->pClientInfo->fsHooks = ptiThread->fsHooks;
if (fAttached) KeDetachProcess(); }
/* * Remember which thread we're hooking. */ phkNew->ptiHooked = ptiThread;
} else { pphkStart = &ptiCurrent->pDeskInfo->aphkStart[nFilterType + 1]; phkNew->flags |= HF_GLOBAL;
/* * Set the WHF_* in the SERVERINFO so we know it's hooked. */ ptiCurrent->pDeskInfo->fsHooks |= WHF_FROM_WH(nFilterType);
phkNew->ptiHooked = NULL; }
/* * Does the hook function expect ANSI or Unicode text? */ phkNew->flags |= (dwFlags & HF_ANSI);
/* * Initialize the HOOK structure. Unreferenced parameters are assumed * to be initialized to zero by LocalAlloc(). */ phkNew->iHook = nFilterType;
/* * Libraries are loaded at different linear addresses in different * process contexts. For this reason, we need to convert the filter * proc address into an offset while setting the hook, and then convert * it back to a real per-process function pointer when calling a * hook. Do this by subtracting the 'hmod' (which is a pointer to the * linear and contiguous .exe header) from the function index. */ phkNew->offPfn = ((ULONG_PTR)pfnFilterProc) - ((ULONG_PTR)hmod);
#ifdef HOOKBATCH phkNew->cEventMessages = 0; phkNew->iCurrentEvent = 0; phkNew->CacheTimeOut = 0; phkNew->aEventCache = NULL; #endif //HOOKBATCH
/* * Link this hook into the front of the hook-list. */ phkNew->phkNext = *pphkStart; *pphkStart = phkNew;
/* * If this is a journal hook, setup synchronized input processing * AFTER we set the hook - so this synchronization can be cancelled * with control-esc. */ if (abHookFlags[nFilterType + 1] & HKF_JOURNAL) { /* * Attach everyone to us so journal-hook processing * will be synchronized. * No need to DeferWinEventNotify() here, since we lock phkNew. */ ThreadLockAlwaysWithPti(ptiCurrent, phkNew, &tlphkNew); if (!zzzJournalAttach(ptiCurrent, TRUE)) { RIPMSG1(RIP_WARNING, "zzzJournalAttach failed, so abort hook %#p", phkNew); if (ThreadUnlock(&tlphkNew) != NULL) { zzzUnhookWindowsHookEx(phkNew); } return NULL; } if ((phkNew = ThreadUnlock(&tlphkNew)) == NULL) { return NULL; } }
UserAssert(phkNew != NULL);
/* * Later 5.0 GerardoB: The old code just to check this but * I think it's some left over stuff from server side days. .* Let's assert on it for a while * Also, I added the assertions in the else's below because I reorganized * the code and want to make sure we don't change behavior */ UserAssert(ptiCurrent->pEThread && THREAD_TO_PROCESS(ptiCurrent->pEThread));
/* * Can't allow a process that has set a global hook that works * on server-side winprocs to run at background priority! Bump * up it's dynamic priority and mark it so it doesn't get reset. */ if ((phkNew->flags & HF_GLOBAL) && (abHookFlags[nFilterType + 1] & HKF_INTERSENDABLE)) {
ptiCurrent->TIF_flags |= TIF_GLOBALHOOKER; KeSetPriorityThread(&ptiCurrent->pEThread->Tcb, LOW_REALTIME_PRIORITY-2);
if (abHookFlags[nFilterType + 1] & HKF_JOURNAL) { ThreadLockAlwaysWithPti(ptiCurrent, phkNew, &tlphkNew); /* * If we're changing the journal hooks, jiggle the mouse. * This way the first event will always be a mouse move, which * will ensure that the cursor is set properly. */ zzzSetFMouseMoved(); phkNew = ThreadUnlock(&tlphkNew); /* * If setting a journal playback hook, this process is the input * provider. This gives it the right to call SetForegroundWindow */ if (nFilterType == WH_JOURNALPLAYBACK) { gppiInputProvider = ptiCurrent->ppi; } } else { UserAssert(nFilterType != WH_JOURNALPLAYBACK); } } else { UserAssert(!(abHookFlags[nFilterType + 1] & HKF_JOURNAL)); UserAssert(nFilterType != WH_JOURNALPLAYBACK); }
/* * Return pointer to our internal hook structure so we know * which hook to call next in CallNextHookEx(). */ DbgValidateHooks(phkNew, phkNew->iHook); return phkNew; }
|