2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Shim engine core
5 * COPYRIGHT: Copyright 2015-2019 Mark Jansen (mark.jansen@reactos.org)
8 #define WIN32_NO_STATUS
13 /* Make sure we don't include apphelp logging */
14 #define APPHELP_NOSDBPAPI
20 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
);
21 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
);
23 static const UNICODE_STRING Ntdll
= RTL_CONSTANT_STRING(L
"ntdll.dll");
24 static const UNICODE_STRING Kernel32
= RTL_CONSTANT_STRING(L
"kernel32.dll");
25 static const UNICODE_STRING Verifier
= RTL_CONSTANT_STRING(L
"verifier.dll");
27 extern HMODULE g_hInstance
;
28 static UNICODE_STRING g_WindowsDirectory
;
29 static UNICODE_STRING g_System32Directory
;
30 static UNICODE_STRING g_SxsDirectory
;
31 static UNICODE_STRING g_LoadingShimDll
;
32 ULONG g_ShimEngDebugLevel
= 0xffffffff;
33 BOOL g_bComPlusImage
= FALSE
;
34 BOOL g_bShimDuringInit
= FALSE
;
35 BOOL g_bInternalHooksUsed
= FALSE
;
36 static ARRAY g_pShimInfo
; /* PSHIMMODULE */
37 static ARRAY g_pHookArray
; /* HOOKMODULEINFO */
38 static ARRAY g_InExclude
; /* INEXCLUDE */
40 /* If we have setup a hook for a function, we should also redirect GetProcAddress for this function */
41 HOOKAPIEX g_IntHookEx
[] =
44 "kernel32.dll", /* LibraryName */
45 "GetProcAddress", /* FunctionName */
46 StubGetProcAddress
, /* ReplacementFunction*/
47 NULL
, /* OriginalFunction */
53 static inline BOOL
ARRAY_InitWorker(PARRAY Array
, DWORD ItemSize
)
56 Array
->Size__
= Array
->MaxSize__
= 0;
57 Array
->ItemSize__
= ItemSize
;
62 static inline BOOL
ARRAY_EnsureSize(PARRAY Array
, DWORD ItemSize
, DWORD GrowWith
)
68 ASSERT(ItemSize
== Array
->ItemSize__
);
70 if (Array
->MaxSize__
> Array
->Size__
)
73 Count
= Array
->Size__
+ GrowWith
;
74 pNewData
= SeiAlloc(Count
* ItemSize
);
78 SHIMENG_FAIL("Failed to allocate %d bytes\n", Count
* ItemSize
);
81 Array
->MaxSize__
= Count
;
85 memcpy(pNewData
, Array
->Data__
, Array
->Size__
* ItemSize
);
86 SeiFree(Array
->Data__
);
88 Array
->Data__
= pNewData
;
93 static inline PVOID
ARRAY_AppendWorker(PARRAY Array
, DWORD ItemSize
, DWORD GrowWith
)
97 if (!ARRAY_EnsureSize(Array
, ItemSize
, GrowWith
))
100 pData
= Array
->Data__
;
101 pData
+= (Array
->Size__
* ItemSize
);
107 static inline PVOID
ARRAY_AtWorker(PARRAY Array
, DWORD ItemSize
, DWORD n
)
112 ASSERT(ItemSize
== Array
->ItemSize__
);
113 ASSERT(n
< Array
->Size__
);
115 pData
= Array
->Data__
;
116 return pData
+ (n
* ItemSize
);
120 #define ARRAY_Init(Array, TypeOfArray) ARRAY_InitWorker((Array), sizeof(TypeOfArray))
121 #define ARRAY_Append(Array, TypeOfArray) (TypeOfArray*)ARRAY_AppendWorker((Array), sizeof(TypeOfArray), 5)
122 #define ARRAY_At(Array, TypeOfArray, at) (TypeOfArray*)ARRAY_AtWorker((Array), sizeof(TypeOfArray), at)
123 #define ARRAY_Size(Array) (Array)->Size__
126 VOID
SeiInitDebugSupport(VOID
)
128 static const UNICODE_STRING DebugKey
= RTL_CONSTANT_STRING(L
"SHIMENG_DEBUG_LEVEL");
129 UNICODE_STRING DebugValue
;
131 ULONG NewLevel
= SEI_MSG
; /* Show some basic info in the logs, unless configured different */
134 RtlInitEmptyUnicodeString(&DebugValue
, Buffer
, sizeof(Buffer
));
136 Status
= RtlQueryEnvironmentVariable_U(NULL
, &DebugKey
, &DebugValue
);
138 if (NT_SUCCESS(Status
))
140 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue
, 10, &NewLevel
)))
143 g_ShimEngDebugLevel
= NewLevel
;
148 * Outputs diagnostic info.
150 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
151 * SHIM_WARN, SHIM_INFO].
152 * @param [in] FunctionName The function this log should be attributed to.
153 * @param [in] Format The format string.
154 * @param ... Variable arguments providing additional information.
156 * @return Success: TRUE Failure: FALSE.
158 BOOL WINAPIV
SeiDbgPrint(SEI_LOG_LEVEL Level
, PCSTR Function
, PCSTR Format
, ...)
161 char* Current
= Buffer
;
162 const char* LevelStr
;
163 size_t Length
= sizeof(Buffer
);
167 if (g_ShimEngDebugLevel
== 0xffffffff)
168 SeiInitDebugSupport();
170 if (Level
> g_ShimEngDebugLevel
)
193 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] [%s] ", LevelStr
, Function
);
195 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] ", LevelStr
);
200 va_start(ArgList
, Format
);
201 hr
= StringCchVPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, Format
, ArgList
);
206 DbgPrint("%s", Buffer
);
211 PVOID
SeiGetModuleFromAddress(PVOID addr
)
213 PVOID hModule
= NULL
;
214 RtlPcToFileHeader(addr
, &hModule
);
220 /* TODO: Guard against recursive calling / calling init multiple times! */
221 VOID
NotifyShims(DWORD dwReason
, PVOID Info
)
225 for (n
= 0; n
< ARRAY_Size(&g_pShimInfo
); ++n
)
227 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, n
);
228 if (!pShimModule
->pNotifyShims
)
231 pShimModule
->pNotifyShims(dwReason
, Info
);
237 VOID
SeiCheckComPlusImage(PVOID BaseAddress
)
239 ULONG ComSectionSize
;
240 g_bComPlusImage
= RtlImageDirectoryEntryToData(BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
, &ComSectionSize
) != NULL
;
242 SHIMENG_INFO("COM+ executable %s\n", g_bComPlusImage
? "TRUE" : "FALSE");
246 PSHIMMODULE
SeiGetShimModuleInfo(PVOID BaseAddress
)
250 for (n
= 0; n
< ARRAY_Size(&g_pShimInfo
); ++n
)
252 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, n
);
254 if (pShimModule
->BaseAddress
== BaseAddress
)
260 PSHIMMODULE
SeiCreateShimModuleInfo(PCWSTR DllName
, PVOID BaseAddress
)
262 static const ANSI_STRING GetHookAPIs
= RTL_CONSTANT_STRING("GetHookAPIs");
263 static const ANSI_STRING NotifyShims
= RTL_CONSTANT_STRING("NotifyShims");
264 PSHIMMODULE
* pData
, Data
;
265 PVOID pGetHookAPIs
, pNotifyShims
;
267 if (!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress
, (PANSI_STRING
)&GetHookAPIs
, 0, &pGetHookAPIs
)) ||
268 !NT_SUCCESS(LdrGetProcedureAddress(BaseAddress
, (PANSI_STRING
)&NotifyShims
, 0, &pNotifyShims
)))
270 SHIMENG_WARN("Failed to resolve entry points for %S\n", DllName
);
274 pData
= ARRAY_Append(&g_pShimInfo
, PSHIMMODULE
);
278 *pData
= SeiAlloc(sizeof(SHIMMODULE
));
282 RtlCreateUnicodeString(&Data
->Name
, DllName
);
283 Data
->BaseAddress
= BaseAddress
;
285 Data
->pGetHookAPIs
= pGetHookAPIs
;
286 Data
->pNotifyShims
= pNotifyShims
;
288 ARRAY_Init(&Data
->EnabledShims
, PSHIMINFO
);
293 PSHIMINFO
SeiAppendHookInfo(PSHIMMODULE pShimModuleInfo
, PHOOKAPIEX pHookApi
, DWORD dwHookCount
, PCWSTR ShimName
)
295 PSHIMINFO
* pData
, Data
;
297 pData
= ARRAY_Append(&pShimModuleInfo
->EnabledShims
, PSHIMINFO
);
301 *pData
= SeiAlloc(sizeof(SHIMINFO
));
307 Data
->ShimName
= SdbpStrDup(ShimName
);
311 Data
->pHookApi
= pHookApi
;
312 Data
->dwHookCount
= dwHookCount
;
313 Data
->pShimModule
= pShimModuleInfo
;
314 ARRAY_Init(&Data
->InExclude
, INEXCLUDE
);
318 PHOOKMODULEINFO
SeiFindHookModuleInfo(PUNICODE_STRING ModuleName
, PVOID BaseAddress
)
322 if (ModuleName
== NULL
&& BaseAddress
== NULL
)
324 BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
327 for (n
= 0; n
< ARRAY_Size(&g_pHookArray
); ++n
)
329 PHOOKMODULEINFO pModuleInfo
= ARRAY_At(&g_pHookArray
, HOOKMODULEINFO
, n
);
331 if (BaseAddress
&& BaseAddress
== pModuleInfo
->BaseAddress
)
334 if (!BaseAddress
&& RtlEqualUnicodeString(ModuleName
, &pModuleInfo
->Name
, TRUE
))
341 PHOOKMODULEINFO
SeiFindHookModuleInfoForImportDescriptor(PBYTE DllBase
, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
)
343 UNICODE_STRING DllName
;
347 if (!RtlCreateUnicodeStringFromAsciiz(&DllName
, (PCSZ
)(DllBase
+ ImportDescriptor
->Name
)))
349 SHIMENG_FAIL("Unable to convert dll name to unicode\n");
353 Success
= LdrGetDllHandle(NULL
, NULL
, &DllName
, &DllHandle
);
355 if (!NT_SUCCESS(Success
))
357 SHIMENG_FAIL("Unable to get module handle for %wZ (%p)\n", &DllName
, DllBase
);
358 RtlFreeUnicodeString(&DllName
);
362 RtlFreeUnicodeString(&DllName
);
364 return SeiFindHookModuleInfo(NULL
, DllHandle
);
367 static LPCWSTR
SeiGetStringPtr(PDB pdb
, TAGID tag
, TAG type
)
369 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
370 if (tagEntry
== TAGID_NULL
)
373 return SdbGetStringTagPtr(pdb
, tagEntry
);
376 static DWORD
SeiGetDWORD(PDB pdb
, TAGID tag
, TAG type
)
378 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
379 if (tagEntry
== TAGID_NULL
)
382 return SdbReadDWORDTag(pdb
, tagEntry
, 0);
385 static QWORD
SeiGetQWORD(PDB pdb
, TAGID tag
, TAG type
)
387 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
388 if (tagEntry
== TAGID_NULL
)
391 return SdbReadQWORDTag(pdb
, tagEntry
, 0);
394 static VOID
SeiAddShim(TAGREF trShimRef
, PARRAY pShimRef
)
398 Data
= ARRAY_Append(pShimRef
, TAGREF
);
405 static VOID
SeiAddFlag(PDB pdb
, TAGID tiFlagRef
, PFLAGINFO pFlagInfo
)
409 /* Resolve the FLAG_REF to the real FLAG node */
410 TAGID FlagTag
= SeiGetDWORD(pdb
, tiFlagRef
, TAG_FLAG_TAGID
);
412 if (FlagTag
== TAGID_NULL
)
415 pFlagInfo
->AppCompatFlags
.QuadPart
|= SeiGetQWORD(pdb
, FlagTag
, TAG_FLAG_MASK_KERNEL
);
416 pFlagInfo
->AppCompatFlagsUser
.QuadPart
|= SeiGetQWORD(pdb
, FlagTag
, TAG_FLAG_MASK_USER
);
417 Flag
.QuadPart
= SeiGetQWORD(pdb
, FlagTag
, TAG_FLAG_PROCESSPARAM
);
418 pFlagInfo
->ProcessParameters_Flags
|= Flag
.LowPart
;
421 /* Propagate layers to child processes */
422 static VOID
SeiSetLayerEnvVar(LPCWSTR wszLayer
)
425 UNICODE_STRING VarName
= RTL_CONSTANT_STRING(L
"__COMPAT_LAYER");
426 UNICODE_STRING Value
;
428 RtlInitUnicodeString(&Value
, wszLayer
);
430 Status
= RtlSetEnvironmentVariable(NULL
, &VarName
, &Value
);
431 if (NT_SUCCESS(Status
))
432 SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName
, &Value
);
434 SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName
, Status
);
437 #define MAX_LAYER_LENGTH 256
439 /* Translate all Exe and Layer entries to Shims, and propagate all layers */
440 static VOID
SeiBuildShimRefArray(HSDB hsdb
, SDBQUERYRESULT
* pQuery
, PARRAY pShimRef
, PFLAGINFO pFlagInfo
)
442 WCHAR wszLayerEnvVar
[MAX_LAYER_LENGTH
] = { 0 };
445 for (n
= 0; n
< pQuery
->dwExeCount
; ++n
)
449 if (SdbTagRefToTagID(hsdb
, pQuery
->atrExes
[n
], &pdb
, &tag
))
451 LPCWSTR ExeName
= SeiGetStringPtr(pdb
, tag
, TAG_NAME
);
452 TAGID ShimRef
= SdbFindFirstTag(pdb
, tag
, TAG_SHIM_REF
);
453 TAGID FlagRef
= SdbFindFirstTag(pdb
, tag
, TAG_FLAG_REF
);
456 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Exe(%S))\n", ExeName
);
458 while (ShimRef
!= TAGID_NULL
)
461 if (SdbTagIDToTagRef(hsdb
, pdb
, ShimRef
, &trShimRef
))
462 SeiAddShim(trShimRef
, pShimRef
);
464 ShimRef
= SdbFindNextTag(pdb
, tag
, ShimRef
);
467 while (FlagRef
!= TAGID_NULL
)
469 SeiAddFlag(pdb
, FlagRef
, pFlagInfo
);
471 FlagRef
= SdbFindNextTag(pdb
, tag
, FlagRef
);
477 for (n
= 0; n
< pQuery
->dwLayerCount
; ++n
)
481 if (SdbTagRefToTagID(hsdb
, pQuery
->atrLayers
[n
], &pdb
, &tag
))
483 LPCWSTR LayerName
= SeiGetStringPtr(pdb
, tag
, TAG_NAME
);
484 TAGID ShimRef
= SdbFindFirstTag(pdb
, tag
, TAG_SHIM_REF
);
485 TAGID FlagRef
= SdbFindFirstTag(pdb
, tag
, TAG_FLAG_REF
);
490 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Layer(%S))\n", LayerName
);
491 if (wszLayerEnvVar
[0])
492 StringCchCatW(wszLayerEnvVar
, ARRAYSIZE(wszLayerEnvVar
), L
" ");
493 hr
= StringCchCatW(wszLayerEnvVar
, ARRAYSIZE(wszLayerEnvVar
), LayerName
);
496 SHIMENG_FAIL("Unable to append %S\n", LayerName
);
500 while (ShimRef
!= TAGID_NULL
)
503 if (SdbTagIDToTagRef(hsdb
, pdb
, ShimRef
, &trShimRef
))
504 SeiAddShim(trShimRef
, pShimRef
);
506 ShimRef
= SdbFindNextTag(pdb
, tag
, ShimRef
);
509 while (FlagRef
!= TAGID_NULL
)
511 SeiAddFlag(pdb
, FlagRef
, pFlagInfo
);
513 FlagRef
= SdbFindNextTag(pdb
, tag
, FlagRef
);
517 if (wszLayerEnvVar
[0])
518 SeiSetLayerEnvVar(wszLayerEnvVar
);
521 /* Given the hooks from one shim, find the relevant modules and store the combination of module + hook */
522 VOID
SeiAddHooks(PHOOKAPIEX hooks
, DWORD dwHookCount
, PSHIMINFO pShim
)
525 UNICODE_STRING UnicodeModName
;
528 RtlInitEmptyUnicodeString(&UnicodeModName
, Buf
, sizeof(Buf
));
530 for (n
= 0; n
< dwHookCount
; ++n
)
532 ANSI_STRING AnsiString
;
534 PHOOKAPIEX hook
= hooks
+ n
;
535 PHOOKAPIEX
* pHookApi
;
536 PHOOKMODULEINFO HookModuleInfo
;
538 RtlInitAnsiString(&AnsiString
, hook
->LibraryName
);
539 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeModName
, &AnsiString
, FALSE
)))
541 SHIMENG_FAIL("Unable to convert %s to Unicode\n", hook
->LibraryName
);
545 RtlInitAnsiString(&AnsiString
, hook
->FunctionName
);
546 if (NT_SUCCESS(LdrGetDllHandle(NULL
, 0, &UnicodeModName
, &DllHandle
)))
551 if (!NT_SUCCESS(LdrGetProcedureAddress(DllHandle
, &AnsiString
, 0, &ProcAddress
)))
553 SHIMENG_FAIL("Unable to retrieve %s!%s\n", hook
->LibraryName
, hook
->FunctionName
);
557 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, DllHandle
);
558 hook
->OriginalFunction
= ProcAddress
;
562 HookModuleInfo
= SeiFindHookModuleInfo(&UnicodeModName
, NULL
);
568 HookModuleInfo
= ARRAY_Append(&g_pHookArray
, HOOKMODULEINFO
);
572 HookModuleInfo
->BaseAddress
= DllHandle
;
573 ARRAY_Init(&HookModuleInfo
->HookApis
, PHOOKAPIEX
);
574 RtlCreateUnicodeString(&HookModuleInfo
->Name
, UnicodeModName
.Buffer
);
577 hook
->pShimInfo
= pShim
;
579 for (j
= 0; j
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++j
)
581 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, j
);
582 int CmpResult
= strcmp(hook
->FunctionName
, HookApi
->FunctionName
);
585 /* Multiple hooks on one function? --> use ApiLink */
586 SHIMENG_FAIL("Multiple hooks on one API is not yet supported!\n");
590 pHookApi
= ARRAY_Append(&HookModuleInfo
->HookApis
, PHOOKAPIEX
);
596 typedef FARPROC(WINAPI
* GETPROCADDRESSPROC
)(HINSTANCE
, LPCSTR
);
598 /* Check if we should fake the return from GetProcAddress (because we also redirected the iat for this module) */
599 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
)
601 char szOrdProcName
[10] = "";
602 LPCSTR lpPrintName
= lpProcName
;
603 PVOID Addr
= _ReturnAddress();
604 PHOOKMODULEINFO HookModuleInfo
;
605 FARPROC proc
= ((GETPROCADDRESSPROC
)g_IntHookEx
[0].OriginalFunction
)(hModule
, lpProcName
);
607 if ((DWORD_PTR
)lpProcName
<= MAXUSHORT
)
609 sprintf(szOrdProcName
, "#%Iu", (DWORD_PTR
)lpProcName
);
610 lpPrintName
= szOrdProcName
;
613 Addr
= SeiGetModuleFromAddress(Addr
);
614 if (SE_IsShimDll(Addr
))
616 SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule
, lpPrintName
);
620 SHIMENG_INFO("(GetProcAddress(%p!%s) => %p\n", hModule
, lpPrintName
, proc
);
622 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, hModule
);
624 /* FIXME: Ordinal not yet supported */
625 if (HookModuleInfo
&& HIWORD(lpProcName
))
628 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
630 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
631 int CmpResult
= strcmp(lpProcName
, HookApi
->FunctionName
);
634 SHIMENG_MSG("Redirecting %p to %p\n", proc
, HookApi
->ReplacementFunction
);
635 proc
= HookApi
->ReplacementFunction
;
644 /* Walk all shim modules / enabled shims, and add their hooks */
645 VOID
SeiResolveAPIs(VOID
)
649 /* Enumerate all Shim modules */
650 for (mod
= 0; mod
< ARRAY_Size(&g_pShimInfo
); ++mod
)
652 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, mod
);
653 DWORD dwShimCount
= ARRAY_Size(&pShimModule
->EnabledShims
);
655 /* Enumerate all Shims */
656 for (n
= 0; n
< dwShimCount
; ++n
)
658 PSHIMINFO pShim
= *ARRAY_At(&pShimModule
->EnabledShims
, PSHIMINFO
, n
);
660 PHOOKAPIEX hooks
= pShim
->pHookApi
;
661 DWORD dwHookCount
= pShim
->dwHookCount
;
663 SeiAddHooks(hooks
, dwHookCount
, pShim
);
668 /* If we hooked something, we should also redirect GetProcAddress */
669 VOID
SeiAddInternalHooks(DWORD dwNumHooks
)
673 g_bInternalHooksUsed
= FALSE
;
677 SeiAddHooks(g_IntHookEx
, ARRAYSIZE(g_IntHookEx
), NULL
);
678 g_bInternalHooksUsed
= TRUE
;
681 /* Patch one function in the iat */
682 VOID
SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk
, PHOOKAPIEX HookApi
, PLDR_DATA_TABLE_ENTRY LdrEntry
)
684 ULONG OldProtection
= 0;
689 SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
691 Ptr
= &FirstThunk
->u1
.Function
;
692 Size
= sizeof(FirstThunk
->u1
.Function
);
693 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, PAGE_EXECUTE_READWRITE
, &OldProtection
);
695 if (!NT_SUCCESS(Status
))
697 SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk
->u1
.Function
);
701 SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk
->u1
.Function
, HookApi
->ReplacementFunction
);
703 FirstThunk
->u1
.Function
= (ULONGLONG
)HookApi
->ReplacementFunction
;
705 FirstThunk
->u1
.Function
= (DWORD
)HookApi
->ReplacementFunction
;
708 Size
= sizeof(FirstThunk
->u1
.Function
);
709 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, OldProtection
, &OldProtection
);
711 if (!NT_SUCCESS(Status
))
713 SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk
->u1
.Function
);
718 PINEXCLUDE
SeiFindInExclude(PARRAY InExclude
, PCUNICODE_STRING DllName
)
722 for (n
= 0; n
< ARRAY_Size(InExclude
); ++n
)
724 PINEXCLUDE InEx
= ARRAY_At(InExclude
, INEXCLUDE
, n
);
726 if (RtlEqualUnicodeString(&InEx
->Module
, DllName
, TRUE
))
733 BOOL
SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry
, PHOOKAPIEX HookApi
)
735 PSHIMINFO pShimInfo
= HookApi
->pShimInfo
;
736 PINEXCLUDE InExclude
;
737 BOOL IsExcluded
= FALSE
;
741 /* Internal hook, do not exclude it */
745 /* By default, everything from System32 or WinSxs is excluded */
746 if (RtlPrefixUnicodeString(&g_System32Directory
, &LdrEntry
->FullDllName
, TRUE
) ||
747 RtlPrefixUnicodeString(&g_SxsDirectory
, &LdrEntry
->FullDllName
, TRUE
))
750 InExclude
= SeiFindInExclude(&pShimInfo
->InExclude
, &LdrEntry
->BaseDllName
);
753 /* If it is on the 'exclude' list, bail out */
754 if (!InExclude
->Include
)
756 SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it on in the exclude list.\n",
757 &LdrEntry
->BaseDllName
, pShimInfo
->ShimName
, HookApi
->LibraryName
, HookApi
->FunctionName
);
761 /* If it is on the 'include' list, override System32 / Winsxs check. */
764 SHIMENG_INFO("Module '%wZ' included for shim %S, API '%s!%s', because it is on the include list.\n",
765 &LdrEntry
->BaseDllName
, pShimInfo
->ShimName
, HookApi
->LibraryName
, HookApi
->FunctionName
);
773 SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it is in System32/WinSXS.\n",
774 &LdrEntry
->BaseDllName
, pShimInfo
->ShimName
, HookApi
->LibraryName
, HookApi
->FunctionName
);
780 VOID
SeiAppendInExclude(PARRAY dest
, PCWSTR ModuleName
, BOOL IsInclude
)
782 PINEXCLUDE InExclude
;
783 UNICODE_STRING ModuleNameU
;
784 RtlInitUnicodeString(&ModuleNameU
, ModuleName
);
786 InExclude
= SeiFindInExclude(dest
, &ModuleNameU
);
789 InExclude
->Include
= IsInclude
;
793 InExclude
= ARRAY_Append(dest
, INEXCLUDE
);
796 PCWSTR ModuleNameCopy
= SdbpStrDup(ModuleName
);
797 RtlInitUnicodeString(&InExclude
->Module
, ModuleNameCopy
);
798 InExclude
->Include
= IsInclude
;
802 /* Read the INEXCLUD tags from a given parent tag */
803 VOID
SeiReadInExclude(PDB pdb
, TAGID parent
, PARRAY dest
)
807 InExcludeTag
= SdbFindFirstTag(pdb
, parent
, TAG_INEXCLUD
);
809 while (InExcludeTag
!= TAGID_NULL
)
812 TAGID ModuleTag
= SdbFindFirstTag(pdb
, InExcludeTag
, TAG_MODULE
);
813 TAGID IncludeTag
= SdbFindFirstTag(pdb
, InExcludeTag
, TAG_INCLUDE
);
815 ModuleName
= SdbGetStringTagPtr(pdb
, ModuleTag
);
818 SeiAppendInExclude(dest
, ModuleName
, IncludeTag
!= TAGID_NULL
);
822 SHIMENG_WARN("INEXCLUDE without Module: 0x%x\n", InExcludeTag
);
825 InExcludeTag
= SdbFindNextTag(pdb
, parent
, InExcludeTag
);
829 VOID
SeiBuildGlobalInclExclList(HSDB hsdb
)
832 TAGREF tr
= TAGREF_ROOT
;
833 TAGID root
, db
, library
;
835 if (!SdbTagRefToTagID(hsdb
, tr
, &pdb
, &root
))
837 SHIMENG_WARN("Unable to resolve database root\n");
840 db
= SdbFindFirstTag(pdb
, root
, TAG_DATABASE
);
841 if (db
== TAGID_NULL
)
843 SHIMENG_WARN("Unable to resolve database\n");
846 library
= SdbFindFirstTag(pdb
, db
, TAG_LIBRARY
);
847 if (library
== TAGID_NULL
)
849 SHIMENG_WARN("Unable to resolve library\n");
853 SeiReadInExclude(pdb
, library
, &g_InExclude
);
856 VOID
SeiBuildInclExclList(PDB pdb
, TAGID ShimTag
, PSHIMINFO pShimInfo
)
860 /* First duplicate the global in/excludes */
861 for (n
= 0; n
< ARRAY_Size(&g_InExclude
); ++n
)
863 PINEXCLUDE InEx
= ARRAY_At(&g_InExclude
, INEXCLUDE
, n
);
864 SeiAppendInExclude(&pShimInfo
->InExclude
, InEx
->Module
.Buffer
, InEx
->Include
);
867 /* Now read this shim's in/excludes (possibly overriding the global ones) */
868 SeiReadInExclude(pdb
, ShimTag
, &pShimInfo
->InExclude
);
871 /* Given one loaded module, redirect (hook) all functions from the iat that are registered by shims */
872 VOID
SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry
)
875 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
876 PBYTE DllBase
= LdrEntry
->DllBase
;
878 if (SE_IsShimDll(DllBase
) ||
879 g_hInstance
== LdrEntry
->DllBase
||
880 RtlEqualUnicodeString(&g_LoadingShimDll
, &LdrEntry
->BaseDllName
, TRUE
))
882 SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
886 if (LdrEntry
->Flags
& LDRP_COMPAT_DATABASE_PROCESSED
)
888 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" because it was already processed\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
892 ImportDescriptor
= RtlImageDirectoryEntryToData(DllBase
, TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &Size
);
893 if (!ImportDescriptor
)
895 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
899 SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
901 for ( ;ImportDescriptor
->Name
&& ImportDescriptor
->OriginalFirstThunk
; ImportDescriptor
++)
903 PHOOKMODULEINFO HookModuleInfo
;
905 /* Do we have hooks for this module? */
906 HookModuleInfo
= SeiFindHookModuleInfoForImportDescriptor(DllBase
, ImportDescriptor
);
910 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
913 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
916 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
918 /* Check if this module should be excluded from being hooked (system32/winsxs, global or shim exclude) */
919 if (SeiIsExcluded(LdrEntry
, HookApi
))
924 OriginalThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->OriginalFirstThunk
);
925 FirstThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->FirstThunk
);
927 /* Walk all imports */
928 for (;OriginalThunk
->u1
.AddressOfData
&& FirstThunk
->u1
.Function
; OriginalThunk
++, FirstThunk
++)
930 if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk
->u1
.AddressOfData
))
932 PIMAGE_IMPORT_BY_NAME ImportName
;
934 ImportName
= (PIMAGE_IMPORT_BY_NAME
)(DllBase
+ OriginalThunk
->u1
.AddressOfData
);
935 if (!strcmp((PCSTR
)ImportName
->Name
, HookApi
->FunctionName
))
937 SeiPatchNewImport(FirstThunk
, HookApi
, LdrEntry
);
939 /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
945 SHIMENG_FAIL("Ordinals not yet supported\n");
952 /* One entry not found. */
954 SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
956 SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, dwFound
, &LdrEntry
->BaseDllName
);
962 /* Mark this module as processed. */
963 LdrEntry
->Flags
|= LDRP_COMPAT_DATABASE_PROCESSED
;
967 VOID
PatchNewModules(PPEB Peb
)
969 PLIST_ENTRY ListHead
, ListEntry
;
970 PLDR_DATA_TABLE_ENTRY LdrEntry
;
972 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
973 ListEntry
= ListHead
->Flink
;
975 while (ListHead
!= ListEntry
)
977 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
978 SeiHookImports(LdrEntry
);
980 ListEntry
= ListEntry
->Flink
;
985 VOID
SeiInitPaths(VOID
)
987 #define SYSTEM32 L"\\system32"
988 #define WINSXS L"\\winsxs"
990 PWSTR WindowsDirectory
= SdbpStrDup(SharedUserData
->NtSystemRoot
);
991 RtlInitUnicodeString(&g_WindowsDirectory
, WindowsDirectory
);
993 g_System32Directory
.MaximumLength
= g_WindowsDirectory
.Length
+ SdbpStrsize(SYSTEM32
);
994 g_System32Directory
.Buffer
= SdbpAlloc(g_System32Directory
.MaximumLength
);
995 RtlCopyUnicodeString(&g_System32Directory
, &g_WindowsDirectory
);
996 RtlAppendUnicodeToString(&g_System32Directory
, SYSTEM32
);
998 g_SxsDirectory
.MaximumLength
= g_WindowsDirectory
.Length
+ SdbpStrsize(WINSXS
);
999 g_SxsDirectory
.Buffer
= SdbpAlloc(g_SxsDirectory
.MaximumLength
);
1000 RtlCopyUnicodeString(&g_SxsDirectory
, &g_WindowsDirectory
);
1001 RtlAppendUnicodeToString(&g_SxsDirectory
, WINSXS
);
1007 VOID
SeiSetEntryProcessed(PPEB Peb
)
1009 PLIST_ENTRY ListHead
, Entry
;
1010 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1012 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1013 Entry
= ListHead
->Flink
;
1014 while (Entry
!= ListHead
)
1016 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
1017 Entry
= Entry
->Flink
;
1019 if (RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Ntdll
, TRUE
) ||
1020 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Kernel32
, TRUE
) ||
1021 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Verifier
, TRUE
) ||
1022 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &g_LoadingShimDll
, TRUE
) ||
1023 SE_IsShimDll(LdrEntry
->DllBase
) ||
1024 (LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
1026 SHIMENG_WARN("Don't mess with 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1030 SHIMENG_WARN("Touching 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1031 LdrEntry
->Flags
|= (LDRP_ENTRY_PROCESSED
| LDRP_SHIMENG_SUPPRESSED_ENTRY
);
1035 ListHead
= &NtCurrentPeb()->Ldr
->InMemoryOrderModuleList
;
1036 Entry
= ListHead
->Flink
;
1037 SHIMENG_INFO("In memory:\n");
1038 while (Entry
!= ListHead
)
1040 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderLinks
);
1041 Entry
= Entry
->Flink
;
1043 SHIMENG_INFO(" 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1046 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1047 Entry
= ListHead
->Flink
;
1048 SHIMENG_INFO("In load:\n");
1049 while (Entry
!= ListHead
)
1051 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1052 Entry
= Entry
->Flink
;
1054 SHIMENG_INFO(" 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1058 VOID
SeiResetEntryProcessed(PPEB Peb
)
1060 PLIST_ENTRY ListHead
, Entry
;
1061 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1063 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1064 Entry
= ListHead
->Flink
;
1065 while (Entry
!= ListHead
)
1067 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
1068 Entry
= Entry
->Flink
;
1070 if (SE_IsShimDll(LdrEntry
->DllBase
) ||
1071 g_hInstance
== LdrEntry
->DllBase
||
1072 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Ntdll
, TRUE
) ||
1073 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Kernel32
, TRUE
) ||
1074 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Verifier
, TRUE
) ||
1075 !(LdrEntry
->Flags
& LDRP_SHIMENG_SUPPRESSED_ENTRY
))
1077 SHIMENG_WARN("Don't mess with 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1081 SHIMENG_WARN("Resetting 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1082 LdrEntry
->Flags
&= ~(LDRP_ENTRY_PROCESSED
| LDRP_SHIMENG_SUPPRESSED_ENTRY
);
1087 VOID
SeiInit(PUNICODE_STRING ProcessImage
, HSDB hsdb
, SDBQUERYRESULT
* pQuery
)
1091 DWORD dwTotalHooks
= 0;
1094 PPEB Peb
= NtCurrentPeb();
1096 /* We should only be called once! */
1097 ASSERT(g_pShimInfo
.ItemSize__
== 0);
1099 ARRAY_Init(&ShimRefArray
, TAGREF
);
1100 ARRAY_Init(&g_pShimInfo
, PSHIMMODULE
);
1101 ARRAY_Init(&g_pHookArray
, HOOKMODULEINFO
);
1102 ARRAY_Init(&g_InExclude
, INEXCLUDE
);
1103 RtlZeroMemory(&ShimFlags
, sizeof(ShimFlags
));
1107 SeiCheckComPlusImage(Peb
->ImageBaseAddress
);
1109 /* Mark all modules loaded until now as 'LDRP_ENTRY_PROCESSED' so that their entrypoint is not called while we are loading shims */
1110 SeiSetEntryProcessed(Peb
);
1113 if (pQuery->trApphelp)
1114 SeiDisplayAppHelp(?pQuery->trApphelp?);
1117 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(ExePath(%wZ))\n", ProcessImage
);
1118 SeiBuildShimRefArray(hsdb
, pQuery
, &ShimRefArray
, &ShimFlags
);
1119 if (ShimFlags
.AppCompatFlags
.QuadPart
)
1121 SeiDbgPrint(SEI_MSG
, NULL
, "Using KERNEL apphack flags 0x%I64x\n", ShimFlags
.AppCompatFlags
.QuadPart
);
1122 Peb
->AppCompatFlags
.QuadPart
|= ShimFlags
.AppCompatFlags
.QuadPart
;
1124 if (ShimFlags
.AppCompatFlagsUser
.QuadPart
)
1126 SeiDbgPrint(SEI_MSG
, NULL
, "Using USER apphack flags 0x%I64x\n", ShimFlags
.AppCompatFlagsUser
.QuadPart
);
1127 Peb
->AppCompatFlagsUser
.QuadPart
|= ShimFlags
.AppCompatFlagsUser
.QuadPart
;
1129 if (ShimFlags
.ProcessParameters_Flags
)
1131 SeiDbgPrint(SEI_MSG
, NULL
, "Using ProcessParameters flags 0x%x\n", ShimFlags
.ProcessParameters_Flags
);
1132 Peb
->ProcessParameters
->Flags
|= ShimFlags
.ProcessParameters_Flags
;
1134 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Complete)\n");
1136 SHIMENG_INFO("Got %d shims\n", ARRAY_Size(&ShimRefArray
));
1137 SeiBuildGlobalInclExclList(hsdb
);
1139 /* Walk all shims referenced (in layers + exes), and load their modules */
1140 for (n
= 0; n
< ARRAY_Size(&ShimRefArray
); ++n
)
1145 TAGREF tr
= *ARRAY_At(&ShimRefArray
, TAGREF
, n
);
1147 if (SdbTagRefToTagID(hsdb
, tr
, &pdb
, &ShimRef
))
1149 LPCWSTR ShimName
, DllName
, CommandLine
= NULL
;
1151 WCHAR FullNameBuffer
[MAX_PATH
];
1152 UNICODE_STRING UnicodeDllName
;
1154 PSHIMMODULE pShimModuleInfo
= NULL
;
1155 ANSI_STRING AnsiCommandLine
= RTL_CONSTANT_STRING("");
1156 PSHIMINFO pShimInfo
= NULL
;
1157 PHOOKAPIEX pHookApi
;
1160 ShimName
= SeiGetStringPtr(pdb
, ShimRef
, TAG_NAME
);
1163 SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", tr
);
1167 CommandLine
= SeiGetStringPtr(pdb
, ShimRef
, TAG_COMMAND_LINE
);
1168 if (CommandLine
&& *CommandLine
)
1170 RtlInitUnicodeString(&UnicodeDllName
, CommandLine
);
1171 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiCommandLine
, &UnicodeDllName
, TRUE
)))
1173 SHIMENG_INFO("COMMAND LINE %s for %S", AnsiCommandLine
.Buffer
, ShimName
);
1177 AnsiCommandLine
.Buffer
= "";
1182 ShimTag
= SeiGetDWORD(pdb
, ShimRef
, TAG_SHIM_TAGID
);
1185 SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName
);
1189 if (!SUCCEEDED(SdbGetAppPatchDir(NULL
, FullNameBuffer
, ARRAYSIZE(FullNameBuffer
))))
1191 SHIMENG_WARN("Failed to get the AppPatch dir\n");
1195 DllName
= SeiGetStringPtr(pdb
, ShimTag
, TAG_DLLFILE
);
1196 if (DllName
== NULL
||
1197 !SUCCEEDED(StringCchCatW(FullNameBuffer
, ARRAYSIZE(FullNameBuffer
), L
"\\")) ||
1198 !SUCCEEDED(StringCchCatW(FullNameBuffer
, ARRAYSIZE(FullNameBuffer
), DllName
)))
1200 SHIMENG_WARN("Failed to build a full path for %S\n", ShimName
);
1204 RtlInitUnicodeString(&g_LoadingShimDll
, DllName
);
1205 RtlInitUnicodeString(&UnicodeDllName
, FullNameBuffer
);
1206 if (NT_SUCCESS(LdrGetDllHandle(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
1208 /* This shim dll was already loaded, let's find it */
1209 pShimModuleInfo
= SeiGetShimModuleInfo(BaseAddress
);
1211 else if (!NT_SUCCESS(LdrLoadDll(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
1213 SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName
, ShimName
);
1216 RtlInitUnicodeString(&g_LoadingShimDll
, NULL
);
1217 /* No shim module found (or we just loaded it) */
1218 if (!pShimModuleInfo
)
1220 pShimModuleInfo
= SeiCreateShimModuleInfo(DllName
, BaseAddress
);
1221 if (!pShimModuleInfo
)
1223 SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName
);
1228 SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress
, &UnicodeDllName
);
1229 SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName
, ShimName
);
1231 /* Ask this shim what hooks it needs (and pass along the commandline) */
1233 pHookApi
= pShimModuleInfo
->pGetHookAPIs(AnsiCommandLine
.Buffer
, ShimName
, &dwHookCount
);
1234 SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount
, &UnicodeDllName
, ShimName
);
1235 if (dwHookCount
&& pHookApi
)
1236 pShimInfo
= SeiAppendHookInfo(pShimModuleInfo
, pHookApi
, dwHookCount
, ShimName
);
1240 /* If this shim has hooks, create the include / exclude lists */
1242 SeiBuildInclExclList(pdb
, ShimTag
, pShimInfo
);
1244 if (CommandLine
&& *CommandLine
)
1245 RtlFreeAnsiString(&AnsiCommandLine
);
1247 dwTotalHooks
+= dwHookCount
;
1251 SeiAddInternalHooks(dwTotalHooks
);
1253 PatchNewModules(Peb
);
1255 /* Remove the 'LDRP_ENTRY_PROCESSED' flag from entries we modified, so that the loader can continue to process them */
1256 SeiResetEntryProcessed(Peb
);
1260 /* Load the database + unpack the shim data (if this process is allowed) */
1261 BOOL
SeiGetShimData(PUNICODE_STRING ProcessImage
, PVOID pShimData
, HSDB
* pHsdb
, SDBQUERYRESULT
* pQuery
)
1263 static const UNICODE_STRING ForbiddenShimmingApps
[] = {
1264 RTL_CONSTANT_STRING(L
"ntsd.exe"),
1265 RTL_CONSTANT_STRING(L
"windbg.exe"),
1267 RTL_CONSTANT_STRING(L
"slsvc.exe"),
1270 static const UNICODE_STRING BackSlash
= RTL_CONSTANT_STRING(L
"\\");
1271 static const UNICODE_STRING ForwdSlash
= RTL_CONSTANT_STRING(L
"/");
1272 UNICODE_STRING ProcessName
;
1273 USHORT Back
, Forward
;
1277 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &BackSlash
, &Back
)))
1280 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &ForwdSlash
, &Forward
)))
1287 Back
+= sizeof(WCHAR
);
1289 ProcessName
.Buffer
= ProcessImage
->Buffer
+ Back
/ sizeof(WCHAR
);
1290 ProcessName
.Length
= ProcessImage
->Length
- Back
;
1291 ProcessName
.MaximumLength
= ProcessImage
->MaximumLength
- Back
;
1293 for (n
= 0; n
< ARRAYSIZE(ForbiddenShimmingApps
); ++n
)
1295 if (RtlEqualUnicodeString(&ProcessName
, ForbiddenShimmingApps
+ n
, TRUE
))
1297 SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps
+ n
);
1302 /* We should probably load all db's here, but since we do not support that yet... */
1303 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
1306 if (SdbUnpackAppCompatData(hsdb
, ProcessImage
->Buffer
, pShimData
, pQuery
))
1311 SdbReleaseDatabase(hsdb
);
1318 VOID NTAPI
SE_InstallBeforeInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
1321 SDBQUERYRESULT QueryResult
= { { 0 } };
1322 SHIMENG_INFO("(%wZ, %p)\n", ProcessImage
, pShimData
);
1324 if (!SeiGetShimData(ProcessImage
, pShimData
, &hsdb
, &QueryResult
))
1326 SHIMENG_FAIL("Failed to get shim data\n");
1330 g_bShimDuringInit
= TRUE
;
1331 SeiInit(ProcessImage
, hsdb
, &QueryResult
);
1332 g_bShimDuringInit
= FALSE
;
1334 SdbReleaseDatabase(hsdb
);
1337 VOID NTAPI
SE_InstallAfterInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
1339 NotifyShims(SHIM_NOTIFY_ATTACH
, NULL
);
1342 VOID NTAPI
SE_ProcessDying(VOID
)
1344 SHIMENG_MSG("()\n");
1345 NotifyShims(SHIM_NOTIFY_DETACH
, NULL
);
1348 VOID WINAPI
SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
1350 SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit
? "" : "AFTER ", &LdrEntry
->BaseDllName
);
1352 SeiHookImports(LdrEntry
);
1354 NotifyShims(SHIM_REASON_DLL_LOAD
, LdrEntry
);
1357 VOID WINAPI
SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
1359 SHIMENG_INFO("(%p)\n", LdrEntry
);
1361 /* Should we unhook here? */
1363 NotifyShims(SHIM_REASON_DLL_UNLOAD
, LdrEntry
);
1366 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
)
1368 SHIMENG_INFO("(%p)\n", BaseAddress
);
1370 return SeiGetShimModuleInfo(BaseAddress
) != NULL
;