[SHIMLIB] Shim helper functions keep a list of used shims, so that events can be forwarded. CORE-11329

svn path=/trunk/; revision=73461
This commit is contained in:
Mark Jansen 2016-12-16 19:18:26 +00:00
parent fa047badd1
commit 3da415c457
9 changed files with 243 additions and 66 deletions

View file

@ -16,10 +16,10 @@ PHOOKAPI WINAPI GetHookAPIs(IN LPCSTR szCommandLine, IN LPCWSTR wszShimName, OUT
return ShimLib_GetHookAPIs(szCommandLine, wszShimName, pdwHookCount);
}
/* PLDR_DATA_TABLE_ENTRY */
BOOL WINAPI NotifyShims(DWORD fdwReason, PVOID P)
/* Forward to the generic implementation */
BOOL WINAPI NotifyShims(DWORD fdwReason, PVOID ptr)
{
return TRUE;
return ShimLib_NotifyShims(fdwReason, ptr);
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

View file

@ -89,7 +89,6 @@ typedef BOOL(WINAPI* GETVERSIONEXAPROC)(LPOSVERSIONINFOEXA);
#define SHIM_NS Win95VersionLie
#include <setup_shim.inl>
DWORD WINAPI SHIM_OBJ_NAME(APIHook_GetVersion)()
@ -128,7 +127,6 @@ BOOL WINAPI SHIM_OBJ_NAME(APIHook_GetVersionExW)(LPOSVERSIONINFOEXA lpOsVersionI
#define SHIM_NS Win98VersionLie
#include <setup_shim.inl>
DWORD WINAPI SHIM_OBJ_NAME(APIHook_GetVersion)()

View file

@ -43,9 +43,9 @@ BOOL WINAPI SHIM_OBJ_NAME(APIHook_RtlGetVersion)(LPOSVERSIONINFOEXA lpOsVersionI
return FALSE;
}
BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason)
BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason, PVOID ptr)
{
if (fdwReason == SHIM_REASON_ATTACH && VERSION_INFO.wServicePackMajor)
if (fdwReason == SHIM_NOTIFY_ATTACH && VERSION_INFO.wServicePackMajor)
{
static CONST WCHAR szServicePack[] = {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','%','u',0};
HRESULT hr = StringCbPrintfA(VERSION_INFO.szCSDVersionA, sizeof(VERSION_INFO.szCSDVersionA),

View file

@ -1,7 +1,11 @@
list(APPEND SOURCE
shimdbgsupp.c
shimlib.c
shimlib.h)
shimlib.h
# These .inl functions are included so they show up in vs
setup_shim.inl
implement_shim.inl)
add_library(shimlib ${SOURCE})
add_dependencies(shimlib xdk)

View file

@ -2,7 +2,7 @@
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Shim library
* FILE: dll/appcompat/shims/shimlib/implement_shim.inl
* PURPOSE: Shimlib helper file, used to register shims using the earlier prepared macro's
* PURPOSE: Shimlib helper file, used to register shims setup with macro's from setup_shim.inl
* PROGRAMMER: Mark Jansen
*/
@ -18,57 +18,56 @@
#error "setup_shim.inl should be included before this file!"
#endif
#if SHIM_NUM_HOOKS > 0
#ifndef SHIM_SETUP_HOOKS
#error "Please define a hook: #define SHIM_SETUP_HOOKS SHIM_HOOK(num, dll_name, function_name, your_function)"
#endif
#else
#ifdef SHIM_SETUP_HOOKS
#error "Hooks are defined, yet SHIM_NUM_HOOKS is <= 0 !"
#endif
#endif
PHOOKAPI WINAPI SHIM_OBJ_NAME(InitializeHooksMulti)(DWORD fdwReason, PCSTR pszCmdLine, PDWORD pdwHookCount)
PHOOKAPI WINAPI SHIM_OBJ_NAME(GetHookAPIs)(DWORD fdwReason, PCSTR pszCmdLine, PDWORD pdwHookCount)
{
if (fdwReason == SHIM_REASON_ATTACH)
if (pszCmdLine)
{
if (pszCmdLine)
{
SHIM_OBJ_NAME(g_szCommandLine) = ShimLib_StringDuplicateA(pszCmdLine);
}
else
{
SHIM_OBJ_NAME(g_szCommandLine) = "";
}
SHIM_OBJ_NAME(g_pAPIHooks) = ShimLib_ShimMalloc(sizeof(HOOKAPI) * SHIM_NUM_HOOKS);
ZeroMemory(SHIM_OBJ_NAME(g_pAPIHooks), sizeof(HOOKAPI) * SHIM_NUM_HOOKS);
*pdwHookCount = SHIM_NUM_HOOKS;
SHIM_OBJ_NAME(g_szCommandLine) = ShimLib_StringDuplicateA(pszCmdLine);
}
else
{
SHIM_OBJ_NAME(g_szCommandLine) = "";
}
SHIM_OBJ_NAME(g_pAPIHooks) = ShimLib_ShimMalloc(sizeof(HOOKAPI) * SHIM_NUM_HOOKS);
ZeroMemory(SHIM_OBJ_NAME(g_pAPIHooks), sizeof(HOOKAPI) * SHIM_NUM_HOOKS);
*pdwHookCount = SHIM_NUM_HOOKS;
#ifdef SHIM_NOTIFY_FN
if (!SHIM_NOTIFY_FN(fdwReason) && fdwReason == SHIM_REASON_ATTACH)
if (!SHIM_NOTIFY_FN(fdwReason, NULL))
return NULL;
#endif
if (fdwReason == SHIM_REASON_ATTACH)
{
SHIM_SETUP_HOOKS
}
#if SHIM_NUM_HOOKS > 0
SHIM_SETUP_HOOKS
#endif
return SHIM_OBJ_NAME(g_pAPIHooks);
}
PVOID SHIM_OBJ_NAME(FindShim)(PCWSTR wszString)
{
PCSTR szString = SHIM_OBJ_NAME(g_szModuleName);
while (*szString == *wszString)
{
if (!*szString)
return SHIM_OBJ_NAME(InitializeHooksMulti);
szString++; wszString++;
}
return NULL;
}
#if defined(_MSC_VER)
#pragma section(".shm$BBB",long,read)
#endif
_SHMALLOC(".shm$BBB") _PVSHIM SHIM_OBJ_NAME(_shim_fn) = SHIM_OBJ_NAME(FindShim);
_SHMALLOC(".shm$BBB") SHIMREG SHIM_OBJ_NAME(_shim_fn) =
{
SHIM_OBJ_NAME(GetHookAPIs),
#ifdef SHIM_NOTIFY_FN
SHIM_NOTIFY_FN,
#else
NULL,
#endif
SHIM_STRINGIFY(SHIM_NS)
};
#undef SHIM_SETUP_HOOKS
#undef SHIM_NOTIFY_FN

View file

@ -19,13 +19,15 @@
#define SHIM_STRINGIFY2(X_) # X_
#define SHIM_STRINGIFY(X_) SHIM_STRINGIFY2(X_)
/* TODO: static_assert on (num < SHIM_NUM_HOOKS) */
#define SHIM_HOOK(num, dll, function, target) \
SHIM_OBJ_NAME(g_pAPIHooks)[num].LibraryName = dll; \
SHIM_OBJ_NAME(g_pAPIHooks)[num].FunctionName = function; \
SHIM_OBJ_NAME(g_pAPIHooks)[num].ReplacementFunction = target; \
SHIM_OBJ_NAME(g_pAPIHooks)[num].OriginalFunction = NULL; \
SHIM_OBJ_NAME(g_pAPIHooks)[num].Unk1 = NULL; \
SHIM_OBJ_NAME(g_pAPIHooks)[num].Unk2 = NULL;
SHIM_OBJ_NAME(g_pAPIHooks)[num].Reserved[0] = NULL; \
SHIM_OBJ_NAME(g_pAPIHooks)[num].Reserved[1] = NULL;
#define CALL_SHIM(SHIM_NUM, SHIM_CALLCONV) \
((SHIM_CALLCONV)(SHIM_OBJ_NAME(g_pAPIHooks)[SHIM_NUM].OriginalFunction))

View file

@ -0,0 +1,79 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Shim library
* FILE: dll/appcompat/shims/shimlib/shimdbgsupp.c
* PURPOSE: Shim debug helper functions
* PROGRAMMER: Mark Jansen
*/
#include <windef.h>
#include <winbase.h>
#include <shimlib.h>
#include <strsafe.h>
#include "wine/winternl.h"
#define DPFLTR_APPCOMPAT_ID 123
void ApphelppInitDebugSupport(PCWSTR KeyName, PULONG Level);
static void SeiInitDebugSupport()
{
ApphelppInitDebugSupport(L"SHIMENG_DEBUG_LEVEL", &g_ShimEngDebugLevel);
}
/**
* Outputs diagnostic info.
*
* @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
* SHIM_WARN, SHIM_INFO].
* @param [in] FunctionName The function this log should be attributed to.
* @param [in] Format The format string.
* @param ... Variable arguments providing additional information.
*
* @return Success: TRUE Failure: FALSE.
*/
BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...)
{
char Buffer[512];
va_list ArgList;
char* Current = Buffer;
const char* LevelStr;
size_t Length = sizeof(Buffer);
if (g_ShimEngDebugLevel == 0xffffffff)
SeiInitDebugSupport();
if (Level > g_ShimEngDebugLevel)
return FALSE;
switch (Level)
{
case SEI_ERR:
LevelStr = "Err ";
Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL);
break;
case SEI_WARN:
LevelStr = "Warn";
Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL);
break;
case SEI_INFO:
LevelStr = "Info";
Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
break;
default:
LevelStr = "User";
Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
break;
}
StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName);
va_start(ArgList, Format);
StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
va_end(ArgList);
#if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
#else
OutputDebugStringA(Buffer);
return TRUE;
#endif
}

View file

@ -11,13 +11,25 @@
#include <shimlib.h>
#include <strsafe.h>
HINSTANCE g_hinstDll;
typedef struct UsedShim
{
SLIST_ENTRY Entry;
PSHIMREG pShim;
#if (WINVER > _WIN32_WINNT_WS03)
BOOL bInitCalled;
#endif
} UsedShim, *pUsedShim;
static HANDLE g_ShimLib_Heap;
static PSLIST_HEADER g_UsedShims;
void ShimLib_Init(HINSTANCE hInstance)
{
g_hinstDll = hInstance;
g_ShimLib_Heap = HeapCreate(0, 0x10000, 0);
g_UsedShims = (PSLIST_HEADER)ShimLib_ShimMalloc(sizeof(SLIST_HEADER));
RtlInitializeSListHead(g_UsedShims);
}
void ShimLib_Deinit()
@ -43,6 +55,18 @@ PCSTR ShimLib_StringDuplicateA(PCSTR szString)
return lstrcpyA(NewString, szString);
}
BOOL ShimLib_StrAEqualsW(PCSTR szString, PCWSTR wszString)
{
while (*szString == *wszString)
{
if (!*szString)
return TRUE;
szString++; wszString++;
}
return FALSE;
}
#if defined(_MSC_VER)
#if defined(_M_IA64) || defined(_M_AMD64)
@ -62,8 +86,8 @@ PCSTR ShimLib_StringDuplicateA(PCSTR szString)
#endif
_SHMALLOC(".shm") _PVSHIM _shim_start = 0;
_SHMALLOC(".shm$ZZZ") _PVSHIM _shim_end = 0;
_SHMALLOC(".shm") SHIMREG _shim_start = { 0 };
_SHMALLOC(".shm$ZZZ") SHIMREG _shim_end = { 0 };
/* Generic GetHookAPIs function.
@ -72,21 +96,53 @@ _SHMALLOC(".shm$ZZZ") _PVSHIM _shim_end = 0;
This helper function will return the correct shim, and call the init function */
PHOOKAPI WINAPI ShimLib_GetHookAPIs(IN LPCSTR szCommandLine, IN LPCWSTR wszShimName, OUT PDWORD pdwHookCount)
{
uintptr_t ps = (uintptr_t)&_shim_start;
ps += sizeof(uintptr_t);
for (; ps != (uintptr_t)&_shim_end; ps += sizeof(uintptr_t))
PSHIMREG ps = &_shim_start;
ps++;
for (; ps != &_shim_end; ps++)
{
_PVSHIM* pfunc = (_PVSHIM *)ps;
if (*pfunc != NULL)
if (ps->GetHookAPIs != NULL && ps->ShimName != NULL)
{
PVOID res = (*pfunc)(wszShimName);
if (res)
if (ShimLib_StrAEqualsW(ps->ShimName, wszShimName))
{
PHOOKAPI (WINAPI* PFN)(DWORD, PCSTR, PDWORD) = res;
return (*PFN)(SHIM_REASON_ATTACH, szCommandLine, pdwHookCount);
pUsedShim shim = (pUsedShim)ShimLib_ShimMalloc(sizeof(UsedShim));
shim->pShim = ps;
#if (WINVER > _WIN32_WINNT_WS03)
shim->bInitCalled = FALSE;
#endif
RtlInterlockedPushEntrySList(g_UsedShims, &(shim->Entry));
return ps->GetHookAPIs(SHIM_NOTIFY_ATTACH, szCommandLine, pdwHookCount);
}
}
}
return NULL;
}
BOOL WINAPI ShimLib_NotifyShims(DWORD fdwReason, PVOID ptr)
{
PSLIST_ENTRY pEntry = RtlFirstEntrySList(g_UsedShims);
if (fdwReason < SHIM_REASON_INIT)
fdwReason += (SHIM_REASON_INIT - SHIM_NOTIFY_ATTACH);
while (pEntry)
{
pUsedShim pUsed = CONTAINING_RECORD(pEntry, UsedShim, Entry);
_PVNotify Notify = pUsed->pShim->Notify;
#if (WINVER > _WIN32_WINNT_WS03)
if (pUsed->bInitCalled && fdwReason == SHIM_REASON_INIT)
Notify = NULL;
#endif
if (Notify)
Notify(fdwReason, ptr);
#if (WINVER > _WIN32_WINNT_WS03)
if (fdwReason == SHIM_REASON_INIT)
pUsed->bInitCalled = TRUE;
#endif
pEntry = pEntry->Next;
}
return TRUE;
}

View file

@ -8,32 +8,71 @@
#pragma once
typedef struct tagHOOKAPI {
typedef struct tagHOOKAPI
{
PCSTR LibraryName;
PCSTR FunctionName;
PVOID ReplacementFunction;
PVOID OriginalFunction;
PVOID Unk1;
PVOID Unk2;
PVOID Reserved[2];
} HOOKAPI, *PHOOKAPI;
extern HINSTANCE g_hinstDll;
void ShimLib_Init(HINSTANCE);
void ShimLib_Deinit(void);
PVOID ShimLib_ShimMalloc(SIZE_T);
void ShimLib_ShimFree(PVOID);
PCSTR ShimLib_StringDuplicateA(PCSTR);
BOOL ShimLib_StrAEqualsW(PCSTR, PCWSTR);
/* Forward events to generic handlers */
void ShimLib_Init(HINSTANCE);
void ShimLib_Deinit(void);
PHOOKAPI WINAPI ShimLib_GetHookAPIs(LPCSTR,LPCWSTR,PDWORD);
BOOL WINAPI ShimLib_NotifyShims(DWORD fdwReason, PVOID ptr);
#define SHIM_REASON_ATTACH 1
#define SHIM_REASON_DETACH 2
#define SHIM_REASON_DLL_LOAD 3 /* Arg: PLDR_DATA_TABLE_ENTRY */
#define SHIM_REASON_DLL_UNLOAD 4 /* Arg: Module Handle */
/* Shims should respond to SHIM_REASON_XXXX in the Notify routines.
SHIM_NOTIFY_ codes are sent by apphelp, and translated to SHIM_REASON_ by the shimlib routines.
The only exception being SHIM_NOTIFY_ATTACH, that is also set for one-time init.
*/
#define SHIM_REASON_INIT 100
#define SHIM_REASON_DEINIT 101
#define SHIM_REASON_DLL_LOAD 102 /* Arg: PLDR_DATA_TABLE_ENTRY */
#define SHIM_REASON_DLL_UNLOAD 103 /* Arg: PLDR_DATA_TABLE_ENTRY */
#define SHIM_NOTIFY_ATTACH 1
#define SHIM_NOTIFY_DETACH 2
#define SHIM_NOTIFY_DLL_LOAD 3 /* Arg: PLDR_DATA_TABLE_ENTRY */
#define SHIM_NOTIFY_DLL_UNLOAD 4 /* Arg: PLDR_DATA_TABLE_ENTRY */
typedef PVOID (__cdecl *_PVSHIM)(PCWSTR);
typedef enum _SEI_LOG_LEVEL {
SEI_ERR = 1,
SEI_WARN = 2,
SEI_INFO = 3,
} SEI_LOG_LEVEL;
BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...);
extern ULONG g_ShimEngDebugLevel;
#define SHIMENG_ERR(fmt, ...) do { if (g_ShimEngDebugLevel) SeiDbgPrint(SEI_ERR, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
#define SHIMENG_WARN(fmt, ...) do { if (g_ShimEngDebugLevel) SeiDbgPrint(SEI_WARN, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
#define SHIMENG_INFO(fmt, ...) do { if (g_ShimEngDebugLevel) SeiDbgPrint(SEI_INFO, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
typedef PHOOKAPI (WINAPI* _PVGetHookAPIs)(DWORD, PCSTR, PDWORD);
typedef BOOL (WINAPI* _PVNotify)(DWORD, PVOID);
typedef struct tagSHIMREG
{
_PVGetHookAPIs GetHookAPIs;
_PVNotify Notify;
PCSTR ShimName;
} SHIMREG, *PSHIMREG;
#if defined(_MSC_VER)
#define _SHMALLOC(x) __declspec(allocate(x))