[APPHELP] Add ordinal import support

This commit is contained in:
Mark Jansen 2018-02-11 22:40:51 +01:00
parent 2872cfc3b7
commit 1570f08b4d
No known key found for this signature in database
GPG key ID: B39240EE84BEAE8B

View file

@ -37,6 +37,7 @@ static ARRAY g_pShimInfo; /* PSHIMMODULE */
static ARRAY g_pHookArray; /* HOOKMODULEINFO */ static ARRAY g_pHookArray; /* HOOKMODULEINFO */
static ARRAY g_InExclude; /* INEXCLUDE */ 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 */ /* If we have setup a hook for a function, we should also redirect GetProcAddress for this function */
HOOKAPIEX g_IntHookEx[] = HOOKAPIEX g_IntHookEx[] =
{ {
@ -207,6 +208,39 @@ BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR Function, PCSTR Format, ...)
return TRUE; 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) PVOID SeiGetModuleFromAddress(PVOID addr)
{ {
@ -216,7 +250,6 @@ PVOID SeiGetModuleFromAddress(PVOID addr)
} }
/* TODO: Guard against recursive calling / calling init multiple times! */ /* TODO: Guard against recursive calling / calling init multiple times! */
VOID NotifyShims(DWORD dwReason, PVOID Info) VOID NotifyShims(DWORD dwReason, PVOID Info)
{ {
@ -429,7 +462,7 @@ static VOID SeiSetLayerEnvVar(LPCWSTR wszLayer)
Status = RtlSetEnvironmentVariable(NULL, &VarName, &Value); Status = RtlSetEnvironmentVariable(NULL, &VarName, &Value);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName, &Value); SHIMENG_INFO("%wZ=%wZ\n", &VarName, &Value);
else else
SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName, Status); SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName, Status);
} }
@ -542,7 +575,6 @@ VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim)
continue; continue;
} }
RtlInitAnsiString(&AnsiString, hook->FunctionName);
if (NT_SUCCESS(LdrGetDllHandle(NULL, 0, &UnicodeModName, &DllHandle))) if (NT_SUCCESS(LdrGetDllHandle(NULL, 0, &UnicodeModName, &DllHandle)))
{ {
HookModuleInfo = SeiFindHookModuleInfo(NULL, 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) for (j = 0; j < ARRAY_Size(&HookModuleInfo->HookApis); ++j)
{ {
PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, 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) if (CmpResult == 0)
{ {
while (HookApi->ApiLink) 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) */ /* 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) FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName)
{ {
char szOrdProcName[10] = "";
LPCSTR lpPrintName = lpProcName;
PVOID Addr = _ReturnAddress(); PVOID Addr = _ReturnAddress();
PHOOKMODULEINFO HookModuleInfo; PHOOKMODULEINFO HookModuleInfo;
FARPROC proc = ((GETPROCADDRESSPROC)g_IntHookEx[0].OriginalFunction)(hModule, lpProcName); FARPROC proc = ((GETPROCADDRESSPROC)g_IntHookEx[0].OriginalFunction)(hModule, lpProcName);
char szOrdProcFmt[10];
if ((DWORD_PTR)lpProcName <= MAXUSHORT)
{
sprintf(szOrdProcName, "#%Iu", (DWORD_PTR)lpProcName);
lpPrintName = szOrdProcName;
}
Addr = SeiGetModuleFromAddress(Addr); Addr = SeiGetModuleFromAddress(Addr);
if (SE_IsShimDll(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; 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); HookModuleInfo = SeiFindHookModuleInfo(NULL, hModule);
/* FIXME: Ordinal not yet supported */ if (HookModuleInfo)
if (HookModuleInfo && HIWORD(lpProcName))
{ {
DWORD n; DWORD n;
for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n) for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n)
{ {
PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n); PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n);
int CmpResult = strcmp(lpProcName, HookApi->FunctionName); int CmpResult = SeiCompareFunctionName(lpProcName, HookApi->FunctionName);
if (CmpResult == 0) if (CmpResult == 0)
{ {
SHIMENG_MSG("Redirecting %p to %p\n", proc, HookApi->ReplacementFunction); 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) for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n)
{ {
NTSTATUS Status;
PVOID ProcAddress; PVOID ProcAddress;
PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n); 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))
{ {
SHIMENG_FAIL("Unable to retrieve %s!%s\n", HookApi->LibraryName, 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))
{
char szOrdProcFmt[10];
LPCSTR lpFunctionName = SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt);
SHIMENG_FAIL("Unable to retrieve %s!%s\n", HookApi->LibraryName, lpFunctionName);
continue; continue;
} }
@ -732,8 +766,9 @@ VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DA
PVOID Ptr; PVOID Ptr;
SIZE_T Size; SIZE_T Size;
NTSTATUS Status; 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; Ptr = &FirstThunk->u1.Function;
Size = sizeof(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); SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk->u1.Function, HookApi->ReplacementFunction);
#ifdef _WIN64 FirstThunk->u1.Function = (ULONG_PTR)HookApi->ReplacementFunction;
FirstThunk->u1.Function = (ULONGLONG)HookApi->ReplacementFunction;
#else
FirstThunk->u1.Function = (DWORD)HookApi->ReplacementFunction;
#endif
Size = sizeof(FirstThunk->u1.Function); Size = sizeof(FirstThunk->u1.Function);
Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, OldProtection, &OldProtection); Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, OldProtection, &OldProtection);
@ -782,6 +813,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi)
PSHIMINFO pShimInfo = HookApi->pShimInfo; PSHIMINFO pShimInfo = HookApi->pShimInfo;
PINEXCLUDE InExclude; PINEXCLUDE InExclude;
BOOL IsExcluded = FALSE; BOOL IsExcluded = FALSE;
char szOrdProcFmt[10];
if (!pShimInfo) if (!pShimInfo)
{ {
@ -801,7 +833,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi)
if (!InExclude->Include) if (!InExclude->Include)
{ {
SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it on in the exclude list.\n", 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; return TRUE;
} }
@ -809,7 +841,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi)
if (IsExcluded) if (IsExcluded)
{ {
SHIMENG_INFO("Module '%wZ' included for shim %S, API '%s!%s', because it is on the include list.\n", 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; IsExcluded = FALSE;
@ -818,7 +850,7 @@ BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi)
if (IsExcluded) if (IsExcluded)
{ {
SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it is in System32/WinSXS.\n", 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; return IsExcluded;
@ -974,33 +1006,45 @@ VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
/* Walk all imports */ /* Walk all imports */
for (;OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function; OriginalThunk++, FirstThunk++) 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; if (!SeiIsOrdinalName(HookApi->FunctionName))
ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData);
if (!strcmp((PCSTR)ImportName->Name, 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. */ ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.Function);
dwFound++; 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 else
{ {
SHIMENG_FAIL("Ordinals not yet supported\n"); if (SeiIsOrdinalName(HookApi->FunctionName))
ASSERT(0); {
if ((PCSTR)IMAGE_ORDINAL(OriginalThunk->u1.Function) == HookApi->FunctionName)
{
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
dwFound++;
}
}
} }
} }
if (dwFound != 1) if (dwFound != 1)
{ {
char szOrdProcFmt[10];
LPCSTR FuncName = SeiPrintFunctionName(HookApi->FunctionName, szOrdProcFmt);
/* One entry not found. */ /* One entry not found. */
if (!dwFound) 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 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"), RTL_CONSTANT_STRING(L"slsvc.exe"),
#endif #endif
}; };
static const UNICODE_STRING BackSlash = RTL_CONSTANT_STRING(L"\\"); static const UNICODE_STRING PathDividerFind = RTL_CONSTANT_STRING(L"\\/");
static const UNICODE_STRING ForwdSlash = RTL_CONSTANT_STRING(L"/");
UNICODE_STRING ProcessName; UNICODE_STRING ProcessName;
USHORT Back, Forward; USHORT PathDivider;
HSDB hsdb; HSDB hsdb;
DWORD n; DWORD n;
if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &BackSlash, &Back))) if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &PathDividerFind, &PathDivider)))
Back = 0; PathDivider = 0;
if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &ForwdSlash, &Forward))) if (PathDivider)
Forward = 0; PathDivider += sizeof(WCHAR);
if (Back < Forward) ProcessName.Buffer = ProcessImage->Buffer + PathDivider / sizeof(WCHAR);
Back = Forward; ProcessName.Length = ProcessImage->Length - PathDivider;
ProcessName.MaximumLength = ProcessImage->MaximumLength - PathDivider;
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 < ARRAYSIZE(ForbiddenShimmingApps); ++n) for (n = 0; n < ARRAYSIZE(ForbiddenShimmingApps); ++n)
{ {