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
)))
548 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, DllHandle
);
552 HookModuleInfo
= SeiFindHookModuleInfo(&UnicodeModName
, NULL
);
558 HookModuleInfo
= ARRAY_Append(&g_pHookArray
, HOOKMODULEINFO
);
562 HookModuleInfo
->BaseAddress
= DllHandle
;
563 ARRAY_Init(&HookModuleInfo
->HookApis
, PHOOKAPIEX
);
564 RtlCreateUnicodeString(&HookModuleInfo
->Name
, UnicodeModName
.Buffer
);
567 hook
->pShimInfo
= pShim
;
569 for (j
= 0; j
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++j
)
571 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, j
);
572 int CmpResult
= strcmp(hook
->FunctionName
, HookApi
->FunctionName
);
575 while (HookApi
->ApiLink
)
577 HookApi
= HookApi
->ApiLink
;
579 HookApi
->ApiLink
= hook
;
584 /* No place found yet, append it */
587 pHookApi
= ARRAY_Append(&HookModuleInfo
->HookApis
, PHOOKAPIEX
);
594 typedef FARPROC(WINAPI
* GETPROCADDRESSPROC
)(HINSTANCE
, LPCSTR
);
596 /* Check if we should fake the return from GetProcAddress (because we also redirected the iat for this module) */
597 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
)
599 char szOrdProcName
[10] = "";
600 LPCSTR lpPrintName
= lpProcName
;
601 PVOID Addr
= _ReturnAddress();
602 PHOOKMODULEINFO HookModuleInfo
;
603 FARPROC proc
= ((GETPROCADDRESSPROC
)g_IntHookEx
[0].OriginalFunction
)(hModule
, lpProcName
);
605 if ((DWORD_PTR
)lpProcName
<= MAXUSHORT
)
607 sprintf(szOrdProcName
, "#%Iu", (DWORD_PTR
)lpProcName
);
608 lpPrintName
= szOrdProcName
;
611 Addr
= SeiGetModuleFromAddress(Addr
);
612 if (SE_IsShimDll(Addr
))
614 SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule
, lpPrintName
);
618 SHIMENG_INFO("(GetProcAddress(%p!%s) => %p\n", hModule
, lpPrintName
, proc
);
620 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, hModule
);
622 /* FIXME: Ordinal not yet supported */
623 if (HookModuleInfo
&& HIWORD(lpProcName
))
626 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
628 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
629 int CmpResult
= strcmp(lpProcName
, HookApi
->FunctionName
);
632 SHIMENG_MSG("Redirecting %p to %p\n", proc
, HookApi
->ReplacementFunction
);
633 proc
= HookApi
->ReplacementFunction
;
642 VOID
SeiResolveAPI(PHOOKMODULEINFO HookModuleInfo
)
645 ANSI_STRING AnsiString
;
647 ASSERT(HookModuleInfo
->BaseAddress
!= NULL
);
649 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
652 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
653 RtlInitAnsiString(&AnsiString
, HookApi
->FunctionName
);
655 if (!NT_SUCCESS(LdrGetProcedureAddress(HookModuleInfo
->BaseAddress
, &AnsiString
, 0, &ProcAddress
)))
657 SHIMENG_FAIL("Unable to retrieve %s!%s\n", HookApi
->LibraryName
, HookApi
->FunctionName
);
661 HookApi
->OriginalFunction
= ProcAddress
;
662 if (HookApi
->ApiLink
)
664 SHIMENG_MSG("TODO: Figure out how to handle conflicting In/Exports with ApiLink!\n");
666 while (HookApi
->ApiLink
)
668 HookApi
->ApiLink
->OriginalFunction
= HookApi
->OriginalFunction
;
669 HookApi
->OriginalFunction
= HookApi
->ApiLink
->ReplacementFunction
;
670 HookApi
= HookApi
->ApiLink
;
675 /* Walk all shim modules / enabled shims, and add their hooks */
676 VOID
SeiResolveAPIs(VOID
)
680 for (n
= 0; n
< ARRAY_Size(&g_pHookArray
); ++n
)
682 PHOOKMODULEINFO pModuleInfo
= ARRAY_At(&g_pHookArray
, HOOKMODULEINFO
, n
);
684 /* Is this module loaded? */
685 if (pModuleInfo
->BaseAddress
)
687 SeiResolveAPI(pModuleInfo
);
692 VOID
SeiCombineHookInfo(VOID
)
696 /* Enumerate all Shim modules */
697 for (mod
= 0; mod
< ARRAY_Size(&g_pShimInfo
); ++mod
)
699 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, mod
);
700 DWORD dwShimCount
= ARRAY_Size(&pShimModule
->EnabledShims
);
702 /* Enumerate all Shims */
703 for (n
= 0; n
< dwShimCount
; ++n
)
705 PSHIMINFO pShim
= *ARRAY_At(&pShimModule
->EnabledShims
, PSHIMINFO
, n
);
707 PHOOKAPIEX hooks
= pShim
->pHookApi
;
708 DWORD dwHookCount
= pShim
->dwHookCount
;
710 SeiAddHooks(hooks
, dwHookCount
, pShim
);
715 /* If we hooked something, we should also redirect GetProcAddress */
716 VOID
SeiAddInternalHooks(DWORD dwNumHooks
)
720 g_bInternalHooksUsed
= FALSE
;
724 SeiAddHooks(g_IntHookEx
, ARRAYSIZE(g_IntHookEx
), NULL
);
725 g_bInternalHooksUsed
= TRUE
;
728 /* Patch one function in the iat */
729 VOID
SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk
, PHOOKAPIEX HookApi
, PLDR_DATA_TABLE_ENTRY LdrEntry
)
731 ULONG OldProtection
= 0;
736 SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
738 Ptr
= &FirstThunk
->u1
.Function
;
739 Size
= sizeof(FirstThunk
->u1
.Function
);
740 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, PAGE_EXECUTE_READWRITE
, &OldProtection
);
742 if (!NT_SUCCESS(Status
))
744 SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk
->u1
.Function
);
748 SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk
->u1
.Function
, HookApi
->ReplacementFunction
);
750 FirstThunk
->u1
.Function
= (ULONGLONG
)HookApi
->ReplacementFunction
;
752 FirstThunk
->u1
.Function
= (DWORD
)HookApi
->ReplacementFunction
;
755 Size
= sizeof(FirstThunk
->u1
.Function
);
756 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, OldProtection
, &OldProtection
);
758 if (!NT_SUCCESS(Status
))
760 SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk
->u1
.Function
);
765 PINEXCLUDE
SeiFindInExclude(PARRAY InExclude
, PCUNICODE_STRING DllName
)
769 for (n
= 0; n
< ARRAY_Size(InExclude
); ++n
)
771 PINEXCLUDE InEx
= ARRAY_At(InExclude
, INEXCLUDE
, n
);
773 if (RtlEqualUnicodeString(&InEx
->Module
, DllName
, TRUE
))
780 BOOL
SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry
, PHOOKAPIEX HookApi
)
782 PSHIMINFO pShimInfo
= HookApi
->pShimInfo
;
783 PINEXCLUDE InExclude
;
784 BOOL IsExcluded
= FALSE
;
788 /* Internal hook, do not exclude it */
792 /* By default, everything from System32 or WinSxs is excluded */
793 if (RtlPrefixUnicodeString(&g_System32Directory
, &LdrEntry
->FullDllName
, TRUE
) ||
794 RtlPrefixUnicodeString(&g_SxsDirectory
, &LdrEntry
->FullDllName
, TRUE
))
797 InExclude
= SeiFindInExclude(&pShimInfo
->InExclude
, &LdrEntry
->BaseDllName
);
800 /* If it is on the 'exclude' list, bail out */
801 if (!InExclude
->Include
)
803 SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it on in the exclude list.\n",
804 &LdrEntry
->BaseDllName
, pShimInfo
->ShimName
, HookApi
->LibraryName
, HookApi
->FunctionName
);
808 /* If it is on the 'include' list, override System32 / Winsxs check. */
811 SHIMENG_INFO("Module '%wZ' included for shim %S, API '%s!%s', because it is on the include list.\n",
812 &LdrEntry
->BaseDllName
, pShimInfo
->ShimName
, HookApi
->LibraryName
, HookApi
->FunctionName
);
820 SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it is in System32/WinSXS.\n",
821 &LdrEntry
->BaseDllName
, pShimInfo
->ShimName
, HookApi
->LibraryName
, HookApi
->FunctionName
);
827 VOID
SeiAppendInExclude(PARRAY dest
, PCWSTR ModuleName
, BOOL IsInclude
)
829 PINEXCLUDE InExclude
;
830 UNICODE_STRING ModuleNameU
;
831 RtlInitUnicodeString(&ModuleNameU
, ModuleName
);
833 InExclude
= SeiFindInExclude(dest
, &ModuleNameU
);
836 InExclude
->Include
= IsInclude
;
840 InExclude
= ARRAY_Append(dest
, INEXCLUDE
);
843 PCWSTR ModuleNameCopy
= SdbpStrDup(ModuleName
);
844 RtlInitUnicodeString(&InExclude
->Module
, ModuleNameCopy
);
845 InExclude
->Include
= IsInclude
;
849 /* Read the INEXCLUD tags from a given parent tag */
850 VOID
SeiReadInExclude(PDB pdb
, TAGID parent
, PARRAY dest
)
854 InExcludeTag
= SdbFindFirstTag(pdb
, parent
, TAG_INEXCLUD
);
856 while (InExcludeTag
!= TAGID_NULL
)
859 TAGID ModuleTag
= SdbFindFirstTag(pdb
, InExcludeTag
, TAG_MODULE
);
860 TAGID IncludeTag
= SdbFindFirstTag(pdb
, InExcludeTag
, TAG_INCLUDE
);
862 ModuleName
= SdbGetStringTagPtr(pdb
, ModuleTag
);
865 SeiAppendInExclude(dest
, ModuleName
, IncludeTag
!= TAGID_NULL
);
869 SHIMENG_WARN("INEXCLUDE without Module: 0x%x\n", InExcludeTag
);
872 InExcludeTag
= SdbFindNextTag(pdb
, parent
, InExcludeTag
);
876 VOID
SeiBuildGlobalInclExclList(HSDB hsdb
)
879 TAGREF tr
= TAGREF_ROOT
;
880 TAGID root
, db
, library
;
882 if (!SdbTagRefToTagID(hsdb
, tr
, &pdb
, &root
))
884 SHIMENG_WARN("Unable to resolve database root\n");
887 db
= SdbFindFirstTag(pdb
, root
, TAG_DATABASE
);
888 if (db
== TAGID_NULL
)
890 SHIMENG_WARN("Unable to resolve database\n");
893 library
= SdbFindFirstTag(pdb
, db
, TAG_LIBRARY
);
894 if (library
== TAGID_NULL
)
896 SHIMENG_WARN("Unable to resolve library\n");
900 SeiReadInExclude(pdb
, library
, &g_InExclude
);
903 VOID
SeiBuildInclExclList(PDB pdb
, TAGID ShimTag
, PSHIMINFO pShimInfo
)
907 /* First duplicate the global in/excludes */
908 for (n
= 0; n
< ARRAY_Size(&g_InExclude
); ++n
)
910 PINEXCLUDE InEx
= ARRAY_At(&g_InExclude
, INEXCLUDE
, n
);
911 SeiAppendInExclude(&pShimInfo
->InExclude
, InEx
->Module
.Buffer
, InEx
->Include
);
914 /* Now read this shim's in/excludes (possibly overriding the global ones) */
915 SeiReadInExclude(pdb
, ShimTag
, &pShimInfo
->InExclude
);
918 /* Given one loaded module, redirect (hook) all functions from the iat that are registered by shims */
919 VOID
SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry
)
922 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
923 PBYTE DllBase
= LdrEntry
->DllBase
;
925 if (SE_IsShimDll(DllBase
) ||
926 g_hInstance
== LdrEntry
->DllBase
||
927 RtlEqualUnicodeString(&g_LoadingShimDll
, &LdrEntry
->BaseDllName
, TRUE
))
929 SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
933 if (LdrEntry
->Flags
& LDRP_COMPAT_DATABASE_PROCESSED
)
935 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" because it was already processed\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
939 ImportDescriptor
= RtlImageDirectoryEntryToData(DllBase
, TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &Size
);
940 if (!ImportDescriptor
)
942 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
946 SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
948 for ( ;ImportDescriptor
->Name
&& ImportDescriptor
->OriginalFirstThunk
; ImportDescriptor
++)
950 PHOOKMODULEINFO HookModuleInfo
;
952 /* Do we have hooks for this module? */
953 HookModuleInfo
= SeiFindHookModuleInfoForImportDescriptor(DllBase
, ImportDescriptor
);
957 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
960 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
963 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
965 /* Check if this module should be excluded from being hooked (system32/winsxs, global or shim exclude) */
966 if (SeiIsExcluded(LdrEntry
, HookApi
))
971 OriginalThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->OriginalFirstThunk
);
972 FirstThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->FirstThunk
);
974 /* Walk all imports */
975 for (;OriginalThunk
->u1
.AddressOfData
&& FirstThunk
->u1
.Function
; OriginalThunk
++, FirstThunk
++)
977 if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk
->u1
.AddressOfData
))
979 PIMAGE_IMPORT_BY_NAME ImportName
;
981 ImportName
= (PIMAGE_IMPORT_BY_NAME
)(DllBase
+ OriginalThunk
->u1
.AddressOfData
);
982 if (!strcmp((PCSTR
)ImportName
->Name
, HookApi
->FunctionName
))
984 SeiPatchNewImport(FirstThunk
, HookApi
, LdrEntry
);
986 /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
992 SHIMENG_FAIL("Ordinals not yet supported\n");
999 /* One entry not found. */
1001 SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
1003 SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, dwFound
, &LdrEntry
->BaseDllName
);
1009 /* Mark this module as processed. */
1010 LdrEntry
->Flags
|= LDRP_COMPAT_DATABASE_PROCESSED
;
1014 VOID
PatchNewModules(PPEB Peb
)
1016 PLIST_ENTRY ListHead
, ListEntry
;
1017 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1019 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1020 ListEntry
= ListHead
->Flink
;
1022 while (ListHead
!= ListEntry
)
1024 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1025 SeiHookImports(LdrEntry
);
1027 ListEntry
= ListEntry
->Flink
;
1032 VOID
SeiInitPaths(VOID
)
1034 #define SYSTEM32 L"\\system32"
1035 #define WINSXS L"\\winsxs"
1037 PWSTR WindowsDirectory
= SdbpStrDup(SharedUserData
->NtSystemRoot
);
1038 RtlInitUnicodeString(&g_WindowsDirectory
, WindowsDirectory
);
1040 g_System32Directory
.MaximumLength
= g_WindowsDirectory
.Length
+ SdbpStrsize(SYSTEM32
);
1041 g_System32Directory
.Buffer
= SdbpAlloc(g_System32Directory
.MaximumLength
);
1042 RtlCopyUnicodeString(&g_System32Directory
, &g_WindowsDirectory
);
1043 RtlAppendUnicodeToString(&g_System32Directory
, SYSTEM32
);
1045 g_SxsDirectory
.MaximumLength
= g_WindowsDirectory
.Length
+ SdbpStrsize(WINSXS
);
1046 g_SxsDirectory
.Buffer
= SdbpAlloc(g_SxsDirectory
.MaximumLength
);
1047 RtlCopyUnicodeString(&g_SxsDirectory
, &g_WindowsDirectory
);
1048 RtlAppendUnicodeToString(&g_SxsDirectory
, WINSXS
);
1054 VOID
SeiSetEntryProcessed(PPEB Peb
)
1056 PLIST_ENTRY ListHead
, Entry
;
1057 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1059 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1060 Entry
= ListHead
->Flink
;
1061 while (Entry
!= ListHead
)
1063 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
1064 Entry
= Entry
->Flink
;
1066 if (RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Ntdll
, TRUE
) ||
1067 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Kernel32
, TRUE
) ||
1068 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Verifier
, TRUE
) ||
1069 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &g_LoadingShimDll
, TRUE
) ||
1070 SE_IsShimDll(LdrEntry
->DllBase
) ||
1071 (LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
1073 SHIMENG_WARN("Don't mess with 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1077 SHIMENG_WARN("Touching 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1078 LdrEntry
->Flags
|= (LDRP_ENTRY_PROCESSED
| LDRP_SHIMENG_SUPPRESSED_ENTRY
);
1082 ListHead
= &NtCurrentPeb()->Ldr
->InMemoryOrderModuleList
;
1083 Entry
= ListHead
->Flink
;
1084 SHIMENG_INFO("In memory:\n");
1085 while (Entry
!= ListHead
)
1087 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderLinks
);
1088 Entry
= Entry
->Flink
;
1090 SHIMENG_INFO(" 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1093 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1094 Entry
= ListHead
->Flink
;
1095 SHIMENG_INFO("In load:\n");
1096 while (Entry
!= ListHead
)
1098 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1099 Entry
= Entry
->Flink
;
1101 SHIMENG_INFO(" 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1105 VOID
SeiResetEntryProcessed(PPEB Peb
)
1107 PLIST_ENTRY ListHead
, Entry
;
1108 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1110 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1111 Entry
= ListHead
->Flink
;
1112 while (Entry
!= ListHead
)
1114 LdrEntry
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
1115 Entry
= Entry
->Flink
;
1117 if (SE_IsShimDll(LdrEntry
->DllBase
) ||
1118 g_hInstance
== LdrEntry
->DllBase
||
1119 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Ntdll
, TRUE
) ||
1120 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Kernel32
, TRUE
) ||
1121 RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &Verifier
, TRUE
) ||
1122 !(LdrEntry
->Flags
& LDRP_SHIMENG_SUPPRESSED_ENTRY
))
1124 SHIMENG_WARN("Don't mess with 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1128 SHIMENG_WARN("Resetting 0x%p '%wZ'\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
1129 LdrEntry
->Flags
&= ~(LDRP_ENTRY_PROCESSED
| LDRP_SHIMENG_SUPPRESSED_ENTRY
);
1134 VOID
SeiInit(PUNICODE_STRING ProcessImage
, HSDB hsdb
, SDBQUERYRESULT
* pQuery
)
1138 DWORD dwTotalHooks
= 0;
1141 PPEB Peb
= NtCurrentPeb();
1143 /* We should only be called once! */
1144 ASSERT(g_pShimInfo
.ItemSize__
== 0);
1146 ARRAY_Init(&ShimRefArray
, TAGREF
);
1147 ARRAY_Init(&g_pShimInfo
, PSHIMMODULE
);
1148 ARRAY_Init(&g_pHookArray
, HOOKMODULEINFO
);
1149 ARRAY_Init(&g_InExclude
, INEXCLUDE
);
1150 RtlZeroMemory(&ShimFlags
, sizeof(ShimFlags
));
1154 SeiCheckComPlusImage(Peb
->ImageBaseAddress
);
1156 /* Mark all modules loaded until now as 'LDRP_ENTRY_PROCESSED' so that their entrypoint is not called while we are loading shims */
1157 SeiSetEntryProcessed(Peb
);
1160 if (pQuery->trApphelp)
1161 SeiDisplayAppHelp(?pQuery->trApphelp?);
1164 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(ExePath(%wZ))\n", ProcessImage
);
1165 SeiBuildShimRefArray(hsdb
, pQuery
, &ShimRefArray
, &ShimFlags
);
1166 if (ShimFlags
.AppCompatFlags
.QuadPart
)
1168 SeiDbgPrint(SEI_MSG
, NULL
, "Using KERNEL apphack flags 0x%I64x\n", ShimFlags
.AppCompatFlags
.QuadPart
);
1169 Peb
->AppCompatFlags
.QuadPart
|= ShimFlags
.AppCompatFlags
.QuadPart
;
1171 if (ShimFlags
.AppCompatFlagsUser
.QuadPart
)
1173 SeiDbgPrint(SEI_MSG
, NULL
, "Using USER apphack flags 0x%I64x\n", ShimFlags
.AppCompatFlagsUser
.QuadPart
);
1174 Peb
->AppCompatFlagsUser
.QuadPart
|= ShimFlags
.AppCompatFlagsUser
.QuadPart
;
1176 if (ShimFlags
.ProcessParameters_Flags
)
1178 SeiDbgPrint(SEI_MSG
, NULL
, "Using ProcessParameters flags 0x%x\n", ShimFlags
.ProcessParameters_Flags
);
1179 Peb
->ProcessParameters
->Flags
|= ShimFlags
.ProcessParameters_Flags
;
1181 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Complete)\n");
1183 SHIMENG_INFO("Got %d shims\n", ARRAY_Size(&ShimRefArray
));
1184 SeiBuildGlobalInclExclList(hsdb
);
1186 /* Walk all shims referenced (in layers + exes), and load their modules */
1187 for (n
= 0; n
< ARRAY_Size(&ShimRefArray
); ++n
)
1192 TAGREF tr
= *ARRAY_At(&ShimRefArray
, TAGREF
, n
);
1194 if (SdbTagRefToTagID(hsdb
, tr
, &pdb
, &ShimRef
))
1196 LPCWSTR ShimName
, DllName
, CommandLine
= NULL
;
1198 WCHAR FullNameBuffer
[MAX_PATH
];
1199 UNICODE_STRING UnicodeDllName
;
1201 PSHIMMODULE pShimModuleInfo
= NULL
;
1202 ANSI_STRING AnsiCommandLine
= RTL_CONSTANT_STRING("");
1203 PSHIMINFO pShimInfo
= NULL
;
1204 PHOOKAPIEX pHookApi
;
1207 ShimName
= SeiGetStringPtr(pdb
, ShimRef
, TAG_NAME
);
1210 SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", tr
);
1214 CommandLine
= SeiGetStringPtr(pdb
, ShimRef
, TAG_COMMAND_LINE
);
1215 if (CommandLine
&& *CommandLine
)
1217 RtlInitUnicodeString(&UnicodeDllName
, CommandLine
);
1218 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiCommandLine
, &UnicodeDllName
, TRUE
)))
1220 SHIMENG_INFO("COMMAND LINE %s for %S", AnsiCommandLine
.Buffer
, ShimName
);
1224 AnsiCommandLine
.Buffer
= "";
1229 ShimTag
= SeiGetDWORD(pdb
, ShimRef
, TAG_SHIM_TAGID
);
1232 SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName
);
1236 if (!SUCCEEDED(SdbGetAppPatchDir(NULL
, FullNameBuffer
, ARRAYSIZE(FullNameBuffer
))))
1238 SHIMENG_WARN("Failed to get the AppPatch dir\n");
1242 DllName
= SeiGetStringPtr(pdb
, ShimTag
, TAG_DLLFILE
);
1243 if (DllName
== NULL
||
1244 !SUCCEEDED(StringCchCatW(FullNameBuffer
, ARRAYSIZE(FullNameBuffer
), L
"\\")) ||
1245 !SUCCEEDED(StringCchCatW(FullNameBuffer
, ARRAYSIZE(FullNameBuffer
), DllName
)))
1247 SHIMENG_WARN("Failed to build a full path for %S\n", ShimName
);
1251 RtlInitUnicodeString(&g_LoadingShimDll
, DllName
);
1252 RtlInitUnicodeString(&UnicodeDllName
, FullNameBuffer
);
1253 if (NT_SUCCESS(LdrGetDllHandle(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
1255 /* This shim dll was already loaded, let's find it */
1256 pShimModuleInfo
= SeiGetShimModuleInfo(BaseAddress
);
1258 else if (!NT_SUCCESS(LdrLoadDll(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
1260 SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName
, ShimName
);
1263 RtlInitUnicodeString(&g_LoadingShimDll
, NULL
);
1264 /* No shim module found (or we just loaded it) */
1265 if (!pShimModuleInfo
)
1267 pShimModuleInfo
= SeiCreateShimModuleInfo(DllName
, BaseAddress
);
1268 if (!pShimModuleInfo
)
1270 SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName
);
1275 SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress
, &UnicodeDllName
);
1276 SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName
, ShimName
);
1278 /* Ask this shim what hooks it needs (and pass along the commandline) */
1280 pHookApi
= pShimModuleInfo
->pGetHookAPIs(AnsiCommandLine
.Buffer
, ShimName
, &dwHookCount
);
1281 SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount
, &UnicodeDllName
, ShimName
);
1282 if (dwHookCount
&& pHookApi
)
1283 pShimInfo
= SeiAppendHookInfo(pShimModuleInfo
, pHookApi
, dwHookCount
, ShimName
);
1287 /* If this shim has hooks, create the include / exclude lists */
1289 SeiBuildInclExclList(pdb
, ShimTag
, pShimInfo
);
1291 if (CommandLine
&& *CommandLine
)
1292 RtlFreeAnsiString(&AnsiCommandLine
);
1294 dwTotalHooks
+= dwHookCount
;
1298 SeiAddInternalHooks(dwTotalHooks
);
1299 SeiCombineHookInfo();
1301 PatchNewModules(Peb
);
1303 /* Remove the 'LDRP_ENTRY_PROCESSED' flag from entries we modified, so that the loader can continue to process them */
1304 SeiResetEntryProcessed(Peb
);
1308 /* Load the database + unpack the shim data (if this process is allowed) */
1309 BOOL
SeiGetShimData(PUNICODE_STRING ProcessImage
, PVOID pShimData
, HSDB
* pHsdb
, SDBQUERYRESULT
* pQuery
)
1311 static const UNICODE_STRING ForbiddenShimmingApps
[] = {
1312 RTL_CONSTANT_STRING(L
"ntsd.exe"),
1313 RTL_CONSTANT_STRING(L
"windbg.exe"),
1315 RTL_CONSTANT_STRING(L
"slsvc.exe"),
1318 static const UNICODE_STRING BackSlash
= RTL_CONSTANT_STRING(L
"\\");
1319 static const UNICODE_STRING ForwdSlash
= RTL_CONSTANT_STRING(L
"/");
1320 UNICODE_STRING ProcessName
;
1321 USHORT Back
, Forward
;
1325 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &BackSlash
, &Back
)))
1328 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &ForwdSlash
, &Forward
)))
1335 Back
+= sizeof(WCHAR
);
1337 ProcessName
.Buffer
= ProcessImage
->Buffer
+ Back
/ sizeof(WCHAR
);
1338 ProcessName
.Length
= ProcessImage
->Length
- Back
;
1339 ProcessName
.MaximumLength
= ProcessImage
->MaximumLength
- Back
;
1341 for (n
= 0; n
< ARRAYSIZE(ForbiddenShimmingApps
); ++n
)
1343 if (RtlEqualUnicodeString(&ProcessName
, ForbiddenShimmingApps
+ n
, TRUE
))
1345 SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps
+ n
);
1350 /* We should probably load all db's here, but since we do not support that yet... */
1351 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
1354 if (SdbUnpackAppCompatData(hsdb
, ProcessImage
->Buffer
, pShimData
, pQuery
))
1359 SdbReleaseDatabase(hsdb
);
1366 VOID NTAPI
SE_InstallBeforeInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
1369 SDBQUERYRESULT QueryResult
= { { 0 } };
1370 SHIMENG_INFO("(%wZ, %p)\n", ProcessImage
, pShimData
);
1372 if (!SeiGetShimData(ProcessImage
, pShimData
, &hsdb
, &QueryResult
))
1374 SHIMENG_FAIL("Failed to get shim data\n");
1378 g_bShimDuringInit
= TRUE
;
1379 SeiInit(ProcessImage
, hsdb
, &QueryResult
);
1380 g_bShimDuringInit
= FALSE
;
1382 SdbReleaseDatabase(hsdb
);
1385 VOID NTAPI
SE_InstallAfterInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
1387 NotifyShims(SHIM_NOTIFY_ATTACH
, NULL
);
1390 VOID NTAPI
SE_ProcessDying(VOID
)
1392 SHIMENG_MSG("()\n");
1393 NotifyShims(SHIM_NOTIFY_DETACH
, NULL
);
1396 VOID WINAPI
SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
1398 PHOOKMODULEINFO HookModuleInfo
;
1399 SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit
? "" : "AFTER ", &LdrEntry
->BaseDllName
);
1401 HookModuleInfo
= SeiFindHookModuleInfo(&LdrEntry
->BaseDllName
, NULL
);
1404 ASSERT(HookModuleInfo
->BaseAddress
== NULL
);
1405 HookModuleInfo
->BaseAddress
= LdrEntry
->DllBase
;
1406 SeiResolveAPI(HookModuleInfo
);
1409 SeiHookImports(LdrEntry
);
1411 NotifyShims(SHIM_REASON_DLL_LOAD
, LdrEntry
);
1414 VOID WINAPI
SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
1416 SHIMENG_INFO("(%p)\n", LdrEntry
);
1418 /* Should we unhook here? */
1420 NotifyShims(SHIM_REASON_DLL_UNLOAD
, LdrEntry
);
1423 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
)
1425 SHIMENG_INFO("(%p)\n", BaseAddress
);
1427 return SeiGetShimModuleInfo(BaseAddress
) != NULL
;