2 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define WIN32_NO_STATUS
24 /* Make sure we don't include apphelp logging */
25 #define APPHELP_NOSDBPAPI
30 typedef FARPROC(WINAPI
* GETPROCADDRESSPROC
)(HINSTANCE
, LPCSTR
);
33 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
);
34 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
);
37 extern HMODULE g_hInstance
;
38 ULONG g_ShimEngDebugLevel
= 0xffffffff;
39 BOOL g_bComPlusImage
= FALSE
;
40 BOOL g_bShimDuringInit
= FALSE
;
41 BOOL g_bInternalHooksUsed
= FALSE
;
42 static ARRAY g_pShimInfo
; /* PSHIMMODULE */
43 static ARRAY g_pHookArray
; /* HOOKMODULEINFO */
45 HOOKAPIEX g_IntHookEx
[] =
48 "kernel32.dll", /* LibraryName */
49 "GetProcAddress", /* FunctionName */
50 StubGetProcAddress
, /* ReplacementFunction*/
51 NULL
, /* OriginalFunction */
57 static inline BOOL
ARRAY_InitWorker(PARRAY Array
, DWORD ItemSize
)
60 Array
->Size__
= Array
->MaxSize__
= 0;
61 Array
->ItemSize__
= ItemSize
;
66 static inline BOOL
ARRAY_EnsureSize(PARRAY Array
, DWORD ItemSize
, DWORD GrowWith
)
72 ASSERT(ItemSize
== Array
->ItemSize__
);
74 if (Array
->MaxSize__
> Array
->Size__
)
77 Count
= Array
->Size__
+ GrowWith
;
78 pNewData
= SeiAlloc(Count
* ItemSize
);
82 SHIMENG_FAIL("Failed to allocate %d bytes\n", Count
* ItemSize
);
85 Array
->MaxSize__
= Count
;
89 memcpy(pNewData
, Array
->Data__
, Array
->Size__
* ItemSize
);
90 SeiFree(Array
->Data__
);
92 Array
->Data__
= pNewData
;
97 static inline PVOID
ARRAY_AppendWorker(PARRAY Array
, DWORD ItemSize
, DWORD GrowWith
)
101 if (!ARRAY_EnsureSize(Array
, ItemSize
, GrowWith
))
104 pData
= Array
->Data__
;
105 pData
+= (Array
->Size__
* ItemSize
);
111 static inline PVOID
ARRAY_AtWorker(PARRAY Array
, DWORD ItemSize
, DWORD n
)
116 ASSERT(ItemSize
== Array
->ItemSize__
);
117 ASSERT(n
< Array
->Size__
);
119 pData
= Array
->Data__
;
120 return pData
+ (n
* ItemSize
);
124 #define ARRAY_Init(Array, TypeOfArray) ARRAY_InitWorker((Array), sizeof(TypeOfArray))
125 #define ARRAY_Append(Array, TypeOfArray) (TypeOfArray*)ARRAY_AppendWorker((Array), sizeof(TypeOfArray), 5)
126 #define ARRAY_At(Array, TypeOfArray, at) (TypeOfArray*)ARRAY_AtWorker((Array), sizeof(TypeOfArray), at)
127 #define ARRAY_Size(Array) (Array)->Size__
130 VOID
SeiInitDebugSupport(VOID
)
132 static const UNICODE_STRING DebugKey
= RTL_CONSTANT_STRING(L
"SHIMENG_DEBUG_LEVEL");
133 UNICODE_STRING DebugValue
;
138 RtlInitEmptyUnicodeString(&DebugValue
, Buffer
, sizeof(Buffer
));
140 Status
= RtlQueryEnvironmentVariable_U(NULL
, &DebugKey
, &DebugValue
);
142 if (NT_SUCCESS(Status
))
144 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue
, 10, &NewLevel
)))
147 g_ShimEngDebugLevel
= NewLevel
;
152 * Outputs diagnostic info.
154 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
155 * SHIM_WARN, SHIM_INFO].
156 * @param [in] FunctionName The function this log should be attributed to.
157 * @param [in] Format The format string.
158 * @param ... Variable arguments providing additional information.
160 * @return Success: TRUE Failure: FALSE.
162 BOOL WINAPIV
SeiDbgPrint(SEI_LOG_LEVEL Level
, PCSTR Function
, PCSTR Format
, ...)
165 char* Current
= Buffer
;
166 const char* LevelStr
;
167 size_t Length
= sizeof(Buffer
);
171 if (g_ShimEngDebugLevel
== 0xffffffff)
172 SeiInitDebugSupport();
174 if (Level
> g_ShimEngDebugLevel
)
197 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] [%s] ", LevelStr
, Function
);
199 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] ", LevelStr
);
204 va_start(ArgList
, Format
);
205 hr
= StringCchVPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, Format
, ArgList
);
210 DbgPrint("%s", Buffer
);
215 PVOID
SeiGetModuleFromAddress(PVOID addr
)
217 PVOID hModule
= NULL
;
218 RtlPcToFileHeader(addr
, &hModule
);
224 /* TODO: Guard against recursive calling / calling init multiple times! */
225 VOID
NotifyShims(DWORD dwReason
, PVOID Info
)
229 for (n
= 0; n
< ARRAY_Size(&g_pShimInfo
); ++n
)
231 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, n
);
232 if (!pShimModule
->pNotifyShims
)
235 pShimModule
->pNotifyShims(dwReason
, Info
);
241 VOID
SeiCheckComPlusImage(PVOID BaseAddress
)
243 ULONG ComSectionSize
;
244 g_bComPlusImage
= RtlImageDirectoryEntryToData(BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
, &ComSectionSize
) != NULL
;
246 SHIMENG_INFO("COM+ executable %s\n", g_bComPlusImage
? "TRUE" : "FALSE");
250 PSHIMMODULE
SeiGetShimModuleInfo(PVOID BaseAddress
)
254 for (n
= 0; n
< ARRAY_Size(&g_pShimInfo
); ++n
)
256 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, n
);
258 if (pShimModule
->BaseAddress
== BaseAddress
)
264 PSHIMMODULE
SeiCreateShimModuleInfo(PCWSTR DllName
, PVOID BaseAddress
)
266 static const ANSI_STRING GetHookAPIs
= RTL_CONSTANT_STRING("GetHookAPIs");
267 static const ANSI_STRING NotifyShims
= RTL_CONSTANT_STRING("NotifyShims");
268 PSHIMMODULE
* pData
, Data
;
269 PVOID pGetHookAPIs
, pNotifyShims
;
271 if (!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress
, (PANSI_STRING
)&GetHookAPIs
, 0, &pGetHookAPIs
)) ||
272 !NT_SUCCESS(LdrGetProcedureAddress(BaseAddress
, (PANSI_STRING
)&NotifyShims
, 0, &pNotifyShims
)))
274 SHIMENG_WARN("Failed to resolve entry points for %S\n", DllName
);
278 pData
= ARRAY_Append(&g_pShimInfo
, PSHIMMODULE
);
282 *pData
= SeiAlloc(sizeof(SHIMMODULE
));
286 RtlCreateUnicodeString(&Data
->Name
, DllName
);
287 Data
->BaseAddress
= BaseAddress
;
289 Data
->pGetHookAPIs
= pGetHookAPIs
;
290 Data
->pNotifyShims
= pNotifyShims
;
292 ARRAY_Init(&Data
->EnabledShims
, PSHIMINFO
);
297 VOID
SeiAppendHookInfo(PSHIMMODULE pShimModuleInfo
, PHOOKAPIEX pHookApi
, DWORD dwHookCount
)
299 PSHIMINFO
* pData
, Data
;
301 pData
= ARRAY_Append(&pShimModuleInfo
->EnabledShims
, PSHIMINFO
);
305 *pData
= SeiAlloc(sizeof(SHIMINFO
));
308 Data
->pHookApi
= pHookApi
;
309 Data
->dwHookCount
= dwHookCount
;
310 Data
->pShimModule
= pShimModuleInfo
;
313 PHOOKMODULEINFO
SeiFindHookModuleInfo(PUNICODE_STRING ModuleName
, PVOID BaseAddress
)
317 for (n
= 0; n
< ARRAY_Size(&g_pHookArray
); ++n
)
319 PHOOKMODULEINFO pModuleInfo
= ARRAY_At(&g_pHookArray
, HOOKMODULEINFO
, n
);
321 if (BaseAddress
&& BaseAddress
== pModuleInfo
->BaseAddress
)
324 if (!BaseAddress
&& RtlEqualUnicodeString(ModuleName
, &pModuleInfo
->Name
, TRUE
))
331 PHOOKMODULEINFO
SeiFindHookModuleInfoForImportDescriptor(PBYTE DllBase
, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
)
333 UNICODE_STRING DllName
;
337 if (!RtlCreateUnicodeStringFromAsciiz(&DllName
, (PCSZ
)(DllBase
+ ImportDescriptor
->Name
)))
339 SHIMENG_FAIL("Unable to convert dll name to unicode\n");
343 Success
= LdrGetDllHandle(NULL
, NULL
, &DllName
, &DllHandle
);
344 RtlFreeUnicodeString(&DllName
);
346 if (!NT_SUCCESS(Success
))
348 SHIMENG_FAIL("Unable to get module handle for %wZ\n", &DllName
);
352 return SeiFindHookModuleInfo(NULL
, DllHandle
);
355 static LPCWSTR
SeiGetStringPtr(PDB pdb
, TAGID tag
, TAG type
)
357 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
358 if (tagEntry
== TAGID_NULL
)
361 return SdbGetStringTagPtr(pdb
, tagEntry
);
364 static DWORD
SeiGetDWORD(PDB pdb
, TAGID tag
, TAG type
)
366 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
367 if (tagEntry
== TAGID_NULL
)
370 return SdbReadDWORDTag(pdb
, tagEntry
, TAGID_NULL
);
374 static VOID
SeiAddShim(TAGREF trShimRef
, PARRAY pShimRef
)
378 Data
= ARRAY_Append(pShimRef
, TAGREF
);
385 static VOID
SeiSetLayerEnvVar(LPCWSTR wszLayer
)
388 UNICODE_STRING VarName
= RTL_CONSTANT_STRING(L
"__COMPAT_LAYER");
389 UNICODE_STRING Value
;
391 RtlInitUnicodeString(&Value
, wszLayer
);
393 Status
= RtlSetEnvironmentVariable(NULL
, &VarName
, &Value
);
394 if (NT_SUCCESS(Status
))
395 SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName
, &Value
);
397 SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName
, Status
);
400 #define MAX_LAYER_LENGTH 256
402 static VOID
SeiBuildShimRefArray(HSDB hsdb
, SDBQUERYRESULT
* pQuery
, PARRAY pShimRef
)
404 WCHAR wszLayerEnvVar
[MAX_LAYER_LENGTH
] = { 0 };
407 for (n
= 0; n
< pQuery
->dwExeCount
; ++n
)
411 if (SdbTagRefToTagID(hsdb
, pQuery
->atrExes
[n
], &pdb
, &tag
))
413 LPCWSTR ExeName
= SeiGetStringPtr(pdb
, tag
, TAG_NAME
);
414 TAGID ShimRef
= SdbFindFirstTag(pdb
, tag
, TAG_SHIM_REF
);
417 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Exe(%S))\n", ExeName
);
419 while (ShimRef
!= TAGID_NULL
)
422 if (SdbTagIDToTagRef(hsdb
, pdb
, ShimRef
, &trShimRef
))
423 SeiAddShim(trShimRef
, pShimRef
);
426 ShimRef
= SdbFindNextTag(pdb
, tag
, ShimRef
);
429 /* Handle FLAG_REF */
434 for (n
= 0; n
< pQuery
->dwLayerCount
; ++n
)
438 if (SdbTagRefToTagID(hsdb
, pQuery
->atrLayers
[n
], &pdb
, &tag
))
440 LPCWSTR LayerName
= SeiGetStringPtr(pdb
, tag
, TAG_NAME
);
441 TAGID ShimRef
= SdbFindFirstTag(pdb
, tag
, TAG_SHIM_REF
);
445 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Layer(%S))\n", LayerName
);
446 if (wszLayerEnvVar
[0])
447 StringCchCatW(wszLayerEnvVar
, ARRAYSIZE(wszLayerEnvVar
), L
" ");
448 hr
= StringCchCatW(wszLayerEnvVar
, ARRAYSIZE(wszLayerEnvVar
), LayerName
);
451 SHIMENG_FAIL("Unable to append %S\n", LayerName
);
455 while (ShimRef
!= TAGID_NULL
)
458 if (SdbTagIDToTagRef(hsdb
, pdb
, ShimRef
, &trShimRef
))
459 SeiAddShim(trShimRef
, pShimRef
);
461 ShimRef
= SdbFindNextTag(pdb
, tag
, ShimRef
);
464 /* Handle FLAG_REF */
467 if (wszLayerEnvVar
[0])
468 SeiSetLayerEnvVar(wszLayerEnvVar
);
472 VOID
SeiAddHooks(PHOOKAPIEX hooks
, DWORD dwHookCount
, PSHIMINFO pShim
)
475 UNICODE_STRING UnicodeModName
;
478 RtlInitEmptyUnicodeString(&UnicodeModName
, Buf
, sizeof(Buf
));
480 for (n
= 0; n
< dwHookCount
; ++n
)
482 ANSI_STRING AnsiString
;
484 PHOOKAPIEX hook
= hooks
+ n
;
485 PHOOKAPIEX
* pHookApi
;
486 PHOOKMODULEINFO HookModuleInfo
;
488 RtlInitAnsiString(&AnsiString
, hook
->LibraryName
);
489 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeModName
, &AnsiString
, FALSE
)))
491 SHIMENG_FAIL("Unable to convert %s to Unicode\n", hook
->LibraryName
);
495 RtlInitAnsiString(&AnsiString
, hook
->FunctionName
);
496 if (NT_SUCCESS(LdrGetDllHandle(NULL
, 0, &UnicodeModName
, &DllHandle
)))
501 if (!NT_SUCCESS(LdrGetProcedureAddress(DllHandle
, &AnsiString
, 0, &ProcAddress
)))
503 SHIMENG_FAIL("Unable to retrieve %s!%s\n", hook
->LibraryName
, hook
->FunctionName
);
507 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, DllHandle
);
508 hook
->OriginalFunction
= ProcAddress
;
512 HookModuleInfo
= SeiFindHookModuleInfo(&UnicodeModName
, NULL
);
518 HookModuleInfo
= ARRAY_Append(&g_pHookArray
, HOOKMODULEINFO
);
522 HookModuleInfo
->BaseAddress
= DllHandle
;
523 ARRAY_Init(&HookModuleInfo
->HookApis
, PHOOKAPIEX
);
524 RtlCreateUnicodeString(&HookModuleInfo
->Name
, UnicodeModName
.Buffer
);
527 hook
->pShimInfo
= pShim
;
529 for (j
= 0; j
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++j
)
531 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, j
);
532 int CmpResult
= strcmp(hook
->FunctionName
, HookApi
->FunctionName
);
535 /* Multiple hooks on one function? --> use ApiLink */
536 SHIMENG_FAIL("Multiple hooks on one API is not yet supported!\n");
540 pHookApi
= ARRAY_Append(&HookModuleInfo
->HookApis
, PHOOKAPIEX
);
546 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
)
548 char szOrdProcName
[10] = "";
549 LPCSTR lpPrintName
= lpProcName
;
550 PVOID Addr
= _ReturnAddress();
551 PHOOKMODULEINFO HookModuleInfo
;
552 FARPROC proc
= ((GETPROCADDRESSPROC
)g_IntHookEx
[0].OriginalFunction
)(hModule
, lpProcName
);
554 if (!HIWORD(lpProcName
))
556 sprintf(szOrdProcName
, "#%lu", (DWORD
)lpProcName
);
557 lpPrintName
= szOrdProcName
;
560 Addr
= SeiGetModuleFromAddress(Addr
);
561 if (SE_IsShimDll(Addr
))
563 SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule
, lpPrintName
);
567 SHIMENG_MSG("(GetProcAddress(%p!%s) => %p\n", hModule
, lpProcName
, lpPrintName
);
569 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, hModule
);
571 /* FIXME: Ordinal not yet supported */
572 if (HookModuleInfo
&& HIWORD(lpProcName
))
575 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
577 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
578 int CmpResult
= strcmp(lpProcName
, HookApi
->FunctionName
);
581 SHIMENG_MSG("Redirecting %p to %p\n", proc
, HookApi
->ReplacementFunction
);
582 proc
= HookApi
->ReplacementFunction
;
591 VOID
SeiResolveAPIs(VOID
)
595 /* Enumerate all Shim modules */
596 for (mod
= 0; mod
< ARRAY_Size(&g_pShimInfo
); ++mod
)
598 PSHIMMODULE pShimModule
= *ARRAY_At(&g_pShimInfo
, PSHIMMODULE
, mod
);
599 DWORD dwShimCount
= ARRAY_Size(&pShimModule
->EnabledShims
);
601 /* Enumerate all Shims */
602 for (n
= 0; n
< dwShimCount
; ++n
)
604 PSHIMINFO pShim
= *ARRAY_At(&pShimModule
->EnabledShims
, PSHIMINFO
, n
);
606 PHOOKAPIEX hooks
= pShim
->pHookApi
;
607 DWORD dwHookCount
= pShim
->dwHookCount
;
609 SeiAddHooks(hooks
, dwHookCount
, pShim
);
614 VOID
SeiAddInternalHooks(DWORD dwNumHooks
)
618 g_bInternalHooksUsed
= FALSE
;
622 SeiAddHooks(g_IntHookEx
, ARRAYSIZE(g_IntHookEx
), NULL
);
623 g_bInternalHooksUsed
= TRUE
;
626 VOID
SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk
, PHOOKAPIEX HookApi
, PLDR_DATA_TABLE_ENTRY LdrEntry
)
628 ULONG OldProtection
= 0;
633 SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
635 Ptr
= &FirstThunk
->u1
.Function
;
636 Size
= sizeof(FirstThunk
->u1
.Function
);
637 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, PAGE_EXECUTE_READWRITE
, &OldProtection
);
639 if (!NT_SUCCESS(Status
))
641 SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk
->u1
.Function
);
645 SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk
->u1
.Function
, HookApi
->ReplacementFunction
);
647 FirstThunk
->u1
.Function
= (ULONGLONG
)HookApi
->ReplacementFunction
;
649 FirstThunk
->u1
.Function
= (DWORD
)HookApi
->ReplacementFunction
;
652 Size
= sizeof(FirstThunk
->u1
.Function
);
653 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, OldProtection
, &OldProtection
);
655 if (!NT_SUCCESS(Status
))
657 SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk
->u1
.Function
);
661 /* Level(INFO) [SeiPrintExcludeInfo] Module "kernel32.dll" excluded for shim VistaRTMVersionLie, API "NTDLL.DLL!RtlGetVersion", because it is in System32/WinSXS. */
663 VOID
SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry
)
666 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
667 PBYTE DllBase
= LdrEntry
->DllBase
;
669 if (SE_IsShimDll(DllBase
) || g_hInstance
== LdrEntry
->DllBase
)
671 SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
675 ImportDescriptor
= RtlImageDirectoryEntryToData(DllBase
, TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &Size
);
676 if (!ImportDescriptor
)
678 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
682 SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
684 for ( ;ImportDescriptor
->Name
&& ImportDescriptor
->OriginalFirstThunk
; ImportDescriptor
++)
686 PHOOKMODULEINFO HookModuleInfo
;
688 /* Do we have hooks for this module? */
689 HookModuleInfo
= SeiFindHookModuleInfoForImportDescriptor(DllBase
, ImportDescriptor
);
693 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
696 for (n
= 0; n
< ARRAY_Size(&HookModuleInfo
->HookApis
); ++n
)
699 PHOOKAPIEX HookApi
= *ARRAY_At(&HookModuleInfo
->HookApis
, PHOOKAPIEX
, n
);
701 OriginalThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->OriginalFirstThunk
);
702 FirstThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->FirstThunk
);
704 for (;OriginalThunk
->u1
.AddressOfData
&& FirstThunk
->u1
.Function
; OriginalThunk
++, FirstThunk
++)
706 if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk
->u1
.AddressOfData
))
708 PIMAGE_IMPORT_BY_NAME ImportName
;
710 ImportName
= (PIMAGE_IMPORT_BY_NAME
)(DllBase
+ OriginalThunk
->u1
.AddressOfData
);
711 if (!strcmp((PCSTR
)ImportName
->Name
, HookApi
->FunctionName
))
713 SeiPatchNewImport(FirstThunk
, HookApi
, LdrEntry
);
715 /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
721 SHIMENG_FAIL("Ordinals not yet supported\n");
728 /* One entry not found. */
730 SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
732 SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, dwFound
, &LdrEntry
->BaseDllName
);
740 VOID
PatchNewModules(PPEB Peb
)
742 PLIST_ENTRY ListHead
, ListEntry
;
743 PLDR_DATA_TABLE_ENTRY LdrEntry
;
745 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
746 ListEntry
= ListHead
->Flink
;
748 while (ListHead
!= ListEntry
)
750 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
751 SeiHookImports(LdrEntry
);
753 ListEntry
= ListEntry
->Flink
;
759 Level(INFO) Using USER apphack flags 0x2080000
762 VOID
SeiInit(PUNICODE_STRING ProcessImage
, HSDB hsdb
, SDBQUERYRESULT
* pQuery
)
766 DWORD dwTotalHooks
= 0;
768 PPEB Peb
= NtCurrentPeb();
770 /* We should only be called once! */
771 ASSERT(g_pShimInfo
.ItemSize__
== 0);
773 ARRAY_Init(&ShimRefArray
, TAGREF
);
774 ARRAY_Init(&g_pShimInfo
, PSHIMMODULE
);
775 ARRAY_Init(&g_pHookArray
, HOOKMODULEINFO
);
777 SeiCheckComPlusImage(Peb
->ImageBaseAddress
);
780 if (pQuery->trApphelp)
781 SeiDisplayAppHelp(?pQuery->trApphelp?);
784 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(ExePath(%wZ))\n", ProcessImage
);
785 SeiBuildShimRefArray(hsdb
, pQuery
, &ShimRefArray
);
786 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Complete)\n");
788 SHIMENG_INFO("Got %d shims\n", ARRAY_Size(&ShimRefArray
));
790 SeiBuildGlobalInclExclList()
793 for (n
= 0; n
< ARRAY_Size(&ShimRefArray
); ++n
)
798 TAGREF tr
= *ARRAY_At(&ShimRefArray
, TAGREF
, n
);
800 if (SdbTagRefToTagID(hsdb
, tr
, &pdb
, &ShimRef
))
802 LPCWSTR ShimName
, DllName
, CommandLine
= NULL
;
804 WCHAR FullNameBuffer
[MAX_PATH
];
805 UNICODE_STRING UnicodeDllName
;
807 PSHIMMODULE pShimModuleInfo
= NULL
;
808 ANSI_STRING AnsiCommandLine
= RTL_CONSTANT_STRING("");
812 ShimName
= SeiGetStringPtr(pdb
, ShimRef
, TAG_NAME
);
815 SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", tr
);
819 CommandLine
= SeiGetStringPtr(pdb
, ShimRef
, TAG_COMMAND_LINE
);
820 if (CommandLine
&& *CommandLine
)
822 RtlInitUnicodeString(&UnicodeDllName
, CommandLine
);
823 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiCommandLine
, &UnicodeDllName
, TRUE
)))
825 SHIMENG_INFO("COMMAND LINE %s for %S", AnsiCommandLine
.Buffer
, ShimName
);
829 AnsiCommandLine
.Buffer
= "";
834 ShimTag
= SeiGetDWORD(pdb
, ShimRef
, TAG_SHIM_TAGID
);
837 SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName
);
841 if (!SdbGetAppPatchDir(NULL
, FullNameBuffer
, ARRAYSIZE(FullNameBuffer
)))
843 SHIMENG_WARN("Failed to get the AppPatch dir\n");
847 DllName
= SeiGetStringPtr(pdb
, ShimTag
, TAG_DLLFILE
);
848 if (DllName
== NULL
||
849 !SUCCEEDED(StringCchCatW(FullNameBuffer
, ARRAYSIZE(FullNameBuffer
), L
"\\")) ||
850 !SUCCEEDED(StringCchCatW(FullNameBuffer
, ARRAYSIZE(FullNameBuffer
), DllName
)))
852 SHIMENG_WARN("Failed to build a full path for %S\n", ShimName
);
856 RtlInitUnicodeString(&UnicodeDllName
, FullNameBuffer
);
857 if (NT_SUCCESS(LdrGetDllHandle(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
859 pShimModuleInfo
= SeiGetShimModuleInfo(BaseAddress
);
861 else if (!NT_SUCCESS(LdrLoadDll(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
863 SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName
, ShimName
);
866 if (!pShimModuleInfo
)
868 pShimModuleInfo
= SeiCreateShimModuleInfo(DllName
, BaseAddress
);
869 if (!pShimModuleInfo
)
871 SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName
);
876 SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress
, &UnicodeDllName
);
877 SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName
, ShimName
);
879 pHookApi
= pShimModuleInfo
->pGetHookAPIs(AnsiCommandLine
.Buffer
, ShimName
, &dwHookCount
);
880 SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount
, &UnicodeDllName
, ShimName
);
882 SeiAppendHookInfo(pShimModuleInfo
, pHookApi
, dwHookCount
);
884 if (CommandLine
&& *CommandLine
)
885 RtlFreeAnsiString(&AnsiCommandLine
);
887 dwTotalHooks
+= dwHookCount
;
888 /*SeiBuildInclExclList*/
892 SeiAddInternalHooks(dwTotalHooks
);
894 PatchNewModules(Peb
);
899 BOOL
SeiGetShimData(PUNICODE_STRING ProcessImage
, PVOID pShimData
, HSDB
* pHsdb
, SDBQUERYRESULT
* pQuery
)
901 static const UNICODE_STRING ForbiddenShimmingApps
[] = {
902 RTL_CONSTANT_STRING(L
"ntsd.exe"),
903 RTL_CONSTANT_STRING(L
"windbg.exe"),
905 RTL_CONSTANT_STRING(L
"slsvc.exe"),
908 static const UNICODE_STRING BackSlash
= RTL_CONSTANT_STRING(L
"\\");
909 static const UNICODE_STRING ForwdSlash
= RTL_CONSTANT_STRING(L
"/");
910 UNICODE_STRING ProcessName
;
911 USHORT Back
, Forward
;
915 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &BackSlash
, &Back
)))
918 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &ForwdSlash
, &Forward
)))
925 Back
+= sizeof(WCHAR
);
927 ProcessName
.Buffer
= ProcessImage
->Buffer
+ Back
/ sizeof(WCHAR
);
928 ProcessName
.Length
= ProcessImage
->Length
- Back
;
929 ProcessName
.MaximumLength
= ProcessImage
->MaximumLength
- Back
;
931 for (n
= 0; n
< ARRAYSIZE(ForbiddenShimmingApps
); ++n
)
933 if (RtlEqualUnicodeString(&ProcessName
, ForbiddenShimmingApps
+ n
, TRUE
))
935 SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps
+ n
);
940 /* We should probably load all db's here, but since we do not support that yet... */
941 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
944 if (SdbUnpackAppCompatData(hsdb
, ProcessImage
->Buffer
, pShimData
, pQuery
))
949 SdbReleaseDatabase(hsdb
);
956 VOID NTAPI
SE_InstallBeforeInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
959 SDBQUERYRESULT QueryResult
= { { 0 } };
960 SHIMENG_MSG("(%wZ, %p)\n", ProcessImage
, pShimData
);
962 if (!SeiGetShimData(ProcessImage
, pShimData
, &hsdb
, &QueryResult
))
964 SHIMENG_FAIL("Failed to get shim data\n");
968 g_bShimDuringInit
= TRUE
;
969 SeiInit(ProcessImage
, hsdb
, &QueryResult
);
970 g_bShimDuringInit
= FALSE
;
972 SdbReleaseDatabase(hsdb
);
975 VOID NTAPI
SE_InstallAfterInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
977 NotifyShims(SHIM_NOTIFY_ATTACH
, NULL
);
980 VOID NTAPI
SE_ProcessDying(VOID
)
983 NotifyShims(SHIM_NOTIFY_DETACH
, NULL
);
986 VOID WINAPI
SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
988 SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit
? "" : "AFTER ", &LdrEntry
->BaseDllName
);
989 NotifyShims(SHIM_REASON_DLL_LOAD
, LdrEntry
);
992 VOID WINAPI
SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
994 SHIMENG_MSG("(%p)\n", LdrEntry
);
995 NotifyShims(SHIM_REASON_DLL_UNLOAD
, LdrEntry
);
998 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
)
1000 SHIMENG_MSG("(%p)\n", BaseAddress
);
1002 return SeiGetShimModuleInfo(BaseAddress
) != NULL
;