Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.6 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. HookCallback.cpp
  5. Abstract:
  6. Hooking mechanism for callbacks.
  7. Notes:
  8. Use the HookCallback mechanism to hook any type of callback
  9. function, like an application-defined WindowProc. HookCallback
  10. will register your hook and insert an extra parameter -- pfnOld.
  11. This will allow you to call the actual callback from your stub
  12. function. pfnOld is inserted as the first parameter. Do not pass
  13. pfnOld to the original callback, use the real prototype for the
  14. callback.
  15. See the shim DisableW2KOwnerDrawButtonStates for example usage.
  16. History:
  17. 02/16/2000 markder Created
  18. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  19. --*/
  20. #include "ShimHook.h"
  21. namespace ShimLib
  22. {
  23. #pragma pack(push)
  24. #pragma pack(1)
  25. typedef struct _JUMPTABLEENTRY
  26. {
  27. BYTE PopEax;
  28. BYTE PushDword;
  29. PVOID pfnOld;
  30. BYTE PushEax;
  31. BYTE Jmp[2];
  32. PVOID ppfnNew;
  33. PVOID pfnNew;
  34. _JUMPTABLEENTRY* pNextEntry;
  35. } JUMPTABLEENTRY, *PJUMPTABLEENTRY;
  36. #pragma pack(pop)
  37. PJUMPTABLEENTRY g_pCallbackJumpTable = NULL;
  38. // defines from user.h to tell if a windowproc is actually a handle to a CPD
  39. #define HMINDEXBITS 0x0000FFFF // bits where index is stored
  40. #define CPDHANDLE_HI ((ULONG_PTR)~HMINDEXBITS)
  41. #define ISCPDTAG(x) (((ULONG_PTR)(x) & CPDHANDLE_HI) == CPDHANDLE_HI)
  42. /*++
  43. Function Description:
  44. Registers a callback hook.
  45. Arguments:
  46. IN pfnOld - The original callback function address.
  47. IN pfnNew - The new (stub) callback function address.
  48. Return Value:
  49. The address to be passed in as the callback. If you wanted
  50. to hook the progress routine that is called when you use
  51. the MoveFileWithProgress API, simply hook the API through the
  52. normal shim mechanism and then use this function to obtain a new
  53. address to pass in as lpProgressRoutine.
  54. Notes:
  55. This was reviewed for security and was noted that the linked list is not
  56. entirely safe when called from multiple threads. However, the worst case is
  57. that we allocate an extra chunk of memory with a duplicate jump, or that one
  58. JUMPTABLEENTRY is not added to the list. The list's integrity is always maintained.
  59. Since this list is never deallocated, nor can it be, we don't have a problem with
  60. memory leaks.
  61. History:
  62. 11/01/1999 markder Created
  63. --*/
  64. PVOID
  65. HookCallback(PVOID pfnOld, PVOID pfnNew)
  66. {
  67. PJUMPTABLEENTRY pJT = g_pCallbackJumpTable;
  68. if (pfnOld == NULL)
  69. {
  70. // NULL has been passed in. Ignore this call.
  71. pJT = NULL;
  72. goto eh;
  73. }
  74. if (ISCPDTAG(pfnOld) || IsBadCodePtr((FARPROC)pfnOld))
  75. {
  76. // This isn't a normal procedure call, and must be from a system DLL.
  77. // We should ignore it.
  78. pJT = (PJUMPTABLEENTRY)pfnOld;
  79. goto eh;
  80. }
  81. // Check to see if we have already made an entry for this pfnOld. If so,
  82. // just pass back the existing jump table.
  83. while (pJT != NULL)
  84. {
  85. if (pJT->pfnOld == pfnOld)
  86. break;
  87. pJT = pJT->pNextEntry;
  88. }
  89. if (pJT == NULL)
  90. {
  91. // Note that this table is allocated and never freed because
  92. // the entries will be used right up until the very last message
  93. // is sent to a window. There is no opportunity for cleanup.
  94. pJT = (PJUMPTABLEENTRY) HeapAlloc(GetProcessHeap(),
  95. HEAP_GENERATE_EXCEPTIONS,
  96. sizeof(JUMPTABLEENTRY) );
  97. // Fill in assembler. Each hard-coded hex value is the i386
  98. // opcode for the particular instruction.
  99. pJT->PopEax = 0x58; // Pop off return address
  100. pJT->PushDword = 0x68; // Push pfnOld as extra parameter
  101. pJT->pfnOld = pfnOld;
  102. pJT->PushEax = 0x50; // Push return address back on
  103. pJT->Jmp[0] = 0xFF; // Jump to pfnNew
  104. pJT->Jmp[1] = 0x25;
  105. pJT->ppfnNew = &(pJT->pfnNew);
  106. // Fill in data members
  107. pJT->pfnNew = pfnNew;
  108. pJT->pNextEntry = g_pCallbackJumpTable;
  109. // Add to top of list
  110. g_pCallbackJumpTable = pJT;
  111. }
  112. eh:
  113. DPF("ShimLib", eDbgLevelInfo, "CallbackHook( pfnOld = 0x%08X, pfnNew = 0x%08X ) returned 0x%08X\n", pfnOld, pfnNew, pJT);
  114. return pJT;
  115. }
  116. }; // end of namespace ShimLib