2 * Copyright 2015-2017 Mark Jansen
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
25 /* Make sure we don't include apphelp logging */
26 #define APPHELP_NOSDBPAPI
31 typedef FARPROC(WINAPI
* GETPROCADDRESSPROC
)(HINSTANCE
, LPCSTR
);
34 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
);
35 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
);
38 extern HMODULE g_hInstance
;
39 ULONG g_ShimEngDebugLevel
= 0xffffffff;
40 BOOL g_bComPlusImage
= FALSE
;
41 BOOL g_bShimDuringInit
= FALSE
;
42 BOOL g_bInternalHooksUsed
= FALSE
;
43 static ARRAY g_pShimInfo
; /* SHIMMODULE */
44 static ARRAY g_pHookArray
; /* HOOKMODULEINFO */
46 HOOKAPIEX g_IntHookEx
[] =
49 "kernel32.dll", /* LibraryName */
50 "GetProcAddress", /* FunctionName */
51 StubGetProcAddress
, /* ReplacementFunction*/
52 NULL
, /* OriginalFunction */
53 { NULL
}, /* ModuleLink */
54 { NULL
} /* ApiLink */
61 static BOOL
ARRAY_EnsureSize(PARRAY Array
, DWORD ItemSize
, DWORD GrowWith
)
66 if (Array
->MaxSize
> Array
->Size
)
69 Count
= Array
->Size
+ GrowWith
;
70 pNewData
= SeiAlloc(Count
* ItemSize
);
74 SHIMENG_FAIL("Failed to allocate %d bytes\n", Count
* ItemSize
);
77 Array
->MaxSize
= Count
;
81 memcpy(pNewData
, Array
->Data
, Array
->Size
* ItemSize
);
84 Array
->Data
= pNewData
;
91 VOID
SeiInitDebugSupport(VOID
)
93 static const UNICODE_STRING DebugKey
= RTL_CONSTANT_STRING(L
"SHIMENG_DEBUG_LEVEL");
94 UNICODE_STRING DebugValue
;
99 RtlInitEmptyUnicodeString(&DebugValue
, Buffer
, sizeof(Buffer
));
101 Status
= RtlQueryEnvironmentVariable_U(NULL
, &DebugKey
, &DebugValue
);
103 if (NT_SUCCESS(Status
))
105 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue
, 10, &NewLevel
)))
108 g_ShimEngDebugLevel
= NewLevel
;
113 * Outputs diagnostic info.
115 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
116 * SHIM_WARN, SHIM_INFO].
117 * @param [in] FunctionName The function this log should be attributed to.
118 * @param [in] Format The format string.
119 * @param ... Variable arguments providing additional information.
121 * @return Success: TRUE Failure: FALSE.
123 BOOL WINAPIV
SeiDbgPrint(SEI_LOG_LEVEL Level
, PCSTR Function
, PCSTR Format
, ...)
126 char* Current
= Buffer
;
127 const char* LevelStr
;
128 size_t Length
= sizeof(Buffer
);
132 if (g_ShimEngDebugLevel
== 0xffffffff)
133 SeiInitDebugSupport();
135 if (Level
> g_ShimEngDebugLevel
)
158 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] [%s] ", LevelStr
, Function
);
160 hr
= StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s] ", LevelStr
);
165 va_start(ArgList
, Format
);
166 hr
= StringCchVPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, Format
, ArgList
);
171 DbgPrint("%s", Buffer
);
176 PVOID
SeiGetModuleFromAddress(PVOID addr
)
178 PVOID hModule
= NULL
;
179 RtlPcToFileHeader(addr
, &hModule
);
185 /* TODO: Guard against recursive calling / calling init multiple times! */
186 VOID
NotifyShims(DWORD dwReason
, PVOID Info
)
191 Data
= g_pShimInfo
.Data
;
192 for (n
= 0; n
< g_pShimInfo
.Size
; ++n
)
194 if (!Data
[n
].pNotifyShims
)
197 Data
[n
].pNotifyShims(dwReason
, Info
);
203 VOID
SeiCheckComPlusImage(PVOID BaseAddress
)
205 ULONG ComSectionSize
;
206 g_bComPlusImage
= RtlImageDirectoryEntryToData(BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
, &ComSectionSize
) != NULL
;
208 SHIMENG_INFO("COM+ executable %s\n", g_bComPlusImage
? "TRUE" : "FALSE");
212 PSHIMMODULE
SeiGetShimInfo(PVOID BaseAddress
)
217 Data
= g_pShimInfo
.Data
;
218 for (n
= 0; n
< g_pShimInfo
.Size
; ++n
)
220 if (Data
[n
].BaseAddress
== BaseAddress
)
226 PSHIMMODULE
SeiCreateShimInfo(PCWSTR DllName
, PVOID BaseAddress
)
228 static const ANSI_STRING GetHookAPIs
= RTL_CONSTANT_STRING("GetHookAPIs");
229 static const ANSI_STRING NotifyShims
= RTL_CONSTANT_STRING("NotifyShims");
231 PVOID pGetHookAPIs
, pNotifyShims
;
233 if (!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress
, (PANSI_STRING
)&GetHookAPIs
, 0, &pGetHookAPIs
)) ||
234 !NT_SUCCESS(LdrGetProcedureAddress(BaseAddress
, (PANSI_STRING
)&NotifyShims
, 0, &pNotifyShims
)))
236 SHIMENG_WARN("Failed to resolve entry points for %S\n", DllName
);
240 if (!ARRAY_EnsureSize(&g_pShimInfo
, sizeof(SHIMMODULE
), 5))
243 Data
= g_pShimInfo
.Data
;
244 Data
+= g_pShimInfo
.Size
;
247 RtlCreateUnicodeString(&Data
->Name
, DllName
);
248 Data
->BaseAddress
= BaseAddress
;
250 Data
->pGetHookAPIs
= pGetHookAPIs
;
251 Data
->pNotifyShims
= pNotifyShims
;
253 Data
->HookApis
.Data
= NULL
;
254 Data
->HookApis
.Size
= 0;
255 Data
->HookApis
.MaxSize
= 0;
260 VOID
SeiAppendHookInfo(PSHIMMODULE pShimInfo
, PHOOKAPIEX pHookApi
, DWORD dwHookCount
)
262 PHOOKAPIPOINTERS Data
;
263 if (!ARRAY_EnsureSize(&pShimInfo
->HookApis
, sizeof(HOOKAPIPOINTERS
), 5))
266 Data
= pShimInfo
->HookApis
.Data
;
267 Data
+= pShimInfo
->HookApis
.Size
;
269 Data
->pHookApi
= pHookApi
;
270 Data
->dwHookCount
= dwHookCount
;
271 pShimInfo
->HookApis
.Size
++;
274 PHOOKMODULEINFO
SeiFindHookModuleInfo(PUNICODE_STRING ModuleName
, PVOID BaseAddress
)
277 PHOOKMODULEINFO Data
= g_pHookArray
.Data
;
279 for (n
= 0; n
< g_pHookArray
.Size
; ++n
)
281 if (BaseAddress
&& BaseAddress
== Data
[n
].BaseAddress
)
284 if (!BaseAddress
&& RtlEqualUnicodeString(ModuleName
, &Data
[n
].Name
, TRUE
))
291 PHOOKMODULEINFO
SeiFindHookModuleInfoForImportDescriptor(PBYTE DllBase
, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
)
293 UNICODE_STRING DllName
;
297 if (!RtlCreateUnicodeStringFromAsciiz(&DllName
, (PCSZ
)(DllBase
+ ImportDescriptor
->Name
)))
299 SHIMENG_FAIL("Unable to convert dll name to unicode\n");
303 Success
= LdrGetDllHandle(NULL
, NULL
, &DllName
, &DllHandle
);
304 RtlFreeUnicodeString(&DllName
);
306 if (!NT_SUCCESS(Success
))
308 SHIMENG_FAIL("Unable to get module handle for %wZ\n", &DllName
);
312 return SeiFindHookModuleInfo(NULL
, DllHandle
);
315 static LPCWSTR
SeiGetStringPtr(PDB pdb
, TAGID tag
, TAG type
)
317 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
318 if (tagEntry
== TAGID_NULL
)
321 return SdbGetStringTagPtr(pdb
, tagEntry
);
324 static DWORD
SeiGetDWORD(PDB pdb
, TAGID tag
, TAG type
)
326 TAGID tagEntry
= SdbFindFirstTag(pdb
, tag
, type
);
327 if (tagEntry
== TAGID_NULL
)
330 return SdbReadDWORDTag(pdb
, tagEntry
, TAGID_NULL
);
334 static VOID
SeiAddShim(TAGREF trShimRef
, PARRAY pShimRef
)
337 if (!ARRAY_EnsureSize(pShimRef
, sizeof(TAGREF
), 10))
340 Data
= pShimRef
->Data
;
341 Data
[pShimRef
->Size
] = trShimRef
;
345 static VOID
SeiSetLayerEnvVar(LPCWSTR wszLayer
)
348 UNICODE_STRING VarName
= RTL_CONSTANT_STRING(L
"__COMPAT_LAYER");
349 UNICODE_STRING Value
;
351 RtlInitUnicodeString(&Value
, wszLayer
);
353 Status
= RtlSetEnvironmentVariable(NULL
, &VarName
, &Value
);
354 if (NT_SUCCESS(Status
))
355 SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName
, &Value
);
357 SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName
, Status
);
360 #define MAX_LAYER_LENGTH 256
362 static VOID
SeiBuildShimRefArray(HSDB hsdb
, SDBQUERYRESULT
* pQuery
, PARRAY pShimRef
)
364 WCHAR wszLayerEnvVar
[MAX_LAYER_LENGTH
] = { 0 };
367 for (n
= 0; n
< pQuery
->dwExeCount
; ++n
)
371 if (SdbTagRefToTagID(hsdb
, pQuery
->atrExes
[n
], &pdb
, &tag
))
373 LPCWSTR ExeName
= SeiGetStringPtr(pdb
, tag
, TAG_NAME
);
374 TAGID ShimRef
= SdbFindFirstTag(pdb
, tag
, TAG_SHIM_REF
);
377 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Exe(%S))\n", ExeName
);
379 while (ShimRef
!= TAGID_NULL
)
382 if (SdbTagIDToTagRef(hsdb
, pdb
, ShimRef
, &trShimRef
))
383 SeiAddShim(trShimRef
, pShimRef
);
386 ShimRef
= SdbFindNextTag(pdb
, tag
, ShimRef
);
389 /* Handle FLAG_REF */
394 for (n
= 0; n
< pQuery
->dwLayerCount
; ++n
)
398 if (SdbTagRefToTagID(hsdb
, pQuery
->atrLayers
[n
], &pdb
, &tag
))
400 LPCWSTR LayerName
= SeiGetStringPtr(pdb
, tag
, TAG_NAME
);
401 TAGID ShimRef
= SdbFindFirstTag(pdb
, tag
, TAG_SHIM_REF
);
405 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Layer(%S))\n", LayerName
);
406 if (wszLayerEnvVar
[0])
407 StringCchCatW(wszLayerEnvVar
, _countof(wszLayerEnvVar
), L
" ");
408 hr
= StringCchCatW(wszLayerEnvVar
, _countof(wszLayerEnvVar
), LayerName
);
411 SHIMENG_FAIL("Unable to append %S\n", LayerName
);
415 while (ShimRef
!= TAGID_NULL
)
418 if (SdbTagIDToTagRef(hsdb
, pdb
, ShimRef
, &trShimRef
))
419 SeiAddShim(trShimRef
, pShimRef
);
421 ShimRef
= SdbFindNextTag(pdb
, tag
, ShimRef
);
424 /* Handle FLAG_REF */
427 if (wszLayerEnvVar
[0])
428 SeiSetLayerEnvVar(wszLayerEnvVar
);
432 VOID
SeiAddHooks(PHOOKAPIEX hooks
, DWORD dwHookCount
)
435 UNICODE_STRING UnicodeModName
;
438 RtlInitEmptyUnicodeString(&UnicodeModName
, Buf
, sizeof(Buf
));
440 for (n
= 0; n
< dwHookCount
; ++n
)
442 ANSI_STRING AnsiString
;
444 PHOOKAPIEX hook
= hooks
+ n
;
445 PHOOKMODULEINFO HookModuleInfo
;
446 PSINGLE_LIST_ENTRY Entry
;
448 RtlInitAnsiString(&AnsiString
, hook
->LibraryName
);
449 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeModName
, &AnsiString
, FALSE
)))
451 SHIMENG_FAIL("Unable to convert %s to Unicode\n", hook
->LibraryName
);
455 RtlInitAnsiString(&AnsiString
, hook
->FunctionName
);
456 if (NT_SUCCESS(LdrGetDllHandle(NULL
, 0, &UnicodeModName
, &DllHandle
)))
461 if (!NT_SUCCESS(LdrGetProcedureAddress(DllHandle
, &AnsiString
, 0, &ProcAddress
)))
463 SHIMENG_FAIL("Unable to retrieve %s!%s\n", hook
->LibraryName
, hook
->FunctionName
);
467 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, DllHandle
);
468 hook
->OriginalFunction
= ProcAddress
;
472 HookModuleInfo
= SeiFindHookModuleInfo(&UnicodeModName
, NULL
);
478 if (!ARRAY_EnsureSize(&g_pHookArray
, sizeof(HOOKMODULEINFO
), 5))
481 HookModuleInfo
= g_pHookArray
.Data
;
482 HookModuleInfo
+= g_pHookArray
.Size
;
485 HookModuleInfo
->BaseAddress
= DllHandle
;
486 RtlCreateUnicodeString(&HookModuleInfo
->Name
, UnicodeModName
.Buffer
);
489 Entry
= &HookModuleInfo
->ModuleLink
;
491 while (Entry
&& Entry
->Next
)
493 PHOOKAPIEX HookApi
= CONTAINING_RECORD(Entry
->Next
, HOOKAPIEX
, ModuleLink
);
495 int CmpResult
= strcmp(hook
->FunctionName
, HookApi
->FunctionName
);
498 /* Multiple hooks on one function? --> use ApiLink */
499 SHIMENG_FAIL("Multiple hooks on one API is not yet supported!\n");
502 else if (CmpResult
< 0)
504 /* Break out of the loop to have the entry inserted 'in place' */
510 /* If Entry is not NULL, the item is not inserted yet, so link it at the end. */
513 hook
->ModuleLink
.Next
= Entry
->Next
;
514 Entry
->Next
= &hook
->ModuleLink
;
520 FARPROC WINAPI
StubGetProcAddress(HINSTANCE hModule
, LPCSTR lpProcName
)
522 char szOrdProcName
[10] = "";
523 LPCSTR lpPrintName
= lpProcName
;
524 PVOID Addr
= _ReturnAddress();
525 PHOOKMODULEINFO HookModuleInfo
;
526 FARPROC proc
= ((GETPROCADDRESSPROC
)g_IntHookEx
[0].OriginalFunction
)(hModule
, lpProcName
);
528 if (!HIWORD(lpProcName
))
530 sprintf(szOrdProcName
, "#%lu", (DWORD
)lpProcName
);
531 lpPrintName
= szOrdProcName
;
534 Addr
= SeiGetModuleFromAddress(Addr
);
535 if (SE_IsShimDll(Addr
))
537 SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule
, lpPrintName
);
541 SHIMENG_MSG("(GetProcAddress(%p!%s) => %p\n", hModule
, lpProcName
, lpPrintName
);
543 HookModuleInfo
= SeiFindHookModuleInfo(NULL
, hModule
);
545 /* FIXME: Ordinal not yet supported */
546 if (HookModuleInfo
&& HIWORD(lpProcName
))
548 PSINGLE_LIST_ENTRY Entry
;
550 Entry
= HookModuleInfo
->ModuleLink
.Next
;
554 PHOOKAPIEX HookApi
= CONTAINING_RECORD(Entry
, HOOKAPIEX
, ModuleLink
);
556 int CmpResult
= strcmp(lpProcName
, HookApi
->FunctionName
);
559 SHIMENG_MSG("Redirecting %p to %p\n", proc
, HookApi
->ReplacementFunction
);
560 proc
= HookApi
->ReplacementFunction
;
563 else if (CmpResult
< 0)
565 SHIMENG_MSG("Not found %s\n", lpProcName
);
566 /* We are not going to find it anymore.. */
577 VOID
SeiResolveAPIs(VOID
)
582 Data
= g_pShimInfo
.Data
;
584 /* Enumerate all Shim modules */
585 for (mod
= 0; mod
< g_pShimInfo
.Size
; ++mod
)
587 PHOOKAPIPOINTERS pShims
= Data
[mod
].HookApis
.Data
;
588 DWORD dwShimCount
= Data
[mod
].HookApis
.Size
;
590 /* Enumerate all Shims */
591 for (n
= 0; n
< dwShimCount
; ++n
)
593 PHOOKAPIEX hooks
= pShims
[n
].pHookApi
;
594 DWORD dwHookCount
= pShims
[n
].dwHookCount
;
596 SeiAddHooks(hooks
, dwHookCount
);
601 VOID
SeiAddInternalHooks(DWORD dwNumHooks
)
605 g_bInternalHooksUsed
= FALSE
;
609 SeiAddHooks(g_IntHookEx
, _countof(g_IntHookEx
));
610 g_bInternalHooksUsed
= TRUE
;
613 VOID
SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk
, PHOOKAPIEX HookApi
, PLDR_DATA_TABLE_ENTRY LdrEntry
)
615 ULONG OldProtection
= 0;
620 SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
622 Ptr
= &FirstThunk
->u1
.Function
;
623 Size
= sizeof(FirstThunk
->u1
.Function
);
624 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, PAGE_EXECUTE_READWRITE
, &OldProtection
);
626 if (!NT_SUCCESS(Status
))
628 SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk
->u1
.Function
);
632 SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk
->u1
.Function
, HookApi
->ReplacementFunction
);
634 FirstThunk
->u1
.Function
= (ULONGLONG
)HookApi
->ReplacementFunction
;
636 FirstThunk
->u1
.Function
= (DWORD
)HookApi
->ReplacementFunction
;
639 Size
= sizeof(FirstThunk
->u1
.Function
);
640 Status
= NtProtectVirtualMemory(NtCurrentProcess(), &Ptr
, &Size
, OldProtection
, &OldProtection
);
642 if (!NT_SUCCESS(Status
))
644 SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk
->u1
.Function
);
648 /* Level(INFO) [SeiPrintExcludeInfo] Module "kernel32.dll" excluded for shim VistaRTMVersionLie, API "NTDLL.DLL!RtlGetVersion", because it is in System32/WinSXS. */
650 VOID
SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry
)
653 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
654 PBYTE DllBase
= LdrEntry
->DllBase
;
656 if (SE_IsShimDll(DllBase
) || g_hInstance
== LdrEntry
->DllBase
)
658 SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
662 ImportDescriptor
= RtlImageDirectoryEntryToData(DllBase
, TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &Size
);
663 if (!ImportDescriptor
)
665 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
669 SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry
->DllBase
, &LdrEntry
->BaseDllName
);
671 for ( ;ImportDescriptor
->Name
&& ImportDescriptor
->OriginalFirstThunk
; ImportDescriptor
++)
673 PHOOKMODULEINFO HookModuleInfo
;
675 /* Do we have hooks for this module? */
676 HookModuleInfo
= SeiFindHookModuleInfoForImportDescriptor(DllBase
, ImportDescriptor
);
680 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
681 PSINGLE_LIST_ENTRY Entry
;
683 Entry
= HookModuleInfo
->ModuleLink
.Next
;
688 OriginalThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->OriginalFirstThunk
);
689 FirstThunk
= (PIMAGE_THUNK_DATA
)(DllBase
+ ImportDescriptor
->FirstThunk
);
691 for (;OriginalThunk
->u1
.AddressOfData
&& FirstThunk
->u1
.Function
&& Entry
; OriginalThunk
++, FirstThunk
++)
693 PHOOKAPIEX HookApi
= CONTAINING_RECORD(Entry
, HOOKAPIEX
, ModuleLink
);
695 if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk
->u1
.AddressOfData
))
697 PIMAGE_IMPORT_BY_NAME ImportName
;
699 ImportName
= (PIMAGE_IMPORT_BY_NAME
)(DllBase
+ OriginalThunk
->u1
.AddressOfData
);
700 if (!strcmp((PCSTR
)ImportName
->Name
, HookApi
->FunctionName
))
702 SeiPatchNewImport(FirstThunk
, HookApi
, LdrEntry
);
704 /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
710 SHIMENG_FAIL("Ordinals not yet supported\n");
719 /* One entry not found. */
720 PHOOKAPIEX HookApi
= CONTAINING_RECORD(Entry
, HOOKAPIEX
, ModuleLink
);
722 SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, &LdrEntry
->BaseDllName
);
724 SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi
->LibraryName
, HookApi
->FunctionName
, dwFound
, &LdrEntry
->BaseDllName
);
735 VOID
PatchNewModules(PPEB Peb
)
737 PLIST_ENTRY ListHead
, ListEntry
;
738 PLDR_DATA_TABLE_ENTRY LdrEntry
;
740 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
741 ListEntry
= ListHead
->Flink
;
743 while (ListHead
!= ListEntry
)
745 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
746 SeiHookImports(LdrEntry
);
748 ListEntry
= ListEntry
->Flink
;
754 Level(INFO) Using USER apphack flags 0x2080000
757 VOID
SeiInit(PUNICODE_STRING ProcessImage
, HSDB hsdb
, SDBQUERYRESULT
* pQuery
)
762 DWORD dwTotalHooks
= 0;
764 PPEB Peb
= NtCurrentPeb();
767 ShimRef
.Size
= ShimRef
.MaxSize
= 0;
769 SeiCheckComPlusImage(Peb
->ImageBaseAddress
);
772 if (pQuery->trApphelp)
773 SeiDisplayAppHelp(?pQuery->trApphelp?);
776 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(ExePath(%wZ))\n", ProcessImage
);
777 SeiBuildShimRefArray(hsdb
, pQuery
, &ShimRef
);
778 SeiDbgPrint(SEI_MSG
, NULL
, "ShimInfo(Complete)\n");
780 SHIMENG_INFO("Got %d shims\n", ShimRef
.Size
);
782 SeiBuildGlobalInclExclList()
787 for (n
= 0; n
< ShimRef
.Size
; ++n
)
791 if (SdbTagRefToTagID(hsdb
, Data
[n
], &pdb
, &ShimRef
))
793 LPCWSTR ShimName
, DllName
;
795 WCHAR FullNameBuffer
[MAX_PATH
];
796 UNICODE_STRING UnicodeDllName
;
798 PSHIMMODULE pShimInfo
= NULL
;
799 const char* szCommandLine
= "";
803 ShimName
= SeiGetStringPtr(pdb
, ShimRef
, TAG_NAME
);
806 SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", Data
[n
]);
810 ShimTag
= SeiGetDWORD(pdb
, ShimRef
, TAG_SHIM_TAGID
);
813 SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName
);
817 if (!SdbGetAppPatchDir(NULL
, FullNameBuffer
, _countof(FullNameBuffer
)))
819 SHIMENG_WARN("Failed to get the AppPatch dir\n");
823 DllName
= SeiGetStringPtr(pdb
, ShimTag
, TAG_DLLFILE
);
824 if (DllName
== NULL
||
825 !SUCCEEDED(StringCchCatW(FullNameBuffer
, _countof(FullNameBuffer
), L
"\\")) ||
826 !SUCCEEDED(StringCchCatW(FullNameBuffer
, _countof(FullNameBuffer
), DllName
)))
828 SHIMENG_WARN("Failed to build a full path for %S\n", ShimName
);
833 SeiGetShimCommandLine();
834 [SeiInit] COMMAND_LINE VirtualRegistry(WINNT;VistaRTMLie) from AcLayers.DLL
837 RtlInitUnicodeString(&UnicodeDllName
, FullNameBuffer
);
838 if (NT_SUCCESS(LdrGetDllHandle(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
840 pShimInfo
= SeiGetShimInfo(BaseAddress
);
842 else if (!NT_SUCCESS(LdrLoadDll(NULL
, NULL
, &UnicodeDllName
, &BaseAddress
)))
844 SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName
, ShimName
);
849 pShimInfo
= SeiCreateShimInfo(DllName
, BaseAddress
);
852 SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName
);
857 SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress
, &UnicodeDllName
);
858 SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName
, ShimName
);
861 pHookApi
= pShimInfo
->pGetHookAPIs(szCommandLine
, ShimName
, &dwHookCount
);
862 SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount
, &UnicodeDllName
, ShimName
);
864 SeiAppendHookInfo(pShimInfo
, pHookApi
, dwHookCount
);
866 dwTotalHooks
+= dwHookCount
;
867 /*SeiBuildInclExclList*/
871 SeiAddInternalHooks(dwTotalHooks
);
873 PatchNewModules(Peb
);
878 BOOL
SeiGetShimData(PUNICODE_STRING ProcessImage
, PVOID pShimData
, HSDB
* pHsdb
, SDBQUERYRESULT
* pQuery
)
880 static const UNICODE_STRING ForbiddenShimmingApps
[] = {
881 RTL_CONSTANT_STRING(L
"ntsd.exe"),
882 RTL_CONSTANT_STRING(L
"windbg.exe"),
884 RTL_CONSTANT_STRING(L
"slsvc.exe"),
887 static const UNICODE_STRING BackSlash
= RTL_CONSTANT_STRING(L
"\\");
888 static const UNICODE_STRING ForwdSlash
= RTL_CONSTANT_STRING(L
"/");
889 UNICODE_STRING ProcessName
;
890 USHORT Back
, Forward
;
894 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &BackSlash
, &Back
)))
897 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
, ProcessImage
, &ForwdSlash
, &Forward
)))
904 Back
+= sizeof(WCHAR
);
906 ProcessName
.Buffer
= ProcessImage
->Buffer
+ Back
/ sizeof(WCHAR
);
907 ProcessName
.Length
= ProcessImage
->Length
- Back
;
908 ProcessName
.MaximumLength
= ProcessImage
->MaximumLength
- Back
;
910 for (n
= 0; n
< _countof(ForbiddenShimmingApps
); ++n
)
912 if (RtlEqualUnicodeString(&ProcessName
, ForbiddenShimmingApps
+ n
, TRUE
))
914 SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps
+ n
);
919 /* We should probably load all db's here, but since we do not support that yet... */
920 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
923 if (SdbUnpackAppCompatData(hsdb
, ProcessImage
->Buffer
, pShimData
, pQuery
))
928 SdbReleaseDatabase(hsdb
);
935 VOID NTAPI
SE_InstallBeforeInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
938 SDBQUERYRESULT QueryResult
= { { 0 } };
939 SHIMENG_MSG("(%wZ, %p)\n", ProcessImage
, pShimData
);
941 if (!SeiGetShimData(ProcessImage
, pShimData
, &hsdb
, &QueryResult
))
943 SHIMENG_FAIL("Failed to get shim data\n");
947 g_bShimDuringInit
= TRUE
;
948 SeiInit(ProcessImage
, hsdb
, &QueryResult
);
949 g_bShimDuringInit
= FALSE
;
951 SdbReleaseDatabase(hsdb
);
954 VOID NTAPI
SE_InstallAfterInit(PUNICODE_STRING ProcessImage
, PVOID pShimData
)
956 NotifyShims(SHIM_NOTIFY_ATTACH
, NULL
);
959 VOID NTAPI
SE_ProcessDying(VOID
)
962 NotifyShims(SHIM_NOTIFY_DETACH
, NULL
);
965 VOID WINAPI
SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
967 SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit
? "" : "AFTER ", &LdrEntry
->BaseDllName
);
968 NotifyShims(SHIM_REASON_DLL_LOAD
, LdrEntry
);
971 VOID WINAPI
SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry
)
973 SHIMENG_MSG("(%p)\n", LdrEntry
);
974 NotifyShims(SHIM_REASON_DLL_UNLOAD
, LdrEntry
);
977 BOOL WINAPI
SE_IsShimDll(PVOID BaseAddress
)
979 SHIMENG_MSG("(%p)\n", BaseAddress
);
981 return SeiGetShimInfo(BaseAddress
) != NULL
;