1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Window hooks 5 * FILE: win32ss/user/ntuser/hook.c 6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * James Tabor (james.tabor@rectos.org) 8 * Rafal Harabien (rafalh@reactos.org) 9 * NOTE: Most of this code was adapted from Wine, 10 * Copyright (C) 2002 Alexandre Julliard 11 */ 12 13 #include <win32k.h> 14 DBG_DEFAULT_CHANNEL(UserHook); 15 16 typedef struct _HOOKPACK 17 { 18 PHOOK pHk; 19 LPARAM lParam; 20 PVOID pHookStructs; 21 } HOOKPACK, *PHOOKPACK; 22 23 UNICODE_STRING strUahModule; 24 UNICODE_STRING strUahInitFunc; 25 PPROCESSINFO ppiUahServer; 26 27 /* PRIVATE FUNCTIONS *********************************************************/ 28 29 /* Calls ClientLoadLibrary in user32 in order to load or unload a module */ 30 BOOL 31 IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload) 32 { 33 PPROCESSINFO ppi; 34 BOOL bResult; 35 36 ppi = PsGetCurrentProcessWin32Process(); 37 38 TRACE("IntLoadHookModule. Client PID: %p\n", PsGetProcessId(ppi->peProcess)); 39 40 /* Check if this is the api hook */ 41 if(iHookID == WH_APIHOOK) 42 { 43 if(!Unload && !(ppi->W32PF_flags & W32PF_APIHOOKLOADED)) 44 { 45 /* A callback in user mode can trigger UserLoadApiHook to be called and 46 as a result IntLoadHookModule will be called recursively. 47 To solve this we set the flag that means that the appliaction has 48 loaded the api hook before the callback and in case of error we remove it */ 49 ppi->W32PF_flags |= W32PF_APIHOOKLOADED; 50 51 /* Call ClientLoadLibrary in user32 */ 52 bResult = co_IntClientLoadLibrary(&strUahModule, &strUahInitFunc, Unload, TRUE); 53 TRACE("co_IntClientLoadLibrary returned %d\n", bResult ); 54 if (!bResult) 55 { 56 /* Remove the flag we set before */ 57 ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED; 58 } 59 return bResult; 60 } 61 else if(Unload && (ppi->W32PF_flags & W32PF_APIHOOKLOADED)) 62 { 63 /* Call ClientLoadLibrary in user32 */ 64 bResult = co_IntClientLoadLibrary(NULL, NULL, Unload, TRUE); 65 if (bResult) 66 { 67 ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED; 68 } 69 return bResult; 70 } 71 72 return TRUE; 73 } 74 75 STUB; 76 77 return FALSE; 78 } 79 80 /* 81 IntHookModuleUnloaded: 82 Sends a internal message to all threads of the requested desktop 83 and notifies them that a global hook was destroyed 84 and an injected module must be unloaded. 85 As a result, IntLoadHookModule will be called for all the threads that 86 will receive the special purpose internal message. 87 */ 88 BOOL 89 IntHookModuleUnloaded(PDESKTOP pdesk, int iHookID, HHOOK hHook) 90 { 91 PTHREADINFO ptiCurrent; 92 PLIST_ENTRY ListEntry; 93 PPROCESSINFO ppiCsr; 94 95 TRACE("IntHookModuleUnloaded: iHookID=%d\n", iHookID); 96 97 ppiCsr = PsGetProcessWin32Process(gpepCSRSS); 98 99 ListEntry = pdesk->PtiList.Flink; 100 while(ListEntry != &pdesk->PtiList) 101 { 102 ptiCurrent = CONTAINING_RECORD(ListEntry, THREADINFO, PtiLink); 103 104 /* FIXME: Do some more security checks here */ 105 106 /* FIXME: HACK: The first check is a reactos specific hack for system threads */ 107 if(!PsIsSystemProcess(ptiCurrent->ppi->peProcess) && 108 ptiCurrent->ppi != ppiCsr) 109 { 110 if(ptiCurrent->ppi->W32PF_flags & W32PF_APIHOOKLOADED) 111 { 112 TRACE("IntHookModuleUnloaded: sending message to PID %p, ppi=%p\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi); 113 co_MsqSendMessageAsync( ptiCurrent, 114 0, 115 iHookID, 116 TRUE, 117 (LPARAM)hHook, 118 NULL, 119 0, 120 FALSE, 121 MSQ_INJECTMODULE); 122 } 123 } 124 ListEntry = ListEntry->Flink; 125 } 126 127 return TRUE; 128 } 129 130 BOOL 131 FASTCALL 132 UserLoadApiHook(VOID) 133 { 134 return IntLoadHookModule(WH_APIHOOK, 0, FALSE); 135 } 136 137 BOOL 138 FASTCALL 139 UserRegisterUserApiHook( 140 PUNICODE_STRING pstrDllName, 141 PUNICODE_STRING pstrFuncName) 142 { 143 PTHREADINFO pti, ptiCurrent; 144 HWND *List; 145 PWND DesktopWindow, pwndCurrent; 146 ULONG i; 147 PPROCESSINFO ppiCsr; 148 149 pti = PsGetCurrentThreadWin32Thread(); 150 ppiCsr = PsGetProcessWin32Process(gpepCSRSS); 151 152 /* Fail if the api hook is already registered */ 153 if(gpsi->dwSRVIFlags & SRVINFO_APIHOOK) 154 { 155 return FALSE; 156 } 157 158 TRACE("UserRegisterUserApiHook. Server PID: %p\n", PsGetProcessId(pti->ppi->peProcess)); 159 160 /* Register the api hook */ 161 gpsi->dwSRVIFlags |= SRVINFO_APIHOOK; 162 163 strUahModule = *pstrDllName; 164 strUahInitFunc = *pstrFuncName; 165 ppiUahServer = pti->ppi; 166 167 /* Broadcast an internal message to every top level window */ 168 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow()); 169 List = IntWinListChildren(DesktopWindow); 170 171 if (List != NULL) 172 { 173 for (i = 0; List[i]; i++) 174 { 175 pwndCurrent = UserGetWindowObject(List[i]); 176 if(pwndCurrent == NULL) 177 { 178 continue; 179 } 180 ptiCurrent = pwndCurrent->head.pti; 181 182 /* FIXME: The first check is a reactos specific hack for system threads */ 183 if(PsIsSystemProcess(ptiCurrent->ppi->peProcess) || 184 ptiCurrent->ppi == ppiCsr) 185 { 186 continue; 187 } 188 189 co_MsqSendMessageAsync( ptiCurrent, 190 0, 191 WH_APIHOOK, 192 FALSE, /* Load the module */ 193 0, 194 NULL, 195 0, 196 FALSE, 197 MSQ_INJECTMODULE); 198 } 199 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 200 } 201 202 return TRUE; 203 } 204 205 BOOL 206 FASTCALL 207 UserUnregisterUserApiHook(VOID) 208 { 209 PTHREADINFO pti; 210 211 pti = PsGetCurrentThreadWin32Thread(); 212 213 /* Fail if the api hook is not registered */ 214 if(!(gpsi->dwSRVIFlags & SRVINFO_APIHOOK)) 215 { 216 return FALSE; 217 } 218 219 /* Only the process that registered the api hook can uregister it */ 220 if(ppiUahServer != PsGetCurrentProcessWin32Process()) 221 { 222 return FALSE; 223 } 224 225 TRACE("UserUnregisterUserApiHook. Server PID: %p\n", PsGetProcessId(pti->ppi->peProcess)); 226 227 /* Unregister the api hook */ 228 gpsi->dwSRVIFlags &= ~SRVINFO_APIHOOK; 229 ppiUahServer = NULL; 230 ReleaseCapturedUnicodeString(&strUahModule, UserMode); 231 ReleaseCapturedUnicodeString(&strUahInitFunc, UserMode); 232 233 /* Notify all applications that the api hook module must be unloaded */ 234 return IntHookModuleUnloaded(pti->rpdesk, WH_APIHOOK, 0); 235 } 236 237 static 238 LRESULT 239 FASTCALL 240 co_IntCallLowLevelHook(PHOOK Hook, 241 INT Code, 242 WPARAM wParam, 243 LPARAM lParam) 244 { 245 NTSTATUS Status; 246 PTHREADINFO pti; 247 PHOOKPACK pHP; 248 INT Size = 0; 249 UINT uTimeout = 300; 250 BOOL Block = FALSE; 251 ULONG_PTR uResult = 0; 252 253 if (Hook->ptiHooked) 254 pti = Hook->ptiHooked; 255 else 256 pti = Hook->head.pti; 257 258 pHP = ExAllocatePoolWithTag(NonPagedPool, sizeof(HOOKPACK), TAG_HOOK); 259 if (!pHP) return 0; 260 261 pHP->pHk = Hook; 262 pHP->lParam = lParam; 263 pHP->pHookStructs = NULL; 264 265 // This prevents stack corruption from the caller. 266 switch(Hook->HookId) 267 { 268 case WH_JOURNALPLAYBACK: 269 case WH_JOURNALRECORD: 270 uTimeout = 0; 271 Size = sizeof(EVENTMSG); 272 break; 273 case WH_KEYBOARD_LL: 274 Size = sizeof(KBDLLHOOKSTRUCT); 275 break; 276 case WH_MOUSE_LL: 277 Size = sizeof(MSLLHOOKSTRUCT); 278 break; 279 case WH_MOUSE: 280 uTimeout = 200; 281 Block = TRUE; 282 Size = sizeof(MOUSEHOOKSTRUCT); 283 break; 284 case WH_KEYBOARD: 285 uTimeout = 200; 286 Block = TRUE; 287 break; 288 } 289 290 if (Size) 291 { 292 pHP->pHookStructs = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK); 293 if (pHP->pHookStructs) RtlCopyMemory(pHP->pHookStructs, (PVOID)lParam, Size); 294 } 295 296 /* FIXME: Should get timeout from 297 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */ 298 Status = co_MsqSendMessage( pti, 299 IntToPtr(Code), // hWnd 300 Hook->HookId, // Msg 301 wParam, 302 (LPARAM)pHP, 303 uTimeout, 304 Block, 305 MSQ_ISHOOK, 306 &uResult); 307 if (!NT_SUCCESS(Status)) 308 { 309 ERR("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook->HookId, Status); 310 if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK); 311 ExFreePoolWithTag(pHP, TAG_HOOK); 312 } 313 return NT_SUCCESS(Status) ? uResult : 0; 314 } 315 316 317 // 318 // Dispatch MsgQueue Hook Call processor! 319 // 320 LRESULT 321 APIENTRY 322 co_CallHook( INT HookId, 323 INT Code, 324 WPARAM wParam, 325 LPARAM lParam) 326 { 327 LRESULT Result = 0; 328 PHOOK phk; 329 PHOOKPACK pHP = (PHOOKPACK)lParam; 330 331 phk = pHP->pHk; 332 lParam = pHP->lParam; 333 334 switch(HookId) 335 { 336 case WH_JOURNALPLAYBACK: 337 case WH_JOURNALRECORD: 338 case WH_KEYBOARD_LL: 339 case WH_MOUSE_LL: 340 case WH_MOUSE: 341 lParam = (LPARAM)pHP->pHookStructs; 342 case WH_KEYBOARD: 343 break; 344 } 345 346 if (!UserObjectInDestroy(UserHMGetHandle(phk))) //// Fix CORE-10549. 347 { 348 /* The odds are high for this to be a Global call. */ 349 Result = co_IntCallHookProc( HookId, 350 Code, 351 wParam, 352 lParam, 353 phk->Proc, 354 phk->ihmod, 355 phk->offPfn, 356 phk->Ansi, 357 &phk->ModuleName); 358 } 359 /* The odds so high, no one is waiting for the results. */ 360 if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK); 361 ExFreePoolWithTag(pHP, TAG_HOOK); 362 return Result; 363 } 364 365 static 366 LRESULT 367 APIENTRY 368 co_HOOK_CallHookNext( PHOOK Hook, 369 INT Code, 370 WPARAM wParam, 371 LPARAM lParam) 372 { 373 TRACE("Calling Next HOOK %d\n", Hook->HookId); 374 375 return co_IntCallHookProc( Hook->HookId, 376 Code, 377 wParam, 378 lParam, 379 Hook->Proc, 380 Hook->ihmod, 381 Hook->offPfn, 382 Hook->Ansi, 383 &Hook->ModuleName); 384 } 385 386 static 387 LRESULT 388 FASTCALL 389 co_IntCallDebugHook(PHOOK Hook, 390 int Code, 391 WPARAM wParam, 392 LPARAM lParam, 393 BOOL Ansi) 394 { 395 LRESULT lResult = 0; 396 ULONG Size; 397 DEBUGHOOKINFO Debug; 398 PVOID HooklParam = NULL; 399 BOOL BadChk = FALSE; 400 401 if (lParam) 402 { 403 _SEH2_TRY 404 { 405 ProbeForRead((PVOID)lParam, 406 sizeof(DEBUGHOOKINFO), 407 1); 408 409 RtlCopyMemory(&Debug, 410 (PVOID)lParam, 411 sizeof(DEBUGHOOKINFO)); 412 } 413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 414 { 415 BadChk = TRUE; 416 } 417 _SEH2_END; 418 419 if (BadChk) 420 { 421 ERR("HOOK WH_DEBUG read from lParam ERROR!\n"); 422 return lResult; 423 } 424 } 425 else 426 return lResult; /* Need lParam! */ 427 428 switch (wParam) 429 { 430 case WH_CBT: 431 { 432 switch (Debug.code) 433 { 434 case HCBT_CLICKSKIPPED: 435 Size = sizeof(MOUSEHOOKSTRUCTEX); 436 break; 437 438 case HCBT_MOVESIZE: 439 Size = sizeof(RECT); 440 break; 441 442 case HCBT_ACTIVATE: 443 Size = sizeof(CBTACTIVATESTRUCT); 444 break; 445 446 case HCBT_CREATEWND: /* Handle ANSI? */ 447 Size = sizeof(CBT_CREATEWND); 448 /* What shall we do? Size += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS); same as CREATESTRUCTEX */ 449 break; 450 451 default: 452 Size = sizeof(LPARAM); 453 } 454 } 455 break; 456 457 case WH_MOUSE_LL: 458 Size = sizeof(MSLLHOOKSTRUCT); 459 break; 460 461 case WH_KEYBOARD_LL: 462 Size = sizeof(KBDLLHOOKSTRUCT); 463 break; 464 465 case WH_MSGFILTER: 466 case WH_SYSMSGFILTER: 467 case WH_GETMESSAGE: 468 Size = sizeof(MSG); 469 break; 470 471 case WH_JOURNALPLAYBACK: 472 case WH_JOURNALRECORD: 473 Size = sizeof(EVENTMSG); 474 break; 475 476 case WH_FOREGROUNDIDLE: 477 case WH_KEYBOARD: 478 case WH_SHELL: 479 default: 480 Size = sizeof(LPARAM); 481 } 482 483 if (Size > sizeof(LPARAM)) 484 HooklParam = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK); 485 486 if (HooklParam) 487 { 488 _SEH2_TRY 489 { 490 ProbeForRead((PVOID)Debug.lParam, 491 Size, 492 1); 493 494 RtlCopyMemory(HooklParam, 495 (PVOID)Debug.lParam, 496 Size); 497 } 498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 499 { 500 BadChk = TRUE; 501 } 502 _SEH2_END; 503 504 if (BadChk) 505 { 506 ERR("HOOK WH_DEBUG read from Debug.lParam ERROR!\n"); 507 ExFreePoolWithTag(HooklParam, TAG_HOOK); 508 return lResult; 509 } 510 } 511 512 if (HooklParam) Debug.lParam = (LPARAM)HooklParam; 513 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Debug); 514 if (HooklParam) ExFreePoolWithTag(HooklParam, TAG_HOOK); 515 516 return lResult; 517 } 518 519 static 520 LRESULT 521 APIENTRY 522 co_UserCallNextHookEx(PHOOK Hook, 523 int Code, 524 WPARAM wParam, 525 LPARAM lParam, 526 BOOL Ansi) 527 { 528 LRESULT lResult = 0; 529 BOOL BadChk = FALSE; 530 531 /* Handle this one first. */ 532 if ((Hook->HookId == WH_MOUSE) || 533 (Hook->HookId == WH_CBT && Code == HCBT_CLICKSKIPPED)) 534 { 535 MOUSEHOOKSTRUCTEX Mouse; 536 if (lParam) 537 { 538 _SEH2_TRY 539 { 540 ProbeForRead((PVOID)lParam, 541 sizeof(MOUSEHOOKSTRUCTEX), 542 1); 543 544 RtlCopyMemory(&Mouse, 545 (PVOID)lParam, 546 sizeof(MOUSEHOOKSTRUCTEX)); 547 } 548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 549 { 550 BadChk = TRUE; 551 } 552 _SEH2_END; 553 554 if (BadChk) 555 { 556 ERR("HOOK WH_MOUSE read from lParam ERROR!\n"); 557 } 558 } 559 560 if (!BadChk) 561 { 562 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse); 563 } 564 565 return lResult; 566 } 567 568 switch(Hook->HookId) 569 { 570 case WH_MOUSE_LL: 571 { 572 MSLLHOOKSTRUCT Mouse; 573 574 if (lParam) 575 { 576 _SEH2_TRY 577 { 578 ProbeForRead((PVOID)lParam, 579 sizeof(MSLLHOOKSTRUCT), 580 1); 581 582 RtlCopyMemory(&Mouse, 583 (PVOID)lParam, 584 sizeof(MSLLHOOKSTRUCT)); 585 } 586 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 587 { 588 BadChk = TRUE; 589 } 590 _SEH2_END; 591 592 if (BadChk) 593 { 594 ERR("HOOK WH_MOUSE_LL read from lParam ERROR!\n"); 595 } 596 } 597 598 if (!BadChk) 599 { 600 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse); 601 } 602 break; 603 } 604 605 case WH_KEYBOARD_LL: 606 { 607 KBDLLHOOKSTRUCT Keyboard; 608 609 if (lParam) 610 { 611 _SEH2_TRY 612 { 613 ProbeForRead((PVOID)lParam, 614 sizeof(KBDLLHOOKSTRUCT), 615 1); 616 617 RtlCopyMemory(&Keyboard, 618 (PVOID)lParam, 619 sizeof(KBDLLHOOKSTRUCT)); 620 } 621 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 622 { 623 BadChk = TRUE; 624 } 625 _SEH2_END; 626 627 if (BadChk) 628 { 629 ERR("HOOK WH_KEYBORD_LL read from lParam ERROR!\n"); 630 } 631 } 632 633 if (!BadChk) 634 { 635 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Keyboard); 636 } 637 break; 638 } 639 640 case WH_MSGFILTER: 641 case WH_SYSMSGFILTER: 642 case WH_GETMESSAGE: 643 { 644 MSG Msg; 645 646 if (lParam) 647 { 648 _SEH2_TRY 649 { 650 ProbeForRead((PVOID)lParam, 651 sizeof(MSG), 652 1); 653 654 RtlCopyMemory(&Msg, 655 (PVOID)lParam, 656 sizeof(MSG)); 657 } 658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 659 { 660 BadChk = TRUE; 661 } 662 _SEH2_END; 663 664 if (BadChk) 665 { 666 ERR("HOOK WH_XMESSAGEX read from lParam ERROR!\n"); 667 } 668 } 669 670 if (!BadChk) 671 { 672 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Msg); 673 674 if (lParam && (Hook->HookId == WH_GETMESSAGE)) 675 { 676 _SEH2_TRY 677 { 678 ProbeForWrite((PVOID)lParam, 679 sizeof(MSG), 680 1); 681 682 RtlCopyMemory((PVOID)lParam, 683 &Msg, 684 sizeof(MSG)); 685 } 686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 687 { 688 BadChk = TRUE; 689 } 690 _SEH2_END; 691 692 if (BadChk) 693 { 694 ERR("HOOK WH_GETMESSAGE write to lParam ERROR!\n"); 695 } 696 } 697 } 698 break; 699 } 700 701 case WH_CBT: 702 TRACE("HOOK WH_CBT!\n"); 703 switch (Code) 704 { 705 case HCBT_CREATEWND: 706 { 707 LPCBT_CREATEWNDW pcbtcww = (LPCBT_CREATEWNDW)lParam; 708 709 TRACE("HOOK HCBT_CREATEWND\n"); 710 _SEH2_TRY 711 { 712 if (Ansi) 713 { 714 ProbeForRead( pcbtcww, 715 sizeof(CBT_CREATEWNDA), 716 1); 717 ProbeForWrite(pcbtcww->lpcs, 718 sizeof(CREATESTRUCTA), 719 1); 720 ProbeForRead( pcbtcww->lpcs->lpszName, 721 sizeof(CHAR), 722 1); 723 724 if (!IS_ATOM(pcbtcww->lpcs->lpszClass)) 725 { 726 _Analysis_assume_(pcbtcww->lpcs->lpszClass != NULL); 727 ProbeForRead(pcbtcww->lpcs->lpszClass, 728 sizeof(CHAR), 729 1); 730 } 731 } 732 else 733 { 734 ProbeForRead( pcbtcww, 735 sizeof(CBT_CREATEWNDW), 736 1); 737 ProbeForWrite(pcbtcww->lpcs, 738 sizeof(CREATESTRUCTW), 739 1); 740 ProbeForRead( pcbtcww->lpcs->lpszName, 741 sizeof(WCHAR), 742 1); 743 744 if (!IS_ATOM(pcbtcww->lpcs->lpszClass)) 745 { 746 _Analysis_assume_(pcbtcww->lpcs->lpszClass != NULL); 747 ProbeForRead(pcbtcww->lpcs->lpszClass, 748 sizeof(WCHAR), 749 1); 750 } 751 } 752 } 753 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 754 { 755 BadChk = TRUE; 756 } 757 _SEH2_END; 758 759 if (BadChk) 760 { 761 ERR("HOOK HCBT_CREATEWND write ERROR!\n"); 762 } 763 /* The next call handles the structures. */ 764 if (!BadChk && Hook->Proc) 765 { 766 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam); 767 } 768 break; 769 } 770 771 case HCBT_MOVESIZE: 772 { 773 RECTL rt; 774 775 TRACE("HOOK HCBT_MOVESIZE\n"); 776 777 if (lParam) 778 { 779 _SEH2_TRY 780 { 781 ProbeForRead((PVOID)lParam, 782 sizeof(RECT), 783 1); 784 785 RtlCopyMemory(&rt, 786 (PVOID)lParam, 787 sizeof(RECT)); 788 } 789 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 790 { 791 BadChk = TRUE; 792 } 793 _SEH2_END; 794 795 if (BadChk) 796 { 797 ERR("HOOK HCBT_MOVESIZE read from lParam ERROR!\n"); 798 } 799 } 800 801 if (!BadChk) 802 { 803 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&rt); 804 } 805 break; 806 } 807 808 case HCBT_ACTIVATE: 809 { 810 CBTACTIVATESTRUCT CbAs; 811 812 TRACE("HOOK HCBT_ACTIVATE\n"); 813 if (lParam) 814 { 815 _SEH2_TRY 816 { 817 ProbeForRead((PVOID)lParam, 818 sizeof(CBTACTIVATESTRUCT), 819 1); 820 821 RtlCopyMemory(&CbAs, 822 (PVOID)lParam, 823 sizeof(CBTACTIVATESTRUCT)); 824 } 825 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 826 { 827 BadChk = TRUE; 828 } 829 _SEH2_END; 830 831 if (BadChk) 832 { 833 ERR("HOOK HCBT_ACTIVATE read from lParam ERROR!\n"); 834 } 835 } 836 837 if (!BadChk) 838 { 839 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&CbAs); 840 } 841 break; 842 } 843 844 /* The rest just use default. */ 845 default: 846 TRACE("HOOK HCBT_ %d\n",Code); 847 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam); 848 break; 849 } 850 break; 851 /* 852 Note WH_JOURNALPLAYBACK, 853 "To have the system wait before processing the message, the return value 854 must be the amount of time, in clock ticks, that the system should wait." 855 */ 856 case WH_JOURNALPLAYBACK: 857 case WH_JOURNALRECORD: 858 { 859 EVENTMSG EventMsg; 860 861 if (lParam) 862 { 863 _SEH2_TRY 864 { 865 ProbeForRead((PVOID)lParam, 866 sizeof(EVENTMSG), 867 1); 868 869 RtlCopyMemory(&EventMsg, 870 (PVOID)lParam, 871 sizeof(EVENTMSG)); 872 } 873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 874 { 875 BadChk = TRUE; 876 } 877 _SEH2_END; 878 879 if (BadChk) 880 { 881 ERR("HOOK WH_JOURNAL read from lParam ERROR!\n"); 882 } 883 } 884 885 if (!BadChk) 886 { 887 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)(lParam ? &EventMsg : NULL)); 888 889 if (lParam) 890 { 891 _SEH2_TRY 892 { 893 ProbeForWrite((PVOID)lParam, 894 sizeof(EVENTMSG), 895 1); 896 897 RtlCopyMemory((PVOID)lParam, 898 &EventMsg, 899 sizeof(EVENTMSG)); 900 } 901 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 902 { 903 BadChk = TRUE; 904 } 905 _SEH2_END; 906 907 if (BadChk) 908 { 909 ERR("HOOK WH_JOURNAL write to lParam ERROR!\n"); 910 } 911 } 912 } 913 break; 914 } 915 916 case WH_DEBUG: 917 lResult = co_IntCallDebugHook(Hook, Code, wParam, lParam, Ansi); 918 break; 919 920 /* 921 * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL. 922 */ 923 case WH_FOREGROUNDIDLE: 924 case WH_KEYBOARD: 925 case WH_SHELL: 926 lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam); 927 break; 928 929 default: 930 ERR("Unsupported HOOK Id -> %d\n",Hook->HookId); 931 break; 932 } 933 return lResult; 934 } 935 936 PHOOK 937 FASTCALL 938 IntGetHookObject(HHOOK hHook) 939 { 940 PHOOK Hook; 941 942 if (!hHook) 943 { 944 EngSetLastError(ERROR_INVALID_HOOK_HANDLE); 945 return NULL; 946 } 947 948 Hook = (PHOOK)UserGetObject(gHandleTable, hHook, TYPE_HOOK); 949 if (!Hook) 950 { 951 EngSetLastError(ERROR_INVALID_HOOK_HANDLE); 952 return NULL; 953 } 954 955 UserReferenceObject(Hook); 956 957 return Hook; 958 } 959 960 static 961 HHOOK* 962 FASTCALL 963 IntGetGlobalHookHandles(PDESKTOP pdo, int HookId) 964 { 965 PLIST_ENTRY pLastHead, pElem; 966 unsigned i = 0; 967 unsigned cHooks = 0; 968 HHOOK *pList; 969 PHOOK pHook; 970 971 pLastHead = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]; 972 for (pElem = pLastHead->Flink; pElem != pLastHead; pElem = pElem->Flink) 973 ++cHooks; 974 975 pList = ExAllocatePoolWithTag(PagedPool, (cHooks + 1) * sizeof(HHOOK), TAG_HOOK); 976 if (!pList) 977 { 978 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 979 return NULL; 980 } 981 982 for (pElem = pLastHead->Flink; pElem != pLastHead; pElem = pElem->Flink) 983 { 984 pHook = CONTAINING_RECORD(pElem, HOOK, Chain); 985 NT_ASSERT(i < cHooks); 986 pList[i++] = pHook->head.h; 987 } 988 pList[i] = NULL; 989 990 return pList; 991 } 992 993 /* Find the next hook in the chain */ 994 PHOOK 995 FASTCALL 996 IntGetNextHook(PHOOK Hook) 997 { 998 int HookId = Hook->HookId; 999 PLIST_ENTRY pLastHead, pElem; 1000 PTHREADINFO pti; 1001 1002 if (Hook->ptiHooked) 1003 { 1004 pti = Hook->ptiHooked; 1005 pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; 1006 } 1007 else 1008 { 1009 pti = PsGetCurrentThreadWin32Thread(); 1010 pLastHead = &pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]; 1011 } 1012 1013 pElem = Hook->Chain.Flink; 1014 if (pElem != pLastHead) 1015 return CONTAINING_RECORD(pElem, HOOK, Chain); 1016 return NULL; 1017 } 1018 1019 /* Free a hook, removing it from its chain */ 1020 static 1021 VOID 1022 FASTCALL 1023 IntFreeHook(PHOOK Hook) 1024 { 1025 RemoveEntryList(&Hook->Chain); 1026 if (Hook->ModuleName.Buffer) 1027 { 1028 ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK); 1029 Hook->ModuleName.Buffer = NULL; 1030 } 1031 /* Close handle */ 1032 UserDeleteObject(UserHMGetHandle(Hook), TYPE_HOOK); 1033 } 1034 1035 /* Remove a hook, freeing it from the chain */ 1036 BOOLEAN 1037 IntRemoveHook(PVOID Object) 1038 { 1039 INT HookId; 1040 PTHREADINFO pti; 1041 PDESKTOP pdo; 1042 PHOOK Hook = Object; 1043 1044 HookId = Hook->HookId; 1045 1046 if (Hook->ptiHooked) // Local 1047 { 1048 pti = Hook->ptiHooked; 1049 1050 IntFreeHook( Hook); 1051 1052 if ( IsListEmpty(&pti->aphkStart[HOOKID_TO_INDEX(HookId)]) ) 1053 { 1054 pti->fsHooks &= ~HOOKID_TO_FLAG(HookId); 1055 _SEH2_TRY 1056 { 1057 pti->pClientInfo->fsHooks = pti->fsHooks; 1058 } 1059 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1060 { 1061 /* Do nothing */ 1062 (void)0; 1063 } 1064 _SEH2_END; 1065 } 1066 } 1067 else // Global 1068 { 1069 IntFreeHook( Hook); 1070 1071 pdo = IntGetActiveDesktop(); 1072 1073 if ( pdo && 1074 pdo->pDeskInfo && 1075 IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) ) 1076 { 1077 pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId); 1078 } 1079 } 1080 1081 return TRUE; 1082 } 1083 1084 /* 1085 Win32k Kernel Space Hook Caller. 1086 */ 1087 LRESULT 1088 APIENTRY 1089 co_HOOK_CallHooks( INT HookId, 1090 INT Code, 1091 WPARAM wParam, 1092 LPARAM lParam) 1093 { 1094 PHOOK Hook, SaveHook; 1095 PTHREADINFO pti; 1096 PCLIENTINFO ClientInfo; 1097 PLIST_ENTRY pLastHead; 1098 PDESKTOP pdo; 1099 BOOL Local = FALSE, Global = FALSE; 1100 LRESULT Result = 0; 1101 USER_REFERENCE_ENTRY Ref; 1102 1103 ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK); 1104 1105 pti = PsGetCurrentThreadWin32Thread(); 1106 if (!pti || !pti->rpdesk || !pti->rpdesk->pDeskInfo) 1107 { 1108 pdo = IntGetActiveDesktop(); 1109 /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads, 1110 pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message. 1111 */ 1112 if ( !pti || !pdo || (!(HookId == WH_KEYBOARD_LL) && !(HookId == WH_MOUSE_LL)) ) 1113 { 1114 TRACE("No PDO %d\n", HookId); 1115 goto Exit; 1116 } 1117 } 1118 else 1119 { 1120 pdo = pti->rpdesk; 1121 } 1122 1123 if ( pti->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS)) 1124 { 1125 TRACE("Hook Thread dead %d\n", HookId); 1126 goto Exit; 1127 } 1128 1129 if ( ISITHOOKED(HookId) ) 1130 { 1131 TRACE("Local Hooker %d\n", HookId); 1132 Local = TRUE; 1133 } 1134 1135 if ( pdo->pDeskInfo->fsHooks & HOOKID_TO_FLAG(HookId) ) 1136 { 1137 TRACE("Global Hooker %d\n", HookId); 1138 Global = TRUE; 1139 } 1140 1141 if ( !Local && !Global ) goto Exit; // No work! 1142 1143 Hook = NULL; 1144 1145 /* SetWindowHookEx sorts out the Thread issue by placing the Hook to 1146 the correct Thread if not NULL. 1147 */ 1148 if ( Local ) 1149 { 1150 pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; 1151 if (IsListEmpty(pLastHead)) 1152 { 1153 ERR("No Local Hook Found!\n"); 1154 goto Exit; 1155 } 1156 1157 Hook = CONTAINING_RECORD(pLastHead->Flink, HOOK, Chain); 1158 ObReferenceObject(pti->pEThread); 1159 IntReferenceThreadInfo(pti); 1160 UserRefObjectCo(Hook, &Ref); 1161 1162 ClientInfo = pti->pClientInfo; 1163 SaveHook = pti->sphkCurrent; 1164 /* Note: Setting pti->sphkCurrent will also lock the next hook to this 1165 * hook ID. So, the CallNextHookEx will only call to that hook ID 1166 * chain anyway. For Thread Hooks.... 1167 */ 1168 1169 /* Load it for the next call. */ 1170 pti->sphkCurrent = Hook; 1171 Hook->phkNext = IntGetNextHook(Hook); 1172 if (ClientInfo) 1173 { 1174 _SEH2_TRY 1175 { 1176 ClientInfo->phkCurrent = Hook; 1177 } 1178 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1179 { 1180 ClientInfo = NULL; // Don't bother next run. 1181 } 1182 _SEH2_END; 1183 } 1184 Result = co_IntCallHookProc( HookId, 1185 Code, 1186 wParam, 1187 lParam, 1188 Hook->Proc, 1189 Hook->ihmod, 1190 Hook->offPfn, 1191 Hook->Ansi, 1192 &Hook->ModuleName); 1193 if (ClientInfo) 1194 { 1195 _SEH2_TRY 1196 { 1197 ClientInfo->phkCurrent = SaveHook; 1198 } 1199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1200 { 1201 /* Do nothing */ 1202 (void)0; 1203 } 1204 _SEH2_END; 1205 } 1206 pti->sphkCurrent = SaveHook; 1207 Hook->phkNext = NULL; 1208 UserDerefObjectCo(Hook); 1209 IntDereferenceThreadInfo(pti); 1210 ObDereferenceObject(pti->pEThread); 1211 } 1212 1213 if ( Global ) 1214 { 1215 PTHREADINFO ptiHook; 1216 HHOOK *pHookHandles; 1217 unsigned i; 1218 1219 /* Keep hooks in array because hooks can be destroyed in user world */ 1220 pHookHandles = IntGetGlobalHookHandles(pdo, HookId); 1221 if(!pHookHandles) 1222 goto Exit; 1223 1224 /* Performance goes down the drain. If more hooks are associated to this 1225 * hook ID, this will have to post to each of the thread message queues 1226 * or make a direct call. 1227 */ 1228 for(i = 0; pHookHandles[i]; ++i) 1229 { 1230 Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], TYPE_HOOK); 1231 if(!Hook) 1232 { 1233 ERR("Invalid hook!\n"); 1234 continue; 1235 } 1236 1237 /* Hook->Thread is null, we hax around this with Hook->head.pti. */ 1238 ptiHook = Hook->head.pti; 1239 1240 if ( (pti->TIF_flags & TIF_DISABLEHOOKS) || (ptiHook->TIF_flags & TIF_INCLEANUP)) 1241 { 1242 TRACE("Next Hook %p, %p\n", ptiHook->rpdesk, pdo); 1243 continue; 1244 } 1245 UserRefObjectCo(Hook, &Ref); 1246 1247 if (ptiHook != pti ) 1248 { 1249 // Block | TimeOut 1250 if ( HookId == WH_JOURNALPLAYBACK || // 1 | 0 1251 HookId == WH_JOURNALRECORD || // 1 | 0 1252 HookId == WH_KEYBOARD || // 1 | 200 1253 HookId == WH_MOUSE || // 1 | 200 1254 HookId == WH_KEYBOARD_LL || // 0 | 300 1255 HookId == WH_MOUSE_LL ) // 0 | 300 1256 { 1257 TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId ); 1258 Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam); 1259 } 1260 else if (ptiHook->ppi == pti->ppi) 1261 { 1262 TRACE("\nGlobal Hook calling to another Thread! %d\n",HookId ); 1263 ObReferenceObject(ptiHook->pEThread); 1264 IntReferenceThreadInfo(ptiHook); 1265 Result = co_IntCallHookProc( HookId, 1266 Code, 1267 wParam, 1268 lParam, 1269 Hook->Proc, 1270 Hook->ihmod, 1271 Hook->offPfn, 1272 Hook->Ansi, 1273 &Hook->ModuleName); 1274 IntDereferenceThreadInfo(ptiHook); 1275 ObDereferenceObject(ptiHook->pEThread); 1276 } 1277 } 1278 else 1279 { /* Make the direct call. */ 1280 TRACE("Global going Local Hook calling to Thread! %d\n",HookId ); 1281 ObReferenceObject(pti->pEThread); 1282 IntReferenceThreadInfo(pti); 1283 Result = co_IntCallHookProc( HookId, 1284 Code, 1285 wParam, 1286 lParam, 1287 Hook->Proc, 1288 Hook->ihmod, 1289 Hook->offPfn, 1290 Hook->Ansi, 1291 &Hook->ModuleName); 1292 IntDereferenceThreadInfo(pti); 1293 ObDereferenceObject(pti->pEThread); 1294 } 1295 UserDerefObjectCo(Hook); 1296 } 1297 ExFreePoolWithTag(pHookHandles, TAG_HOOK); 1298 TRACE("Ret: Global HookId %d Result 0x%x\n", HookId,Result); 1299 } 1300 Exit: 1301 return Result; 1302 } 1303 1304 BOOL 1305 FASTCALL 1306 IntUnhookWindowsHook(int HookId, HOOKPROC pfnFilterProc) 1307 { 1308 PHOOK Hook; 1309 PLIST_ENTRY pLastHead, pElement; 1310 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1311 1312 if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId ) 1313 { 1314 EngSetLastError(ERROR_INVALID_HOOK_FILTER); 1315 return FALSE; 1316 } 1317 1318 if (pti->fsHooks) 1319 { 1320 pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; 1321 1322 pElement = pLastHead->Flink; 1323 while (pElement != pLastHead) 1324 { 1325 Hook = CONTAINING_RECORD(pElement, HOOK, Chain); 1326 1327 /* Get the next element now, we might free the hook in what follows */ 1328 pElement = Hook->Chain.Flink; 1329 1330 if (Hook->Proc == pfnFilterProc) 1331 { 1332 if (Hook->head.pti == pti) 1333 { 1334 IntRemoveHook(Hook); 1335 return TRUE; 1336 } 1337 else 1338 { 1339 EngSetLastError(ERROR_ACCESS_DENIED); 1340 return FALSE; 1341 } 1342 } 1343 } 1344 } 1345 return FALSE; 1346 } 1347 1348 /* 1349 * Support for compatibility only? Global hooks are processed in kernel space. 1350 * This is very thread specific! Never seeing applications with more than one 1351 * hook per thread installed. Most of the applications are Global hookers and 1352 * associated with just one hook Id. Maybe it's for diagnostic testing or a 1353 * throw back to 3.11? 1354 */ 1355 LRESULT 1356 APIENTRY 1357 NtUserCallNextHookEx( int Code, 1358 WPARAM wParam, 1359 LPARAM lParam, 1360 BOOL Ansi) 1361 { 1362 PTHREADINFO pti; 1363 PHOOK HookObj, NextObj; 1364 PCLIENTINFO ClientInfo; 1365 LRESULT lResult = 0; 1366 DECLARE_RETURN(LRESULT); 1367 1368 TRACE("Enter NtUserCallNextHookEx\n"); 1369 UserEnterExclusive(); 1370 1371 pti = GetW32ThreadInfo(); 1372 1373 HookObj = pti->sphkCurrent; 1374 1375 if (!HookObj) RETURN( 0); 1376 1377 NextObj = HookObj->phkNext; 1378 1379 pti->sphkCurrent = NextObj; 1380 ClientInfo = pti->pClientInfo; 1381 _SEH2_TRY 1382 { 1383 ClientInfo->phkCurrent = NextObj; 1384 } 1385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1386 { 1387 ClientInfo = NULL; 1388 } 1389 _SEH2_END; 1390 1391 /* Now in List run down. */ 1392 if (ClientInfo && NextObj) 1393 { 1394 NextObj->phkNext = IntGetNextHook(NextObj); 1395 lResult = co_UserCallNextHookEx( NextObj, Code, wParam, lParam, NextObj->Ansi); 1396 } 1397 RETURN( lResult); 1398 1399 CLEANUP: 1400 TRACE("Leave NtUserCallNextHookEx, ret=%i\n",_ret_); 1401 UserLeave(); 1402 END_CLEANUP; 1403 } 1404 1405 HHOOK 1406 APIENTRY 1407 NtUserSetWindowsHookAW( int idHook, 1408 HOOKPROC lpfn, 1409 BOOL Ansi) 1410 { 1411 DWORD ThreadId; 1412 UNICODE_STRING USModuleName; 1413 1414 RtlInitUnicodeString(&USModuleName, NULL); 1415 ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread); 1416 1417 return NtUserSetWindowsHookEx( NULL, 1418 &USModuleName, 1419 ThreadId, 1420 idHook, 1421 lpfn, 1422 Ansi); 1423 } 1424 1425 HHOOK 1426 APIENTRY 1427 NtUserSetWindowsHookEx( HINSTANCE Mod, 1428 PUNICODE_STRING UnsafeModuleName, 1429 DWORD ThreadId, 1430 int HookId, 1431 HOOKPROC HookProc, 1432 BOOL Ansi) 1433 { 1434 PWINSTATION_OBJECT WinStaObj; 1435 PHOOK Hook = NULL; 1436 UNICODE_STRING ModuleName; 1437 NTSTATUS Status; 1438 HHOOK Handle; 1439 PTHREADINFO pti, ptiHook = NULL; 1440 DECLARE_RETURN(HHOOK); 1441 1442 TRACE("Enter NtUserSetWindowsHookEx\n"); 1443 UserEnterExclusive(); 1444 1445 pti = PsGetCurrentThreadWin32Thread(); 1446 1447 if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId ) 1448 { 1449 EngSetLastError(ERROR_INVALID_HOOK_FILTER); 1450 RETURN( NULL); 1451 } 1452 1453 if (!HookProc) 1454 { 1455 EngSetLastError(ERROR_INVALID_FILTER_PROC); 1456 RETURN( NULL); 1457 } 1458 1459 if (ThreadId) /* thread-local hook */ 1460 { 1461 if ( HookId == WH_JOURNALRECORD || 1462 HookId == WH_JOURNALPLAYBACK || 1463 HookId == WH_KEYBOARD_LL || 1464 HookId == WH_MOUSE_LL || 1465 HookId == WH_SYSMSGFILTER) 1466 { 1467 TRACE("Local hook installing Global HookId: %d\n",HookId); 1468 /* these can only be global */ 1469 EngSetLastError(ERROR_GLOBAL_ONLY_HOOK); 1470 RETURN( NULL); 1471 } 1472 1473 if ( !(ptiHook = IntTID2PTI( UlongToHandle(ThreadId) ))) 1474 { 1475 ERR("Invalid thread id 0x%x\n", ThreadId); 1476 EngSetLastError(ERROR_INVALID_PARAMETER); 1477 RETURN( NULL); 1478 } 1479 1480 if ( ptiHook->rpdesk != pti->rpdesk) // gptiCurrent->rpdesk) 1481 { 1482 ERR("Local hook wrong desktop HookId: %d\n",HookId); 1483 EngSetLastError(ERROR_ACCESS_DENIED); 1484 RETURN( NULL); 1485 } 1486 1487 if (ptiHook->ppi != pti->ppi) 1488 { 1489 if ( !Mod && 1490 (HookId == WH_GETMESSAGE || 1491 HookId == WH_CALLWNDPROC || 1492 HookId == WH_CBT || 1493 HookId == WH_HARDWARE || 1494 HookId == WH_DEBUG || 1495 HookId == WH_SHELL || 1496 HookId == WH_FOREGROUNDIDLE || 1497 HookId == WH_CALLWNDPROCRET) ) 1498 { 1499 ERR("Local hook needs hMod HookId: %d\n",HookId); 1500 EngSetLastError(ERROR_HOOK_NEEDS_HMOD); 1501 RETURN( NULL); 1502 } 1503 1504 if ( (ptiHook->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD)) && 1505 (HookId == WH_GETMESSAGE || 1506 HookId == WH_CALLWNDPROC || 1507 HookId == WH_CBT || 1508 HookId == WH_HARDWARE || 1509 HookId == WH_DEBUG || 1510 HookId == WH_SHELL || 1511 HookId == WH_FOREGROUNDIDLE || 1512 HookId == WH_CALLWNDPROCRET) ) 1513 { 1514 EngSetLastError(ERROR_HOOK_TYPE_NOT_ALLOWED); 1515 RETURN( NULL); 1516 } 1517 } 1518 } 1519 else /* System-global hook */ 1520 { 1521 ptiHook = pti; // gptiCurrent; 1522 if ( !Mod && 1523 (HookId == WH_GETMESSAGE || 1524 HookId == WH_CALLWNDPROC || 1525 HookId == WH_CBT || 1526 HookId == WH_SYSMSGFILTER || 1527 HookId == WH_HARDWARE || 1528 HookId == WH_DEBUG || 1529 HookId == WH_SHELL || 1530 HookId == WH_FOREGROUNDIDLE || 1531 HookId == WH_CALLWNDPROCRET) ) 1532 { 1533 ERR("Global hook needs hMod HookId: %d\n",HookId); 1534 EngSetLastError(ERROR_HOOK_NEEDS_HMOD); 1535 RETURN( NULL); 1536 } 1537 } 1538 1539 Status = IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation, 1540 UserMode, 1541 0, 1542 &WinStaObj, 1543 0); 1544 1545 if (!NT_SUCCESS(Status)) 1546 { 1547 SetLastNtError(Status); 1548 RETURN( NULL); 1549 } 1550 ObDereferenceObject(WinStaObj); 1551 1552 Hook = UserCreateObject(gHandleTable, NULL, ptiHook, (PHANDLE)&Handle, TYPE_HOOK, sizeof(HOOK)); 1553 1554 if (!Hook) 1555 { 1556 RETURN( NULL); 1557 } 1558 1559 Hook->ihmod = (INT_PTR)Mod; // Module Index from atom table, Do this for now. 1560 Hook->HookId = HookId; 1561 Hook->rpdesk = ptiHook->rpdesk; 1562 Hook->phkNext = NULL; /* Dont use as a chain! Use link lists for chaining. */ 1563 Hook->Proc = HookProc; 1564 Hook->Ansi = Ansi; 1565 1566 TRACE("Set Hook Desk %p DeskInfo %p Handle Desk %p\n", pti->rpdesk, pti->pDeskInfo, Hook->head.rpdesk); 1567 1568 if (ThreadId) /* Thread-local hook */ 1569 { 1570 InsertHeadList(&ptiHook->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); 1571 ptiHook->sphkCurrent = NULL; 1572 Hook->ptiHooked = ptiHook; 1573 ptiHook->fsHooks |= HOOKID_TO_FLAG(HookId); 1574 1575 if (ptiHook->pClientInfo) 1576 { 1577 if ( ptiHook->ppi == pti->ppi) /* gptiCurrent->ppi) */ 1578 { 1579 _SEH2_TRY 1580 { 1581 ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks; 1582 ptiHook->pClientInfo->phkCurrent = NULL; 1583 } 1584 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1585 { 1586 ERR("Problem writing to Local ClientInfo!\n"); 1587 } 1588 _SEH2_END; 1589 } 1590 else 1591 { 1592 KeAttachProcess(&ptiHook->ppi->peProcess->Pcb); 1593 _SEH2_TRY 1594 { 1595 ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks; 1596 ptiHook->pClientInfo->phkCurrent = NULL; 1597 } 1598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1599 { 1600 ERR("Problem writing to Remote ClientInfo!\n"); 1601 } 1602 _SEH2_END; 1603 KeDetachProcess(); 1604 } 1605 } 1606 } 1607 else 1608 { 1609 InsertHeadList(&ptiHook->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); 1610 Hook->ptiHooked = NULL; 1611 //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); 1612 ptiHook->rpdesk->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); 1613 ptiHook->sphkCurrent = NULL; 1614 ptiHook->pClientInfo->phkCurrent = NULL; 1615 } 1616 1617 RtlInitUnicodeString(&Hook->ModuleName, NULL); 1618 1619 if (Mod) 1620 { 1621 Status = MmCopyFromCaller(&ModuleName, 1622 UnsafeModuleName, 1623 sizeof(UNICODE_STRING)); 1624 if (!NT_SUCCESS(Status)) 1625 { 1626 IntRemoveHook(Hook); 1627 SetLastNtError(Status); 1628 RETURN( NULL); 1629 } 1630 1631 Hook->ModuleName.Buffer = ExAllocatePoolWithTag( PagedPool, 1632 ModuleName.MaximumLength, 1633 TAG_HOOK); 1634 if (NULL == Hook->ModuleName.Buffer) 1635 { 1636 IntRemoveHook(Hook); 1637 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1638 RETURN( NULL); 1639 } 1640 1641 Hook->ModuleName.MaximumLength = ModuleName.MaximumLength; 1642 Status = MmCopyFromCaller( Hook->ModuleName.Buffer, 1643 ModuleName.Buffer, 1644 ModuleName.MaximumLength); 1645 if (!NT_SUCCESS(Status)) 1646 { 1647 ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK); 1648 Hook->ModuleName.Buffer = NULL; 1649 IntRemoveHook(Hook); 1650 SetLastNtError(Status); 1651 RETURN( NULL); 1652 } 1653 1654 Hook->ModuleName.Length = ModuleName.Length; 1655 //// FIXME: Need to load from user32 to verify hMod before calling hook with hMod set!!!! 1656 //// Mod + offPfn == new HookProc Justin Case module is from another process. 1657 FIXME("NtUserSetWindowsHookEx Setting process hMod instance addressing.\n"); 1658 /* Make proc relative to the module base */ 1659 Hook->offPfn = (ULONG_PTR)((char *)HookProc - (char *)Mod); 1660 } 1661 else 1662 Hook->offPfn = 0; 1663 1664 TRACE("Installing: HookId %d Global %s\n", HookId, !ThreadId ? "TRUE" : "FALSE"); 1665 RETURN( Handle); 1666 1667 CLEANUP: 1668 if (Hook) 1669 UserDereferenceObject(Hook); 1670 TRACE("Leave NtUserSetWindowsHookEx, ret=%p\n", _ret_); 1671 UserLeave(); 1672 END_CLEANUP; 1673 } 1674 1675 BOOL 1676 APIENTRY 1677 NtUserUnhookWindowsHookEx(HHOOK Hook) 1678 { 1679 PHOOK HookObj; 1680 DECLARE_RETURN(BOOL); 1681 1682 TRACE("Enter NtUserUnhookWindowsHookEx\n"); 1683 UserEnterExclusive(); 1684 1685 if (!(HookObj = IntGetHookObject(Hook))) 1686 { 1687 ERR("Invalid handle passed to NtUserUnhookWindowsHookEx\n"); 1688 /* SetLastNtError(Status); */ 1689 RETURN( FALSE); 1690 } 1691 1692 ASSERT(Hook == UserHMGetHandle(HookObj)); 1693 1694 IntRemoveHook(HookObj); 1695 1696 UserDereferenceObject(HookObj); 1697 1698 RETURN( TRUE); 1699 1700 CLEANUP: 1701 TRACE("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_); 1702 UserLeave(); 1703 END_CLEANUP; 1704 } 1705 1706 BOOL 1707 APIENTRY 1708 NtUserRegisterUserApiHook( 1709 PUNICODE_STRING m_dllname1, 1710 PUNICODE_STRING m_funname1, 1711 DWORD dwUnknown3, 1712 DWORD dwUnknown4) 1713 { 1714 BOOL ret; 1715 UNICODE_STRING strDllNameSafe; 1716 UNICODE_STRING strFuncNameSafe; 1717 NTSTATUS Status; 1718 1719 /* Probe and capture parameters */ 1720 Status = ProbeAndCaptureUnicodeString(&strDllNameSafe, UserMode, m_dllname1); 1721 if(!NT_SUCCESS(Status)) 1722 { 1723 EngSetLastError(RtlNtStatusToDosError(Status)); 1724 return FALSE; 1725 } 1726 1727 Status = ProbeAndCaptureUnicodeString(&strFuncNameSafe, UserMode, m_funname1); 1728 if(!NT_SUCCESS(Status)) 1729 { 1730 ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode); 1731 EngSetLastError(RtlNtStatusToDosError(Status)); 1732 return FALSE; 1733 } 1734 1735 UserEnterExclusive(); 1736 1737 /* Call internal function */ 1738 ret = UserRegisterUserApiHook(&strDllNameSafe, &strFuncNameSafe); 1739 1740 UserLeave(); 1741 1742 /* Cleanup only in case of failure */ 1743 if(ret == FALSE) 1744 { 1745 ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode); 1746 ReleaseCapturedUnicodeString(&strFuncNameSafe, UserMode); 1747 } 1748 1749 return ret; 1750 } 1751 1752 BOOL 1753 APIENTRY 1754 NtUserUnregisterUserApiHook(VOID) 1755 { 1756 BOOL ret; 1757 1758 UserEnterExclusive(); 1759 ret = UserUnregisterUserApiHook(); 1760 UserLeave(); 1761 1762 return ret; 1763 } 1764 1765 /* EOF */ 1766