From 1570f08b4d82e44928d7b328fa07aa32759858e5 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Sun, 11 Feb 2018 22:40:51 +0100 Subject: [PATCH] [APPHELP] Add ordinal import support --- dll/appcompat/apphelp/shimeng.c | 155 ++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 59 deletions(-) diff --git a/dll/appcompat/apphelp/shimeng.c b/dll/appcompat/apphelp/shimeng.c index 3e8a1696177..190e17c2a72 100644 --- a/dll/appcompat/apphelp/shimeng.c +++ b/dll/appcompat/apphelp/shimeng.c @@ -37,6 +37,7 @@ static ARRAY g_pShimInfo; /* PSHIMMODULE */ static ARRAY g_pHookArray; /* HOOKMODULEINFO */ static ARRAY g_InExclude; /* INEXCLUDE */ +typedef FARPROC(WINAPI* GETPROCADDRESSPROC)(HINSTANCE, LPCSTR); /* If we have setup a hook for a function, we should also redirect GetProcAddress for this function */ HOOKAPIEX g_IntHookEx[] = { @@ -207,6 +208,39 @@ BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR Function, PCSTR Format, ...) return TRUE; } +static +BOOL SeiIsOrdinalName(LPCSTR lpProcName) +{ + return (ULONG_PTR)lpProcName <= MAXUSHORT; +} + +LPCSTR SeiPrintFunctionName(LPCSTR lpProcName, char szOrdProcFmt[10]) +{ + if (SeiIsOrdinalName(lpProcName)) + { + StringCchPrintfA(szOrdProcFmt, 10, "#%Iu", (ULONG_PTR)lpProcName); + return szOrdProcFmt; + } + return lpProcName; +} + +int SeiCompareFunctionName(LPCSTR lpProcName1, LPCSTR lpProcName2) +{ + BOOL Ord1 = SeiIsOrdinalName(lpProcName1); + BOOL Ord2 = SeiIsOrdinalName(lpProcName2); + + /* One is an ordinal, the other not */ + if (Ord1 != Ord2) + return 1; + + /* Compare ordinals */ + if (Ord1) + return (ULONG_PTR)lpProcName1 != (ULONG_PTR)lpProcName2; + + /* Compare names */ + return strcmp(lpProcName1, lpProcName2); +} + PVOID SeiGetModuleFromAddress(PVOID addr) { @@ -216,7 +250,6 @@ PVOID SeiGetModuleFromAddress(PVOID addr) } - /* TODO: Guard against recursive calling / calling init multiple times! */ VOID NotifyShims(DWORD dwReason, PVOID Info) { @@ -429,7 +462,7 @@ static VOID SeiSetLayerEnvVar(LPCWSTR wszLayer) Status = RtlSetEnvironmentVariable(NULL, &VarName, &Value); if (NT_SUCCESS(Status)) - SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName, &Value); + SHIMENG_INFO("%wZ=%wZ\n", &VarName, &Value); else SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName, Status); } @@ -542,7 +575,6 @@ VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim) continue; } - RtlInitAnsiString(&AnsiString, hook->FunctionName); if (NT_SUCCESS(LdrGetDllHandle(NULL, 0, &UnicodeModName, &DllHandle))) { HookModuleInfo = SeiFindHookModuleInfo(NULL, DllHandle); @@ -569,7 +601,7 @@ VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim) for (j = 0; j < ARRAY_Size(&HookModuleInfo->HookApis); ++j) { PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, j); - int CmpResult = strcmp(hook->FunctionName, HookApi->FunctionName); + int CmpResult = SeiCompareFunctionName(hook->FunctionName, HookApi->FunctionName); if (CmpResult == 0) { while (HookApi->ApiLink) @@ -591,42 +623,32 @@ VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim) } } -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] = ""; - LPCSTR lpPrintName = lpProcName; PVOID Addr = _ReturnAddress(); PHOOKMODULEINFO HookModuleInfo; FARPROC proc = ((GETPROCADDRESSPROC)g_IntHookEx[0].OriginalFunction)(hModule, lpProcName); - - if ((DWORD_PTR)lpProcName <= MAXUSHORT) - { - sprintf(szOrdProcName, "#%Iu", (DWORD_PTR)lpProcName); - lpPrintName = szOrdProcName; - } + char szOrdProcFmt[10]; Addr = SeiGetModuleFromAddress(Addr); if (SE_IsShimDll(Addr)) { - SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule, lpPrintName); + SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule, SeiPrintFunctionName(lpProcName, szOrdProcFmt)); return proc; } - SHIMENG_INFO("(GetProcAddress(%p!%s) => %p\n", hModule, lpPrintName, proc); + SHIMENG_INFO("(GetProcAddress(%p!%s) => %p\n", hModule, SeiPrintFunctionName(lpProcName, szOrdProcFmt), proc); HookModuleInfo = SeiFindHookModuleInfo(NULL, hModule); - /* FIXME: Ordinal not yet supported */ - if (HookModuleInfo && HIWORD(lpProcName)) + if (HookModuleInfo) { DWORD n; for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n) { PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n); - int CmpResult = strcmp(lpProcName, HookApi->FunctionName); + int CmpResult = SeiCompareFunctionName(lpProcName, HookApi->FunctionName); if (CmpResult == 0) { SHIMENG_MSG("Redirecting %p to %p\n", proc, HookApi->ReplacementFunction); @@ -648,13 +670,25 @@ VOID SeiResolveAPI(PHOOKMODULEINFO HookModuleInfo) for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n) { + NTSTATUS Status; PVOID ProcAddress; PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n); - RtlInitAnsiString(&AnsiString, HookApi->FunctionName); - if (!NT_SUCCESS(LdrGetProcedureAddress(HookModuleInfo->BaseAddress, &AnsiString, 0, &ProcAddress))) + if (!SeiIsOrdinalName(HookApi->FunctionName)) + { + RtlInitAnsiString(&AnsiString, HookApi->FunctionName); + Status = LdrGetProcedureAddress(HookModuleInfo->BaseAddress, &AnsiString, 0, &ProcAddress); + } + else + { + Status = LdrGetProcedureAddress(HookModuleInfo->BaseAddress, NULL, (ULONG_PTR)HookApi->FunctionName, &ProcAddress); + } + + if (!NT_SUCCESS(Status)) { - SHIMENG_FAIL("Unable to retrieve %s!%s\n", HookApi->LibraryName, HookApi->FunctionName); + char szOrdProcFmt[10]; + LPCSTR lpFunctionName = SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt); + SHIMENG_FAIL("Unable to retrieve %s!%s\n", HookApi->LibraryName, lpFunctionName); continue; } @@ -732,8 +766,9 @@ VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DA PVOID Ptr; SIZE_T Size; NTSTATUS Status; + char szOrdProcFmt[10]; - SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName); + SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi->LibraryName, SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt), &LdrEntry->BaseDllName); Ptr = &FirstThunk->u1.Function; Size = sizeof(FirstThunk->u1.Function); @@ -746,11 +781,7 @@ VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DA } 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 + FirstThunk->u1.Function = (ULONG_PTR)HookApi->ReplacementFunction; Size = sizeof(FirstThunk->u1.Function); Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, OldProtection, &OldProtection); @@ -782,6 +813,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi) PSHIMINFO pShimInfo = HookApi->pShimInfo; PINEXCLUDE InExclude; BOOL IsExcluded = FALSE; + char szOrdProcFmt[10]; if (!pShimInfo) { @@ -801,7 +833,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi) 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); + &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt)); return TRUE; } @@ -809,7 +841,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi) 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); + &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt)); } IsExcluded = FALSE; @@ -818,7 +850,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi) 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); + &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt)); } return IsExcluded; @@ -974,33 +1006,45 @@ VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry) /* Walk all imports */ for (;OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function; OriginalThunk++, FirstThunk++) { - if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData)) + if (!IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Function)) { - PIMAGE_IMPORT_BY_NAME ImportName; - - ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData); - if (!strcmp((PCSTR)ImportName->Name, HookApi->FunctionName)) + if (!SeiIsOrdinalName(HookApi->FunctionName)) { - SeiPatchNewImport(FirstThunk, HookApi, LdrEntry); + PIMAGE_IMPORT_BY_NAME ImportName; - /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */ - dwFound++; + ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.Function); + 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 (SeiIsOrdinalName(HookApi->FunctionName)) + { + if ((PCSTR)IMAGE_ORDINAL(OriginalThunk->u1.Function) == HookApi->FunctionName) + { + SeiPatchNewImport(FirstThunk, HookApi, LdrEntry); + dwFound++; + } + } } } if (dwFound != 1) { + char szOrdProcFmt[10]; + LPCSTR FuncName = SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt); + /* One entry not found. */ if (!dwFound) - SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName); + SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi->LibraryName, FuncName, &LdrEntry->BaseDllName); else - SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, dwFound, &LdrEntry->BaseDllName); + SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi->LibraryName, FuncName, dwFound, &LdrEntry->BaseDllName); } } } @@ -1315,28 +1359,21 @@ BOOL SeiGetShimData(PUNICODE_STRING ProcessImage, PVOID pShimData, HSDB* pHsdb, 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"/"); + static const UNICODE_STRING PathDividerFind = RTL_CONSTANT_STRING(L"\\/"); UNICODE_STRING ProcessName; - USHORT Back, Forward; + USHORT PathDivider; 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 (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &PathDividerFind, &PathDivider))) + PathDivider = 0; - if (Back) - Back += sizeof(WCHAR); + if (PathDivider) + PathDivider += sizeof(WCHAR); - ProcessName.Buffer = ProcessImage->Buffer + Back / sizeof(WCHAR); - ProcessName.Length = ProcessImage->Length - Back; - ProcessName.MaximumLength = ProcessImage->MaximumLength - Back; + ProcessName.Buffer = ProcessImage->Buffer + PathDivider / sizeof(WCHAR); + ProcessName.Length = ProcessImage->Length - PathDivider; + ProcessName.MaximumLength = ProcessImage->MaximumLength - PathDivider; for (n = 0; n < ARRAYSIZE(ForbiddenShimmingApps); ++n) { -- 2.17.1