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 ptiHook, pti; 1041 PDESKTOP pdo; 1042 PHOOK Hook = Object; 1043 1044 NT_ASSERT(UserIsEnteredExclusive()); 1045 1046 HookId = Hook->HookId; 1047 pti = PsGetCurrentThreadWin32Thread(); 1048 1049 if (Hook->ptiHooked) // Local 1050 { 1051 ptiHook = Hook->ptiHooked; 1052 1053 IntFreeHook(Hook); 1054 1055 if (IsListEmpty(&ptiHook->aphkStart[HOOKID_TO_INDEX(HookId)])) 1056 { 1057 BOOL bOtherProcess; 1058 KAPC_STATE ApcState; 1059 1060 ptiHook->fsHooks &= ~HOOKID_TO_FLAG(HookId); 1061 bOtherProcess = (ptiHook->ppi != pti->ppi); 1062 1063 if (bOtherProcess) 1064 KeStackAttachProcess(&ptiHook->ppi->peProcess->Pcb, &ApcState); 1065 1066 _SEH2_TRY 1067 { 1068 ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks; 1069 } 1070 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1071 { 1072 /* Do nothing */ 1073 (void)0; 1074 } 1075 _SEH2_END; 1076 1077 if (bOtherProcess) 1078 KeUnstackDetachProcess(&ApcState); 1079 } 1080 } 1081 else // Global 1082 { 1083 IntFreeHook(Hook); 1084 1085 pdo = IntGetActiveDesktop(); 1086 1087 if (pdo && 1088 pdo->pDeskInfo && 1089 IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)])) 1090 { 1091 pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId); 1092 } 1093 } 1094 1095 return TRUE; 1096 } 1097 1098 /* 1099 Win32k Kernel Space Hook Caller. 1100 */ 1101 LRESULT 1102 APIENTRY 1103 co_HOOK_CallHooks( INT HookId, 1104 INT Code, 1105 WPARAM wParam, 1106 LPARAM lParam) 1107 { 1108 PHOOK Hook, SaveHook; 1109 PTHREADINFO pti; 1110 PCLIENTINFO ClientInfo; 1111 PLIST_ENTRY pLastHead; 1112 PDESKTOP pdo; 1113 BOOL Local = FALSE, Global = FALSE; 1114 LRESULT Result = 0; 1115 USER_REFERENCE_ENTRY Ref; 1116 1117 ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK); 1118 1119 pti = PsGetCurrentThreadWin32Thread(); 1120 if (!pti || !pti->rpdesk || !pti->rpdesk->pDeskInfo) 1121 { 1122 pdo = IntGetActiveDesktop(); 1123 /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads, 1124 pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message. 1125 */ 1126 if ( !pti || !pdo || (!(HookId == WH_KEYBOARD_LL) && !(HookId == WH_MOUSE_LL)) ) 1127 { 1128 TRACE("No PDO %d\n", HookId); 1129 goto Exit; 1130 } 1131 } 1132 else 1133 { 1134 pdo = pti->rpdesk; 1135 } 1136 1137 if ( pti->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS)) 1138 { 1139 TRACE("Hook Thread dead %d\n", HookId); 1140 goto Exit; 1141 } 1142 1143 if ( ISITHOOKED(HookId) ) 1144 { 1145 TRACE("Local Hooker %d\n", HookId); 1146 Local = TRUE; 1147 } 1148 1149 if ( pdo->pDeskInfo->fsHooks & HOOKID_TO_FLAG(HookId) ) 1150 { 1151 TRACE("Global Hooker %d\n", HookId); 1152 Global = TRUE; 1153 } 1154 1155 if ( !Local && !Global ) goto Exit; // No work! 1156 1157 Hook = NULL; 1158 1159 /* SetWindowHookEx sorts out the Thread issue by placing the Hook to 1160 the correct Thread if not NULL. 1161 */ 1162 if ( Local ) 1163 { 1164 pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; 1165 if (IsListEmpty(pLastHead)) 1166 { 1167 ERR("No Local Hook Found!\n"); 1168 goto Exit; 1169 } 1170 1171 Hook = CONTAINING_RECORD(pLastHead->Flink, HOOK, Chain); 1172 ObReferenceObject(pti->pEThread); 1173 IntReferenceThreadInfo(pti); 1174 UserRefObjectCo(Hook, &Ref); 1175 1176 ClientInfo = pti->pClientInfo; 1177 SaveHook = pti->sphkCurrent; 1178 /* Note: Setting pti->sphkCurrent will also lock the next hook to this 1179 * hook ID. So, the CallNextHookEx will only call to that hook ID 1180 * chain anyway. For Thread Hooks.... 1181 */ 1182 1183 /* Load it for the next call. */ 1184 pti->sphkCurrent = Hook; 1185 Hook->phkNext = IntGetNextHook(Hook); 1186 if (ClientInfo) 1187 { 1188 _SEH2_TRY 1189 { 1190 ClientInfo->phkCurrent = Hook; 1191 } 1192 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1193 { 1194 ClientInfo = NULL; // Don't bother next run. 1195 } 1196 _SEH2_END; 1197 } 1198 Result = co_IntCallHookProc( HookId, 1199 Code, 1200 wParam, 1201 lParam, 1202 Hook->Proc, 1203 Hook->ihmod, 1204 Hook->offPfn, 1205 Hook->Ansi, 1206 &Hook->ModuleName); 1207 if (ClientInfo) 1208 { 1209 _SEH2_TRY 1210 { 1211 ClientInfo->phkCurrent = SaveHook; 1212 } 1213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1214 { 1215 /* Do nothing */ 1216 (void)0; 1217 } 1218 _SEH2_END; 1219 } 1220 pti->sphkCurrent = SaveHook; 1221 Hook->phkNext = NULL; 1222 UserDerefObjectCo(Hook); 1223 IntDereferenceThreadInfo(pti); 1224 ObDereferenceObject(pti->pEThread); 1225 } 1226 1227 if ( Global ) 1228 { 1229 PTHREADINFO ptiHook; 1230 HHOOK *pHookHandles; 1231 unsigned i; 1232 1233 /* Keep hooks in array because hooks can be destroyed in user world */ 1234 pHookHandles = IntGetGlobalHookHandles(pdo, HookId); 1235 if(!pHookHandles) 1236 goto Exit; 1237 1238 /* Performance goes down the drain. If more hooks are associated to this 1239 * hook ID, this will have to post to each of the thread message queues 1240 * or make a direct call. 1241 */ 1242 for(i = 0; pHookHandles[i]; ++i) 1243 { 1244 Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], TYPE_HOOK); 1245 if(!Hook) 1246 { 1247 ERR("Invalid hook!\n"); 1248 continue; 1249 } 1250 1251 /* Hook->Thread is null, we hax around this with Hook->head.pti. */ 1252 ptiHook = Hook->head.pti; 1253 1254 if ( (pti->TIF_flags & TIF_DISABLEHOOKS) || (ptiHook->TIF_flags & TIF_INCLEANUP)) 1255 { 1256 TRACE("Next Hook %p, %p\n", ptiHook->rpdesk, pdo); 1257 continue; 1258 } 1259 UserRefObjectCo(Hook, &Ref); 1260 1261 if (ptiHook != pti ) 1262 { 1263 // Block | TimeOut 1264 if ( HookId == WH_JOURNALPLAYBACK || // 1 | 0 1265 HookId == WH_JOURNALRECORD || // 1 | 0 1266 HookId == WH_KEYBOARD || // 1 | 200 1267 HookId == WH_MOUSE || // 1 | 200 1268 HookId == WH_KEYBOARD_LL || // 0 | 300 1269 HookId == WH_MOUSE_LL ) // 0 | 300 1270 { 1271 TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId ); 1272 Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam); 1273 } 1274 else if (ptiHook->ppi == pti->ppi) 1275 { 1276 TRACE("\nGlobal Hook calling to another Thread! %d\n",HookId ); 1277 ObReferenceObject(ptiHook->pEThread); 1278 IntReferenceThreadInfo(ptiHook); 1279 Result = co_IntCallHookProc( HookId, 1280 Code, 1281 wParam, 1282 lParam, 1283 Hook->Proc, 1284 Hook->ihmod, 1285 Hook->offPfn, 1286 Hook->Ansi, 1287 &Hook->ModuleName); 1288 IntDereferenceThreadInfo(ptiHook); 1289 ObDereferenceObject(ptiHook->pEThread); 1290 } 1291 } 1292 else 1293 { /* Make the direct call. */ 1294 TRACE("Global going Local Hook calling to Thread! %d\n",HookId ); 1295 ObReferenceObject(pti->pEThread); 1296 IntReferenceThreadInfo(pti); 1297 Result = co_IntCallHookProc( HookId, 1298 Code, 1299 wParam, 1300 lParam, 1301 Hook->Proc, 1302 Hook->ihmod, 1303 Hook->offPfn, 1304 Hook->Ansi, 1305 &Hook->ModuleName); 1306 IntDereferenceThreadInfo(pti); 1307 ObDereferenceObject(pti->pEThread); 1308 } 1309 UserDerefObjectCo(Hook); 1310 } 1311 ExFreePoolWithTag(pHookHandles, TAG_HOOK); 1312 TRACE("Ret: Global HookId %d Result 0x%x\n", HookId,Result); 1313 } 1314 Exit: 1315 return Result; 1316 } 1317 1318 BOOL 1319 FASTCALL 1320 IntUnhookWindowsHook(int HookId, HOOKPROC pfnFilterProc) 1321 { 1322 PHOOK Hook; 1323 PLIST_ENTRY pLastHead, pElement; 1324 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1325 1326 if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId ) 1327 { 1328 EngSetLastError(ERROR_INVALID_HOOK_FILTER); 1329 return FALSE; 1330 } 1331 1332 if (pti->fsHooks) 1333 { 1334 pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; 1335 1336 pElement = pLastHead->Flink; 1337 while (pElement != pLastHead) 1338 { 1339 Hook = CONTAINING_RECORD(pElement, HOOK, Chain); 1340 1341 /* Get the next element now, we might free the hook in what follows */ 1342 pElement = Hook->Chain.Flink; 1343 1344 if (Hook->Proc == pfnFilterProc) 1345 { 1346 if (Hook->head.pti == pti) 1347 { 1348 IntRemoveHook(Hook); 1349 return TRUE; 1350 } 1351 else 1352 { 1353 EngSetLastError(ERROR_ACCESS_DENIED); 1354 return FALSE; 1355 } 1356 } 1357 } 1358 } 1359 return FALSE; 1360 } 1361 1362 /* 1363 * Support for compatibility only? Global hooks are processed in kernel space. 1364 * This is very thread specific! Never seeing applications with more than one 1365 * hook per thread installed. Most of the applications are Global hookers and 1366 * associated with just one hook Id. Maybe it's for diagnostic testing or a 1367 * throw back to 3.11? 1368 */ 1369 LRESULT 1370 APIENTRY 1371 NtUserCallNextHookEx( int Code, 1372 WPARAM wParam, 1373 LPARAM lParam, 1374 BOOL Ansi) 1375 { 1376 PTHREADINFO pti; 1377 PHOOK HookObj, NextObj; 1378 PCLIENTINFO ClientInfo; 1379 LRESULT lResult = 0; 1380 DECLARE_RETURN(LRESULT); 1381 1382 TRACE("Enter NtUserCallNextHookEx\n"); 1383 UserEnterExclusive(); 1384 1385 pti = GetW32ThreadInfo(); 1386 1387 HookObj = pti->sphkCurrent; 1388 1389 if (!HookObj) RETURN( 0); 1390 1391 NextObj = HookObj->phkNext; 1392 1393 pti->sphkCurrent = NextObj; 1394 ClientInfo = pti->pClientInfo; 1395 _SEH2_TRY 1396 { 1397 ClientInfo->phkCurrent = NextObj; 1398 } 1399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1400 { 1401 ClientInfo = NULL; 1402 } 1403 _SEH2_END; 1404 1405 /* Now in List run down. */ 1406 if (ClientInfo && NextObj) 1407 { 1408 NextObj->phkNext = IntGetNextHook(NextObj); 1409 lResult = co_UserCallNextHookEx( NextObj, Code, wParam, lParam, NextObj->Ansi); 1410 } 1411 RETURN( lResult); 1412 1413 CLEANUP: 1414 TRACE("Leave NtUserCallNextHookEx, ret=%i\n",_ret_); 1415 UserLeave(); 1416 END_CLEANUP; 1417 } 1418 1419 HHOOK 1420 APIENTRY 1421 NtUserSetWindowsHookAW( int idHook, 1422 HOOKPROC lpfn, 1423 BOOL Ansi) 1424 { 1425 DWORD ThreadId; 1426 UNICODE_STRING USModuleName; 1427 1428 RtlInitUnicodeString(&USModuleName, NULL); 1429 ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread); 1430 1431 return NtUserSetWindowsHookEx( NULL, 1432 &USModuleName, 1433 ThreadId, 1434 idHook, 1435 lpfn, 1436 Ansi); 1437 } 1438 1439 HHOOK 1440 APIENTRY 1441 NtUserSetWindowsHookEx( HINSTANCE Mod, 1442 PUNICODE_STRING UnsafeModuleName, 1443 DWORD ThreadId, 1444 int HookId, 1445 HOOKPROC HookProc, 1446 BOOL Ansi) 1447 { 1448 PWINSTATION_OBJECT WinStaObj; 1449 PHOOK Hook = NULL; 1450 UNICODE_STRING ModuleName; 1451 NTSTATUS Status; 1452 HHOOK Handle; 1453 PTHREADINFO pti, ptiHook = NULL; 1454 DECLARE_RETURN(HHOOK); 1455 1456 TRACE("Enter NtUserSetWindowsHookEx\n"); 1457 UserEnterExclusive(); 1458 1459 pti = PsGetCurrentThreadWin32Thread(); 1460 1461 if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId ) 1462 { 1463 EngSetLastError(ERROR_INVALID_HOOK_FILTER); 1464 RETURN( NULL); 1465 } 1466 1467 if (!HookProc) 1468 { 1469 EngSetLastError(ERROR_INVALID_FILTER_PROC); 1470 RETURN( NULL); 1471 } 1472 1473 if (ThreadId) /* thread-local hook */ 1474 { 1475 if ( HookId == WH_JOURNALRECORD || 1476 HookId == WH_JOURNALPLAYBACK || 1477 HookId == WH_KEYBOARD_LL || 1478 HookId == WH_MOUSE_LL || 1479 HookId == WH_SYSMSGFILTER) 1480 { 1481 TRACE("Local hook installing Global HookId: %d\n",HookId); 1482 /* these can only be global */ 1483 EngSetLastError(ERROR_GLOBAL_ONLY_HOOK); 1484 RETURN( NULL); 1485 } 1486 1487 if ( !(ptiHook = IntTID2PTI( UlongToHandle(ThreadId) ))) 1488 { 1489 ERR("Invalid thread id 0x%x\n", ThreadId); 1490 EngSetLastError(ERROR_INVALID_PARAMETER); 1491 RETURN( NULL); 1492 } 1493 1494 if ( ptiHook->rpdesk != pti->rpdesk) // gptiCurrent->rpdesk) 1495 { 1496 ERR("Local hook wrong desktop HookId: %d\n",HookId); 1497 EngSetLastError(ERROR_ACCESS_DENIED); 1498 RETURN( NULL); 1499 } 1500 1501 if (ptiHook->ppi != pti->ppi) 1502 { 1503 if ( !Mod && 1504 (HookId == WH_GETMESSAGE || 1505 HookId == WH_CALLWNDPROC || 1506 HookId == WH_CBT || 1507 HookId == WH_HARDWARE || 1508 HookId == WH_DEBUG || 1509 HookId == WH_SHELL || 1510 HookId == WH_FOREGROUNDIDLE || 1511 HookId == WH_CALLWNDPROCRET) ) 1512 { 1513 ERR("Local hook needs hMod HookId: %d\n",HookId); 1514 EngSetLastError(ERROR_HOOK_NEEDS_HMOD); 1515 RETURN( NULL); 1516 } 1517 1518 if ( (ptiHook->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD)) && 1519 (HookId == WH_GETMESSAGE || 1520 HookId == WH_CALLWNDPROC || 1521 HookId == WH_CBT || 1522 HookId == WH_HARDWARE || 1523 HookId == WH_DEBUG || 1524 HookId == WH_SHELL || 1525 HookId == WH_FOREGROUNDIDLE || 1526 HookId == WH_CALLWNDPROCRET) ) 1527 { 1528 EngSetLastError(ERROR_HOOK_TYPE_NOT_ALLOWED); 1529 RETURN( NULL); 1530 } 1531 } 1532 } 1533 else /* System-global hook */ 1534 { 1535 ptiHook = pti; // gptiCurrent; 1536 if ( !Mod && 1537 (HookId == WH_GETMESSAGE || 1538 HookId == WH_CALLWNDPROC || 1539 HookId == WH_CBT || 1540 HookId == WH_SYSMSGFILTER || 1541 HookId == WH_HARDWARE || 1542 HookId == WH_DEBUG || 1543 HookId == WH_SHELL || 1544 HookId == WH_FOREGROUNDIDLE || 1545 HookId == WH_CALLWNDPROCRET) ) 1546 { 1547 ERR("Global hook needs hMod HookId: %d\n",HookId); 1548 EngSetLastError(ERROR_HOOK_NEEDS_HMOD); 1549 RETURN( NULL); 1550 } 1551 } 1552 1553 Status = IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation, 1554 UserMode, 1555 0, 1556 &WinStaObj, 1557 0); 1558 1559 if (!NT_SUCCESS(Status)) 1560 { 1561 SetLastNtError(Status); 1562 RETURN( NULL); 1563 } 1564 ObDereferenceObject(WinStaObj); 1565 1566 Hook = UserCreateObject(gHandleTable, NULL, ptiHook, (PHANDLE)&Handle, TYPE_HOOK, sizeof(HOOK)); 1567 1568 if (!Hook) 1569 { 1570 RETURN( NULL); 1571 } 1572 1573 Hook->ihmod = (INT_PTR)Mod; // Module Index from atom table, Do this for now. 1574 Hook->HookId = HookId; 1575 Hook->rpdesk = ptiHook->rpdesk; 1576 Hook->phkNext = NULL; /* Dont use as a chain! Use link lists for chaining. */ 1577 Hook->Proc = HookProc; 1578 Hook->Ansi = Ansi; 1579 1580 TRACE("Set Hook Desk %p DeskInfo %p Handle Desk %p\n", pti->rpdesk, pti->pDeskInfo, Hook->head.rpdesk); 1581 1582 if (ThreadId) /* Thread-local hook */ 1583 { 1584 InsertHeadList(&ptiHook->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); 1585 ptiHook->sphkCurrent = NULL; 1586 Hook->ptiHooked = ptiHook; 1587 ptiHook->fsHooks |= HOOKID_TO_FLAG(HookId); 1588 1589 if (ptiHook->pClientInfo) 1590 { 1591 if ( ptiHook->ppi == pti->ppi) /* gptiCurrent->ppi) */ 1592 { 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 Local ClientInfo!\n"); 1601 } 1602 _SEH2_END; 1603 } 1604 else 1605 { 1606 KAPC_STATE ApcState; 1607 1608 KeStackAttachProcess(&ptiHook->ppi->peProcess->Pcb, &ApcState); 1609 _SEH2_TRY 1610 { 1611 ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks; 1612 ptiHook->pClientInfo->phkCurrent = NULL; 1613 } 1614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1615 { 1616 ERR("Problem writing to Remote ClientInfo!\n"); 1617 } 1618 _SEH2_END; 1619 KeUnstackDetachProcess(&ApcState); 1620 } 1621 } 1622 } 1623 else 1624 { 1625 InsertHeadList(&ptiHook->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); 1626 Hook->ptiHooked = NULL; 1627 //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); 1628 ptiHook->rpdesk->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); 1629 ptiHook->sphkCurrent = NULL; 1630 ptiHook->pClientInfo->phkCurrent = NULL; 1631 } 1632 1633 RtlInitUnicodeString(&Hook->ModuleName, NULL); 1634 1635 if (Mod) 1636 { 1637 Status = MmCopyFromCaller(&ModuleName, 1638 UnsafeModuleName, 1639 sizeof(UNICODE_STRING)); 1640 if (!NT_SUCCESS(Status)) 1641 { 1642 IntRemoveHook(Hook); 1643 SetLastNtError(Status); 1644 RETURN( NULL); 1645 } 1646 1647 Hook->ModuleName.Buffer = ExAllocatePoolWithTag( PagedPool, 1648 ModuleName.MaximumLength, 1649 TAG_HOOK); 1650 if (NULL == Hook->ModuleName.Buffer) 1651 { 1652 IntRemoveHook(Hook); 1653 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1654 RETURN( NULL); 1655 } 1656 1657 Hook->ModuleName.MaximumLength = ModuleName.MaximumLength; 1658 Status = MmCopyFromCaller( Hook->ModuleName.Buffer, 1659 ModuleName.Buffer, 1660 ModuleName.MaximumLength); 1661 if (!NT_SUCCESS(Status)) 1662 { 1663 ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK); 1664 Hook->ModuleName.Buffer = NULL; 1665 IntRemoveHook(Hook); 1666 SetLastNtError(Status); 1667 RETURN( NULL); 1668 } 1669 1670 Hook->ModuleName.Length = ModuleName.Length; 1671 //// FIXME: Need to load from user32 to verify hMod before calling hook with hMod set!!!! 1672 //// Mod + offPfn == new HookProc Justin Case module is from another process. 1673 FIXME("NtUserSetWindowsHookEx Setting process hMod instance addressing.\n"); 1674 /* Make proc relative to the module base */ 1675 Hook->offPfn = (ULONG_PTR)((char *)HookProc - (char *)Mod); 1676 } 1677 else 1678 Hook->offPfn = 0; 1679 1680 TRACE("Installing: HookId %d Global %s\n", HookId, !ThreadId ? "TRUE" : "FALSE"); 1681 RETURN( Handle); 1682 1683 CLEANUP: 1684 if (Hook) 1685 UserDereferenceObject(Hook); 1686 TRACE("Leave NtUserSetWindowsHookEx, ret=%p\n", _ret_); 1687 UserLeave(); 1688 END_CLEANUP; 1689 } 1690 1691 BOOL 1692 APIENTRY 1693 NtUserUnhookWindowsHookEx(HHOOK Hook) 1694 { 1695 PHOOK HookObj; 1696 DECLARE_RETURN(BOOL); 1697 1698 TRACE("Enter NtUserUnhookWindowsHookEx\n"); 1699 UserEnterExclusive(); 1700 1701 if (!(HookObj = IntGetHookObject(Hook))) 1702 { 1703 ERR("Invalid handle passed to NtUserUnhookWindowsHookEx\n"); 1704 /* SetLastNtError(Status); */ 1705 RETURN( FALSE); 1706 } 1707 1708 ASSERT(Hook == UserHMGetHandle(HookObj)); 1709 1710 IntRemoveHook(HookObj); 1711 1712 UserDereferenceObject(HookObj); 1713 1714 RETURN( TRUE); 1715 1716 CLEANUP: 1717 TRACE("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_); 1718 UserLeave(); 1719 END_CLEANUP; 1720 } 1721 1722 BOOL 1723 APIENTRY 1724 NtUserRegisterUserApiHook( 1725 PUNICODE_STRING m_dllname1, 1726 PUNICODE_STRING m_funname1, 1727 DWORD dwUnknown3, 1728 DWORD dwUnknown4) 1729 { 1730 BOOL ret; 1731 UNICODE_STRING strDllNameSafe; 1732 UNICODE_STRING strFuncNameSafe; 1733 NTSTATUS Status; 1734 1735 /* Probe and capture parameters */ 1736 Status = ProbeAndCaptureUnicodeString(&strDllNameSafe, UserMode, m_dllname1); 1737 if(!NT_SUCCESS(Status)) 1738 { 1739 EngSetLastError(RtlNtStatusToDosError(Status)); 1740 return FALSE; 1741 } 1742 1743 Status = ProbeAndCaptureUnicodeString(&strFuncNameSafe, UserMode, m_funname1); 1744 if(!NT_SUCCESS(Status)) 1745 { 1746 ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode); 1747 EngSetLastError(RtlNtStatusToDosError(Status)); 1748 return FALSE; 1749 } 1750 1751 UserEnterExclusive(); 1752 1753 /* Call internal function */ 1754 ret = UserRegisterUserApiHook(&strDllNameSafe, &strFuncNameSafe); 1755 1756 UserLeave(); 1757 1758 /* Cleanup only in case of failure */ 1759 if(ret == FALSE) 1760 { 1761 ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode); 1762 ReleaseCapturedUnicodeString(&strFuncNameSafe, UserMode); 1763 } 1764 1765 return ret; 1766 } 1767 1768 BOOL 1769 APIENTRY 1770 NtUserUnregisterUserApiHook(VOID) 1771 { 1772 BOOL ret; 1773 1774 UserEnterExclusive(); 1775 ret = UserUnregisterUserApiHook(); 1776 UserLeave(); 1777 1778 return ret; 1779 } 1780 1781 /* EOF */ 1782