[APPHELP] Add ordinal import support
authorMark Jansen <mark.jansen@reactos.org>
Sun, 11 Feb 2018 21:40:51 +0000 (22:40 +0100)
committerMark Jansen <mark.jansen@reactos.org>
Wed, 1 May 2019 17:22:19 +0000 (19:22 +0200)
dll/appcompat/apphelp/shimeng.c

index 3e8a169..190e17c 100644 (file)
@@ -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)
     {