1 /* 2 * PROJECT: ReactOS Shim helper library 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Shim helper functions 5 * COPYRIGHT: Copyright 2016-2018 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #define WIN32_NO_STATUS 9 #include <windef.h> 10 #include <winbase.h> 11 #include <shimlib.h> 12 #include <strsafe.h> 13 #include <ndk/rtlfuncs.h> 14 15 typedef struct UsedShim 16 { 17 SLIST_ENTRY Entry; 18 PSHIMREG pShim; 19 #if (WINVER > _WIN32_WINNT_WS03) 20 BOOL bInitCalled; 21 #endif 22 } UsedShim, *pUsedShim; 23 24 25 ULONG g_ShimEngDebugLevel = 0xffffffff; 26 static HANDLE g_ShimLib_Heap; 27 static PSLIST_HEADER g_UsedShims; 28 29 void ShimLib_Init(HINSTANCE hInstance) 30 { 31 g_ShimLib_Heap = HeapCreate(0, 0x10000, 0); 32 33 g_UsedShims = (PSLIST_HEADER)ShimLib_ShimMalloc(sizeof(SLIST_HEADER)); 34 RtlInitializeSListHead(g_UsedShims); 35 } 36 37 void ShimLib_Deinit() 38 { 39 // Is this a good idea? 40 HeapDestroy(g_ShimLib_Heap); 41 } 42 43 PVOID ShimLib_ShimMalloc(SIZE_T dwSize) 44 { 45 return HeapAlloc(g_ShimLib_Heap, 0, dwSize); 46 } 47 48 void ShimLib_ShimFree(PVOID pData) 49 { 50 HeapFree(g_ShimLib_Heap, 0, pData); 51 } 52 53 PCSTR ShimLib_StringNDuplicateA(PCSTR szString, SIZE_T stringLengthIncludingNullTerm) 54 { 55 PSTR NewString = ShimLib_ShimMalloc(stringLengthIncludingNullTerm); 56 StringCchCopyA(NewString, stringLengthIncludingNullTerm, szString); 57 return NewString; 58 } 59 60 PCSTR ShimLib_StringDuplicateA(PCSTR szString) 61 { 62 return ShimLib_StringNDuplicateA(szString, lstrlenA(szString) + 1); 63 } 64 65 BOOL ShimLib_StrAEqualsW(PCSTR szString, PCWSTR wszString) 66 { 67 while (*szString == *wszString) 68 { 69 if (!*szString) 70 return TRUE; 71 72 szString++; wszString++; 73 } 74 return FALSE; 75 } 76 77 #if defined(_MSC_VER) 78 79 #if defined(_M_IA64) || defined(_M_AMD64) 80 #define _ATTRIBUTES read 81 #else 82 #define _ATTRIBUTES read 83 #endif 84 85 86 #pragma section(".shm",long,read) 87 #pragma section(".shm$AAA",long,read) 88 #pragma section(".shm$ZZZ",long,read) 89 #endif 90 91 #ifdef _MSC_VER 92 #pragma comment(linker, "/merge:.shm=.rdata") 93 #endif 94 95 96 _SHMALLOC(".shm") SHIMREG _shim_start = { 0 }; 97 _SHMALLOC(".shm$ZZZ") SHIMREG _shim_end = { 0 }; 98 99 100 /* Generic GetHookAPIs function. 101 The macro's from <setup_shim.inl> and <implement_shim.inl> will register a list of all apis that should be hooked 102 for a specific shim 103 This helper function will return the correct shim, and call the init function */ 104 PHOOKAPI WINAPI ShimLib_GetHookAPIs(IN LPCSTR szCommandLine, IN LPCWSTR wszShimName, OUT PDWORD pdwHookCount) 105 { 106 PSHIMREG ps = &_shim_start; 107 ps++; 108 for (; ps != &_shim_end; ps++) 109 { 110 if (ps->GetHookAPIs != NULL && ps->ShimName != NULL) 111 { 112 if (ShimLib_StrAEqualsW(ps->ShimName, wszShimName)) 113 { 114 pUsedShim shim = (pUsedShim)ShimLib_ShimMalloc(sizeof(UsedShim)); 115 shim->pShim = ps; 116 #if (WINVER > _WIN32_WINNT_WS03) 117 shim->bInitCalled = FALSE; 118 #endif 119 RtlInterlockedPushEntrySList(g_UsedShims, &(shim->Entry)); 120 121 return ps->GetHookAPIs(SHIM_NOTIFY_ATTACH, szCommandLine, pdwHookCount); 122 } 123 } 124 } 125 return NULL; 126 } 127 128 129 BOOL WINAPI ShimLib_NotifyShims(DWORD fdwReason, PVOID ptr) 130 { 131 PSLIST_ENTRY pEntry = RtlFirstEntrySList(g_UsedShims); 132 133 if (fdwReason < SHIM_REASON_INIT) 134 fdwReason += (SHIM_REASON_INIT - SHIM_NOTIFY_ATTACH); 135 136 while (pEntry) 137 { 138 pUsedShim pUsed = CONTAINING_RECORD(pEntry, UsedShim, Entry); 139 _PVNotify Notify = pUsed->pShim->Notify; 140 #if (WINVER > _WIN32_WINNT_WS03) 141 if (pUsed->bInitCalled && fdwReason == SHIM_REASON_INIT) 142 Notify = NULL; 143 #endif 144 if (Notify) 145 Notify(fdwReason, ptr); 146 #if (WINVER > _WIN32_WINNT_WS03) 147 if (fdwReason == SHIM_REASON_INIT) 148 pUsed->bInitCalled = TRUE; 149 #endif 150 151 pEntry = pEntry->Next; 152 } 153 154 return TRUE; 155 } 156 157 158 VOID SeiInitDebugSupport(VOID) 159 { 160 static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL"); 161 UNICODE_STRING DebugValue; 162 NTSTATUS Status; 163 ULONG NewLevel = SEI_MSG; 164 WCHAR Buffer[40]; 165 166 RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer)); 167 168 Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue); 169 170 if (NT_SUCCESS(Status)) 171 { 172 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel))) 173 NewLevel = 0; 174 } 175 g_ShimEngDebugLevel = NewLevel; 176 } 177 178 179 /** 180 * Outputs diagnostic info. 181 * 182 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR, 183 * SHIM_WARN, SHIM_INFO]. 184 * @param [in] FunctionName The function this log should be attributed to. 185 * @param [in] Format The format string. 186 * @param ... Variable arguments providing additional information. 187 * 188 * @return Success: TRUE Failure: FALSE. 189 */ 190 BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR Function, PCSTR Format, ...) 191 { 192 char Buffer[512]; 193 char* Current = Buffer; 194 const char* LevelStr; 195 size_t Length = sizeof(Buffer); 196 va_list ArgList; 197 HRESULT hr; 198 199 if (g_ShimEngDebugLevel == 0xffffffff) 200 SeiInitDebugSupport(); 201 202 if (Level > g_ShimEngDebugLevel) 203 return FALSE; 204 205 switch (Level) 206 { 207 case SEI_MSG: 208 LevelStr = "MSG "; 209 break; 210 case SEI_FAIL: 211 LevelStr = "FAIL"; 212 break; 213 case SEI_WARN: 214 LevelStr = "WARN"; 215 break; 216 case SEI_INFO: 217 LevelStr = "INFO"; 218 break; 219 default: 220 LevelStr = "USER"; 221 break; 222 } 223 224 if (Function) 225 hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] [%s] ", LevelStr, Function); 226 else 227 hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] ", LevelStr); 228 229 if (!SUCCEEDED(hr)) 230 return FALSE; 231 232 va_start(ArgList, Format); 233 hr = StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList); 234 va_end(ArgList); 235 if (!SUCCEEDED(hr)) 236 return FALSE; 237 238 DbgPrint("%s", Buffer); 239 return TRUE; 240 } 241 242