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)
8 #define WIN32_NO_STATUS
13 #include <ndk/rtlfuncs.h>
15 typedef struct UsedShim
19 #if (WINVER > _WIN32_WINNT_WS03)
22 } UsedShim
, *pUsedShim
;
25 ULONG g_ShimEngDebugLevel
= 0xffffffff;
26 static HINSTANCE g_ShimLib_hInstance
;
27 static HANDLE g_ShimLib_Heap
;
28 static PSLIST_HEADER g_UsedShims
;
30 void ShimLib_Init(HINSTANCE hInstance
)
32 g_ShimLib_hInstance
= hInstance
;
33 g_ShimLib_Heap
= HeapCreate(0, 0x10000, 0);
35 g_UsedShims
= (PSLIST_HEADER
)ShimLib_ShimMalloc(sizeof(SLIST_HEADER
));
36 RtlInitializeSListHead(g_UsedShims
);
39 void ShimLib_Deinit(VOID
)
41 // Is this a good idea?
42 HeapDestroy(g_ShimLib_Heap
);
45 PVOID
ShimLib_ShimMalloc(SIZE_T dwSize
)
47 return HeapAlloc(g_ShimLib_Heap
, 0, dwSize
);
50 void ShimLib_ShimFree(PVOID pData
)
52 HeapFree(g_ShimLib_Heap
, 0, pData
);
55 HINSTANCE
ShimLib_Instance(VOID
)
57 return g_ShimLib_hInstance
;
60 PCSTR
ShimLib_StringNDuplicateA(PCSTR szString
, SIZE_T stringLengthIncludingNullTerm
)
62 PSTR NewString
= ShimLib_ShimMalloc(stringLengthIncludingNullTerm
);
63 StringCchCopyA(NewString
, stringLengthIncludingNullTerm
, szString
);
67 PCSTR
ShimLib_StringDuplicateA(PCSTR szString
)
69 return ShimLib_StringNDuplicateA(szString
, lstrlenA(szString
) + 1);
72 BOOL
ShimLib_StrAEqualsW(PCSTR szString
, PCWSTR wszString
)
74 while (*szString
== *wszString
)
79 szString
++; wszString
++;
86 #if defined(_M_IA64) || defined(_M_AMD64)
87 #define _ATTRIBUTES read
89 #define _ATTRIBUTES read
93 #pragma section(".shm",long,read)
94 #pragma section(".shm$AAA",long,read)
95 #pragma section(".shm$ZZZ",long,read)
99 #pragma comment(linker, "/merge:.shm=.rdata")
103 _SHMALLOC(".shm") SHIMREG _shim_start
= { 0 };
104 _SHMALLOC(".shm$ZZZ") SHIMREG _shim_end
= { 0 };
107 /* Generic GetHookAPIs function.
108 The macro's from <setup_shim.inl> and <implement_shim.inl> will register a list of all apis that should be hooked
110 This helper function will return the correct shim, and call the init function */
111 PHOOKAPI WINAPI
ShimLib_GetHookAPIs(IN LPCSTR szCommandLine
, IN LPCWSTR wszShimName
, OUT PDWORD pdwHookCount
)
113 PSHIMREG ps
= &_shim_start
;
115 for (; ps
!= &_shim_end
; ps
++)
117 if (ps
->GetHookAPIs
!= NULL
&& ps
->ShimName
!= NULL
)
119 if (ShimLib_StrAEqualsW(ps
->ShimName
, wszShimName
))
121 pUsedShim shim
= (pUsedShim
)ShimLib_ShimMalloc(sizeof(UsedShim
));
123 #if (WINVER > _WIN32_WINNT_WS03)
124 shim
->bInitCalled
= FALSE
;
126 RtlInterlockedPushEntrySList(g_UsedShims
, &(shim
->Entry
));
128 return ps
->GetHookAPIs(SHIM_NOTIFY_ATTACH
, szCommandLine
, pdwHookCount
);
136 BOOL WINAPI
ShimLib_NotifyShims(DWORD fdwReason
, PVOID ptr
)
138 PSLIST_ENTRY pEntry
= RtlFirstEntrySList(g_UsedShims
);
140 if (fdwReason
< SHIM_REASON_INIT
)
141 fdwReason
+= (SHIM_REASON_INIT
- SHIM_NOTIFY_ATTACH
);
145 pUsedShim pUsed
= CONTAINING_RECORD(pEntry
, UsedShim
, Entry
);
146 _PVNotify Notify
= pUsed
->pShim
->Notify
;
147 #if (WINVER > _WIN32_WINNT_WS03)
148 if (pUsed
->bInitCalled
&& fdwReason
== SHIM_REASON_INIT
)
152 Notify(fdwReason
, ptr
);
153 #if (WINVER > _WIN32_WINNT_WS03)
154 if (fdwReason
== SHIM_REASON_INIT
)
155 pUsed
->bInitCalled
= TRUE
;
158 pEntry
= pEntry
->Next
;
165 VOID
SeiInitDebugSupport(VOID
)
167 static const UNICODE_STRING DebugKey
= RTL_CONSTANT_STRING(L
"SHIM_DEBUG_LEVEL");
168 UNICODE_STRING DebugValue
;
170 ULONG NewLevel
= SEI_MSG
;
173 RtlInitEmptyUnicodeString(&DebugValue
, Buffer
, sizeof(Buffer
));
175 Status
= RtlQueryEnvironmentVariable_U(NULL
, &DebugKey
, &DebugValue
);
177 if (NT_SUCCESS(Status
))
179 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue
, 10, &NewLevel
)))
182 g_ShimEngDebugLevel
= NewLevel
;
187 * Outputs diagnostic info.
189 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
190 * SHIM_WARN, SHIM_INFO].
191 * @param [in] FunctionName The function this log should be attributed to.
192 * @param [in] Format The format string.
193 * @param ... Variable arguments providing additional information.
195 * @return Success: TRUE Failure: FALSE.
197 BOOL WINAPIV
SeiDbgPrint(SEI_LOG_LEVEL Level
, PCSTR Function
, PCSTR Format
, ...)
200 char* Current
= Buffer
;
201 const char* LevelStr
;
202 size_t Length
= sizeof(Buffer
);
206 if (g_ShimEngDebugLevel
== 0xffffffff)
207 SeiInitDebugSupport();
209 if (Level
> g_ShimEngDebugLevel
)
232 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] [%s] ", LevelStr
, Function
);
234 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] ", LevelStr
);
239 va_start(ArgList
, Format
);
240 hr
= StringCchVPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, Format
, ArgList
);
245 DbgPrint("%s", Buffer
);