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; }
|