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

  1. /****************************** Module Header ******************************\
  2. * Module Name: srvhook.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Server side of hook calls and callbacks.
  7. *
  8. * 05-09-91 ScottLu Created.
  9. \***************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. LRESULT fnHkINLPCBTCREATESTRUCT(UINT msg, WPARAM wParam, LPCBT_CREATEWND pcbt,
  13. PROC xpfnProc, BOOL bAnsi);
  14. /***************************************************************************\
  15. * xxxHkCallHook
  16. *
  17. * This is the server-side stub that calls to the client to call the actual
  18. * hook function.
  19. *
  20. * History:
  21. * 05-09-91 ScottLu Rewrote to make all hooks work client/server!
  22. * 01-28-91 DavidPe Created.
  23. \***************************************************************************/
  24. LRESULT xxxHkCallHook(
  25. PHOOK phk,
  26. int nCode,
  27. WPARAM wParam,
  28. LPARAM lParam)
  29. {
  30. LRESULT nRet;
  31. PROC pfnHk, pfnHookProc;
  32. PPFNCLIENT ppfnClient;
  33. PCWPSTRUCTEX pcwp;
  34. PCWPRETSTRUCTEX pcwpret;
  35. PCLIENTINFO pci;
  36. ULONG_PTR dwHookData;
  37. ULONG_PTR dwFlags;
  38. struct tagSMS *psms;
  39. #ifdef LATER
  40. /*
  41. * WindowsBug 246329
  42. * The code was supposed to prevent the backdoor
  43. * for the surprise foreground change.
  44. * However, the implementation below locks the
  45. * entire system, preventing the legit, expected
  46. * foreground change too. It's obvious on MP systems.
  47. * E.g. in the case global hooks such as
  48. * GETMESSAGEHOOK are installed, the chances are
  49. * pretty high.
  50. * For this time being, instead of making the lock
  51. * per process or per thread, we decided to simply
  52. * disable the foreground lock during the hook
  53. * callback.
  54. */
  55. TL tlSFWLock;
  56. BOOL fLockForeground;
  57. #endif
  58. DbgValidateHooks(phk, phk->iHook);
  59. /*
  60. * Only low level hooks are allowed in the RIT context.
  61. * Also asssert that the hook is not destroyed
  62. */
  63. #ifdef REDIRECTION
  64. UserAssert((PtiCurrent() != gptiRit)
  65. || (phk->iHook == WH_MOUSE_LL)
  66. || (phk->iHook == WH_KEYBOARD_LL)
  67. || (phk->iHook == WH_HITTEST));
  68. #else
  69. UserAssert((PtiCurrent() != gptiRit)
  70. || (phk->iHook == WH_MOUSE_LL)
  71. || (phk->iHook == WH_KEYBOARD_LL));
  72. #endif // REDIRECTION
  73. /*
  74. * While we're still inside the critical section make sure the
  75. * hook hasn't been 'freed'. If so just return 0.
  76. */
  77. if (phk->offPfn != 0) {
  78. pfnHookProc = PFNHOOK(phk);
  79. } else {
  80. return 0;
  81. }
  82. ppfnClient = (phk->flags & HF_ANSI) ? &gpsi->apfnClientA :
  83. &gpsi->apfnClientW;
  84. #ifdef LATER // per 246329
  85. /*
  86. * LATER5.0 GerardoB. This might generate some hate reactions but I'm
  87. * not sure we want people hooking just to steal the foreground.
  88. * Prevent hookprocs from other processes from switching the foreground
  89. */
  90. fLockForeground = (GETPTI(phk)->ppi != PpiCurrent());
  91. if (fLockForeground) {
  92. ThreadLockSFWLockCount(&tlSFWLock);
  93. }
  94. #endif
  95. switch(phk->iHook) {
  96. case WH_CALLWNDPROC:
  97. case WH_CALLWNDPROCRET:
  98. if (phk->iHook == WH_CALLWNDPROC) {
  99. pcwp = (PCWPSTRUCTEX)lParam;
  100. psms = pcwp->psmsSender;
  101. } else {
  102. pcwpret = (PCWPRETSTRUCTEX)lParam;
  103. psms = pcwpret->psmsSender;
  104. }
  105. /*
  106. * If the sender has died or timed out, don't call the
  107. * hook because any memory the message points to may be invalid.
  108. */
  109. if (psms != NULL && (psms->flags & (SMF_SENDERDIED | SMF_REPLY))) {
  110. nRet = 0;
  111. break;
  112. }
  113. /*
  114. * This is the hardest of the hooks because we need to thunk through
  115. * the message hooks in order to deal with synchronously sent messages
  116. * that point to structures - to get the structures passed across
  117. * alright, etc.
  118. *
  119. * This will call a special client-side routine that'll rebundle the
  120. * arguments and call the hook in the right format.
  121. *
  122. * Currently, the message thunk callbacks to the client-side don't take
  123. * enough parameters to pass wParam (which == fInterThread send msg).
  124. * To do this, call one of two functions.
  125. */
  126. pci = GetClientInfo();
  127. if (phk->iHook == WH_CALLWNDPROC) {
  128. pfnHk = ppfnClient->pfnHkINLPCWPSTRUCT;
  129. } else {
  130. pfnHk = ppfnClient->pfnHkINLPCWPRETSTRUCT;
  131. try {
  132. pci->dwHookData = pcwpret->lResult;
  133. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  134. nRet = 0;
  135. break;
  136. }
  137. }
  138. /*
  139. * Save current hook state.
  140. */
  141. try {
  142. dwFlags = pci->CI_flags & CI_INTERTHREAD_HOOK;
  143. dwHookData = pci->dwHookData;
  144. if (wParam) {
  145. pci->CI_flags |= CI_INTERTHREAD_HOOK;
  146. } else {
  147. pci->CI_flags &= ~CI_INTERTHREAD_HOOK;
  148. }
  149. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  150. nRet = 0;
  151. break;
  152. }
  153. if (phk->iHook == WH_CALLWNDPROC) {
  154. nRet = ScSendMessageSMS(
  155. PW(pcwp->hwnd),
  156. pcwp->message,
  157. pcwp->wParam,
  158. pcwp->lParam,
  159. (ULONG_PTR)pfnHookProc, pfnHk,
  160. (phk->flags & HF_ANSI) ?
  161. (SCMS_FLAGS_ANSI|SCMS_FLAGS_INONLY) :
  162. SCMS_FLAGS_INONLY,
  163. psms);
  164. } else {
  165. nRet = ScSendMessageSMS(
  166. PW(pcwpret->hwnd),
  167. pcwpret->message,
  168. pcwpret->wParam,
  169. pcwpret->lParam,
  170. (ULONG_PTR)pfnHookProc, pfnHk,
  171. (phk->flags & HF_ANSI) ?
  172. (SCMS_FLAGS_ANSI|SCMS_FLAGS_INONLY) :
  173. SCMS_FLAGS_INONLY,
  174. psms);
  175. }
  176. /*
  177. * Restore previous hook state.
  178. */
  179. try {
  180. pci->CI_flags ^= ((pci->CI_flags ^ dwFlags) & CI_INTERTHREAD_HOOK);
  181. pci->dwHookData = dwHookData;
  182. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  183. nRet = 0;
  184. }
  185. break;
  186. case WH_CBT:
  187. /*
  188. * There are many different types of CBT hooks!
  189. */
  190. switch(nCode) {
  191. case HCBT_CLICKSKIPPED:
  192. goto MouseHook;
  193. break;
  194. case HCBT_CREATEWND:
  195. /*
  196. * This hook type points to a CREATESTRUCT, so we need to
  197. * be fancy with it's thunking, because a CREATESTRUCT contains
  198. * a pointer to CREATEPARAMS which can be anything... so
  199. * funnel this through our message thunks.
  200. */
  201. nRet = fnHkINLPCBTCREATESTRUCT(
  202. MAKELONG((WORD)nCode, (WORD)phk->iHook),
  203. wParam,
  204. (LPCBT_CREATEWND)lParam,
  205. pfnHookProc,
  206. (phk->flags & HF_ANSI) ? TRUE : FALSE);
  207. break;
  208. #ifdef REDIRECTION
  209. case HCBT_GETCURSORPOS:
  210. /*
  211. * This hook type points to a POINT structure, so it's pretty
  212. * simple.
  213. */
  214. nRet = fnHkINLPPOINT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  215. wParam, (LPPOINT)lParam, (ULONG_PTR)pfnHookProc,
  216. ppfnClient->pfnDispatchHook);
  217. break;
  218. #endif // REDIRECTION
  219. case HCBT_MOVESIZE:
  220. /*
  221. * This hook type points to a RECT structure, so it's pretty
  222. * simple.
  223. */
  224. nRet = fnHkINLPRECT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  225. wParam, (LPRECT)lParam, (ULONG_PTR)pfnHookProc,
  226. ppfnClient->pfnDispatchHook);
  227. break;
  228. case HCBT_ACTIVATE:
  229. /*
  230. * This hook type points to a CBTACTIVATESTRUCT
  231. */
  232. nRet = fnHkINLPCBTACTIVATESTRUCT(MAKELONG((UINT)nCode,
  233. (UINT)phk->iHook), wParam, (LPCBTACTIVATESTRUCT)lParam,
  234. (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
  235. break;
  236. default:
  237. /*
  238. * The rest of the cbt hooks are all dword parameters.
  239. */
  240. nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  241. wParam, lParam, (ULONG_PTR)pfnHookProc,
  242. ppfnClient->pfnDispatchHook, &phk->flags);
  243. break;
  244. }
  245. break;
  246. case WH_FOREGROUNDIDLE:
  247. /*
  248. * These are dword parameters and are therefore real easy.
  249. *
  250. */
  251. nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  252. wParam, lParam, (ULONG_PTR)pfnHookProc,
  253. ppfnClient->pfnDispatchHook, &phk->flags);
  254. break;
  255. case WH_SHELL:
  256. if (nCode == HSHELL_GETMINRECT) {
  257. /*
  258. * This hook type points to a RECT structure, so it's pretty
  259. * simple.
  260. */
  261. nRet = fnHkINLPRECT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  262. wParam, (LPRECT)lParam, (ULONG_PTR)pfnHookProc,
  263. ppfnClient->pfnDispatchHook);
  264. break;
  265. }
  266. /*
  267. * Otherwise fall through to the simple case of DWORD below
  268. */
  269. case WH_KEYBOARD:
  270. /*
  271. * These are dword parameters and are therefore real easy.
  272. */
  273. nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  274. wParam, lParam, (ULONG_PTR)pfnHookProc,
  275. ppfnClient->pfnDispatchHook, &phk->flags);
  276. break;
  277. case WH_MSGFILTER:
  278. case WH_SYSMSGFILTER:
  279. case WH_GETMESSAGE:
  280. /*
  281. * These take an lpMsg as their last parameter. Since these are
  282. * exclusively posted parameters, and since nowhere on the server
  283. * do we post a message with a pointer to some other structure in
  284. * it, the lpMsg structure contents can all be treated verbatim.
  285. */
  286. nRet = fnHkINLPMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  287. wParam, (LPMSG)lParam, (ULONG_PTR)pfnHookProc,
  288. ppfnClient->pfnDispatchHook,
  289. (phk->flags & HF_ANSI) ? TRUE : FALSE, &phk->flags);
  290. break;
  291. case WH_JOURNALPLAYBACK:
  292. #ifdef HOOKBATCH
  293. /*
  294. * If this hook has cached playback info then we need to grab
  295. * the info out of the cache.
  296. */
  297. if (phk->cEventMessages) {
  298. if (nCode == HC_GETNEXT) {
  299. LPEVENTMSG pEventMsg;
  300. pEventMsg = (LPEVENTMSG)lParam;
  301. if (phk->flags & HF_NEEDHC_SKIP)
  302. phk->iCurrentEvent++;
  303. if (phk->iCurrentEvent < phk->cEventMessages) {
  304. *pEventMsg = phk->aEventCache[phk->iCurrentEvent];
  305. } else {
  306. /*
  307. * Free the cache set if it is still around
  308. */
  309. if (phk->aEventCache) {
  310. UserFreePool(phk->aEventCache);
  311. phk->aEventCache = NULL;
  312. }
  313. phk->cEventMessages = 0;
  314. phk->iCurrentEvent = 0;
  315. goto MakeClientJournalPlaybackCall;
  316. }
  317. /*
  318. * Return the time and zero the batched time so if we sleep
  319. * this time we won't sleep again next time
  320. */
  321. nRet = pEventMsg->time;
  322. if (nRet)
  323. phk->aEventCache[phk->iCurrentEvent].time = 0;
  324. } else if (nCode == HC_SKIP) {
  325. phk->iCurrentEvent++;
  326. nRet = 0;
  327. }
  328. } else {
  329. #endif // HOOKBATCH
  330. /*
  331. * In order to avoid a client/server transition for HC_SKIP we
  332. * piggy-back it on top of the next journal playback event and
  333. * send it from there.
  334. */
  335. // MakeClientJournalPlaybackCall:
  336. nRet = fnHkOPTINLPEVENTMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  337. (WPARAM)PtoHq(phk), (LPEVENTMSG)lParam, (ULONG_PTR)pfnHookProc,
  338. ppfnClient->pfnDispatchHook);
  339. #ifdef HOOKBATCH
  340. }
  341. /*
  342. * Determine if we received a cached set of events if so then store
  343. * them away off of the hook.
  344. * paramL will be the number of events.
  345. * paramH will be the array of events.
  346. */
  347. if ((nCode == HC_GETNEXT) && (((LPEVENTMSG)lParam)->message == 0x12341234)) {
  348. NTSTATUS Status;
  349. LPEVENTMSG pEventMsg = (LPEVENTMSG)lParam;
  350. /*
  351. * We should not be getting another cached set if we aren't
  352. * done with the first set
  353. */
  354. UserAssert((phk->cEventMessages == 0) ||
  355. (phk->cEventMessages >= phk->iCurrentEvent));
  356. UserAssert((pEventMsg->paramL < 500) && (pEventMsg->paramL > 1));
  357. /*
  358. * Free the last cache set if it is still around
  359. */
  360. if (phk->aEventCache) {
  361. UserFreePool(phk->aEventCache);
  362. phk->aEventCache = NULL;
  363. }
  364. if (phk->aEventCache = LocalAlloc(LPTR,
  365. pEventMsg->paramL*sizeof(EVENTMSG))) {
  366. PETHREAD Thread = PsGetCurrentThread();
  367. Status = ZwReadVirtualMemory(Thread->Process->ProcessHandle,
  368. (PVOID)pEventMsg->paramH, phk->aEventCache,
  369. pEventMsg->paramL*sizeof(EVENTMSG), NULL);
  370. if (NT_SUCCESS(Status)) {
  371. phk->cEventMessages = pEventMsg->paramL;
  372. phk->iCurrentEvent = 0;
  373. /*
  374. * Fill in the real EventMsg for this message
  375. */
  376. *pEventMsg = phk->aEventCache[0];
  377. phk->aEventCache[0].time = 0;
  378. }
  379. } else {
  380. phk->cEventMessages = 0;
  381. phk->iCurrentEvent = 0;
  382. }
  383. }
  384. #endif // HOOKBATCH
  385. phk->flags &= ~HF_NEEDHC_SKIP;
  386. break;
  387. case WH_JOURNALRECORD:
  388. nRet = fnHkOPTINLPEVENTMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  389. wParam, (LPEVENTMSG)lParam, (ULONG_PTR)pfnHookProc,
  390. ppfnClient->pfnDispatchHook);
  391. break;
  392. case WH_DEBUG:
  393. /*
  394. * This takes an lpDebugHookStruct.
  395. */
  396. nRet = fnHkINLPDEBUGHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  397. wParam, (LPDEBUGHOOKINFO)lParam, (ULONG_PTR)pfnHookProc,
  398. ppfnClient->pfnDispatchHook);
  399. break;
  400. case WH_KEYBOARD_LL:
  401. /*
  402. * This takes an lpKbdHookStruct.
  403. */
  404. nRet = fnHkINLPKBDLLHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  405. wParam, (LPKBDLLHOOKSTRUCT)lParam,
  406. (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
  407. break;
  408. case WH_MOUSE_LL:
  409. /*
  410. * This takes an lpMsllHookStruct.
  411. */
  412. nRet = fnHkINLPMSLLHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  413. wParam, (LPMSLLHOOKSTRUCT)lParam,
  414. (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
  415. break;
  416. case WH_MOUSE:
  417. /*
  418. * This takes an lpMouseHookStructEx.
  419. */
  420. MouseHook:
  421. nRet = fnHkINLPMOUSEHOOKSTRUCTEX(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  422. wParam, (LPMOUSEHOOKSTRUCTEX)lParam,
  423. (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook, &phk->flags);
  424. break;
  425. #ifdef REDIRECTION
  426. case WH_HITTEST:
  427. /*
  428. * This takes an lpHTHookStruct.
  429. */
  430. nRet = fnHkINLPHTHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
  431. wParam, (LPHTHOOKSTRUCT)lParam,
  432. (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
  433. break;
  434. #endif // REDIRECTION
  435. }
  436. #ifdef LATER // per 246329
  437. if (fLockForeground) {
  438. ThreadUnlockSFWLockCount(&tlSFWLock);
  439. }
  440. #endif
  441. return nRet;
  442. }
  443. /***************************************************************************\
  444. * fnHkINLPCWPEXSTRUCT
  445. *
  446. * This gets thunked through the message thunks, so it has the format
  447. * of a c/s message thunk call.
  448. *
  449. * 05-09-91 ScottLu Created.
  450. \***************************************************************************/
  451. LRESULT fnHkINLPCWPEXSTRUCT(
  452. PWND pwnd,
  453. UINT message,
  454. WPARAM wParam,
  455. LPARAM lParam,
  456. ULONG_PTR xParam)
  457. {
  458. CWPSTRUCTEX cwp;
  459. PCLIENTINFO pci = GetClientInfo();
  460. BOOL bInterThread;
  461. UNREFERENCED_PARAMETER(xParam);
  462. cwp.hwnd = HW(pwnd);
  463. cwp.message = message;
  464. cwp.wParam = wParam;
  465. cwp.lParam = lParam;
  466. cwp.psmsSender = NULL;
  467. try {
  468. bInterThread = (pci->CI_flags & CI_INTERTHREAD_HOOK) != 0;
  469. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  470. return 0;
  471. }
  472. return xxxCallNextHookEx(HC_ACTION, bInterThread, (LPARAM)&cwp);
  473. }
  474. LRESULT fnHkINLPCWPRETEXSTRUCT(
  475. PWND pwnd,
  476. UINT message,
  477. WPARAM wParam,
  478. LPARAM lParam,
  479. ULONG_PTR xParam)
  480. {
  481. CWPRETSTRUCTEX cwp;
  482. PCLIENTINFO pci = GetClientInfo();
  483. BOOL bInterThread;
  484. UNREFERENCED_PARAMETER(xParam);
  485. cwp.hwnd = HW(pwnd);
  486. cwp.message = message;
  487. cwp.wParam = wParam;
  488. cwp.lParam = lParam;
  489. cwp.psmsSender = NULL;
  490. try {
  491. cwp.lResult = pci->dwHookData;
  492. bInterThread = (pci->CI_flags & CI_INTERTHREAD_HOOK) != 0;
  493. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  494. return 0;
  495. }
  496. return xxxCallNextHookEx(HC_ACTION, bInterThread, (LPARAM)&cwp);
  497. }