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