2016-05-28 16:42:57 +00:00
|
|
|
/*
|
2017-09-08 20:19:51 +00:00
|
|
|
* PROJECT: ReactOS Shim helper library
|
|
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
|
|
* PURPOSE: Shim helper functions
|
2018-01-15 21:36:07 +00:00
|
|
|
* COPYRIGHT: Copyright 2016-2018 Mark Jansen (mark.jansen@reactos.org)
|
2016-05-28 16:42:57 +00:00
|
|
|
*/
|
|
|
|
|
2017-07-16 13:50:23 +00:00
|
|
|
#define WIN32_NO_STATUS
|
2016-08-10 13:37:22 +00:00
|
|
|
#include <windef.h>
|
|
|
|
#include <winbase.h>
|
2016-05-28 16:42:57 +00:00
|
|
|
#include <shimlib.h>
|
|
|
|
#include <strsafe.h>
|
2017-07-16 13:50:23 +00:00
|
|
|
#include <ndk/rtlfuncs.h>
|
2016-05-28 16:42:57 +00:00
|
|
|
|
2016-12-16 19:18:26 +00:00
|
|
|
typedef struct UsedShim
|
|
|
|
{
|
|
|
|
SLIST_ENTRY Entry;
|
|
|
|
PSHIMREG pShim;
|
|
|
|
#if (WINVER > _WIN32_WINNT_WS03)
|
|
|
|
BOOL bInitCalled;
|
|
|
|
#endif
|
|
|
|
} UsedShim, *pUsedShim;
|
|
|
|
|
|
|
|
|
2017-07-16 13:50:23 +00:00
|
|
|
ULONG g_ShimEngDebugLevel = 0xffffffff;
|
2019-03-07 23:32:20 +00:00
|
|
|
static HINSTANCE g_ShimLib_hInstance;
|
2016-05-28 16:42:57 +00:00
|
|
|
static HANDLE g_ShimLib_Heap;
|
2016-12-16 19:18:26 +00:00
|
|
|
static PSLIST_HEADER g_UsedShims;
|
2016-05-28 16:42:57 +00:00
|
|
|
|
|
|
|
void ShimLib_Init(HINSTANCE hInstance)
|
|
|
|
{
|
2019-03-07 23:32:20 +00:00
|
|
|
g_ShimLib_hInstance = hInstance;
|
2016-05-28 16:42:57 +00:00
|
|
|
g_ShimLib_Heap = HeapCreate(0, 0x10000, 0);
|
2016-12-16 19:18:26 +00:00
|
|
|
|
|
|
|
g_UsedShims = (PSLIST_HEADER)ShimLib_ShimMalloc(sizeof(SLIST_HEADER));
|
|
|
|
RtlInitializeSListHead(g_UsedShims);
|
2016-05-28 16:42:57 +00:00
|
|
|
}
|
|
|
|
|
2019-03-07 23:32:20 +00:00
|
|
|
void ShimLib_Deinit(VOID)
|
2016-05-28 16:42:57 +00:00
|
|
|
{
|
|
|
|
// Is this a good idea?
|
|
|
|
HeapDestroy(g_ShimLib_Heap);
|
|
|
|
}
|
|
|
|
|
|
|
|
PVOID ShimLib_ShimMalloc(SIZE_T dwSize)
|
|
|
|
{
|
|
|
|
return HeapAlloc(g_ShimLib_Heap, 0, dwSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShimLib_ShimFree(PVOID pData)
|
|
|
|
{
|
|
|
|
HeapFree(g_ShimLib_Heap, 0, pData);
|
|
|
|
}
|
|
|
|
|
2019-03-07 23:32:20 +00:00
|
|
|
HINSTANCE ShimLib_Instance(VOID)
|
|
|
|
{
|
|
|
|
return g_ShimLib_hInstance;
|
|
|
|
}
|
|
|
|
|
2018-02-24 13:57:00 +00:00
|
|
|
PCSTR ShimLib_StringNDuplicateA(PCSTR szString, SIZE_T stringLengthIncludingNullTerm)
|
|
|
|
{
|
|
|
|
PSTR NewString = ShimLib_ShimMalloc(stringLengthIncludingNullTerm);
|
|
|
|
StringCchCopyA(NewString, stringLengthIncludingNullTerm, szString);
|
|
|
|
return NewString;
|
|
|
|
}
|
|
|
|
|
2016-05-28 16:42:57 +00:00
|
|
|
PCSTR ShimLib_StringDuplicateA(PCSTR szString)
|
|
|
|
{
|
2018-02-24 13:57:00 +00:00
|
|
|
return ShimLib_StringNDuplicateA(szString, lstrlenA(szString) + 1);
|
2016-05-28 16:42:57 +00:00
|
|
|
}
|
|
|
|
|
2019-03-11 21:46:18 +00:00
|
|
|
BOOL ShimLib_StrAEqualsWNC(PCSTR szString, PCWSTR wszString)
|
2016-12-16 19:18:26 +00:00
|
|
|
{
|
2019-03-11 21:46:18 +00:00
|
|
|
while (toupper(*szString) == towupper(*wszString))
|
2016-12-16 19:18:26 +00:00
|
|
|
{
|
|
|
|
if (!*szString)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
szString++; wszString++;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-05-28 16:42:57 +00:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
|
|
|
|
#if defined(_M_IA64) || defined(_M_AMD64)
|
|
|
|
#define _ATTRIBUTES read
|
|
|
|
#else
|
|
|
|
#define _ATTRIBUTES read
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#pragma section(".shm",long,read)
|
|
|
|
#pragma section(".shm$AAA",long,read)
|
|
|
|
#pragma section(".shm$ZZZ",long,read)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma comment(linker, "/merge:.shm=.rdata")
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2020-04-07 18:47:47 +00:00
|
|
|
_SHMALLOC(".shm$AAA") SHIMREG _shim_start = { 0 };
|
2016-12-16 19:18:26 +00:00
|
|
|
_SHMALLOC(".shm$ZZZ") SHIMREG _shim_end = { 0 };
|
2016-05-28 16:42:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Generic GetHookAPIs function.
|
|
|
|
The macro's from <setup_shim.inl> and <implement_shim.inl> will register a list of all apis that should be hooked
|
|
|
|
for a specific shim
|
|
|
|
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)
|
|
|
|
{
|
2016-12-16 19:18:26 +00:00
|
|
|
PSHIMREG ps = &_shim_start;
|
|
|
|
ps++;
|
2020-04-07 18:47:47 +00:00
|
|
|
for (; ps < &_shim_end; ps++)
|
2016-05-28 16:42:57 +00:00
|
|
|
{
|
2016-12-16 19:18:26 +00:00
|
|
|
if (ps->GetHookAPIs != NULL && ps->ShimName != NULL)
|
2016-05-28 16:42:57 +00:00
|
|
|
{
|
2019-03-11 21:46:18 +00:00
|
|
|
if (ShimLib_StrAEqualsWNC(ps->ShimName, wszShimName))
|
2016-05-28 16:42:57 +00:00
|
|
|
{
|
2016-12-16 19:18:26 +00:00
|
|
|
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);
|
2016-05-28 16:42:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-16 19:18:26 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2017-07-16 13:50:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
VOID SeiInitDebugSupport(VOID)
|
|
|
|
{
|
|
|
|
static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL");
|
|
|
|
UNICODE_STRING DebugValue;
|
|
|
|
NTSTATUS Status;
|
2018-01-15 21:36:07 +00:00
|
|
|
ULONG NewLevel = SEI_MSG;
|
2017-07-16 13:50:23 +00:00
|
|
|
WCHAR Buffer[40];
|
|
|
|
|
|
|
|
RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
|
|
|
|
|
|
|
|
Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
|
|
|
|
NewLevel = 0;
|
|
|
|
}
|
|
|
|
g_ShimEngDebugLevel = NewLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 Function, PCSTR Format, ...)
|
|
|
|
{
|
|
|
|
char Buffer[512];
|
|
|
|
char* Current = Buffer;
|
|
|
|
const char* LevelStr;
|
|
|
|
size_t Length = sizeof(Buffer);
|
|
|
|
va_list ArgList;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (g_ShimEngDebugLevel == 0xffffffff)
|
|
|
|
SeiInitDebugSupport();
|
|
|
|
|
|
|
|
if (Level > g_ShimEngDebugLevel)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (Level)
|
|
|
|
{
|
|
|
|
case SEI_MSG:
|
|
|
|
LevelStr = "MSG ";
|
|
|
|
break;
|
|
|
|
case SEI_FAIL:
|
|
|
|
LevelStr = "FAIL";
|
|
|
|
break;
|
|
|
|
case SEI_WARN:
|
|
|
|
LevelStr = "WARN";
|
|
|
|
break;
|
|
|
|
case SEI_INFO:
|
|
|
|
LevelStr = "INFO";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LevelStr = "USER";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Function)
|
|
|
|
hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] [%s] ", LevelStr, Function);
|
|
|
|
else
|
|
|
|
hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] ", LevelStr);
|
|
|
|
|
|
|
|
if (!SUCCEEDED(hr))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
va_start(ArgList, Format);
|
|
|
|
hr = StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
|
|
|
|
va_end(ArgList);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
DbgPrint("%s", Buffer);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|