271 lines
7.9 KiB
C++
271 lines
7.9 KiB
C++
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
#include "ShimHook.h"
|
|
|
|
//
|
|
// 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
|
|
|