Source code of Windows XP (NT5)
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.

270 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. SampleShim.cpp
  5. Abstract:
  6. This DLL serves as a template for the creation of shim DLLs. Follow
  7. the commenting/coding style of this source file wherever possible.
  8. Never use tabs, configure your editor to insert spaces instead of
  9. tab characters.
  10. Notes:
  11. Hooking COM functions is also possible but is not covered in this
  12. sample for simplicity sake. Contact markder or linstev for more
  13. information on COM hooking.
  14. History:
  15. 02/02/2000 markder Created
  16. 11/14/2000 markder Converted to framework version 2
  17. 02/13/2001 mnikkel Changed notify to handle new DLL_PROCESS
  18. capabilities
  19. 03/31/2001 robkenny Changed to use CString
  20. --*/
  21. #include "ShimHook.h"
  22. //
  23. // You must declare the type of shim this is at the top. If your shim
  24. // coexists with other shims in the same DLL,
  25. // use IMPLEMENT_SHIM_BEGIN(SampleShim)
  26. // otherwise use IMPLEMENT_SHIM_STANDALONE(SampleShim)
  27. //
  28. IMPLEMENT_SHIM_STANDALONE(SampleShim)
  29. #include "ShimHookMacro.h"
  30. //
  31. // Add APIs that you wish to hook to this macro construction.
  32. //
  33. APIHOOK_ENUM_BEGIN
  34. APIHOOK_ENUM_ENTRY(MessageBoxA)
  35. APIHOOK_ENUM_ENTRY(MessageBoxW)
  36. APIHOOK_ENUM_END
  37. /*++
  38. This stub function intercepts all calls to MessageBoxA
  39. and prefixes the output string with "SampleShim says:".
  40. --*/
  41. int
  42. APIHOOK(MessageBoxA)(
  43. HWND hWnd, // handle to owner window
  44. LPCSTR lpText, // text in message box
  45. LPCSTR lpCaption, // message box title
  46. UINT uType // message box style
  47. )
  48. {
  49. //
  50. // Use Hungarian notation for local variables:
  51. //
  52. // Type Scope
  53. // ----------------------- ------------------
  54. // Pointers p Global g_
  55. // DWORD dw Class member m_
  56. // LONG l Static s_
  57. // ANSI strings sz
  58. // Wide-char strings wsz
  59. // Arrays rg
  60. // CString cs
  61. //
  62. int iReturnValue;
  63. //
  64. // We use the CString class to perform all string operations in UNICODE
  65. // to prevent any problems with DBCS characters.
  66. //
  67. // Place all CString operations inside a CSTRING_TRY/CSTRING_CATCH
  68. // exception handler. CString will throw an exception if it encounters
  69. // any memory allocation failures.
  70. //
  71. // Performing all string operations by using the CString class also prevents
  72. // us from accidentally modifying the original string.
  73. //
  74. CSTRING_TRY
  75. {
  76. CString csNewOutputString(lpText);
  77. csNewOutputString.Insert(0, L"SampleShim says: ");
  78. //
  79. // Use the DPF macro to print debug strings. See Hooks\inc\ShimDebug.h
  80. // for debug level values. Use eDbgLevelError if an unexpected error
  81. // occurs in your shim code. For informational output, use eDbgLevelInfo.
  82. //
  83. // Make sure you don't end the message with '\n' in this case because
  84. // the macro will do it by default.
  85. //
  86. // Note that when printing CString, use %S and you must call the Get() method,
  87. // to explicitly return a WCHAR *.
  88. //
  89. DPFN( eDbgLevelInfo,
  90. "MessageBoxA called with lpText = \"%s\".", lpText);
  91. //
  92. // Use the ORIGINAL_API macro to call the original API. You must use
  93. // this so that API chaining and inclusion/exclusion information is
  94. // preserved.
  95. //
  96. // CString will perform automatic type conversion to const WCHAR * (LPCWSTR)
  97. // It will not, however, automatically convert to char *, you must call GetAnsi()
  98. // (or GetAnsiNIE() if you wish a NULL pointer be returned when the string is empty)
  99. //
  100. iReturnValue = ORIGINAL_API(MessageBoxA)(hWnd, csNewOutputString.GetAnsi(), lpCaption, uType);
  101. //
  102. // Use the LOG macro to print messages to the log file. This macro should
  103. // be used to indicate that the shim had affected execution of the program
  104. // in some way. Use eDbgLevelError to indicate that the shim has
  105. // consciously fixed something that would have caused problems. Use
  106. // eDbgLevelWarning if the shim has affected execution, but it is unclear
  107. // whether it actually helped the program.
  108. //
  109. LOGN( eDbgLevelWarning,
  110. "MessageBoxA converted lpText from \"%s\" to \"%S\".", lpText, csNewOutputString.Get());
  111. }
  112. CSTRING_CATCH
  113. {
  114. //
  115. // We had a CString failure, call the original API with the original args
  116. //
  117. iReturnValue = ORIGINAL_API(MessageBoxA)(hWnd, lpText, lpCaption, uType);
  118. }
  119. return iReturnValue;
  120. }
  121. /*++
  122. This stub function intercepts all calls to MessageBoxW and prefixes the
  123. output string with "SampleShim says:".
  124. Note that to make your shim generally applicable in an NT environment,
  125. you should include both ANSI and wide-character versions of your stub
  126. function. However, if your shim emulates Win9x behaviour, it is
  127. redundant to include wide-character versions because Win9x did not
  128. support them.
  129. --*/
  130. int
  131. APIHOOK(MessageBoxW)(
  132. HWND hWnd, // handle to owner window
  133. LPCWSTR lpText, // text in message box
  134. LPCWSTR lpCaption, // message box title
  135. UINT uType // message box style
  136. )
  137. {
  138. int iReturnValue;
  139. CSTRING_TRY
  140. {
  141. CString csNewOutputString(lpText);
  142. csNewOutputString.Insert(0, L"SampleShim says: ");
  143. DPFN( eDbgLevelInfo,
  144. "MessageBoxW called with lpText = \"%S\".", lpText);
  145. iReturnValue = ORIGINAL_API(MessageBoxW)(
  146. hWnd,
  147. csNewOutputString,
  148. lpCaption,
  149. uType);
  150. LOGN( eDbgLevelWarning,
  151. "MessageBoxW converted lpText from \"%S\" to \"%S\".",
  152. lpText, csNewOutputString.Get());
  153. }
  154. CSTRING_CATCH
  155. {
  156. iReturnValue = ORIGINAL_API(MessageBoxW)(
  157. hWnd,
  158. lpText,
  159. lpCaption,
  160. uType);
  161. }
  162. return iReturnValue;
  163. }
  164. /*++
  165. Handle DLL_PROCESS_ATTACH, SHIM_STATIC_DLLS_INITIALIZED
  166. and DLL_PROCESS_DETACH in your notify function
  167. to do initialization and uninitialization.
  168. IMPORTANT: Make sure you ONLY call NTDLL and KERNEL32 APIs during
  169. DLL_PROCESS_ATTACH notification. No other DLLs are initialized at that
  170. point.
  171. SHIM_STATIC_DLLS_INITIALIZED is called after all of the application's
  172. DLLs have been initialized.
  173. If your shim cannot initialize properly (during DLL_PROCESS_ATTACH),
  174. return FALSE and none of the APIs specified will be hooked.
  175. --*/
  176. BOOL
  177. NOTIFY_FUNCTION(
  178. DWORD fdwReason)
  179. {
  180. //
  181. // Note that there are further cases besides attach and detach.
  182. //
  183. switch (fdwReason)
  184. {
  185. case DLL_PROCESS_ATTACH:
  186. DPFN( eDbgLevelSpew, "Sample Shim initialized.");
  187. break;
  188. case SHIM_STATIC_DLLS_INITIALIZED:
  189. DPFN( eDbgLevelSpew,
  190. "Sample Shim notification: All DLLs have been loaded.");
  191. break;
  192. case DLL_PROCESS_DETACH:
  193. DPFN( eDbgLevelSpew, "Sample Shim uninitialized.");
  194. break;
  195. default:
  196. break;
  197. }
  198. return TRUE;
  199. }
  200. /*++
  201. Register hooked functions
  202. --*/
  203. HOOK_BEGIN
  204. //
  205. // If you have any initialization to do, you must include this line.
  206. // Then you must implement the NOTIFY_FUNCTION as above.
  207. //
  208. CALL_NOTIFY_FUNCTION
  209. //
  210. // Add APIs that you wish to hook here. All API prototypes
  211. // must be declared in Hooks\inc\ShimProto.h. Compiler errors
  212. // will result if you forget to add them.
  213. //
  214. APIHOOK_ENTRY(USER32.DLL, MessageBoxA)
  215. APIHOOK_ENTRY(USER32.DLL, MessageBoxW)
  216. HOOK_END
  217. IMPLEMENT_SHIM_END