xref: /reactos/dll/appcompat/apphelp/shimeng.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * PROJECT:     ReactOS Application compatibility module
3*c2c66affSColin Finck  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4*c2c66affSColin Finck  * PURPOSE:     Shim engine core
5*c2c66affSColin Finck  * COPYRIGHT:   Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
6*c2c66affSColin Finck  */
7*c2c66affSColin Finck 
8*c2c66affSColin Finck #define WIN32_NO_STATUS
9*c2c66affSColin Finck #include "ntndk.h"
10*c2c66affSColin Finck #define IN_APPHELP
11*c2c66affSColin Finck #include "shimlib.h"
12*c2c66affSColin Finck #include <strsafe.h>
13*c2c66affSColin Finck /* Make sure we don't include apphelp logging */
14*c2c66affSColin Finck #define APPHELP_NOSDBPAPI
15*c2c66affSColin Finck #include "apphelp.h"
16*c2c66affSColin Finck #include "shimeng.h"
17*c2c66affSColin Finck 
18*c2c66affSColin Finck 
19*c2c66affSColin Finck 
20*c2c66affSColin Finck FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName);
21*c2c66affSColin Finck BOOL WINAPI SE_IsShimDll(PVOID BaseAddress);
22*c2c66affSColin Finck 
23*c2c66affSColin Finck 
24*c2c66affSColin Finck extern HMODULE g_hInstance;
25*c2c66affSColin Finck static UNICODE_STRING g_WindowsDirectory;
26*c2c66affSColin Finck static UNICODE_STRING g_System32Directory;
27*c2c66affSColin Finck static UNICODE_STRING g_SxsDirectory;
28*c2c66affSColin Finck ULONG g_ShimEngDebugLevel = 0xffffffff;
29*c2c66affSColin Finck BOOL g_bComPlusImage = FALSE;
30*c2c66affSColin Finck BOOL g_bShimDuringInit = FALSE;
31*c2c66affSColin Finck BOOL g_bInternalHooksUsed = FALSE;
32*c2c66affSColin Finck static ARRAY g_pShimInfo;   /* PSHIMMODULE */
33*c2c66affSColin Finck static ARRAY g_pHookArray;  /* HOOKMODULEINFO */
34*c2c66affSColin Finck static ARRAY g_InExclude;   /* INEXCLUDE */
35*c2c66affSColin Finck 
36*c2c66affSColin Finck /* If we have setup a hook for a function, we should also redirect GetProcAddress for this function */
37*c2c66affSColin Finck HOOKAPIEX g_IntHookEx[] =
38*c2c66affSColin Finck {
39*c2c66affSColin Finck     {
40*c2c66affSColin Finck         "kernel32.dll",     /* LibraryName */
41*c2c66affSColin Finck         "GetProcAddress",   /* FunctionName */
42*c2c66affSColin Finck         StubGetProcAddress, /* ReplacementFunction*/
43*c2c66affSColin Finck         NULL,               /* OriginalFunction */
44*c2c66affSColin Finck         NULL,               /* pShimInfo */
45*c2c66affSColin Finck         NULL                /* Unused */
46*c2c66affSColin Finck     },
47*c2c66affSColin Finck };
48*c2c66affSColin Finck 
49*c2c66affSColin Finck static inline BOOL ARRAY_InitWorker(PARRAY Array, DWORD ItemSize)
50*c2c66affSColin Finck {
51*c2c66affSColin Finck     Array->Data__ = NULL;
52*c2c66affSColin Finck     Array->Size__ = Array->MaxSize__ = 0;
53*c2c66affSColin Finck     Array->ItemSize__ = ItemSize;
54*c2c66affSColin Finck 
55*c2c66affSColin Finck     return TRUE;
56*c2c66affSColin Finck }
57*c2c66affSColin Finck 
58*c2c66affSColin Finck static inline BOOL ARRAY_EnsureSize(PARRAY Array, DWORD ItemSize, DWORD GrowWith)
59*c2c66affSColin Finck {
60*c2c66affSColin Finck     PVOID pNewData;
61*c2c66affSColin Finck     DWORD Count;
62*c2c66affSColin Finck 
63*c2c66affSColin Finck     ASSERT(Array);
64*c2c66affSColin Finck     ASSERT(ItemSize == Array->ItemSize__);
65*c2c66affSColin Finck 
66*c2c66affSColin Finck     if (Array->MaxSize__ > Array->Size__)
67*c2c66affSColin Finck         return TRUE;
68*c2c66affSColin Finck 
69*c2c66affSColin Finck     Count = Array->Size__ + GrowWith;
70*c2c66affSColin Finck     pNewData = SeiAlloc(Count * ItemSize);
71*c2c66affSColin Finck 
72*c2c66affSColin Finck     if (!pNewData)
73*c2c66affSColin Finck     {
74*c2c66affSColin Finck         SHIMENG_FAIL("Failed to allocate %d bytes\n", Count * ItemSize);
75*c2c66affSColin Finck         return FALSE;
76*c2c66affSColin Finck     }
77*c2c66affSColin Finck     Array->MaxSize__ = Count;
78*c2c66affSColin Finck 
79*c2c66affSColin Finck     if (Array->Data__)
80*c2c66affSColin Finck     {
81*c2c66affSColin Finck         memcpy(pNewData, Array->Data__, Array->Size__ * ItemSize);
82*c2c66affSColin Finck         SeiFree(Array->Data__);
83*c2c66affSColin Finck     }
84*c2c66affSColin Finck     Array->Data__ = pNewData;
85*c2c66affSColin Finck 
86*c2c66affSColin Finck     return TRUE;
87*c2c66affSColin Finck }
88*c2c66affSColin Finck 
89*c2c66affSColin Finck static inline PVOID ARRAY_AppendWorker(PARRAY Array, DWORD ItemSize, DWORD GrowWith)
90*c2c66affSColin Finck {
91*c2c66affSColin Finck     PBYTE pData;
92*c2c66affSColin Finck 
93*c2c66affSColin Finck     if (!ARRAY_EnsureSize(Array, ItemSize, GrowWith))
94*c2c66affSColin Finck         return NULL;
95*c2c66affSColin Finck 
96*c2c66affSColin Finck     pData = Array->Data__;
97*c2c66affSColin Finck     pData += (Array->Size__ * ItemSize);
98*c2c66affSColin Finck     Array->Size__++;
99*c2c66affSColin Finck 
100*c2c66affSColin Finck     return pData;
101*c2c66affSColin Finck }
102*c2c66affSColin Finck 
103*c2c66affSColin Finck static inline PVOID ARRAY_AtWorker(PARRAY Array, DWORD ItemSize, DWORD n)
104*c2c66affSColin Finck {
105*c2c66affSColin Finck     PBYTE pData;
106*c2c66affSColin Finck 
107*c2c66affSColin Finck     ASSERT(Array);
108*c2c66affSColin Finck     ASSERT(ItemSize == Array->ItemSize__);
109*c2c66affSColin Finck     ASSERT(n < Array->Size__);
110*c2c66affSColin Finck 
111*c2c66affSColin Finck     pData = Array->Data__;
112*c2c66affSColin Finck     return pData + (n * ItemSize);
113*c2c66affSColin Finck }
114*c2c66affSColin Finck 
115*c2c66affSColin Finck 
116*c2c66affSColin Finck #define ARRAY_Init(Array, TypeOfArray)      ARRAY_InitWorker((Array), sizeof(TypeOfArray))
117*c2c66affSColin Finck #define ARRAY_Append(Array, TypeOfArray)    (TypeOfArray*)ARRAY_AppendWorker((Array), sizeof(TypeOfArray), 5)
118*c2c66affSColin Finck #define ARRAY_At(Array, TypeOfArray, at)    (TypeOfArray*)ARRAY_AtWorker((Array), sizeof(TypeOfArray), at)
119*c2c66affSColin Finck #define ARRAY_Size(Array)                   (Array)->Size__
120*c2c66affSColin Finck 
121*c2c66affSColin Finck 
122*c2c66affSColin Finck VOID SeiInitDebugSupport(VOID)
123*c2c66affSColin Finck {
124*c2c66affSColin Finck     static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIMENG_DEBUG_LEVEL");
125*c2c66affSColin Finck     UNICODE_STRING DebugValue;
126*c2c66affSColin Finck     NTSTATUS Status;
127*c2c66affSColin Finck     ULONG NewLevel = SEI_MSG;   /* Show some basic info in the logs, unless configured different */
128*c2c66affSColin Finck     WCHAR Buffer[40];
129*c2c66affSColin Finck 
130*c2c66affSColin Finck     RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
131*c2c66affSColin Finck 
132*c2c66affSColin Finck     Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
133*c2c66affSColin Finck 
134*c2c66affSColin Finck     if (NT_SUCCESS(Status))
135*c2c66affSColin Finck     {
136*c2c66affSColin Finck         if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
137*c2c66affSColin Finck             NewLevel = 0;
138*c2c66affSColin Finck     }
139*c2c66affSColin Finck     g_ShimEngDebugLevel = NewLevel;
140*c2c66affSColin Finck }
141*c2c66affSColin Finck 
142*c2c66affSColin Finck 
143*c2c66affSColin Finck /**
144*c2c66affSColin Finck  * Outputs diagnostic info.
145*c2c66affSColin Finck  *
146*c2c66affSColin Finck  * @param [in]  Level           The level to log this message with, choose any of [SHIM_ERR,
147*c2c66affSColin Finck  *                              SHIM_WARN, SHIM_INFO].
148*c2c66affSColin Finck  * @param [in]  FunctionName    The function this log should be attributed to.
149*c2c66affSColin Finck  * @param [in]  Format          The format string.
150*c2c66affSColin Finck  * @param   ...                 Variable arguments providing additional information.
151*c2c66affSColin Finck  *
152*c2c66affSColin Finck  * @return  Success: TRUE Failure: FALSE.
153*c2c66affSColin Finck  */
154*c2c66affSColin Finck BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR Function, PCSTR Format, ...)
155*c2c66affSColin Finck {
156*c2c66affSColin Finck     char Buffer[512];
157*c2c66affSColin Finck     char* Current = Buffer;
158*c2c66affSColin Finck     const char* LevelStr;
159*c2c66affSColin Finck     size_t Length = sizeof(Buffer);
160*c2c66affSColin Finck     va_list ArgList;
161*c2c66affSColin Finck     HRESULT hr;
162*c2c66affSColin Finck 
163*c2c66affSColin Finck     if (g_ShimEngDebugLevel == 0xffffffff)
164*c2c66affSColin Finck         SeiInitDebugSupport();
165*c2c66affSColin Finck 
166*c2c66affSColin Finck     if (Level > g_ShimEngDebugLevel)
167*c2c66affSColin Finck         return FALSE;
168*c2c66affSColin Finck 
169*c2c66affSColin Finck     switch (Level)
170*c2c66affSColin Finck     {
171*c2c66affSColin Finck     case SEI_MSG:
172*c2c66affSColin Finck         LevelStr = "MSG ";
173*c2c66affSColin Finck         break;
174*c2c66affSColin Finck     case SEI_FAIL:
175*c2c66affSColin Finck         LevelStr = "FAIL";
176*c2c66affSColin Finck         break;
177*c2c66affSColin Finck     case SEI_WARN:
178*c2c66affSColin Finck         LevelStr = "WARN";
179*c2c66affSColin Finck         break;
180*c2c66affSColin Finck     case SEI_INFO:
181*c2c66affSColin Finck         LevelStr = "INFO";
182*c2c66affSColin Finck         break;
183*c2c66affSColin Finck     default:
184*c2c66affSColin Finck         LevelStr = "USER";
185*c2c66affSColin Finck         break;
186*c2c66affSColin Finck     }
187*c2c66affSColin Finck 
188*c2c66affSColin Finck     if (Function)
189*c2c66affSColin Finck         hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] [%s] ", LevelStr, Function);
190*c2c66affSColin Finck     else
191*c2c66affSColin Finck         hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] ", LevelStr);
192*c2c66affSColin Finck 
193*c2c66affSColin Finck     if (!SUCCEEDED(hr))
194*c2c66affSColin Finck         return FALSE;
195*c2c66affSColin Finck 
196*c2c66affSColin Finck     va_start(ArgList, Format);
197*c2c66affSColin Finck     hr = StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
198*c2c66affSColin Finck     va_end(ArgList);
199*c2c66affSColin Finck     if (!SUCCEEDED(hr))
200*c2c66affSColin Finck         return FALSE;
201*c2c66affSColin Finck 
202*c2c66affSColin Finck     DbgPrint("%s", Buffer);
203*c2c66affSColin Finck     return TRUE;
204*c2c66affSColin Finck }
205*c2c66affSColin Finck 
206*c2c66affSColin Finck 
207*c2c66affSColin Finck PVOID SeiGetModuleFromAddress(PVOID addr)
208*c2c66affSColin Finck {
209*c2c66affSColin Finck     PVOID hModule = NULL;
210*c2c66affSColin Finck     RtlPcToFileHeader(addr, &hModule);
211*c2c66affSColin Finck     return hModule;
212*c2c66affSColin Finck }
213*c2c66affSColin Finck 
214*c2c66affSColin Finck 
215*c2c66affSColin Finck 
216*c2c66affSColin Finck /* TODO: Guard against recursive calling / calling init multiple times! */
217*c2c66affSColin Finck VOID NotifyShims(DWORD dwReason, PVOID Info)
218*c2c66affSColin Finck {
219*c2c66affSColin Finck     DWORD n;
220*c2c66affSColin Finck 
221*c2c66affSColin Finck     for (n = 0; n < ARRAY_Size(&g_pShimInfo); ++n)
222*c2c66affSColin Finck     {
223*c2c66affSColin Finck         PSHIMMODULE pShimModule = *ARRAY_At(&g_pShimInfo, PSHIMMODULE, n);
224*c2c66affSColin Finck         if (!pShimModule->pNotifyShims)
225*c2c66affSColin Finck             continue;
226*c2c66affSColin Finck 
227*c2c66affSColin Finck         pShimModule->pNotifyShims(dwReason, Info);
228*c2c66affSColin Finck     }
229*c2c66affSColin Finck }
230*c2c66affSColin Finck 
231*c2c66affSColin Finck 
232*c2c66affSColin Finck 
233*c2c66affSColin Finck VOID SeiCheckComPlusImage(PVOID BaseAddress)
234*c2c66affSColin Finck {
235*c2c66affSColin Finck     ULONG ComSectionSize;
236*c2c66affSColin Finck     g_bComPlusImage = RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &ComSectionSize) != NULL;
237*c2c66affSColin Finck 
238*c2c66affSColin Finck     SHIMENG_INFO("COM+ executable %s\n", g_bComPlusImage ? "TRUE" : "FALSE");
239*c2c66affSColin Finck }
240*c2c66affSColin Finck 
241*c2c66affSColin Finck 
242*c2c66affSColin Finck PSHIMMODULE SeiGetShimModuleInfo(PVOID BaseAddress)
243*c2c66affSColin Finck {
244*c2c66affSColin Finck     DWORD n;
245*c2c66affSColin Finck 
246*c2c66affSColin Finck     for (n = 0; n < ARRAY_Size(&g_pShimInfo); ++n)
247*c2c66affSColin Finck     {
248*c2c66affSColin Finck         PSHIMMODULE pShimModule = *ARRAY_At(&g_pShimInfo, PSHIMMODULE, n);
249*c2c66affSColin Finck 
250*c2c66affSColin Finck         if (pShimModule->BaseAddress == BaseAddress)
251*c2c66affSColin Finck             return pShimModule;
252*c2c66affSColin Finck     }
253*c2c66affSColin Finck     return NULL;
254*c2c66affSColin Finck }
255*c2c66affSColin Finck 
256*c2c66affSColin Finck PSHIMMODULE SeiCreateShimModuleInfo(PCWSTR DllName, PVOID BaseAddress)
257*c2c66affSColin Finck {
258*c2c66affSColin Finck     static const ANSI_STRING GetHookAPIs = RTL_CONSTANT_STRING("GetHookAPIs");
259*c2c66affSColin Finck     static const ANSI_STRING NotifyShims = RTL_CONSTANT_STRING("NotifyShims");
260*c2c66affSColin Finck     PSHIMMODULE* pData, Data;
261*c2c66affSColin Finck     PVOID pGetHookAPIs, pNotifyShims;
262*c2c66affSColin Finck 
263*c2c66affSColin Finck     if (!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress, (PANSI_STRING)&GetHookAPIs, 0, &pGetHookAPIs)) ||
264*c2c66affSColin Finck         !NT_SUCCESS(LdrGetProcedureAddress(BaseAddress, (PANSI_STRING)&NotifyShims, 0, &pNotifyShims)))
265*c2c66affSColin Finck     {
266*c2c66affSColin Finck         SHIMENG_WARN("Failed to resolve entry points for %S\n", DllName);
267*c2c66affSColin Finck         return NULL;
268*c2c66affSColin Finck     }
269*c2c66affSColin Finck 
270*c2c66affSColin Finck     pData = ARRAY_Append(&g_pShimInfo, PSHIMMODULE);
271*c2c66affSColin Finck     if (!pData)
272*c2c66affSColin Finck         return NULL;
273*c2c66affSColin Finck 
274*c2c66affSColin Finck     *pData = SeiAlloc(sizeof(SHIMMODULE));
275*c2c66affSColin Finck 
276*c2c66affSColin Finck     Data = *pData;
277*c2c66affSColin Finck 
278*c2c66affSColin Finck     RtlCreateUnicodeString(&Data->Name, DllName);
279*c2c66affSColin Finck     Data->BaseAddress = BaseAddress;
280*c2c66affSColin Finck 
281*c2c66affSColin Finck     Data->pGetHookAPIs = pGetHookAPIs;
282*c2c66affSColin Finck     Data->pNotifyShims = pNotifyShims;
283*c2c66affSColin Finck 
284*c2c66affSColin Finck     ARRAY_Init(&Data->EnabledShims, PSHIMINFO);
285*c2c66affSColin Finck 
286*c2c66affSColin Finck     return Data;
287*c2c66affSColin Finck }
288*c2c66affSColin Finck 
289*c2c66affSColin Finck PSHIMINFO SeiAppendHookInfo(PSHIMMODULE pShimModuleInfo, PHOOKAPIEX pHookApi, DWORD dwHookCount, PCWSTR ShimName)
290*c2c66affSColin Finck {
291*c2c66affSColin Finck     PSHIMINFO* pData, Data;
292*c2c66affSColin Finck 
293*c2c66affSColin Finck     pData = ARRAY_Append(&pShimModuleInfo->EnabledShims, PSHIMINFO);
294*c2c66affSColin Finck     if (!pData)
295*c2c66affSColin Finck         return NULL;
296*c2c66affSColin Finck 
297*c2c66affSColin Finck     *pData = SeiAlloc(sizeof(SHIMINFO));
298*c2c66affSColin Finck     Data = *pData;
299*c2c66affSColin Finck 
300*c2c66affSColin Finck     if (!Data)
301*c2c66affSColin Finck         return NULL;
302*c2c66affSColin Finck 
303*c2c66affSColin Finck     Data->ShimName = SdbpStrDup(ShimName);
304*c2c66affSColin Finck     if (!Data->ShimName)
305*c2c66affSColin Finck         return NULL;
306*c2c66affSColin Finck 
307*c2c66affSColin Finck     Data->pHookApi = pHookApi;
308*c2c66affSColin Finck     Data->dwHookCount = dwHookCount;
309*c2c66affSColin Finck     Data->pShimModule = pShimModuleInfo;
310*c2c66affSColin Finck     ARRAY_Init(&Data->InExclude, INEXCLUDE);
311*c2c66affSColin Finck     return Data;
312*c2c66affSColin Finck }
313*c2c66affSColin Finck 
314*c2c66affSColin Finck PHOOKMODULEINFO SeiFindHookModuleInfo(PUNICODE_STRING ModuleName, PVOID BaseAddress)
315*c2c66affSColin Finck {
316*c2c66affSColin Finck     DWORD n;
317*c2c66affSColin Finck 
318*c2c66affSColin Finck     for (n = 0; n < ARRAY_Size(&g_pHookArray); ++n)
319*c2c66affSColin Finck     {
320*c2c66affSColin Finck         PHOOKMODULEINFO pModuleInfo = ARRAY_At(&g_pHookArray, HOOKMODULEINFO, n);
321*c2c66affSColin Finck 
322*c2c66affSColin Finck         if (BaseAddress && BaseAddress == pModuleInfo->BaseAddress)
323*c2c66affSColin Finck             return pModuleInfo;
324*c2c66affSColin Finck 
325*c2c66affSColin Finck         if (!BaseAddress && RtlEqualUnicodeString(ModuleName, &pModuleInfo->Name, TRUE))
326*c2c66affSColin Finck             return pModuleInfo;
327*c2c66affSColin Finck     }
328*c2c66affSColin Finck 
329*c2c66affSColin Finck     return NULL;
330*c2c66affSColin Finck }
331*c2c66affSColin Finck 
332*c2c66affSColin Finck PHOOKMODULEINFO SeiFindHookModuleInfoForImportDescriptor(PBYTE DllBase, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor)
333*c2c66affSColin Finck {
334*c2c66affSColin Finck     UNICODE_STRING DllName;
335*c2c66affSColin Finck     PVOID DllHandle;
336*c2c66affSColin Finck     NTSTATUS Success;
337*c2c66affSColin Finck 
338*c2c66affSColin Finck     if (!RtlCreateUnicodeStringFromAsciiz(&DllName, (PCSZ)(DllBase + ImportDescriptor->Name)))
339*c2c66affSColin Finck     {
340*c2c66affSColin Finck         SHIMENG_FAIL("Unable to convert dll name to unicode\n");
341*c2c66affSColin Finck         return NULL;
342*c2c66affSColin Finck     }
343*c2c66affSColin Finck 
344*c2c66affSColin Finck     Success = LdrGetDllHandle(NULL, NULL, &DllName, &DllHandle);
345*c2c66affSColin Finck     RtlFreeUnicodeString(&DllName);
346*c2c66affSColin Finck 
347*c2c66affSColin Finck     if (!NT_SUCCESS(Success))
348*c2c66affSColin Finck     {
349*c2c66affSColin Finck         SHIMENG_FAIL("Unable to get module handle for %wZ\n", &DllName);
350*c2c66affSColin Finck         return NULL;
351*c2c66affSColin Finck     }
352*c2c66affSColin Finck 
353*c2c66affSColin Finck     return SeiFindHookModuleInfo(NULL, DllHandle);
354*c2c66affSColin Finck }
355*c2c66affSColin Finck 
356*c2c66affSColin Finck static LPCWSTR SeiGetStringPtr(PDB pdb, TAGID tag, TAG type)
357*c2c66affSColin Finck {
358*c2c66affSColin Finck     TAGID tagEntry = SdbFindFirstTag(pdb, tag, type);
359*c2c66affSColin Finck     if (tagEntry == TAGID_NULL)
360*c2c66affSColin Finck         return NULL;
361*c2c66affSColin Finck 
362*c2c66affSColin Finck     return SdbGetStringTagPtr(pdb, tagEntry);
363*c2c66affSColin Finck }
364*c2c66affSColin Finck 
365*c2c66affSColin Finck static DWORD SeiGetDWORD(PDB pdb, TAGID tag, TAG type)
366*c2c66affSColin Finck {
367*c2c66affSColin Finck     TAGID tagEntry = SdbFindFirstTag(pdb, tag, type);
368*c2c66affSColin Finck     if (tagEntry == TAGID_NULL)
369*c2c66affSColin Finck         return 0;
370*c2c66affSColin Finck 
371*c2c66affSColin Finck     return SdbReadDWORDTag(pdb, tagEntry, TAGID_NULL);
372*c2c66affSColin Finck }
373*c2c66affSColin Finck 
374*c2c66affSColin Finck 
375*c2c66affSColin Finck static VOID SeiAddShim(TAGREF trShimRef, PARRAY pShimRef)
376*c2c66affSColin Finck {
377*c2c66affSColin Finck     TAGREF* Data;
378*c2c66affSColin Finck 
379*c2c66affSColin Finck     Data = ARRAY_Append(pShimRef, TAGREF);
380*c2c66affSColin Finck     if (!Data)
381*c2c66affSColin Finck         return;
382*c2c66affSColin Finck 
383*c2c66affSColin Finck     *Data = trShimRef;
384*c2c66affSColin Finck }
385*c2c66affSColin Finck 
386*c2c66affSColin Finck /* Propagate layers to child processes */
387*c2c66affSColin Finck static VOID SeiSetLayerEnvVar(LPCWSTR wszLayer)
388*c2c66affSColin Finck {
389*c2c66affSColin Finck     NTSTATUS Status;
390*c2c66affSColin Finck     UNICODE_STRING VarName = RTL_CONSTANT_STRING(L"__COMPAT_LAYER");
391*c2c66affSColin Finck     UNICODE_STRING Value;
392*c2c66affSColin Finck 
393*c2c66affSColin Finck     RtlInitUnicodeString(&Value, wszLayer);
394*c2c66affSColin Finck 
395*c2c66affSColin Finck     Status = RtlSetEnvironmentVariable(NULL, &VarName, &Value);
396*c2c66affSColin Finck     if (NT_SUCCESS(Status))
397*c2c66affSColin Finck         SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName, &Value);
398*c2c66affSColin Finck     else
399*c2c66affSColin Finck         SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName, Status);
400*c2c66affSColin Finck }
401*c2c66affSColin Finck 
402*c2c66affSColin Finck #define MAX_LAYER_LENGTH            256
403*c2c66affSColin Finck 
404*c2c66affSColin Finck /* Translate all Exe and Layer entries to Shims, and propagate all layers */
405*c2c66affSColin Finck static VOID SeiBuildShimRefArray(HSDB hsdb, SDBQUERYRESULT* pQuery, PARRAY pShimRef)
406*c2c66affSColin Finck {
407*c2c66affSColin Finck     WCHAR wszLayerEnvVar[MAX_LAYER_LENGTH] = { 0 };
408*c2c66affSColin Finck     DWORD n;
409*c2c66affSColin Finck 
410*c2c66affSColin Finck     for (n = 0; n < pQuery->dwExeCount; ++n)
411*c2c66affSColin Finck     {
412*c2c66affSColin Finck         PDB pdb;
413*c2c66affSColin Finck         TAGID tag;
414*c2c66affSColin Finck         if (SdbTagRefToTagID(hsdb, pQuery->atrExes[n], &pdb, &tag))
415*c2c66affSColin Finck         {
416*c2c66affSColin Finck             LPCWSTR ExeName = SeiGetStringPtr(pdb, tag, TAG_NAME);
417*c2c66affSColin Finck             TAGID ShimRef = SdbFindFirstTag(pdb, tag, TAG_SHIM_REF);
418*c2c66affSColin Finck 
419*c2c66affSColin Finck             if (ExeName)
420*c2c66affSColin Finck                 SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Exe(%S))\n", ExeName);
421*c2c66affSColin Finck 
422*c2c66affSColin Finck             while (ShimRef != TAGID_NULL)
423*c2c66affSColin Finck             {
424*c2c66affSColin Finck                 TAGREF trShimRef;
425*c2c66affSColin Finck                 if (SdbTagIDToTagRef(hsdb, pdb, ShimRef, &trShimRef))
426*c2c66affSColin Finck                     SeiAddShim(trShimRef, pShimRef);
427*c2c66affSColin Finck 
428*c2c66affSColin Finck 
429*c2c66affSColin Finck                 ShimRef = SdbFindNextTag(pdb, tag, ShimRef);
430*c2c66affSColin Finck             }
431*c2c66affSColin Finck 
432*c2c66affSColin Finck             /* Handle FLAG_REF */
433*c2c66affSColin Finck         }
434*c2c66affSColin Finck     }
435*c2c66affSColin Finck 
436*c2c66affSColin Finck 
437*c2c66affSColin Finck     for (n = 0; n < pQuery->dwLayerCount; ++n)
438*c2c66affSColin Finck     {
439*c2c66affSColin Finck         PDB pdb;
440*c2c66affSColin Finck         TAGID tag;
441*c2c66affSColin Finck         if (SdbTagRefToTagID(hsdb, pQuery->atrLayers[n], &pdb, &tag))
442*c2c66affSColin Finck         {
443*c2c66affSColin Finck             LPCWSTR LayerName = SeiGetStringPtr(pdb, tag, TAG_NAME);
444*c2c66affSColin Finck             TAGID ShimRef = SdbFindFirstTag(pdb, tag, TAG_SHIM_REF);
445*c2c66affSColin Finck             if (LayerName)
446*c2c66affSColin Finck             {
447*c2c66affSColin Finck                 HRESULT hr;
448*c2c66affSColin Finck                 SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Layer(%S))\n", LayerName);
449*c2c66affSColin Finck                 if (wszLayerEnvVar[0])
450*c2c66affSColin Finck                     StringCchCatW(wszLayerEnvVar, ARRAYSIZE(wszLayerEnvVar), L" ");
451*c2c66affSColin Finck                 hr = StringCchCatW(wszLayerEnvVar, ARRAYSIZE(wszLayerEnvVar), LayerName);
452*c2c66affSColin Finck                 if (!SUCCEEDED(hr))
453*c2c66affSColin Finck                 {
454*c2c66affSColin Finck                     SHIMENG_FAIL("Unable to append %S\n", LayerName);
455*c2c66affSColin Finck                 }
456*c2c66affSColin Finck             }
457*c2c66affSColin Finck 
458*c2c66affSColin Finck             while (ShimRef != TAGID_NULL)
459*c2c66affSColin Finck             {
460*c2c66affSColin Finck                 TAGREF trShimRef;
461*c2c66affSColin Finck                 if (SdbTagIDToTagRef(hsdb, pdb, ShimRef, &trShimRef))
462*c2c66affSColin Finck                     SeiAddShim(trShimRef, pShimRef);
463*c2c66affSColin Finck 
464*c2c66affSColin Finck                 ShimRef = SdbFindNextTag(pdb, tag, ShimRef);
465*c2c66affSColin Finck             }
466*c2c66affSColin Finck 
467*c2c66affSColin Finck             /* Handle FLAG_REF */
468*c2c66affSColin Finck         }
469*c2c66affSColin Finck     }
470*c2c66affSColin Finck     if (wszLayerEnvVar[0])
471*c2c66affSColin Finck         SeiSetLayerEnvVar(wszLayerEnvVar);
472*c2c66affSColin Finck }
473*c2c66affSColin Finck 
474*c2c66affSColin Finck /* Given the hooks from one shim, find the relevant modules and store the combination of module + hook */
475*c2c66affSColin Finck VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim)
476*c2c66affSColin Finck {
477*c2c66affSColin Finck     DWORD n, j;
478*c2c66affSColin Finck     UNICODE_STRING UnicodeModName;
479*c2c66affSColin Finck     WCHAR Buf[512];
480*c2c66affSColin Finck 
481*c2c66affSColin Finck     RtlInitEmptyUnicodeString(&UnicodeModName, Buf, sizeof(Buf));
482*c2c66affSColin Finck 
483*c2c66affSColin Finck     for (n = 0; n < dwHookCount; ++n)
484*c2c66affSColin Finck     {
485*c2c66affSColin Finck         ANSI_STRING AnsiString;
486*c2c66affSColin Finck         PVOID DllHandle;
487*c2c66affSColin Finck         PHOOKAPIEX hook = hooks + n;
488*c2c66affSColin Finck         PHOOKAPIEX* pHookApi;
489*c2c66affSColin Finck         PHOOKMODULEINFO HookModuleInfo;
490*c2c66affSColin Finck 
491*c2c66affSColin Finck         RtlInitAnsiString(&AnsiString, hook->LibraryName);
492*c2c66affSColin Finck         if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeModName, &AnsiString, FALSE)))
493*c2c66affSColin Finck         {
494*c2c66affSColin Finck             SHIMENG_FAIL("Unable to convert %s to Unicode\n", hook->LibraryName);
495*c2c66affSColin Finck             continue;
496*c2c66affSColin Finck         }
497*c2c66affSColin Finck 
498*c2c66affSColin Finck         RtlInitAnsiString(&AnsiString, hook->FunctionName);
499*c2c66affSColin Finck         if (NT_SUCCESS(LdrGetDllHandle(NULL, 0, &UnicodeModName, &DllHandle)))
500*c2c66affSColin Finck         {
501*c2c66affSColin Finck             PVOID ProcAddress;
502*c2c66affSColin Finck 
503*c2c66affSColin Finck 
504*c2c66affSColin Finck             if (!NT_SUCCESS(LdrGetProcedureAddress(DllHandle, &AnsiString, 0, &ProcAddress)))
505*c2c66affSColin Finck             {
506*c2c66affSColin Finck                 SHIMENG_FAIL("Unable to retrieve %s!%s\n", hook->LibraryName, hook->FunctionName);
507*c2c66affSColin Finck                 continue;
508*c2c66affSColin Finck             }
509*c2c66affSColin Finck 
510*c2c66affSColin Finck             HookModuleInfo = SeiFindHookModuleInfo(NULL, DllHandle);
511*c2c66affSColin Finck             hook->OriginalFunction = ProcAddress;
512*c2c66affSColin Finck         }
513*c2c66affSColin Finck         else
514*c2c66affSColin Finck         {
515*c2c66affSColin Finck             HookModuleInfo = SeiFindHookModuleInfo(&UnicodeModName, NULL);
516*c2c66affSColin Finck             DllHandle = NULL;
517*c2c66affSColin Finck         }
518*c2c66affSColin Finck 
519*c2c66affSColin Finck         if (!HookModuleInfo)
520*c2c66affSColin Finck         {
521*c2c66affSColin Finck             HookModuleInfo = ARRAY_Append(&g_pHookArray, HOOKMODULEINFO);
522*c2c66affSColin Finck             if (!HookModuleInfo)
523*c2c66affSColin Finck                 continue;
524*c2c66affSColin Finck 
525*c2c66affSColin Finck             HookModuleInfo->BaseAddress = DllHandle;
526*c2c66affSColin Finck             ARRAY_Init(&HookModuleInfo->HookApis, PHOOKAPIEX);
527*c2c66affSColin Finck             RtlCreateUnicodeString(&HookModuleInfo->Name, UnicodeModName.Buffer);
528*c2c66affSColin Finck         }
529*c2c66affSColin Finck 
530*c2c66affSColin Finck         hook->pShimInfo = pShim;
531*c2c66affSColin Finck 
532*c2c66affSColin Finck         for (j = 0; j < ARRAY_Size(&HookModuleInfo->HookApis); ++j)
533*c2c66affSColin Finck         {
534*c2c66affSColin Finck             PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, j);
535*c2c66affSColin Finck             int CmpResult = strcmp(hook->FunctionName, HookApi->FunctionName);
536*c2c66affSColin Finck             if (CmpResult == 0)
537*c2c66affSColin Finck             {
538*c2c66affSColin Finck                 /* Multiple hooks on one function? --> use ApiLink */
539*c2c66affSColin Finck                 SHIMENG_FAIL("Multiple hooks on one API is not yet supported!\n");
540*c2c66affSColin Finck                 ASSERT(0);
541*c2c66affSColin Finck             }
542*c2c66affSColin Finck         }
543*c2c66affSColin Finck         pHookApi = ARRAY_Append(&HookModuleInfo->HookApis, PHOOKAPIEX);
544*c2c66affSColin Finck         *pHookApi = hook;
545*c2c66affSColin Finck     }
546*c2c66affSColin Finck }
547*c2c66affSColin Finck 
548*c2c66affSColin Finck typedef FARPROC(WINAPI* GETPROCADDRESSPROC)(HINSTANCE, LPCSTR);
549*c2c66affSColin Finck 
550*c2c66affSColin Finck /* Check if we should fake the return from GetProcAddress (because we also redirected the iat for this module) */
551*c2c66affSColin Finck FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName)
552*c2c66affSColin Finck {
553*c2c66affSColin Finck     char szOrdProcName[10] = "";
554*c2c66affSColin Finck     LPCSTR lpPrintName = lpProcName;
555*c2c66affSColin Finck     PVOID Addr = _ReturnAddress();
556*c2c66affSColin Finck     PHOOKMODULEINFO HookModuleInfo;
557*c2c66affSColin Finck     FARPROC proc = ((GETPROCADDRESSPROC)g_IntHookEx[0].OriginalFunction)(hModule, lpProcName);
558*c2c66affSColin Finck 
559*c2c66affSColin Finck     if (!HIWORD(lpProcName))
560*c2c66affSColin Finck     {
561*c2c66affSColin Finck         sprintf(szOrdProcName, "#%lu", (DWORD)lpProcName);
562*c2c66affSColin Finck         lpPrintName = szOrdProcName;
563*c2c66affSColin Finck     }
564*c2c66affSColin Finck 
565*c2c66affSColin Finck     Addr = SeiGetModuleFromAddress(Addr);
566*c2c66affSColin Finck     if (SE_IsShimDll(Addr))
567*c2c66affSColin Finck     {
568*c2c66affSColin Finck         SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule, lpPrintName);
569*c2c66affSColin Finck         return proc;
570*c2c66affSColin Finck     }
571*c2c66affSColin Finck 
572*c2c66affSColin Finck     SHIMENG_MSG("(GetProcAddress(%p!%s) => %p\n", hModule, lpPrintName, proc);
573*c2c66affSColin Finck 
574*c2c66affSColin Finck     HookModuleInfo = SeiFindHookModuleInfo(NULL, hModule);
575*c2c66affSColin Finck 
576*c2c66affSColin Finck     /* FIXME: Ordinal not yet supported */
577*c2c66affSColin Finck     if (HookModuleInfo && HIWORD(lpProcName))
578*c2c66affSColin Finck     {
579*c2c66affSColin Finck         DWORD n;
580*c2c66affSColin Finck         for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n)
581*c2c66affSColin Finck         {
582*c2c66affSColin Finck             PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n);
583*c2c66affSColin Finck             int CmpResult = strcmp(lpProcName, HookApi->FunctionName);
584*c2c66affSColin Finck             if (CmpResult == 0)
585*c2c66affSColin Finck             {
586*c2c66affSColin Finck                 SHIMENG_MSG("Redirecting %p to %p\n", proc, HookApi->ReplacementFunction);
587*c2c66affSColin Finck                 proc = HookApi->ReplacementFunction;
588*c2c66affSColin Finck                 break;
589*c2c66affSColin Finck             }
590*c2c66affSColin Finck         }
591*c2c66affSColin Finck     }
592*c2c66affSColin Finck 
593*c2c66affSColin Finck     return proc;
594*c2c66affSColin Finck }
595*c2c66affSColin Finck 
596*c2c66affSColin Finck /* Walk all shim modules / enabled shims, and add their hooks */
597*c2c66affSColin Finck VOID SeiResolveAPIs(VOID)
598*c2c66affSColin Finck {
599*c2c66affSColin Finck     DWORD mod, n;
600*c2c66affSColin Finck 
601*c2c66affSColin Finck     /* Enumerate all Shim modules */
602*c2c66affSColin Finck     for (mod = 0; mod < ARRAY_Size(&g_pShimInfo); ++mod)
603*c2c66affSColin Finck     {
604*c2c66affSColin Finck         PSHIMMODULE pShimModule = *ARRAY_At(&g_pShimInfo, PSHIMMODULE, mod);
605*c2c66affSColin Finck         DWORD dwShimCount = ARRAY_Size(&pShimModule->EnabledShims);
606*c2c66affSColin Finck 
607*c2c66affSColin Finck         /* Enumerate all Shims */
608*c2c66affSColin Finck         for (n = 0; n < dwShimCount; ++n)
609*c2c66affSColin Finck         {
610*c2c66affSColin Finck             PSHIMINFO pShim = *ARRAY_At(&pShimModule->EnabledShims, PSHIMINFO, n);
611*c2c66affSColin Finck 
612*c2c66affSColin Finck             PHOOKAPIEX hooks = pShim->pHookApi;
613*c2c66affSColin Finck             DWORD dwHookCount = pShim->dwHookCount;
614*c2c66affSColin Finck 
615*c2c66affSColin Finck             SeiAddHooks(hooks, dwHookCount, pShim);
616*c2c66affSColin Finck         }
617*c2c66affSColin Finck     }
618*c2c66affSColin Finck }
619*c2c66affSColin Finck 
620*c2c66affSColin Finck /* If we hooked something, we should also redirect GetProcAddress */
621*c2c66affSColin Finck VOID SeiAddInternalHooks(DWORD dwNumHooks)
622*c2c66affSColin Finck {
623*c2c66affSColin Finck     if (dwNumHooks == 0)
624*c2c66affSColin Finck     {
625*c2c66affSColin Finck         g_bInternalHooksUsed = FALSE;
626*c2c66affSColin Finck         return;
627*c2c66affSColin Finck     }
628*c2c66affSColin Finck 
629*c2c66affSColin Finck     SeiAddHooks(g_IntHookEx, ARRAYSIZE(g_IntHookEx), NULL);
630*c2c66affSColin Finck     g_bInternalHooksUsed = TRUE;
631*c2c66affSColin Finck }
632*c2c66affSColin Finck 
633*c2c66affSColin Finck /* Patch one function in the iat */
634*c2c66affSColin Finck VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DATA_TABLE_ENTRY LdrEntry)
635*c2c66affSColin Finck {
636*c2c66affSColin Finck     ULONG OldProtection = 0;
637*c2c66affSColin Finck     PVOID Ptr;
638*c2c66affSColin Finck     ULONG Size;
639*c2c66affSColin Finck     NTSTATUS Status;
640*c2c66affSColin Finck 
641*c2c66affSColin Finck     SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName);
642*c2c66affSColin Finck 
643*c2c66affSColin Finck     Ptr = &FirstThunk->u1.Function;
644*c2c66affSColin Finck     Size = sizeof(FirstThunk->u1.Function);
645*c2c66affSColin Finck     Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, PAGE_EXECUTE_READWRITE, &OldProtection);
646*c2c66affSColin Finck 
647*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
648*c2c66affSColin Finck     {
649*c2c66affSColin Finck         SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk->u1.Function);
650*c2c66affSColin Finck         return;
651*c2c66affSColin Finck     }
652*c2c66affSColin Finck 
653*c2c66affSColin Finck     SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk->u1.Function, HookApi->ReplacementFunction);
654*c2c66affSColin Finck #ifdef _WIN64
655*c2c66affSColin Finck     FirstThunk->u1.Function = (ULONGLONG)HookApi->ReplacementFunction;
656*c2c66affSColin Finck #else
657*c2c66affSColin Finck     FirstThunk->u1.Function = (DWORD)HookApi->ReplacementFunction;
658*c2c66affSColin Finck #endif
659*c2c66affSColin Finck 
660*c2c66affSColin Finck     Size = sizeof(FirstThunk->u1.Function);
661*c2c66affSColin Finck     Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, OldProtection, &OldProtection);
662*c2c66affSColin Finck 
663*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
664*c2c66affSColin Finck     {
665*c2c66affSColin Finck         SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk->u1.Function);
666*c2c66affSColin Finck     }
667*c2c66affSColin Finck }
668*c2c66affSColin Finck 
669*c2c66affSColin Finck 
670*c2c66affSColin Finck PINEXCLUDE SeiFindInExclude(PARRAY InExclude, PCUNICODE_STRING DllName)
671*c2c66affSColin Finck {
672*c2c66affSColin Finck     DWORD n;
673*c2c66affSColin Finck 
674*c2c66affSColin Finck     for (n = 0; n < ARRAY_Size(InExclude); ++n)
675*c2c66affSColin Finck     {
676*c2c66affSColin Finck         PINEXCLUDE InEx = ARRAY_At(InExclude, INEXCLUDE, n);
677*c2c66affSColin Finck 
678*c2c66affSColin Finck         if (RtlEqualUnicodeString(&InEx->Module, DllName, TRUE))
679*c2c66affSColin Finck             return InEx;
680*c2c66affSColin Finck     }
681*c2c66affSColin Finck 
682*c2c66affSColin Finck     return NULL;
683*c2c66affSColin Finck }
684*c2c66affSColin Finck 
685*c2c66affSColin Finck BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi)
686*c2c66affSColin Finck {
687*c2c66affSColin Finck     PSHIMINFO pShimInfo = HookApi->pShimInfo;
688*c2c66affSColin Finck     PINEXCLUDE InExclude;
689*c2c66affSColin Finck     BOOL IsExcluded = FALSE;
690*c2c66affSColin Finck 
691*c2c66affSColin Finck     if (!pShimInfo)
692*c2c66affSColin Finck     {
693*c2c66affSColin Finck         /* Internal hook, do not exclude it */
694*c2c66affSColin Finck         return FALSE;
695*c2c66affSColin Finck     }
696*c2c66affSColin Finck 
697*c2c66affSColin Finck     /* By default, everything from System32 or WinSxs is excluded */
698*c2c66affSColin Finck     if (RtlPrefixUnicodeString(&g_System32Directory, &LdrEntry->FullDllName, TRUE) ||
699*c2c66affSColin Finck         RtlPrefixUnicodeString(&g_SxsDirectory, &LdrEntry->FullDllName, TRUE))
700*c2c66affSColin Finck         IsExcluded = TRUE;
701*c2c66affSColin Finck 
702*c2c66affSColin Finck     InExclude = SeiFindInExclude(&pShimInfo->InExclude, &LdrEntry->BaseDllName);
703*c2c66affSColin Finck     if (InExclude)
704*c2c66affSColin Finck     {
705*c2c66affSColin Finck         /* If it is on the 'exclude' list, bail out */
706*c2c66affSColin Finck         if (!InExclude->Include)
707*c2c66affSColin Finck         {
708*c2c66affSColin Finck             SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it on in the exclude list.\n",
709*c2c66affSColin Finck                          &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, HookApi->FunctionName);
710*c2c66affSColin Finck 
711*c2c66affSColin Finck             return TRUE;
712*c2c66affSColin Finck         }
713*c2c66affSColin Finck         /* If it is on the 'include' list, override System32 / Winsxs check. */
714*c2c66affSColin Finck         if (IsExcluded)
715*c2c66affSColin Finck         {
716*c2c66affSColin Finck             SHIMENG_INFO("Module '%wZ' included for shim %S, API '%s!%s', because it is on the include list.\n",
717*c2c66affSColin Finck                          &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, HookApi->FunctionName);
718*c2c66affSColin Finck 
719*c2c66affSColin Finck         }
720*c2c66affSColin Finck         IsExcluded = FALSE;
721*c2c66affSColin Finck     }
722*c2c66affSColin Finck 
723*c2c66affSColin Finck     if (IsExcluded)
724*c2c66affSColin Finck     {
725*c2c66affSColin Finck         SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it is in System32/WinSXS.\n",
726*c2c66affSColin Finck                      &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, HookApi->FunctionName);
727*c2c66affSColin Finck     }
728*c2c66affSColin Finck 
729*c2c66affSColin Finck     return IsExcluded;
730*c2c66affSColin Finck }
731*c2c66affSColin Finck 
732*c2c66affSColin Finck VOID SeiAppendInExclude(PARRAY dest, PCWSTR ModuleName, BOOL IsInclude)
733*c2c66affSColin Finck {
734*c2c66affSColin Finck     PINEXCLUDE InExclude;
735*c2c66affSColin Finck     UNICODE_STRING ModuleNameU;
736*c2c66affSColin Finck     RtlInitUnicodeString(&ModuleNameU, ModuleName);
737*c2c66affSColin Finck 
738*c2c66affSColin Finck     InExclude = SeiFindInExclude(dest, &ModuleNameU);
739*c2c66affSColin Finck     if (InExclude)
740*c2c66affSColin Finck     {
741*c2c66affSColin Finck         InExclude->Include = IsInclude;
742*c2c66affSColin Finck         return;
743*c2c66affSColin Finck     }
744*c2c66affSColin Finck 
745*c2c66affSColin Finck     InExclude = ARRAY_Append(dest, INEXCLUDE);
746*c2c66affSColin Finck     if (InExclude)
747*c2c66affSColin Finck     {
748*c2c66affSColin Finck         PCWSTR ModuleNameCopy = SdbpStrDup(ModuleName);
749*c2c66affSColin Finck         RtlInitUnicodeString(&InExclude->Module, ModuleNameCopy);
750*c2c66affSColin Finck         InExclude->Include = IsInclude;
751*c2c66affSColin Finck     }
752*c2c66affSColin Finck }
753*c2c66affSColin Finck 
754*c2c66affSColin Finck /* Read the INEXCLUD tags from a given parent tag */
755*c2c66affSColin Finck VOID SeiReadInExclude(PDB pdb, TAGID parent, PARRAY dest)
756*c2c66affSColin Finck {
757*c2c66affSColin Finck     TAGID InExcludeTag;
758*c2c66affSColin Finck 
759*c2c66affSColin Finck     InExcludeTag = SdbFindFirstTag(pdb, parent, TAG_INEXCLUD);
760*c2c66affSColin Finck 
761*c2c66affSColin Finck     while (InExcludeTag != TAGID_NULL)
762*c2c66affSColin Finck     {
763*c2c66affSColin Finck         PCWSTR ModuleName;
764*c2c66affSColin Finck         TAGID ModuleTag = SdbFindFirstTag(pdb, InExcludeTag, TAG_MODULE);
765*c2c66affSColin Finck         TAGID IncludeTag = SdbFindFirstTag(pdb, InExcludeTag, TAG_INCLUDE);
766*c2c66affSColin Finck 
767*c2c66affSColin Finck         ModuleName = SdbGetStringTagPtr(pdb, ModuleTag);
768*c2c66affSColin Finck         if (ModuleName)
769*c2c66affSColin Finck         {
770*c2c66affSColin Finck             SeiAppendInExclude(dest, ModuleName, IncludeTag != TAGID_NULL);
771*c2c66affSColin Finck         }
772*c2c66affSColin Finck         else
773*c2c66affSColin Finck         {
774*c2c66affSColin Finck             SHIMENG_WARN("INEXCLUDE without Module: 0x%x\n", InExcludeTag);
775*c2c66affSColin Finck         }
776*c2c66affSColin Finck 
777*c2c66affSColin Finck         InExcludeTag = SdbFindNextTag(pdb, parent, InExcludeTag);
778*c2c66affSColin Finck     }
779*c2c66affSColin Finck }
780*c2c66affSColin Finck 
781*c2c66affSColin Finck VOID SeiBuildGlobalInclExclList(HSDB hsdb)
782*c2c66affSColin Finck {
783*c2c66affSColin Finck     PDB pdb;
784*c2c66affSColin Finck     TAGREF tr = TAGREF_ROOT;
785*c2c66affSColin Finck     TAGID root, db, library;
786*c2c66affSColin Finck 
787*c2c66affSColin Finck     if (!SdbTagRefToTagID(hsdb, tr, &pdb, &root))
788*c2c66affSColin Finck     {
789*c2c66affSColin Finck         SHIMENG_WARN("Unable to resolve database root\n");
790*c2c66affSColin Finck         return;
791*c2c66affSColin Finck     }
792*c2c66affSColin Finck     db = SdbFindFirstTag(pdb, root, TAG_DATABASE);
793*c2c66affSColin Finck     if (db == TAGID_NULL)
794*c2c66affSColin Finck     {
795*c2c66affSColin Finck         SHIMENG_WARN("Unable to resolve database\n");
796*c2c66affSColin Finck         return;
797*c2c66affSColin Finck     }
798*c2c66affSColin Finck     library = SdbFindFirstTag(pdb, db, TAG_LIBRARY);
799*c2c66affSColin Finck     if (library == TAGID_NULL)
800*c2c66affSColin Finck     {
801*c2c66affSColin Finck         SHIMENG_WARN("Unable to resolve library\n");
802*c2c66affSColin Finck         return;
803*c2c66affSColin Finck     }
804*c2c66affSColin Finck 
805*c2c66affSColin Finck     SeiReadInExclude(pdb, library, &g_InExclude);
806*c2c66affSColin Finck }
807*c2c66affSColin Finck 
808*c2c66affSColin Finck VOID SeiBuildInclExclList(PDB pdb, TAGID ShimTag, PSHIMINFO pShimInfo)
809*c2c66affSColin Finck {
810*c2c66affSColin Finck     DWORD n;
811*c2c66affSColin Finck 
812*c2c66affSColin Finck     /* First duplicate the global in/excludes */
813*c2c66affSColin Finck     for (n = 0; n < ARRAY_Size(&g_InExclude); ++n)
814*c2c66affSColin Finck     {
815*c2c66affSColin Finck         PINEXCLUDE InEx = ARRAY_At(&g_InExclude, INEXCLUDE, n);
816*c2c66affSColin Finck         SeiAppendInExclude(&pShimInfo->InExclude, InEx->Module.Buffer, InEx->Include);
817*c2c66affSColin Finck     }
818*c2c66affSColin Finck 
819*c2c66affSColin Finck     /* Now read this shim's in/excludes (possibly overriding the global ones) */
820*c2c66affSColin Finck     SeiReadInExclude(pdb, ShimTag, &pShimInfo->InExclude);
821*c2c66affSColin Finck }
822*c2c66affSColin Finck 
823*c2c66affSColin Finck /* Given one loaded module, redirect (hook) all functions from the iat that are registered by shims */
824*c2c66affSColin Finck VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
825*c2c66affSColin Finck {
826*c2c66affSColin Finck     ULONG Size;
827*c2c66affSColin Finck     PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
828*c2c66affSColin Finck     PBYTE DllBase = LdrEntry->DllBase;
829*c2c66affSColin Finck 
830*c2c66affSColin Finck     if (SE_IsShimDll(DllBase) || g_hInstance == LdrEntry->DllBase)
831*c2c66affSColin Finck     {
832*c2c66affSColin Finck         SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
833*c2c66affSColin Finck         return;
834*c2c66affSColin Finck     }
835*c2c66affSColin Finck 
836*c2c66affSColin Finck     ImportDescriptor = RtlImageDirectoryEntryToData(DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size);
837*c2c66affSColin Finck     if (!ImportDescriptor)
838*c2c66affSColin Finck     {
839*c2c66affSColin Finck         SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
840*c2c66affSColin Finck         return;
841*c2c66affSColin Finck     }
842*c2c66affSColin Finck 
843*c2c66affSColin Finck     SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
844*c2c66affSColin Finck 
845*c2c66affSColin Finck     for ( ;ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk; ImportDescriptor++)
846*c2c66affSColin Finck     {
847*c2c66affSColin Finck         PHOOKMODULEINFO HookModuleInfo;
848*c2c66affSColin Finck 
849*c2c66affSColin Finck         /* Do we have hooks for this module? */
850*c2c66affSColin Finck         HookModuleInfo = SeiFindHookModuleInfoForImportDescriptor(DllBase, ImportDescriptor);
851*c2c66affSColin Finck 
852*c2c66affSColin Finck         if (HookModuleInfo)
853*c2c66affSColin Finck         {
854*c2c66affSColin Finck             PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
855*c2c66affSColin Finck             DWORD n;
856*c2c66affSColin Finck 
857*c2c66affSColin Finck             for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n)
858*c2c66affSColin Finck             {
859*c2c66affSColin Finck                 DWORD dwFound = 0;
860*c2c66affSColin Finck                 PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n);
861*c2c66affSColin Finck 
862*c2c66affSColin Finck                 /* Check if this module should be excluded from being hooked (system32/winsxs, global or shim exclude) */
863*c2c66affSColin Finck                 if (SeiIsExcluded(LdrEntry, HookApi))
864*c2c66affSColin Finck                 {
865*c2c66affSColin Finck                     continue;
866*c2c66affSColin Finck                 }
867*c2c66affSColin Finck 
868*c2c66affSColin Finck                 OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk);
869*c2c66affSColin Finck                 FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk);
870*c2c66affSColin Finck 
871*c2c66affSColin Finck                 /* Walk all imports */
872*c2c66affSColin Finck                 for (;OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function; OriginalThunk++, FirstThunk++)
873*c2c66affSColin Finck                 {
874*c2c66affSColin Finck                     if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData))
875*c2c66affSColin Finck                     {
876*c2c66affSColin Finck                         PIMAGE_IMPORT_BY_NAME ImportName;
877*c2c66affSColin Finck 
878*c2c66affSColin Finck                         ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData);
879*c2c66affSColin Finck                         if (!strcmp((PCSTR)ImportName->Name, HookApi->FunctionName))
880*c2c66affSColin Finck                         {
881*c2c66affSColin Finck                             SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
882*c2c66affSColin Finck 
883*c2c66affSColin Finck                             /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
884*c2c66affSColin Finck                             dwFound++;
885*c2c66affSColin Finck                         }
886*c2c66affSColin Finck                     }
887*c2c66affSColin Finck                     else
888*c2c66affSColin Finck                     {
889*c2c66affSColin Finck                         SHIMENG_FAIL("Ordinals not yet supported\n");
890*c2c66affSColin Finck                         ASSERT(0);
891*c2c66affSColin Finck                     }
892*c2c66affSColin Finck                 }
893*c2c66affSColin Finck 
894*c2c66affSColin Finck                 if (dwFound != 1)
895*c2c66affSColin Finck                 {
896*c2c66affSColin Finck                     /* One entry not found. */
897*c2c66affSColin Finck                     if (!dwFound)
898*c2c66affSColin Finck                         SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName);
899*c2c66affSColin Finck                     else
900*c2c66affSColin Finck                         SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, dwFound, &LdrEntry->BaseDllName);
901*c2c66affSColin Finck                 }
902*c2c66affSColin Finck             }
903*c2c66affSColin Finck         }
904*c2c66affSColin Finck     }
905*c2c66affSColin Finck }
906*c2c66affSColin Finck 
907*c2c66affSColin Finck 
908*c2c66affSColin Finck VOID PatchNewModules(PPEB Peb)
909*c2c66affSColin Finck {
910*c2c66affSColin Finck     PLIST_ENTRY ListHead, ListEntry;
911*c2c66affSColin Finck     PLDR_DATA_TABLE_ENTRY LdrEntry;
912*c2c66affSColin Finck 
913*c2c66affSColin Finck     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
914*c2c66affSColin Finck     ListEntry = ListHead->Flink;
915*c2c66affSColin Finck 
916*c2c66affSColin Finck     while (ListHead != ListEntry)
917*c2c66affSColin Finck     {
918*c2c66affSColin Finck         LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
919*c2c66affSColin Finck         SeiHookImports(LdrEntry);
920*c2c66affSColin Finck 
921*c2c66affSColin Finck         ListEntry = ListEntry->Flink;
922*c2c66affSColin Finck     }
923*c2c66affSColin Finck }
924*c2c66affSColin Finck 
925*c2c66affSColin Finck 
926*c2c66affSColin Finck VOID SeiInitPaths(VOID)
927*c2c66affSColin Finck {
928*c2c66affSColin Finck #define SYSTEM32  L"\\system32"
929*c2c66affSColin Finck #define WINSXS  L"\\winsxs"
930*c2c66affSColin Finck 
931*c2c66affSColin Finck     PWSTR WindowsDirectory = SdbpStrDup(SharedUserData->NtSystemRoot);
932*c2c66affSColin Finck     RtlInitUnicodeString(&g_WindowsDirectory, WindowsDirectory);
933*c2c66affSColin Finck 
934*c2c66affSColin Finck     g_System32Directory.MaximumLength = g_WindowsDirectory.Length + SdbpStrsize(SYSTEM32);
935*c2c66affSColin Finck     g_System32Directory.Buffer = SdbpAlloc(g_System32Directory.MaximumLength);
936*c2c66affSColin Finck     RtlCopyUnicodeString(&g_System32Directory, &g_WindowsDirectory);
937*c2c66affSColin Finck     RtlAppendUnicodeToString(&g_System32Directory, SYSTEM32);
938*c2c66affSColin Finck 
939*c2c66affSColin Finck     g_SxsDirectory.MaximumLength = g_WindowsDirectory.Length + SdbpStrsize(WINSXS);
940*c2c66affSColin Finck     g_SxsDirectory.Buffer = SdbpAlloc(g_SxsDirectory.MaximumLength);
941*c2c66affSColin Finck     RtlCopyUnicodeString(&g_SxsDirectory, &g_WindowsDirectory);
942*c2c66affSColin Finck     RtlAppendUnicodeToString(&g_SxsDirectory, WINSXS);
943*c2c66affSColin Finck 
944*c2c66affSColin Finck #undef SYSTEM32
945*c2c66affSColin Finck #undef WINSXS
946*c2c66affSColin Finck }
947*c2c66affSColin Finck 
948*c2c66affSColin Finck /*
949*c2c66affSColin Finck Level(INFO) Using USER apphack flags 0x2080000
950*c2c66affSColin Finck */
951*c2c66affSColin Finck 
952*c2c66affSColin Finck VOID SeiInit(PUNICODE_STRING ProcessImage, HSDB hsdb, SDBQUERYRESULT* pQuery)
953*c2c66affSColin Finck {
954*c2c66affSColin Finck     DWORD n;
955*c2c66affSColin Finck     ARRAY ShimRefArray;
956*c2c66affSColin Finck     DWORD dwTotalHooks = 0;
957*c2c66affSColin Finck 
958*c2c66affSColin Finck     PPEB Peb = NtCurrentPeb();
959*c2c66affSColin Finck 
960*c2c66affSColin Finck     /* We should only be called once! */
961*c2c66affSColin Finck     ASSERT(g_pShimInfo.ItemSize__ == 0);
962*c2c66affSColin Finck 
963*c2c66affSColin Finck     ARRAY_Init(&ShimRefArray, TAGREF);
964*c2c66affSColin Finck     ARRAY_Init(&g_pShimInfo, PSHIMMODULE);
965*c2c66affSColin Finck     ARRAY_Init(&g_pHookArray, HOOKMODULEINFO);
966*c2c66affSColin Finck     ARRAY_Init(&g_InExclude, INEXCLUDE);
967*c2c66affSColin Finck 
968*c2c66affSColin Finck     SeiInitPaths();
969*c2c66affSColin Finck 
970*c2c66affSColin Finck     SeiCheckComPlusImage(Peb->ImageBaseAddress);
971*c2c66affSColin Finck 
972*c2c66affSColin Finck     /* TODO:
973*c2c66affSColin Finck     if (pQuery->trApphelp)
974*c2c66affSColin Finck         SeiDisplayAppHelp(?pQuery->trApphelp?);
975*c2c66affSColin Finck     */
976*c2c66affSColin Finck 
977*c2c66affSColin Finck     SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(ExePath(%wZ))\n", ProcessImage);
978*c2c66affSColin Finck     SeiBuildShimRefArray(hsdb, pQuery, &ShimRefArray);
979*c2c66affSColin Finck     SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Complete)\n");
980*c2c66affSColin Finck 
981*c2c66affSColin Finck     SHIMENG_INFO("Got %d shims\n", ARRAY_Size(&ShimRefArray));
982*c2c66affSColin Finck     SeiBuildGlobalInclExclList(hsdb);
983*c2c66affSColin Finck 
984*c2c66affSColin Finck     /* Walk all shims referenced (in layers + exes), and load their modules */
985*c2c66affSColin Finck     for (n = 0; n < ARRAY_Size(&ShimRefArray); ++n)
986*c2c66affSColin Finck     {
987*c2c66affSColin Finck         PDB pdb;
988*c2c66affSColin Finck         TAGID ShimRef;
989*c2c66affSColin Finck 
990*c2c66affSColin Finck         TAGREF tr = *ARRAY_At(&ShimRefArray, TAGREF, n);
991*c2c66affSColin Finck 
992*c2c66affSColin Finck         if (SdbTagRefToTagID(hsdb, tr, &pdb, &ShimRef))
993*c2c66affSColin Finck         {
994*c2c66affSColin Finck             LPCWSTR ShimName, DllName, CommandLine = NULL;
995*c2c66affSColin Finck             TAGID ShimTag;
996*c2c66affSColin Finck             WCHAR FullNameBuffer[MAX_PATH];
997*c2c66affSColin Finck             UNICODE_STRING UnicodeDllName;
998*c2c66affSColin Finck             PVOID BaseAddress;
999*c2c66affSColin Finck             PSHIMMODULE pShimModuleInfo = NULL;
1000*c2c66affSColin Finck             ANSI_STRING AnsiCommandLine = RTL_CONSTANT_STRING("");
1001*c2c66affSColin Finck             PSHIMINFO pShimInfo = NULL;
1002*c2c66affSColin Finck             PHOOKAPIEX pHookApi;
1003*c2c66affSColin Finck             DWORD dwHookCount;
1004*c2c66affSColin Finck 
1005*c2c66affSColin Finck             ShimName = SeiGetStringPtr(pdb, ShimRef, TAG_NAME);
1006*c2c66affSColin Finck             if (!ShimName)
1007*c2c66affSColin Finck             {
1008*c2c66affSColin Finck                 SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", tr);
1009*c2c66affSColin Finck                 continue;
1010*c2c66affSColin Finck             }
1011*c2c66affSColin Finck 
1012*c2c66affSColin Finck             CommandLine = SeiGetStringPtr(pdb, ShimRef, TAG_COMMAND_LINE);
1013*c2c66affSColin Finck             if (CommandLine && *CommandLine)
1014*c2c66affSColin Finck             {
1015*c2c66affSColin Finck                 RtlInitUnicodeString(&UnicodeDllName, CommandLine);
1016*c2c66affSColin Finck                 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiCommandLine, &UnicodeDllName, TRUE)))
1017*c2c66affSColin Finck                 {
1018*c2c66affSColin Finck                     SHIMENG_INFO("COMMAND LINE %s for %S", AnsiCommandLine.Buffer, ShimName);
1019*c2c66affSColin Finck                 }
1020*c2c66affSColin Finck                 else
1021*c2c66affSColin Finck                 {
1022*c2c66affSColin Finck                     AnsiCommandLine.Buffer = "";
1023*c2c66affSColin Finck                     CommandLine = NULL;
1024*c2c66affSColin Finck                 }
1025*c2c66affSColin Finck             }
1026*c2c66affSColin Finck 
1027*c2c66affSColin Finck             ShimTag = SeiGetDWORD(pdb, ShimRef, TAG_SHIM_TAGID);
1028*c2c66affSColin Finck             if (!ShimTag)
1029*c2c66affSColin Finck             {
1030*c2c66affSColin Finck                 SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName);
1031*c2c66affSColin Finck                 continue;
1032*c2c66affSColin Finck             }
1033*c2c66affSColin Finck 
1034*c2c66affSColin Finck             if (!SdbGetAppPatchDir(NULL, FullNameBuffer, ARRAYSIZE(FullNameBuffer)))
1035*c2c66affSColin Finck             {
1036*c2c66affSColin Finck                 SHIMENG_WARN("Failed to get the AppPatch dir\n");
1037*c2c66affSColin Finck                 continue;
1038*c2c66affSColin Finck             }
1039*c2c66affSColin Finck 
1040*c2c66affSColin Finck             DllName = SeiGetStringPtr(pdb, ShimTag, TAG_DLLFILE);
1041*c2c66affSColin Finck             if (DllName == NULL ||
1042*c2c66affSColin Finck                 !SUCCEEDED(StringCchCatW(FullNameBuffer, ARRAYSIZE(FullNameBuffer), L"\\")) ||
1043*c2c66affSColin Finck                 !SUCCEEDED(StringCchCatW(FullNameBuffer, ARRAYSIZE(FullNameBuffer), DllName)))
1044*c2c66affSColin Finck             {
1045*c2c66affSColin Finck                 SHIMENG_WARN("Failed to build a full path for %S\n", ShimName);
1046*c2c66affSColin Finck                 continue;
1047*c2c66affSColin Finck             }
1048*c2c66affSColin Finck 
1049*c2c66affSColin Finck             RtlInitUnicodeString(&UnicodeDllName, FullNameBuffer);
1050*c2c66affSColin Finck             if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &UnicodeDllName, &BaseAddress)))
1051*c2c66affSColin Finck             {
1052*c2c66affSColin Finck                 /* This shim dll was already loaded, let's find it */
1053*c2c66affSColin Finck                 pShimModuleInfo = SeiGetShimModuleInfo(BaseAddress);
1054*c2c66affSColin Finck             }
1055*c2c66affSColin Finck             else if (!NT_SUCCESS(LdrLoadDll(NULL, NULL, &UnicodeDllName, &BaseAddress)))
1056*c2c66affSColin Finck             {
1057*c2c66affSColin Finck                 SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName, ShimName);
1058*c2c66affSColin Finck                 continue;
1059*c2c66affSColin Finck             }
1060*c2c66affSColin Finck             /* No shim module found (or we just loaded it) */
1061*c2c66affSColin Finck             if (!pShimModuleInfo)
1062*c2c66affSColin Finck             {
1063*c2c66affSColin Finck                 pShimModuleInfo = SeiCreateShimModuleInfo(DllName, BaseAddress);
1064*c2c66affSColin Finck                 if (!pShimModuleInfo)
1065*c2c66affSColin Finck                 {
1066*c2c66affSColin Finck                     SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName);
1067*c2c66affSColin Finck                     continue;
1068*c2c66affSColin Finck                 }
1069*c2c66affSColin Finck             }
1070*c2c66affSColin Finck 
1071*c2c66affSColin Finck             SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress, &UnicodeDllName);
1072*c2c66affSColin Finck             SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName, ShimName);
1073*c2c66affSColin Finck 
1074*c2c66affSColin Finck             /* Ask this shim what hooks it needs (and pass along the commandline) */
1075*c2c66affSColin Finck             pHookApi = pShimModuleInfo->pGetHookAPIs(AnsiCommandLine.Buffer, ShimName, &dwHookCount);
1076*c2c66affSColin Finck             SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount, &UnicodeDllName, ShimName);
1077*c2c66affSColin Finck             if (dwHookCount)
1078*c2c66affSColin Finck                 pShimInfo = SeiAppendHookInfo(pShimModuleInfo, pHookApi, dwHookCount, ShimName);
1079*c2c66affSColin Finck 
1080*c2c66affSColin Finck             /* If this shim has hooks, create the include / exclude lists */
1081*c2c66affSColin Finck             if (pShimInfo)
1082*c2c66affSColin Finck                 SeiBuildInclExclList(pdb, ShimTag, pShimInfo);
1083*c2c66affSColin Finck 
1084*c2c66affSColin Finck             if (CommandLine && *CommandLine)
1085*c2c66affSColin Finck                 RtlFreeAnsiString(&AnsiCommandLine);
1086*c2c66affSColin Finck 
1087*c2c66affSColin Finck             dwTotalHooks += dwHookCount;
1088*c2c66affSColin Finck         }
1089*c2c66affSColin Finck     }
1090*c2c66affSColin Finck 
1091*c2c66affSColin Finck     SeiAddInternalHooks(dwTotalHooks);
1092*c2c66affSColin Finck     SeiResolveAPIs();
1093*c2c66affSColin Finck     PatchNewModules(Peb);
1094*c2c66affSColin Finck }
1095*c2c66affSColin Finck 
1096*c2c66affSColin Finck 
1097*c2c66affSColin Finck /* Load the database + unpack the shim data (if this process is allowed) */
1098*c2c66affSColin Finck BOOL SeiGetShimData(PUNICODE_STRING ProcessImage, PVOID pShimData, HSDB* pHsdb, SDBQUERYRESULT* pQuery)
1099*c2c66affSColin Finck {
1100*c2c66affSColin Finck     static const UNICODE_STRING ForbiddenShimmingApps[] = {
1101*c2c66affSColin Finck         RTL_CONSTANT_STRING(L"ntsd.exe"),
1102*c2c66affSColin Finck         RTL_CONSTANT_STRING(L"windbg.exe"),
1103*c2c66affSColin Finck #if WINVER >= 0x600
1104*c2c66affSColin Finck         RTL_CONSTANT_STRING(L"slsvc.exe"),
1105*c2c66affSColin Finck #endif
1106*c2c66affSColin Finck     };
1107*c2c66affSColin Finck     static const UNICODE_STRING BackSlash = RTL_CONSTANT_STRING(L"\\");
1108*c2c66affSColin Finck     static const UNICODE_STRING ForwdSlash = RTL_CONSTANT_STRING(L"/");
1109*c2c66affSColin Finck     UNICODE_STRING ProcessName;
1110*c2c66affSColin Finck     USHORT Back, Forward;
1111*c2c66affSColin Finck     HSDB hsdb;
1112*c2c66affSColin Finck     DWORD n;
1113*c2c66affSColin Finck 
1114*c2c66affSColin Finck     if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &BackSlash, &Back)))
1115*c2c66affSColin Finck         Back = 0;
1116*c2c66affSColin Finck 
1117*c2c66affSColin Finck     if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &ForwdSlash, &Forward)))
1118*c2c66affSColin Finck         Forward = 0;
1119*c2c66affSColin Finck 
1120*c2c66affSColin Finck     if (Back < Forward)
1121*c2c66affSColin Finck         Back = Forward;
1122*c2c66affSColin Finck 
1123*c2c66affSColin Finck     if (Back)
1124*c2c66affSColin Finck         Back += sizeof(WCHAR);
1125*c2c66affSColin Finck 
1126*c2c66affSColin Finck     ProcessName.Buffer = ProcessImage->Buffer + Back / sizeof(WCHAR);
1127*c2c66affSColin Finck     ProcessName.Length = ProcessImage->Length - Back;
1128*c2c66affSColin Finck     ProcessName.MaximumLength = ProcessImage->MaximumLength - Back;
1129*c2c66affSColin Finck 
1130*c2c66affSColin Finck     for (n = 0; n < ARRAYSIZE(ForbiddenShimmingApps); ++n)
1131*c2c66affSColin Finck     {
1132*c2c66affSColin Finck         if (RtlEqualUnicodeString(&ProcessName, ForbiddenShimmingApps + n, TRUE))
1133*c2c66affSColin Finck         {
1134*c2c66affSColin Finck             SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps + n);
1135*c2c66affSColin Finck             return FALSE;
1136*c2c66affSColin Finck         }
1137*c2c66affSColin Finck     }
1138*c2c66affSColin Finck 
1139*c2c66affSColin Finck     /* We should probably load all db's here, but since we do not support that yet... */
1140*c2c66affSColin Finck     hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
1141*c2c66affSColin Finck     if (hsdb)
1142*c2c66affSColin Finck     {
1143*c2c66affSColin Finck         if (SdbUnpackAppCompatData(hsdb, ProcessImage->Buffer, pShimData, pQuery))
1144*c2c66affSColin Finck         {
1145*c2c66affSColin Finck             *pHsdb = hsdb;
1146*c2c66affSColin Finck             return TRUE;
1147*c2c66affSColin Finck         }
1148*c2c66affSColin Finck         SdbReleaseDatabase(hsdb);
1149*c2c66affSColin Finck     }
1150*c2c66affSColin Finck     return FALSE;
1151*c2c66affSColin Finck }
1152*c2c66affSColin Finck 
1153*c2c66affSColin Finck 
1154*c2c66affSColin Finck 
1155*c2c66affSColin Finck VOID NTAPI SE_InstallBeforeInit(PUNICODE_STRING ProcessImage, PVOID pShimData)
1156*c2c66affSColin Finck {
1157*c2c66affSColin Finck     HSDB hsdb = NULL;
1158*c2c66affSColin Finck     SDBQUERYRESULT QueryResult = { { 0 } };
1159*c2c66affSColin Finck     SHIMENG_MSG("(%wZ, %p)\n", ProcessImage, pShimData);
1160*c2c66affSColin Finck 
1161*c2c66affSColin Finck     if (!SeiGetShimData(ProcessImage, pShimData, &hsdb, &QueryResult))
1162*c2c66affSColin Finck     {
1163*c2c66affSColin Finck         SHIMENG_FAIL("Failed to get shim data\n");
1164*c2c66affSColin Finck         return;
1165*c2c66affSColin Finck     }
1166*c2c66affSColin Finck 
1167*c2c66affSColin Finck     g_bShimDuringInit = TRUE;
1168*c2c66affSColin Finck     SeiInit(ProcessImage, hsdb, &QueryResult);
1169*c2c66affSColin Finck     g_bShimDuringInit = FALSE;
1170*c2c66affSColin Finck 
1171*c2c66affSColin Finck     SdbReleaseDatabase(hsdb);
1172*c2c66affSColin Finck }
1173*c2c66affSColin Finck 
1174*c2c66affSColin Finck VOID NTAPI SE_InstallAfterInit(PUNICODE_STRING ProcessImage, PVOID pShimData)
1175*c2c66affSColin Finck {
1176*c2c66affSColin Finck     NotifyShims(SHIM_NOTIFY_ATTACH, NULL);
1177*c2c66affSColin Finck }
1178*c2c66affSColin Finck 
1179*c2c66affSColin Finck VOID NTAPI SE_ProcessDying(VOID)
1180*c2c66affSColin Finck {
1181*c2c66affSColin Finck     SHIMENG_MSG("()\n");
1182*c2c66affSColin Finck     NotifyShims(SHIM_NOTIFY_DETACH, NULL);
1183*c2c66affSColin Finck }
1184*c2c66affSColin Finck 
1185*c2c66affSColin Finck VOID WINAPI SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry)
1186*c2c66affSColin Finck {
1187*c2c66affSColin Finck     SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit ? "" : "AFTER ", &LdrEntry->BaseDllName);
1188*c2c66affSColin Finck     NotifyShims(SHIM_REASON_DLL_LOAD, LdrEntry);
1189*c2c66affSColin Finck }
1190*c2c66affSColin Finck 
1191*c2c66affSColin Finck VOID WINAPI SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry)
1192*c2c66affSColin Finck {
1193*c2c66affSColin Finck     SHIMENG_INFO("(%p)\n", LdrEntry);
1194*c2c66affSColin Finck     NotifyShims(SHIM_REASON_DLL_UNLOAD, LdrEntry);
1195*c2c66affSColin Finck }
1196*c2c66affSColin Finck 
1197*c2c66affSColin Finck BOOL WINAPI SE_IsShimDll(PVOID BaseAddress)
1198*c2c66affSColin Finck {
1199*c2c66affSColin Finck     SHIMENG_INFO("(%p)\n", BaseAddress);
1200*c2c66affSColin Finck 
1201*c2c66affSColin Finck     return SeiGetShimModuleInfo(BaseAddress) != NULL;
1202*c2c66affSColin Finck }
1203*c2c66affSColin Finck 
1204