|
|
/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
SampleShim.cpp
Abstract:
This DLL serves as a template for the creation of shim DLLs. Follow the commenting/coding style of this source file wherever possible. Never use tabs, configure your editor to insert spaces instead of tab characters. Notes:
Hooking COM functions is also possible but is not covered in this sample for simplicity sake. Contact markder or linstev for more information on COM hooking.
History:
02/02/2000 markder Created 11/14/2000 markder Converted to framework version 2 02/13/2001 mnikkel Changed notify to handle new DLL_PROCESS capabilities 03/31/2001 robkenny Changed to use CString 04/10/2002 robkenny Updated to compile.
--*/
#include "ShimHook.h"
#include "StrSafe.h"
using namespace ShimLib;
//
// You must declare the type of shim this is at the top. If your shim
// coexists with other shims in the same DLL,
// use IMPLEMENT_SHIM_BEGIN(SampleShim)
// otherwise use IMPLEMENT_SHIM_STANDALONE(SampleShim)
//
IMPLEMENT_SHIM_STANDALONE(SampleShim) #include "ShimHookMacro.h"
//
// Add APIs that you wish to hook to this macro construction.
//
APIHOOK_ENUM_BEGIN APIHOOK_ENUM_ENTRY(MessageBoxA) APIHOOK_ENUM_ENTRY(MessageBoxW) APIHOOK_ENUM_END
/*++
This stub function intercepts all calls to MessageBoxA and prefixes the output string with "SampleShim says:". --*/
int APIHOOK(MessageBoxA)( HWND hWnd, // handle to owner window
LPCSTR lpText, // text in message box
LPCSTR lpCaption, // message box title
UINT uType // message box style
) { //
// Use Hungarian notation for local variables:
//
// Type Scope
// ----------------------- ------------------
// Pointers p Global g_
// DWORD dw Class member m_
// LONG l Static s_
// ANSI strings sz
// Wide-char strings wsz
// Arrays rg
// CString cs
//
int iReturnValue; //
// We use the CString class to perform all string operations in UNICODE
// to prevent any problems with DBCS characters.
//
// Place all CString operations inside a CSTRING_TRY/CSTRING_CATCH
// exception handler. CString will throw an exception if it encounters
// any memory allocation failures.
//
// Performing all string operations by using the CString class also prevents
// us from accidentally modifying the original string.
//
CSTRING_TRY { CString csNewOutputString(lpText); csNewOutputString.Insert(0, L"SampleShim says: ");
//
// Use the DPF macro to print debug strings. See Hooks\inc\ShimDebug.h
// for debug level values. Use eDbgLevelError if an unexpected error
// occurs in your shim code. For informational output, use eDbgLevelInfo.
//
// Make sure you don't end the message with '\n' in this case because
// the macro will do it by default.
//
// Note that when printing CString, use %S and you must call the Get() method,
// to explicitly return a WCHAR *.
//
DPFN( eDbgLevelInfo, "MessageBoxA called with lpText = \"%s\".", lpText); //
// Use the ORIGINAL_API macro to call the original API. You must use
// this so that API chaining and inclusion/exclusion information is
// preserved.
//
// CString will perform automatic type conversion to const WCHAR * (LPCWSTR)
// It will not, however, automatically convert to char *, you must call GetAnsi()
// (or GetAnsiNIE() if you wish a NULL pointer be returned when the string is empty)
//
iReturnValue = ORIGINAL_API(MessageBoxA)(hWnd, csNewOutputString.GetAnsi(), lpCaption, uType); //
// Use the LOG macro to print messages to the log file. This macro should
// be used to indicate that the shim had affected execution of the program
// in some way. Use eDbgLevelError to indicate that the shim has
// consciously fixed something that would have caused problems. Use
// eDbgLevelWarning if the shim has affected execution, but it is unclear
// whether it actually helped the program.
//
LOGN( eDbgLevelWarning, "MessageBoxA converted lpText from \"%s\" to \"%S\".", lpText, csNewOutputString.Get()); } CSTRING_CATCH { //
// We had a CString failure, call the original API with the original args
//
iReturnValue = ORIGINAL_API(MessageBoxA)(hWnd, lpText, lpCaption, uType); } return iReturnValue; }
/*++
This stub function intercepts all calls to MessageBoxW and prefixes the output string with "SampleShim says:".
Note that to make your shim generally applicable in an NT environment, you should include both ANSI and wide-character versions of your stub function. However, if your shim emulates Win9x behaviour, it is redundant to include wide-character versions because Win9x did not support them.
--*/
int APIHOOK(MessageBoxW)( HWND hWnd, // handle to owner window
LPCWSTR lpText, // text in message box
LPCWSTR lpCaption, // message box title
UINT uType // message box style
) { int iReturnValue; CSTRING_TRY { CString csNewOutputString(lpText); csNewOutputString.Insert(0, L"SampleShim says: ");
DPFN( eDbgLevelInfo, "MessageBoxW called with lpText = \"%S\".", lpText); iReturnValue = ORIGINAL_API(MessageBoxW)( hWnd, csNewOutputString, lpCaption, uType); LOGN( eDbgLevelWarning, "MessageBoxW converted lpText from \"%S\" to \"%S\".", lpText, csNewOutputString.Get()); } CSTRING_CATCH { iReturnValue = ORIGINAL_API(MessageBoxW)( hWnd, lpText, lpCaption, uType); } return iReturnValue;
}
/*++
Handle DLL_PROCESS_ATTACH, SHIM_STATIC_DLLS_INITIALIZED and DLL_PROCESS_DETACH in your notify function to do initialization and uninitialization.
IMPORTANT: Make sure you ONLY call NTDLL and KERNEL32 APIs during DLL_PROCESS_ATTACH notification. No other DLLs are initialized at that point. SHIM_STATIC_DLLS_INITIALIZED is called after all of the application's DLLs have been initialized. If your shim cannot initialize properly (during DLL_PROCESS_ATTACH), return FALSE and none of the APIs specified will be hooked.
--*/ BOOL NOTIFY_FUNCTION( DWORD fdwReason) { //
// Note that there are further cases besides attach and detach.
//
switch (fdwReason) { case DLL_PROCESS_ATTACH: DPFN( eDbgLevelSpew, "Sample Shim initialized."); break; case SHIM_STATIC_DLLS_INITIALIZED: DPFN( eDbgLevelSpew, "Sample Shim notification: All DLLs have been loaded."); break; case DLL_PROCESS_DETACH: DPFN( eDbgLevelSpew, "Sample Shim uninitialized."); break;
default: break; }
return TRUE; }
/*++
Register hooked functions
--*/
HOOK_BEGIN //
// If you have any initialization to do, you must include this line.
// Then you must implement the NOTIFY_FUNCTION as above.
//
CALL_NOTIFY_FUNCTION
//
// Add APIs that you wish to hook here. All API prototypes
// must be declared in Hooks\inc\ShimProto.h. Compiler errors
// will result if you forget to add them.
//
APIHOOK_ENTRY(USER32.DLL, MessageBoxA) APIHOOK_ENTRY(USER32.DLL, MessageBoxW)
HOOK_END
IMPLEMENT_SHIM_END
|