Author: mjansen
Date: Mon Aug 14 16:34:56 2017
New Revision: 75541
URL:
http://svn.reactos.org/svn/reactos?rev=75541&view=rev
Log:
[SHIMENG] Filter shims based on the include/exclude node specified, as well as their
presence in certain directories.
- Shims are not allowed on files from System32 / WinSxs.
- Individual shims can override this per module with includes/excludes.
- Shims can specify additional dlls to ignore or include.
- Specify a default list of dlls to be included from system32.
CORE-13618
Modified:
trunk/reactos/dll/appcompat/apphelp/apphelp.h
trunk/reactos/dll/appcompat/apphelp/shimeng.c
trunk/reactos/dll/appcompat/apphelp/shimeng.h
trunk/reactos/media/sdb/sysmain.xml
Modified: trunk/reactos/dll/appcompat/apphelp/apphelp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/apph…
==============================================================================
--- trunk/reactos/dll/appcompat/apphelp/apphelp.h [iso-8859-1] (original)
+++ trunk/reactos/dll/appcompat/apphelp/apphelp.h [iso-8859-1] Mon Aug 14 16:34:56 2017
@@ -89,6 +89,7 @@
/* sdbapi.c */
PWSTR SdbpStrDup(LPCWSTR string);
+DWORD SdbpStrsize(PCWSTR string);
HSDB WINAPI SdbInitDatabase(DWORD, LPCWSTR);
void WINAPI SdbReleaseDatabase(HSDB);
BOOL WINAPI SdbGUIDToString(CONST GUID *Guid, PWSTR GuidString, SIZE_T Length);
Modified: trunk/reactos/dll/appcompat/apphelp/shimeng.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/shim…
==============================================================================
--- trunk/reactos/dll/appcompat/apphelp/shimeng.c [iso-8859-1] (original)
+++ trunk/reactos/dll/appcompat/apphelp/shimeng.c [iso-8859-1] Mon Aug 14 16:34:56 2017
@@ -27,21 +27,24 @@
#include "shimeng.h"
-typedef FARPROC(WINAPI* GETPROCADDRESSPROC)(HINSTANCE, LPCSTR);
-
FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName);
BOOL WINAPI SE_IsShimDll(PVOID BaseAddress);
extern HMODULE g_hInstance;
+static UNICODE_STRING g_WindowsDirectory;
+static UNICODE_STRING g_System32Directory;
+static UNICODE_STRING g_SxsDirectory;
ULONG g_ShimEngDebugLevel = 0xffffffff;
BOOL g_bComPlusImage = FALSE;
BOOL g_bShimDuringInit = FALSE;
BOOL g_bInternalHooksUsed = FALSE;
-static ARRAY g_pShimInfo; /* PSHIMMODULE */
-static ARRAY g_pHookArray; /* HOOKMODULEINFO */
-
+static ARRAY g_pShimInfo; /* PSHIMMODULE */
+static ARRAY g_pHookArray; /* HOOKMODULEINFO */
+static ARRAY g_InExclude; /* INEXCLUDE */
+
+/* If we have setup a hook for a function, we should also redirect GetProcAddress for
this function */
HOOKAPIEX g_IntHookEx[] =
{
{
@@ -132,7 +135,7 @@
static const UNICODE_STRING DebugKey =
RTL_CONSTANT_STRING(L"SHIMENG_DEBUG_LEVEL");
UNICODE_STRING DebugValue;
NTSTATUS Status;
- ULONG NewLevel = 0;
+ ULONG NewLevel = SEI_MSG; /* Show some basic info in the logs, unless configured
different */
WCHAR Buffer[40];
RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
@@ -294,20 +297,29 @@
return Data;
}
-VOID SeiAppendHookInfo(PSHIMMODULE pShimModuleInfo, PHOOKAPIEX pHookApi, DWORD
dwHookCount)
+PSHIMINFO SeiAppendHookInfo(PSHIMMODULE pShimModuleInfo, PHOOKAPIEX pHookApi, DWORD
dwHookCount, PCWSTR ShimName)
{
PSHIMINFO* pData, Data;
pData = ARRAY_Append(&pShimModuleInfo->EnabledShims, PSHIMINFO);
if (!pData)
- return;
+ return NULL;
*pData = SeiAlloc(sizeof(SHIMINFO));
Data = *pData;
+
+ if (!Data)
+ return NULL;
+
+ Data->ShimName = SdbpStrDup(ShimName);
+ if (!Data->ShimName)
+ return NULL;
Data->pHookApi = pHookApi;
Data->dwHookCount = dwHookCount;
Data->pShimModule = pShimModuleInfo;
+ ARRAY_Init(&Data->InExclude, INEXCLUDE);
+ return Data;
}
PHOOKMODULEINFO SeiFindHookModuleInfo(PUNICODE_STRING ModuleName, PVOID BaseAddress)
@@ -382,6 +394,7 @@
*Data = trShimRef;
}
+/* Propagate layers to child processes */
static VOID SeiSetLayerEnvVar(LPCWSTR wszLayer)
{
NTSTATUS Status;
@@ -399,6 +412,7 @@
#define MAX_LAYER_LENGTH 256
+/* Translate all Exe and Layer entries to Shims, and propagate all layers */
static VOID SeiBuildShimRefArray(HSDB hsdb, SDBQUERYRESULT* pQuery, PARRAY pShimRef)
{
WCHAR wszLayerEnvVar[MAX_LAYER_LENGTH] = { 0 };
@@ -468,7 +482,7 @@
SeiSetLayerEnvVar(wszLayerEnvVar);
}
-
+/* Given the hooks from one shim, find the relevant modules and store the combination of
module + hook */
VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim)
{
DWORD n, j;
@@ -542,7 +556,9 @@
}
}
-
+typedef FARPROC(WINAPI* GETPROCADDRESSPROC)(HINSTANCE, LPCSTR);
+
+/* Check if we should fake the return from GetProcAddress (because we also redirected the
iat for this module) */
FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName)
{
char szOrdProcName[10] = "";
@@ -588,6 +604,7 @@
return proc;
}
+/* Walk all shim modules / enabled shims, and add their hooks */
VOID SeiResolveAPIs(VOID)
{
DWORD mod, n;
@@ -611,6 +628,7 @@
}
}
+/* If we hooked something, we should also redirect GetProcAddress */
VOID SeiAddInternalHooks(DWORD dwNumHooks)
{
if (dwNumHooks == 0)
@@ -623,6 +641,7 @@
g_bInternalHooksUsed = TRUE;
}
+/* Patch one function in the iat */
VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi,
PLDR_DATA_TABLE_ENTRY LdrEntry)
{
ULONG OldProtection = 0;
@@ -658,8 +677,161 @@
}
}
-/* Level(INFO) [SeiPrintExcludeInfo] Module "kernel32.dll" excluded for shim
VistaRTMVersionLie, API "NTDLL.DLL!RtlGetVersion", because it is in
System32/WinSXS. */
-
+
+PINEXCLUDE SeiFindInExclude(PARRAY InExclude, PCUNICODE_STRING DllName)
+{
+ DWORD n;
+
+ for (n = 0; n < ARRAY_Size(InExclude); ++n)
+ {
+ PINEXCLUDE InEx = ARRAY_At(InExclude, INEXCLUDE, n);
+
+ if (RtlEqualUnicodeString(&InEx->Module, DllName, TRUE))
+ return InEx;
+ }
+
+ return NULL;
+}
+
+BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi)
+{
+ PSHIMINFO pShimInfo = HookApi->pShimInfo;
+ PINEXCLUDE InExclude;
+ BOOL IsExcluded = FALSE;
+
+ if (!pShimInfo)
+ {
+ /* Internal hook, do not exclude it */
+ return FALSE;
+ }
+
+ /* By default, everything from System32 or WinSxs is excluded */
+ if (RtlPrefixUnicodeString(&g_System32Directory, &LdrEntry->FullDllName,
TRUE) ||
+ RtlPrefixUnicodeString(&g_SxsDirectory, &LdrEntry->FullDllName,
TRUE))
+ IsExcluded = TRUE;
+
+ InExclude = SeiFindInExclude(&pShimInfo->InExclude,
&LdrEntry->BaseDllName);
+ if (InExclude)
+ {
+ /* If it is on the 'exclude' list, bail out */
+ if (!InExclude->Include)
+ {
+ SHIMENG_INFO("Module '%wZ' excluded for shim %S, API
'%s!%s', because it on in the exclude list.\n",
+ &LdrEntry->BaseDllName, pShimInfo->ShimName,
HookApi->LibraryName, HookApi->FunctionName);
+
+ return TRUE;
+ }
+ /* If it is on the 'include' list, override System32 / Winsxs check. */
+ if (IsExcluded)
+ {
+ SHIMENG_INFO("Module '%wZ' included for shim %S, API
'%s!%s', because it is on the include list.\n",
+ &LdrEntry->BaseDllName, pShimInfo->ShimName,
HookApi->LibraryName, HookApi->FunctionName);
+
+ }
+ IsExcluded = FALSE;
+ }
+
+ if (IsExcluded)
+ {
+ SHIMENG_INFO("Module '%wZ' excluded for shim %S, API
'%s!%s', because it is in System32/WinSXS.\n",
+ &LdrEntry->BaseDllName, pShimInfo->ShimName,
HookApi->LibraryName, HookApi->FunctionName);
+ }
+
+ return IsExcluded;
+}
+
+VOID SeiAppendInExclude(PARRAY dest, PCWSTR ModuleName, BOOL IsInclude)
+{
+ PINEXCLUDE InExclude;
+ UNICODE_STRING ModuleNameU;
+ RtlInitUnicodeString(&ModuleNameU, ModuleName);
+
+ InExclude = SeiFindInExclude(dest, &ModuleNameU);
+ if (InExclude)
+ {
+ InExclude->Include = IsInclude;
+ return;
+ }
+
+ InExclude = ARRAY_Append(dest, INEXCLUDE);
+ if (InExclude)
+ {
+ PCWSTR ModuleNameCopy = SdbpStrDup(ModuleName);
+ RtlInitUnicodeString(&InExclude->Module, ModuleNameCopy);
+ InExclude->Include = IsInclude;
+ }
+}
+
+/* Read the INEXCLUD tags from a given parent tag */
+VOID SeiReadInExclude(PDB pdb, TAGID parent, PARRAY dest)
+{
+ TAGID InExcludeTag;
+
+ InExcludeTag = SdbFindFirstTag(pdb, parent, TAG_INEXCLUD);
+
+ while (InExcludeTag != TAGID_NULL)
+ {
+ PCWSTR ModuleName;
+ TAGID ModuleTag = SdbFindFirstTag(pdb, InExcludeTag, TAG_MODULE);
+ TAGID IncludeTag = SdbFindFirstTag(pdb, InExcludeTag, TAG_INCLUDE);
+
+ ModuleName = SdbGetStringTagPtr(pdb, ModuleTag);
+ if (ModuleName)
+ {
+ SeiAppendInExclude(dest, ModuleName, IncludeTag != TAGID_NULL);
+ }
+ else
+ {
+ SHIMENG_WARN("INEXCLUDE without Module: 0x%x\n", InExcludeTag);
+ }
+
+ InExcludeTag = SdbFindNextTag(pdb, parent, InExcludeTag);
+ }
+}
+
+VOID SeiBuildGlobalInclExclList(HSDB hsdb)
+{
+ PDB pdb;
+ TAGREF tr = TAGREF_ROOT;
+ TAGID root, db, library;
+
+ if (!SdbTagRefToTagID(hsdb, tr, &pdb, &root))
+ {
+ SHIMENG_WARN("Unable to resolve database root\n");
+ return;
+ }
+ db = SdbFindFirstTag(pdb, root, TAG_DATABASE);
+ if (db == TAGID_NULL)
+ {
+ SHIMENG_WARN("Unable to resolve database\n");
+ return;
+ }
+ library = SdbFindFirstTag(pdb, db, TAG_LIBRARY);
+ if (library == TAGID_NULL)
+ {
+ SHIMENG_WARN("Unable to resolve library\n");
+ return;
+ }
+
+ SeiReadInExclude(pdb, library, &g_InExclude);
+}
+
+VOID SeiBuildInclExclList(PDB pdb, TAGID ShimTag, PSHIMINFO pShimInfo)
+{
+ DWORD n;
+
+ /* First duplicate the global in/excludes */
+ for (n = 0; n < ARRAY_Size(&g_InExclude); ++n)
+ {
+ PINEXCLUDE InEx = ARRAY_At(&g_InExclude, INEXCLUDE, n);
+ SeiAppendInExclude(&pShimInfo->InExclude, InEx->Module.Buffer,
InEx->Include);
+ }
+
+ /* Now read this shim's in/excludes (possibly overriding the global ones) */
+ SeiReadInExclude(pdb, ShimTag, &pShimInfo->InExclude);
+}
+
+/* Given one loaded module, redirect (hook) all functions from the iat that are
registered by shims */
VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
{
ULONG Size;
@@ -698,9 +870,16 @@
DWORD dwFound = 0;
PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis,
PHOOKAPIEX, n);
+ /* Check if this module should be excluded from being hooked
(system32/winsxs, global or shim exclude) */
+ if (SeiIsExcluded(LdrEntry, HookApi))
+ {
+ continue;
+ }
+
OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase +
ImportDescriptor->OriginalFirstThunk);
FirstThunk = (PIMAGE_THUNK_DATA)(DllBase +
ImportDescriptor->FirstThunk);
+ /* Walk all imports */
for (;OriginalThunk->u1.AddressOfData &&
FirstThunk->u1.Function; OriginalThunk++, FirstThunk++)
{
if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData))
@@ -755,6 +934,28 @@
}
+VOID SeiInitPaths(VOID)
+{
+#define SYSTEM32 L"\\system32"
+#define WINSXS L"\\winsxs"
+
+ PWSTR WindowsDirectory = SdbpStrDup(SharedUserData->NtSystemRoot);
+ RtlInitUnicodeString(&g_WindowsDirectory, WindowsDirectory);
+
+ g_System32Directory.MaximumLength = g_WindowsDirectory.Length +
SdbpStrsize(SYSTEM32);
+ g_System32Directory.Buffer = SdbpAlloc(g_System32Directory.MaximumLength);
+ RtlCopyUnicodeString(&g_System32Directory, &g_WindowsDirectory);
+ RtlAppendUnicodeToString(&g_System32Directory, SYSTEM32);
+
+ g_SxsDirectory.MaximumLength = g_WindowsDirectory.Length + SdbpStrsize(WINSXS);
+ g_SxsDirectory.Buffer = SdbpAlloc(g_SxsDirectory.MaximumLength);
+ RtlCopyUnicodeString(&g_SxsDirectory, &g_WindowsDirectory);
+ RtlAppendUnicodeToString(&g_SxsDirectory, WINSXS);
+
+#undef SYSTEM32
+#undef WINSXS
+}
+
/*
Level(INFO) Using USER apphack flags 0x2080000
*/
@@ -773,6 +974,9 @@
ARRAY_Init(&ShimRefArray, TAGREF);
ARRAY_Init(&g_pShimInfo, PSHIMMODULE);
ARRAY_Init(&g_pHookArray, HOOKMODULEINFO);
+ ARRAY_Init(&g_InExclude, INEXCLUDE);
+
+ SeiInitPaths();
SeiCheckComPlusImage(Peb->ImageBaseAddress);
@@ -786,10 +990,9 @@
SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Complete)\n");
SHIMENG_INFO("Got %d shims\n", ARRAY_Size(&ShimRefArray));
- /* TODO:
- SeiBuildGlobalInclExclList()
- */
-
+ SeiBuildGlobalInclExclList(hsdb);
+
+ /* Walk all shims referenced (in layers + exes), and load their modules */
for (n = 0; n < ARRAY_Size(&ShimRefArray); ++n)
{
PDB pdb;
@@ -806,6 +1009,7 @@
PVOID BaseAddress;
PSHIMMODULE pShimModuleInfo = NULL;
ANSI_STRING AnsiCommandLine = RTL_CONSTANT_STRING("");
+ PSHIMINFO pShimInfo = NULL;
PHOOKAPIEX pHookApi;
DWORD dwHookCount;
@@ -856,6 +1060,7 @@
RtlInitUnicodeString(&UnicodeDllName, FullNameBuffer);
if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &UnicodeDllName,
&BaseAddress)))
{
+ /* This shim dll was already loaded, let's find it */
pShimModuleInfo = SeiGetShimModuleInfo(BaseAddress);
}
else if (!NT_SUCCESS(LdrLoadDll(NULL, NULL, &UnicodeDllName,
&BaseAddress)))
@@ -863,6 +1068,7 @@
SHIMENG_WARN("Failed to load %wZ for %S\n",
&UnicodeDllName, ShimName);
continue;
}
+ /* No shim module found (or we just loaded it) */
if (!pShimModuleInfo)
{
pShimModuleInfo = SeiCreateShimModuleInfo(DllName, BaseAddress);
@@ -876,16 +1082,20 @@
SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n",
BaseAddress, &UnicodeDllName);
SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName,
ShimName);
+ /* Ask this shim what hooks it needs (and pass along the commandline) */
pHookApi = pShimModuleInfo->pGetHookAPIs(AnsiCommandLine.Buffer, ShimName,
&dwHookCount);
SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\"
SHIM \"%S\"\n", dwHookCount, &UnicodeDllName, ShimName);
if (dwHookCount)
- SeiAppendHookInfo(pShimModuleInfo, pHookApi, dwHookCount);
+ pShimInfo = SeiAppendHookInfo(pShimModuleInfo, pHookApi, dwHookCount,
ShimName);
+
+ /* If this shim has hooks, create the include / exclude lists */
+ if (pShimInfo)
+ SeiBuildInclExclList(pdb, ShimTag, pShimInfo);
if (CommandLine && *CommandLine)
RtlFreeAnsiString(&AnsiCommandLine);
dwTotalHooks += dwHookCount;
- /*SeiBuildInclExclList*/
}
}
@@ -895,7 +1105,7 @@
}
-
+/* Load the database + unpack the shim data (if this process is allowed) */
BOOL SeiGetShimData(PUNICODE_STRING ProcessImage, PVOID pShimData, HSDB* pHsdb,
SDBQUERYRESULT* pQuery)
{
static const UNICODE_STRING ForbiddenShimmingApps[] = {
Modified: trunk/reactos/dll/appcompat/apphelp/shimeng.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/shim…
==============================================================================
--- trunk/reactos/dll/appcompat/apphelp/shimeng.h [iso-8859-1] (original)
+++ trunk/reactos/dll/appcompat/apphelp/shimeng.h [iso-8859-1] Mon Aug 14 16:34:56 2017
@@ -19,7 +19,7 @@
#ifndef SHIMENG_H
#define SHIMENG_H
-/* ReactOS specific */
+/* This header is ReactOS specific */
/* Structure that allows dynamic growing.
Be aware, the data may move! */
@@ -48,12 +48,19 @@
C_ASSERT(sizeof(HOOKAPIEX) == sizeof(HOOKAPI));
C_ASSERT(offsetof(HOOKAPIEX, pShimInfo) == offsetof(HOOKAPI, Reserved));
+typedef struct _INEXCLUDE
+{
+ UNICODE_STRING Module;
+ BOOL Include;
+} INEXCLUDE, *PINEXCLUDE;
typedef struct _SHIMINFO
{
+ PCWSTR ShimName;
PHOOKAPIEX pHookApi;
DWORD dwHookCount;
PSHIMMODULE pShimModule;
+ ARRAY InExclude; /* INEXCLUDE */
} SHIMINFO, *PSHIMINFO;
typedef struct _SHIMMODULE
Modified: trunk/reactos/media/sdb/sysmain.xml
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/media/sdb/sysmain.xml?rev=…
==============================================================================
--- trunk/reactos/media/sdb/sysmain.xml [iso-8859-1] (original)
+++ trunk/reactos/media/sdb/sysmain.xml [iso-8859-1] Mon Aug 14 16:34:56 2017
@@ -4,6 +4,10 @@
<OS_PLATFORM >1</OS_PLATFORM>
<DATABASE_ID>{11111111-1111-1111-1111-111111111111}</DATABASE_ID>
<LIBRARY>
+ <INCLUDE MODULE="kernel32.dll" />
+ <INCLUDE MODULE="msvcrt.dll" />
+ <INCLUDE MODULE="ole32.dll" />
+ <INCLUDE MODULE="oleaut32.dll" />
<!-- Version lie shims -->