mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
[APPHELP/SHIMENG] Begin implementing the core of the SHIM engine.
With this, the basics of the app compat engine are implemented and should be functional. Currently it is disable with a policy, to be enabled soon. CORE-13284 CORE-11300 svn path=/trunk/; revision=75258
This commit is contained in:
parent
1fa3c1a922
commit
711a1cb341
4 changed files with 904 additions and 14 deletions
|
@ -2,7 +2,7 @@
|
|||
include_directories(${SHIMLIB_DIR})
|
||||
|
||||
remove_definitions(-D_WIN32_WINNT=0x502 -DWINVER=0x502)
|
||||
add_definitions(-D_WIN32_WINNT=0x600 -DWINVER=0x600)
|
||||
add_definitions(-D_WIN32_WINNT=0x601 -DWINVER=0x601)
|
||||
|
||||
spec2def(apphelp.dll apphelp.spec ADD_IMPORTLIB)
|
||||
|
||||
|
|
|
@ -83,7 +83,9 @@ typedef struct tagSDBQUERYRESULT {
|
|||
GUID rgGuidDB[SDB_MAX_SDBS];
|
||||
} SDBQUERYRESULT, *PSDBQUERYRESULT;
|
||||
|
||||
#ifndef APPHELP_NOSDBPAPI
|
||||
#include "sdbpapi.h"
|
||||
#endif
|
||||
|
||||
/* sdbapi.c */
|
||||
PWSTR SdbpStrDup(LPCWSTR string);
|
||||
|
@ -122,7 +124,8 @@ BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BO
|
|||
/* hsdb.c */
|
||||
BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name, LPCWSTR env, DWORD flags, PSDBQUERYRESULT result);
|
||||
BOOL WINAPI SdbTagIDToTagRef(HSDB hsdb, PDB pdb, TAGID tiWhich, TAGREF* ptrWhich);
|
||||
|
||||
BOOL WINAPI SdbTagRefToTagID(HSDB hsdb, TAGREF trWhich, PDB* ppdb, TAGID* ptiWhich);
|
||||
BOOL WINAPI SdbUnpackAppCompatData(HSDB hsdb, LPCWSTR pszImageName, PVOID pData, PSDBQUERYRESULT pQueryResult);
|
||||
|
||||
#define ATTRIBUTE_AVAILABLE 0x1
|
||||
#define ATTRIBUTE_FAILED 0x2
|
||||
|
|
|
@ -21,12 +21,69 @@
|
|||
#include "ntndk.h"
|
||||
#include "shimlib.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
HANDLE g_pShimEngModHandle = 0;
|
||||
/* Make sure we don't include apphelp logging */
|
||||
#define APPHELP_NOSDBPAPI
|
||||
#include "apphelp.h"
|
||||
#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;
|
||||
ULONG g_ShimEngDebugLevel = 0xffffffff;
|
||||
BOOL g_bComPlusImage = FALSE;
|
||||
BOOL g_bShimDuringInit = FALSE;
|
||||
BOOL g_bInternalHooksUsed = FALSE;
|
||||
static ARRAY g_pShimInfo; /* SHIMMODULE */
|
||||
static ARRAY g_pHookArray; /* HOOKMODULEINFO */
|
||||
|
||||
HOOKAPIEX g_IntHookEx[] =
|
||||
{
|
||||
{
|
||||
"kernel32.dll", /* LibraryName */
|
||||
"GetProcAddress", /* FunctionName */
|
||||
StubGetProcAddress, /* ReplacementFunction*/
|
||||
NULL, /* OriginalFunction */
|
||||
{ NULL }, /* ModuleLink */
|
||||
{ NULL } /* ApiLink */
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static BOOL ARRAY_EnsureSize(PARRAY Array, DWORD ItemSize, DWORD GrowWith)
|
||||
{
|
||||
PVOID pNewData;
|
||||
DWORD Count;
|
||||
|
||||
if (Array->MaxSize > Array->Size)
|
||||
return TRUE;
|
||||
|
||||
Count = Array->Size + GrowWith;
|
||||
pNewData = SeiAlloc(Count * ItemSize);
|
||||
|
||||
if (!pNewData)
|
||||
{
|
||||
SHIMENG_FAIL("Failed to allocate %d bytes\n", Count * ItemSize);
|
||||
return FALSE;
|
||||
}
|
||||
Array->MaxSize = Count;
|
||||
|
||||
if (Array->Data)
|
||||
{
|
||||
memcpy(pNewData, Array->Data, Array->Size * ItemSize);
|
||||
SeiFree(Array->Data);
|
||||
}
|
||||
Array->Data = pNewData;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -115,49 +172,782 @@ BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR Function, PCSTR Format, ...)
|
|||
}
|
||||
|
||||
|
||||
PVOID SeiGetModuleFromAddress(PVOID addr)
|
||||
{
|
||||
PVOID hModule = NULL;
|
||||
RtlPcToFileHeader(addr, &hModule);
|
||||
return hModule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* TODO: Guard against recursive calling / calling init multiple times! */
|
||||
VOID NotifyShims(DWORD dwReason, PVOID Info)
|
||||
{
|
||||
/* Enumerate all loaded shims */
|
||||
PSHIMMODULE Data;
|
||||
DWORD n;
|
||||
|
||||
Data = g_pShimInfo.Data;
|
||||
for (n = 0; n < g_pShimInfo.Size; ++n)
|
||||
{
|
||||
if (!Data[n].pNotifyShims)
|
||||
continue;
|
||||
|
||||
Data[n].pNotifyShims(dwReason, Info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID SeiCheckComPlusImage(PVOID BaseAddress)
|
||||
{
|
||||
ULONG ComSectionSize;
|
||||
g_bComPlusImage = RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &ComSectionSize) != NULL;
|
||||
|
||||
SHIMENG_INFO("COM+ executable %s\n", g_bComPlusImage ? "TRUE" : "FALSE");
|
||||
}
|
||||
|
||||
|
||||
PSHIMMODULE SeiGetShimInfo(PVOID BaseAddress)
|
||||
{
|
||||
PSHIMMODULE Data;
|
||||
DWORD n;
|
||||
|
||||
Data = g_pShimInfo.Data;
|
||||
for (n = 0; n < g_pShimInfo.Size; ++n)
|
||||
{
|
||||
if (Data[n].BaseAddress == BaseAddress)
|
||||
return &Data[n];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PSHIMMODULE SeiCreateShimInfo(PCWSTR DllName, PVOID BaseAddress)
|
||||
{
|
||||
static const ANSI_STRING GetHookAPIs = RTL_CONSTANT_STRING("GetHookAPIs");
|
||||
static const ANSI_STRING NotifyShims = RTL_CONSTANT_STRING("NotifyShims");
|
||||
PSHIMMODULE Data;
|
||||
PVOID pGetHookAPIs, pNotifyShims;
|
||||
|
||||
if (!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress, (PANSI_STRING)&GetHookAPIs, 0, &pGetHookAPIs)) ||
|
||||
!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress, (PANSI_STRING)&NotifyShims, 0, &pNotifyShims)))
|
||||
{
|
||||
SHIMENG_WARN("Failed to resolve entry points for %S\n", DllName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ARRAY_EnsureSize(&g_pShimInfo, sizeof(SHIMMODULE), 5))
|
||||
return NULL;
|
||||
|
||||
Data = g_pShimInfo.Data;
|
||||
Data += g_pShimInfo.Size;
|
||||
g_pShimInfo.Size++;
|
||||
|
||||
RtlCreateUnicodeString(&Data->Name, DllName);
|
||||
Data->BaseAddress = BaseAddress;
|
||||
|
||||
Data->pGetHookAPIs = pGetHookAPIs;
|
||||
Data->pNotifyShims = pNotifyShims;
|
||||
|
||||
Data->HookApis.Data = NULL;
|
||||
Data->HookApis.Size = 0;
|
||||
Data->HookApis.MaxSize = 0;
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
VOID SeiAppendHookInfo(PSHIMMODULE pShimInfo, PHOOKAPIEX pHookApi, DWORD dwHookCount)
|
||||
{
|
||||
PHOOKAPIPOINTERS Data;
|
||||
if (!ARRAY_EnsureSize(&pShimInfo->HookApis, sizeof(HOOKAPIPOINTERS), 5))
|
||||
return;
|
||||
|
||||
Data = pShimInfo->HookApis.Data;
|
||||
Data += pShimInfo->HookApis.Size;
|
||||
|
||||
Data->pHookApi = pHookApi;
|
||||
Data->dwHookCount = dwHookCount;
|
||||
pShimInfo->HookApis.Size++;
|
||||
}
|
||||
|
||||
PHOOKMODULEINFO SeiFindHookModuleInfo(PUNICODE_STRING ModuleName, PVOID BaseAddress)
|
||||
{
|
||||
DWORD n;
|
||||
PHOOKMODULEINFO Data = g_pHookArray.Data;
|
||||
|
||||
for (n = 0; n < g_pHookArray.Size; ++n)
|
||||
{
|
||||
if (BaseAddress && BaseAddress == Data[n].BaseAddress)
|
||||
return &Data[n];
|
||||
|
||||
if (!BaseAddress && RtlEqualUnicodeString(ModuleName, &Data[n].Name, TRUE))
|
||||
return &Data[n];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PHOOKMODULEINFO SeiFindHookModuleInfoForImportDescriptor(PBYTE DllBase, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor)
|
||||
{
|
||||
UNICODE_STRING DllName;
|
||||
PVOID DllHandle;
|
||||
NTSTATUS Success;
|
||||
|
||||
if (!RtlCreateUnicodeStringFromAsciiz(&DllName, (PCSZ)(DllBase + ImportDescriptor->Name)))
|
||||
{
|
||||
SHIMENG_FAIL("Unable to convert dll name to unicode\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Success = LdrGetDllHandle(NULL, NULL, &DllName, &DllHandle);
|
||||
RtlFreeUnicodeString(&DllName);
|
||||
|
||||
if (!NT_SUCCESS(Success))
|
||||
{
|
||||
SHIMENG_FAIL("Unable to get module handle for %wZ\n", &DllName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SeiFindHookModuleInfo(NULL, DllHandle);
|
||||
}
|
||||
|
||||
static LPCWSTR SeiGetStringPtr(PDB pdb, TAGID tag, TAG type)
|
||||
{
|
||||
TAGID tagEntry = SdbFindFirstTag(pdb, tag, type);
|
||||
if (tagEntry == TAGID_NULL)
|
||||
return NULL;
|
||||
|
||||
return SdbGetStringTagPtr(pdb, tagEntry);
|
||||
}
|
||||
|
||||
static DWORD SeiGetDWORD(PDB pdb, TAGID tag, TAG type)
|
||||
{
|
||||
TAGID tagEntry = SdbFindFirstTag(pdb, tag, type);
|
||||
if (tagEntry == TAGID_NULL)
|
||||
return 0;
|
||||
|
||||
return SdbReadDWORDTag(pdb, tagEntry, TAGID_NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID SeiAddShim(TAGREF trShimRef, PARRAY pShimRef)
|
||||
{
|
||||
TAGREF* Data;
|
||||
if (!ARRAY_EnsureSize(pShimRef, sizeof(TAGREF), 10))
|
||||
return;
|
||||
|
||||
Data = pShimRef->Data;
|
||||
Data[pShimRef->Size] = trShimRef;
|
||||
pShimRef->Size++;
|
||||
}
|
||||
|
||||
VOID SeiBuildShimRefArray(HSDB hsdb, SDBQUERYRESULT* pQuery, PARRAY pShimRef)
|
||||
{
|
||||
DWORD n;
|
||||
|
||||
for (n = 0; n < pQuery->dwExeCount; ++n)
|
||||
{
|
||||
PDB pdb;
|
||||
TAGID tag;
|
||||
if (SdbTagRefToTagID(hsdb, pQuery->atrExes[n], &pdb, &tag))
|
||||
{
|
||||
LPCWSTR ExeName = SeiGetStringPtr(pdb, tag, TAG_NAME);
|
||||
TAGID ShimRef = SdbFindFirstTag(pdb, tag, TAG_SHIM_REF);
|
||||
|
||||
if (ExeName)
|
||||
SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Exe(%S))\n", ExeName);
|
||||
|
||||
while (ShimRef != TAGID_NULL)
|
||||
{
|
||||
TAGREF trShimRef;
|
||||
if (SdbTagIDToTagRef(hsdb, pdb, ShimRef, &trShimRef))
|
||||
SeiAddShim(trShimRef, pShimRef);
|
||||
|
||||
|
||||
ShimRef = SdbFindNextTag(pdb, tag, ShimRef);
|
||||
}
|
||||
|
||||
/* Handle FLAG_REF */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (n = 0; n < pQuery->dwLayerCount; ++n)
|
||||
{
|
||||
PDB pdb;
|
||||
TAGID tag;
|
||||
if (SdbTagRefToTagID(hsdb, pQuery->atrLayers[n], &pdb, &tag))
|
||||
{
|
||||
LPCWSTR LayerName = SeiGetStringPtr(pdb, tag, TAG_NAME);
|
||||
TAGID ShimRef = SdbFindFirstTag(pdb, tag, TAG_SHIM_REF);
|
||||
if (LayerName)
|
||||
SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Layer(%S))\n", LayerName);
|
||||
|
||||
while (ShimRef != TAGID_NULL)
|
||||
{
|
||||
TAGREF trShimRef;
|
||||
if (SdbTagIDToTagRef(hsdb, pdb, ShimRef, &trShimRef))
|
||||
SeiAddShim(trShimRef, pShimRef);
|
||||
|
||||
ShimRef = SdbFindNextTag(pdb, tag, ShimRef);
|
||||
}
|
||||
|
||||
/* Handle FLAG_REF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount)
|
||||
{
|
||||
DWORD n;
|
||||
UNICODE_STRING UnicodeModName;
|
||||
WCHAR Buf[512];
|
||||
|
||||
RtlInitEmptyUnicodeString(&UnicodeModName, Buf, sizeof(Buf));
|
||||
|
||||
for (n = 0; n < dwHookCount; ++n)
|
||||
{
|
||||
ANSI_STRING AnsiString;
|
||||
PVOID DllHandle;
|
||||
PHOOKAPIEX hook = hooks + n;
|
||||
PHOOKMODULEINFO HookModuleInfo;
|
||||
PSINGLE_LIST_ENTRY Entry;
|
||||
|
||||
RtlInitAnsiString(&AnsiString, hook->LibraryName);
|
||||
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeModName, &AnsiString, FALSE)))
|
||||
{
|
||||
SHIMENG_FAIL("Unable to convert %s to Unicode\n", hook->LibraryName);
|
||||
continue;
|
||||
}
|
||||
|
||||
RtlInitAnsiString(&AnsiString, hook->FunctionName);
|
||||
if (NT_SUCCESS(LdrGetDllHandle(NULL, 0, &UnicodeModName, &DllHandle)))
|
||||
{
|
||||
PVOID ProcAddress;
|
||||
|
||||
|
||||
if (!NT_SUCCESS(LdrGetProcedureAddress(DllHandle, &AnsiString, 0, &ProcAddress)))
|
||||
{
|
||||
SHIMENG_FAIL("Unable to retrieve %s!%s\n", hook->LibraryName, hook->FunctionName);
|
||||
continue;
|
||||
}
|
||||
|
||||
HookModuleInfo = SeiFindHookModuleInfo(NULL, DllHandle);
|
||||
hook->OriginalFunction = ProcAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
HookModuleInfo = SeiFindHookModuleInfo(&UnicodeModName, NULL);
|
||||
DllHandle = NULL;
|
||||
}
|
||||
|
||||
if (!HookModuleInfo)
|
||||
{
|
||||
if (!ARRAY_EnsureSize(&g_pHookArray, sizeof(HOOKMODULEINFO), 5))
|
||||
continue;
|
||||
|
||||
HookModuleInfo = g_pHookArray.Data;
|
||||
HookModuleInfo += g_pHookArray.Size;
|
||||
g_pHookArray.Size++;
|
||||
|
||||
HookModuleInfo->BaseAddress = DllHandle;
|
||||
RtlCreateUnicodeString(&HookModuleInfo->Name, UnicodeModName.Buffer);
|
||||
}
|
||||
|
||||
Entry = &HookModuleInfo->ModuleLink;
|
||||
|
||||
while (Entry && Entry->Next)
|
||||
{
|
||||
PHOOKAPIEX HookApi = CONTAINING_RECORD(Entry->Next, HOOKAPIEX, ModuleLink);
|
||||
|
||||
int CmpResult = strcmp(hook->FunctionName, HookApi->FunctionName);
|
||||
if (CmpResult == 0)
|
||||
{
|
||||
/* Multiple hooks on one function? --> use ApiLink */
|
||||
SHIMENG_FAIL("Multiple hooks on one API is not yet supported!\n");
|
||||
ASSERT(0);
|
||||
}
|
||||
else if (CmpResult < 0)
|
||||
{
|
||||
/* Break out of the loop to have the entry inserted 'in place' */
|
||||
break;
|
||||
}
|
||||
|
||||
Entry = Entry->Next;
|
||||
}
|
||||
/* If Entry is not NULL, the item is not inserted yet, so link it at the end. */
|
||||
if (Entry)
|
||||
{
|
||||
hook->ModuleLink.Next = Entry->Next;
|
||||
Entry->Next = &hook->ModuleLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName)
|
||||
{
|
||||
char szOrdProcName[10] = "";
|
||||
LPCSTR lpPrintName = lpProcName;
|
||||
PVOID Addr = _ReturnAddress();
|
||||
PHOOKMODULEINFO HookModuleInfo;
|
||||
FARPROC proc = ((GETPROCADDRESSPROC)g_IntHookEx[0].OriginalFunction)(hModule, lpProcName);
|
||||
|
||||
if (!HIWORD(lpProcName))
|
||||
{
|
||||
sprintf(szOrdProcName, "#%lu", (DWORD)lpProcName);
|
||||
lpPrintName = szOrdProcName;
|
||||
}
|
||||
|
||||
Addr = SeiGetModuleFromAddress(Addr);
|
||||
if (SE_IsShimDll(Addr))
|
||||
{
|
||||
SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule, lpPrintName);
|
||||
return proc;
|
||||
}
|
||||
|
||||
SHIMENG_MSG("(GetProcAddress(%p!%s) => %p\n", hModule, lpProcName, lpPrintName);
|
||||
|
||||
HookModuleInfo = SeiFindHookModuleInfo(NULL, hModule);
|
||||
|
||||
/* FIXME: Ordinal not yet supported */
|
||||
if (HookModuleInfo && HIWORD(lpProcName))
|
||||
{
|
||||
PSINGLE_LIST_ENTRY Entry;
|
||||
|
||||
Entry = HookModuleInfo->ModuleLink.Next;
|
||||
|
||||
while (Entry)
|
||||
{
|
||||
PHOOKAPIEX HookApi = CONTAINING_RECORD(Entry, HOOKAPIEX, ModuleLink);
|
||||
|
||||
int CmpResult = strcmp(lpProcName, HookApi->FunctionName);
|
||||
if (CmpResult == 0)
|
||||
{
|
||||
SHIMENG_MSG("Redirecting %p to %p\n", proc, HookApi->ReplacementFunction);
|
||||
proc = HookApi->ReplacementFunction;
|
||||
break;
|
||||
}
|
||||
else if (CmpResult < 0)
|
||||
{
|
||||
SHIMENG_MSG("Not found %s\n", lpProcName);
|
||||
/* We are not going to find it anymore.. */
|
||||
break;
|
||||
}
|
||||
|
||||
Entry = Entry->Next;
|
||||
}
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
VOID SeiResolveAPIs(VOID)
|
||||
{
|
||||
PSHIMMODULE Data;
|
||||
DWORD mod, n;
|
||||
|
||||
Data = g_pShimInfo.Data;
|
||||
|
||||
/* Enumerate all Shim modules */
|
||||
for (mod = 0; mod < g_pShimInfo.Size; ++mod)
|
||||
{
|
||||
PHOOKAPIPOINTERS pShims = Data[mod].HookApis.Data;
|
||||
DWORD dwShimCount = Data[mod].HookApis.Size;
|
||||
|
||||
/* Enumerate all Shims */
|
||||
for (n = 0; n < dwShimCount; ++n)
|
||||
{
|
||||
PHOOKAPIEX hooks = pShims[n].pHookApi;
|
||||
DWORD dwHookCount = pShims[n].dwHookCount;
|
||||
|
||||
SeiAddHooks(hooks, dwHookCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID SeiAddInternalHooks(DWORD dwNumHooks)
|
||||
{
|
||||
if (dwNumHooks == 0)
|
||||
{
|
||||
g_bInternalHooksUsed = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
SeiAddHooks(g_IntHookEx, _countof(g_IntHookEx));
|
||||
g_bInternalHooksUsed = TRUE;
|
||||
}
|
||||
|
||||
VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DATA_TABLE_ENTRY LdrEntry)
|
||||
{
|
||||
ULONG OldProtection = 0;
|
||||
PVOID Ptr;
|
||||
ULONG Size;
|
||||
NTSTATUS Status;
|
||||
|
||||
SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName);
|
||||
|
||||
Ptr = &FirstThunk->u1.Function;
|
||||
Size = sizeof(FirstThunk->u1.Function);
|
||||
Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, PAGE_EXECUTE_READWRITE, &OldProtection);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk->u1.Function);
|
||||
return;
|
||||
}
|
||||
|
||||
SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk->u1.Function, HookApi->ReplacementFunction);
|
||||
#ifdef _WIN64
|
||||
FirstThunk->u1.Function = (ULONGLONG)HookApi->ReplacementFunction;
|
||||
#else
|
||||
FirstThunk->u1.Function = (DWORD)HookApi->ReplacementFunction;
|
||||
#endif
|
||||
|
||||
Size = sizeof(FirstThunk->u1.Function);
|
||||
Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, OldProtection, &OldProtection);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk->u1.Function);
|
||||
}
|
||||
}
|
||||
|
||||
/* Level(INFO) [SeiPrintExcludeInfo] Module "kernel32.dll" excluded for shim VistaRTMVersionLie, API "NTDLL.DLL!RtlGetVersion", because it is in System32/WinSXS. */
|
||||
|
||||
VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
|
||||
{
|
||||
ULONG Size;
|
||||
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
|
||||
PBYTE DllBase = LdrEntry->DllBase;
|
||||
|
||||
if (SE_IsShimDll(DllBase) || g_hInstance == LdrEntry->DllBase)
|
||||
{
|
||||
SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
|
||||
return;
|
||||
}
|
||||
|
||||
ImportDescriptor = RtlImageDirectoryEntryToData(DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size);
|
||||
if (!ImportDescriptor)
|
||||
{
|
||||
SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
|
||||
return;
|
||||
}
|
||||
|
||||
SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
|
||||
|
||||
for ( ;ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk; ImportDescriptor++)
|
||||
{
|
||||
PHOOKMODULEINFO HookModuleInfo;
|
||||
|
||||
/* Do we have hooks for this module? */
|
||||
HookModuleInfo = SeiFindHookModuleInfoForImportDescriptor(DllBase, ImportDescriptor);
|
||||
|
||||
if (HookModuleInfo)
|
||||
{
|
||||
PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
|
||||
PSINGLE_LIST_ENTRY Entry;
|
||||
|
||||
Entry = HookModuleInfo->ModuleLink.Next;
|
||||
|
||||
while (Entry)
|
||||
{
|
||||
DWORD dwFound = 0;
|
||||
OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk);
|
||||
FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk);
|
||||
|
||||
for (;OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function && Entry; OriginalThunk++, FirstThunk++)
|
||||
{
|
||||
PHOOKAPIEX HookApi = CONTAINING_RECORD(Entry, HOOKAPIEX, ModuleLink);
|
||||
|
||||
if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData))
|
||||
{
|
||||
PIMAGE_IMPORT_BY_NAME ImportName;
|
||||
|
||||
ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData);
|
||||
if (!strcmp((PCSTR)ImportName->Name, HookApi->FunctionName))
|
||||
{
|
||||
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
|
||||
|
||||
/* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
|
||||
dwFound++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHIMENG_FAIL("Ordinals not yet supported\n");
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry)
|
||||
{
|
||||
if (dwFound != 1)
|
||||
{
|
||||
/* One entry not found. */
|
||||
PHOOKAPIEX HookApi = CONTAINING_RECORD(Entry, HOOKAPIEX, ModuleLink);
|
||||
if (!dwFound)
|
||||
SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName);
|
||||
else
|
||||
SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, dwFound, &LdrEntry->BaseDllName);
|
||||
}
|
||||
|
||||
Entry = Entry->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID PatchNewModules(PPEB Peb)
|
||||
{
|
||||
PLIST_ENTRY ListHead, ListEntry;
|
||||
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
||||
|
||||
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
||||
ListEntry = ListHead->Flink;
|
||||
|
||||
while (ListHead != ListEntry)
|
||||
{
|
||||
LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
||||
SeiHookImports(LdrEntry);
|
||||
|
||||
ListEntry = ListEntry->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Level(INFO) Using USER apphack flags 0x2080000
|
||||
*/
|
||||
|
||||
VOID SeiInit(PUNICODE_STRING ProcessImage, HSDB hsdb, SDBQUERYRESULT* pQuery)
|
||||
{
|
||||
DWORD n;
|
||||
ARRAY ShimRef;
|
||||
TAGREF* Data;
|
||||
DWORD dwTotalHooks = 0;
|
||||
|
||||
PPEB Peb = NtCurrentPeb();
|
||||
|
||||
ShimRef.Data = NULL;
|
||||
ShimRef.Size = ShimRef.MaxSize = 0;
|
||||
|
||||
SeiCheckComPlusImage(Peb->ImageBaseAddress);
|
||||
|
||||
/* TODO:
|
||||
if (pQuery->trApphelp)
|
||||
SeiDisplayAppHelp(?pQuery->trApphelp?);
|
||||
*/
|
||||
|
||||
SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(ExePath(%wZ))\n", ProcessImage);
|
||||
SeiBuildShimRefArray(hsdb, pQuery, &ShimRef);
|
||||
SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Complete)\n");
|
||||
|
||||
SHIMENG_INFO("Got %d shims\n", ShimRef.Size);
|
||||
/* TODO:
|
||||
SeiBuildGlobalInclExclList()
|
||||
*/
|
||||
|
||||
Data = ShimRef.Data;
|
||||
|
||||
for (n = 0; n < ShimRef.Size; ++n)
|
||||
{
|
||||
PDB pdb;
|
||||
TAGID ShimRef;
|
||||
if (SdbTagRefToTagID(hsdb, Data[n], &pdb, &ShimRef))
|
||||
{
|
||||
LPCWSTR ShimName, DllName;
|
||||
TAGID ShimTag;
|
||||
WCHAR FullNameBuffer[MAX_PATH];
|
||||
UNICODE_STRING UnicodeDllName;
|
||||
PVOID BaseAddress;
|
||||
PSHIMMODULE pShimInfo = NULL;
|
||||
const char* szCommandLine = "";
|
||||
PHOOKAPIEX pHookApi;
|
||||
DWORD dwHookCount;
|
||||
|
||||
ShimName = SeiGetStringPtr(pdb, ShimRef, TAG_NAME);
|
||||
if (!ShimName)
|
||||
{
|
||||
SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", Data[n]);
|
||||
continue;
|
||||
}
|
||||
|
||||
ShimTag = SeiGetDWORD(pdb, ShimRef, TAG_SHIM_TAGID);
|
||||
if (!ShimTag)
|
||||
{
|
||||
SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SdbGetAppPatchDir(NULL, FullNameBuffer, _countof(FullNameBuffer)))
|
||||
{
|
||||
SHIMENG_WARN("Failed to get the AppPatch dir\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
DllName = SeiGetStringPtr(pdb, ShimTag, TAG_DLLFILE);
|
||||
if (DllName == NULL ||
|
||||
!SUCCEEDED(StringCchCatW(FullNameBuffer, _countof(FullNameBuffer), L"\\")) ||
|
||||
!SUCCEEDED(StringCchCatW(FullNameBuffer, _countof(FullNameBuffer), DllName)))
|
||||
{
|
||||
SHIMENG_WARN("Failed to build a full path for %S\n", ShimName);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
SeiGetShimCommandLine();
|
||||
[SeiInit] COMMAND_LINE VirtualRegistry(WINNT;VistaRTMLie) from AcLayers.DLL
|
||||
*/
|
||||
|
||||
RtlInitUnicodeString(&UnicodeDllName, FullNameBuffer);
|
||||
if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &UnicodeDllName, &BaseAddress)))
|
||||
{
|
||||
pShimInfo = SeiGetShimInfo(BaseAddress);
|
||||
}
|
||||
else if (!NT_SUCCESS(LdrLoadDll(NULL, NULL, &UnicodeDllName, &BaseAddress)))
|
||||
{
|
||||
SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName, ShimName);
|
||||
continue;
|
||||
}
|
||||
if (!pShimInfo)
|
||||
{
|
||||
pShimInfo = SeiCreateShimInfo(DllName, BaseAddress);
|
||||
if (!pShimInfo)
|
||||
{
|
||||
SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress, &UnicodeDllName);
|
||||
SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName, ShimName);
|
||||
|
||||
|
||||
pHookApi = pShimInfo->pGetHookAPIs(szCommandLine, ShimName, &dwHookCount);
|
||||
SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount, &UnicodeDllName, ShimName);
|
||||
if (dwHookCount)
|
||||
SeiAppendHookInfo(pShimInfo, pHookApi, dwHookCount);
|
||||
|
||||
dwTotalHooks += dwHookCount;
|
||||
/*SeiBuildInclExclList*/
|
||||
}
|
||||
}
|
||||
|
||||
SeiAddInternalHooks(dwTotalHooks);
|
||||
SeiResolveAPIs();
|
||||
PatchNewModules(Peb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL SeiGetShimData(PUNICODE_STRING ProcessImage, PVOID pShimData, HSDB* pHsdb, SDBQUERYRESULT* pQuery)
|
||||
{
|
||||
static const UNICODE_STRING ForbiddenShimmingApps[] = {
|
||||
RTL_CONSTANT_STRING(L"ntsd.exe"),
|
||||
RTL_CONSTANT_STRING(L"windbg.exe"),
|
||||
#if WINVER >= 0x600
|
||||
RTL_CONSTANT_STRING(L"slsvc.exe"),
|
||||
#endif
|
||||
};
|
||||
static const UNICODE_STRING BackSlash = RTL_CONSTANT_STRING(L"\\");
|
||||
static const UNICODE_STRING ForwdSlash = RTL_CONSTANT_STRING(L"/");
|
||||
UNICODE_STRING ProcessName;
|
||||
USHORT Back, Forward;
|
||||
HSDB hsdb;
|
||||
DWORD n;
|
||||
|
||||
if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &BackSlash, &Back)))
|
||||
Back = 0;
|
||||
|
||||
if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &ForwdSlash, &Forward)))
|
||||
Forward = 0;
|
||||
|
||||
if (Back < Forward)
|
||||
Back = Forward;
|
||||
|
||||
if (Back)
|
||||
Back += sizeof(WCHAR);
|
||||
|
||||
ProcessName.Buffer = ProcessImage->Buffer + Back / sizeof(WCHAR);
|
||||
ProcessName.Length = ProcessImage->Length - Back;
|
||||
ProcessName.MaximumLength = ProcessImage->MaximumLength - Back;
|
||||
|
||||
for (n = 0; n < _countof(ForbiddenShimmingApps); ++n)
|
||||
{
|
||||
if (RtlEqualUnicodeString(&ProcessName, ForbiddenShimmingApps + n, TRUE))
|
||||
{
|
||||
SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps + n);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We should probably load all db's here, but since we do not support that yet... */
|
||||
hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
|
||||
if (hsdb)
|
||||
{
|
||||
if (SdbUnpackAppCompatData(hsdb, ProcessImage->Buffer, pShimData, pQuery))
|
||||
{
|
||||
*pHsdb = hsdb;
|
||||
return TRUE;
|
||||
}
|
||||
SdbReleaseDatabase(hsdb);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID NTAPI SE_InstallBeforeInit(PUNICODE_STRING ProcessImage, PVOID pShimData)
|
||||
{
|
||||
SHIMENG_FAIL("(%wZ, %p)", ProcessImage, pShimData);
|
||||
/* Find & Load all shims.. */
|
||||
HSDB hsdb = NULL;
|
||||
SDBQUERYRESULT QueryResult = { { 0 } };
|
||||
SHIMENG_MSG("(%wZ, %p)\n", ProcessImage, pShimData);
|
||||
|
||||
if (!SeiGetShimData(ProcessImage, pShimData, &hsdb, &QueryResult))
|
||||
{
|
||||
SHIMENG_FAIL("Failed to get shim data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
g_bShimDuringInit = TRUE;
|
||||
SeiInit(ProcessImage, hsdb, &QueryResult);
|
||||
g_bShimDuringInit = FALSE;
|
||||
|
||||
SdbReleaseDatabase(hsdb);
|
||||
}
|
||||
|
||||
VOID NTAPI SE_InstallAfterInit(PUNICODE_STRING ProcessImage, PVOID pShimData)
|
||||
{
|
||||
SHIMENG_FAIL("(%wZ, %p)", ProcessImage, pShimData);
|
||||
NotifyShims(SHIM_NOTIFY_ATTACH, NULL);
|
||||
}
|
||||
|
||||
VOID NTAPI SE_ProcessDying(VOID)
|
||||
{
|
||||
SHIMENG_FAIL("()");
|
||||
SHIMENG_MSG("()\n");
|
||||
NotifyShims(SHIM_NOTIFY_DETACH, NULL);
|
||||
}
|
||||
|
||||
VOID WINAPI SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry)
|
||||
{
|
||||
SHIMENG_FAIL("(%p)", LdrEntry);
|
||||
SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit ? "" : "AFTER ", &LdrEntry->BaseDllName);
|
||||
NotifyShims(SHIM_REASON_DLL_LOAD, LdrEntry);
|
||||
}
|
||||
|
||||
VOID WINAPI SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry)
|
||||
{
|
||||
SHIMENG_FAIL("(%p)", LdrEntry);
|
||||
SHIMENG_MSG("(%p)\n", LdrEntry);
|
||||
NotifyShims(SHIM_REASON_DLL_UNLOAD, LdrEntry);
|
||||
}
|
||||
|
||||
BOOL WINAPI SE_IsShimDll(PVOID BaseAddress)
|
||||
{
|
||||
SHIMENG_FAIL("(%p)", BaseAddress);
|
||||
return FALSE;
|
||||
SHIMENG_MSG("(%p)\n", BaseAddress);
|
||||
|
||||
return SeiGetShimInfo(BaseAddress) != NULL;
|
||||
}
|
||||
|
||||
|
|
97
reactos/dll/appcompat/apphelp/shimeng.h
Normal file
97
reactos/dll/appcompat/apphelp/shimeng.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2017 Mark Jansen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef SHIMENG_H
|
||||
#define SHIMENG_H
|
||||
|
||||
/* Structure that allows dynamic growing */
|
||||
typedef struct _ARRAY
|
||||
{
|
||||
PVOID Data;
|
||||
DWORD Size;
|
||||
DWORD MaxSize;
|
||||
} ARRAY, *PARRAY;
|
||||
|
||||
|
||||
/* Shims do not know it, but actually they use the type HOOKAPIEX.
|
||||
We use the 'Reserved' entry for our own purposes. */
|
||||
|
||||
typedef struct tagHOOKAPIEX
|
||||
{
|
||||
PCSTR LibraryName;
|
||||
PCSTR FunctionName;
|
||||
PVOID ReplacementFunction;
|
||||
PVOID OriginalFunction;
|
||||
SINGLE_LIST_ENTRY ModuleLink;
|
||||
SINGLE_LIST_ENTRY ApiLink;
|
||||
} HOOKAPIEX, *PHOOKAPIEX;
|
||||
|
||||
C_ASSERT(sizeof(HOOKAPIEX) == sizeof(HOOKAPI));
|
||||
C_ASSERT(offsetof(HOOKAPIEX, ModuleLink) == offsetof(HOOKAPI, Reserved));
|
||||
|
||||
|
||||
typedef struct _HOOKAPIPOINTERS
|
||||
{
|
||||
PHOOKAPIEX pHookApi;
|
||||
DWORD dwHookCount;
|
||||
} HOOKAPIPOINTERS, *PHOOKAPIPOINTERS;
|
||||
|
||||
typedef struct _SHIMMODULE
|
||||
{
|
||||
UNICODE_STRING Name;
|
||||
PVOID BaseAddress;
|
||||
|
||||
PHOOKAPIEX (WINAPI* pGetHookAPIs)(LPCSTR szCommandLine, LPCWSTR wszShimName, PDWORD pdwHookCount);
|
||||
BOOL (WINAPI* pNotifyShims)(DWORD fdwReason, PVOID ptr);
|
||||
|
||||
ARRAY HookApis; /* HOOKAPIPOINTERS */
|
||||
} SHIMMODULE, *PSHIMMODULE;
|
||||
|
||||
typedef struct _HOOKMODULEINFO
|
||||
{
|
||||
UNICODE_STRING Name;
|
||||
PVOID BaseAddress;
|
||||
|
||||
SINGLE_LIST_ENTRY ModuleLink; /* Normal link, all entries from this module */
|
||||
SINGLE_LIST_ENTRY ApiLink; /* Multiple hooks on one api, unsupported for now */
|
||||
} HOOKMODULEINFO, *PHOOKMODULEINFO;
|
||||
|
||||
|
||||
#if SDBAPI_DEBUG_ALLOC
|
||||
|
||||
LPVOID SdbpAlloc(SIZE_T size, int line, const char* file);
|
||||
LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size, SIZE_T oldSize, int line, const char* file);
|
||||
VOID SdbpFree(LPVOID mem, int line, const char* file);
|
||||
|
||||
#define SeiAlloc(size) SdbpAlloc(size, __LINE__, __FILE__)
|
||||
#define SeiReAlloc(mem, size, oldSize) SdbpReAlloc(mem, size, oldSize, __LINE__, __FILE__)
|
||||
#define SeiFree(mem) SdbpFree(mem, __LINE__, __FILE__)
|
||||
|
||||
#else
|
||||
|
||||
LPVOID SdbpAlloc(SIZE_T size);
|
||||
LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size, SIZE_T oldSize);
|
||||
VOID SdbpFree(LPVOID mem);
|
||||
|
||||
#define SeiAlloc(size) SdbpAlloc(size)
|
||||
#define SeiReAlloc(mem, size, oldSize) SdbpReAlloc(mem, size, oldSize)
|
||||
#define SeiFree(mem) SdbpFree(mem)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SHIMENG_H
|
Loading…
Reference in a new issue