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