阅读:3360回复:2
谁能剖析一下setwindowshookex的内部执行情况?
谁能剖析一下setwindowshookex的内部执行情况?
|
|
沙发#
发布于:2005-02-28 10:05
本人知道在内核中可以hook _NtUserSetWindowsHookEx这个函数,在win32k.sys中,对应系统服务号是1225h,其主要意思是将hook连接到你要 hook的进程,并连接到这个module,建立与该module的依赖关系,同时增加模块引用计数。找到模块,其中便有这个模块的PE头,这里面会有输出函数的定位信息,从这里可以实现hook。
|
|
|
板凳#
发布于:2005-04-01 09:46
看进来,这是核心函数,Win2k的,有详细的英文注释。
/***************************************************************************\\ * zzzSetWindowsHookEx * * SetWindowsHookEx() is the updated version of SetWindowsHook(). It allows * applications to set hooks on specific threads or throughout the entire * system. The function returns a hook handle to the application if * successful and NULL if a failure occured. * * History: * 28-Jan-1991 DavidPe Created. * 15-May-1991 ScottLu Changed to work client/server. * 30-Jan-1992 IanJa Added bAnsi parameter \\***************************************************************************/ 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; } |
|