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