[SHIMENG] Implement experimental support for multiple hooks on the same function 1417/head
authorMark Jansen <mark.jansen@reactos.org>
Wed, 13 Mar 2019 19:15:18 +0000 (20:15 +0100)
committerMark Jansen <mark.jansen@reactos.org>
Thu, 14 Mar 2019 19:02:01 +0000 (20:02 +0100)
dll/appcompat/apphelp/shimeng.c
dll/appcompat/apphelp/shimeng.h

index e3c152b..3e8a169 100644 (file)
@@ -46,7 +46,7 @@ HOOKAPIEX g_IntHookEx[] =
         StubGetProcAddress, /* ReplacementFunction*/
         NULL,               /* OriginalFunction */
         NULL,               /* pShimInfo */
-        NULL                /* Unused */
+        NULL                /* ApiLink */
     },
 };
 
@@ -545,17 +545,7 @@ VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim)
         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
         {
@@ -582,14 +572,22 @@ VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim)
             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);
+                while (HookApi->ApiLink)
+                {
+                    HookApi = HookApi->ApiLink;
+                }
+                HookApi->ApiLink = hook;
+                hook = NULL;
+                break;
             }
         }
-        pHookApi = ARRAY_Append(&HookModuleInfo->HookApis, PHOOKAPIEX);
-        if (pHookApi)
-            *pHookApi = hook;
+        /* No place found yet, append it */
+        if (hook)
+        {
+            pHookApi = ARRAY_Append(&HookModuleInfo->HookApis, PHOOKAPIEX);
+            if (pHookApi)
+                *pHookApi = hook;
+        }
     }
 }
 
@@ -641,8 +639,57 @@ FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName)
     return proc;
 }
 
+VOID SeiResolveAPI(PHOOKMODULEINFO HookModuleInfo)
+{
+    DWORD n;
+    ANSI_STRING AnsiString;
+
+    ASSERT(HookModuleInfo->BaseAddress != NULL);
+
+    for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n)
+    {
+        PVOID ProcAddress;
+        PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n);
+        RtlInitAnsiString(&AnsiString, HookApi->FunctionName);
+
+        if (!NT_SUCCESS(LdrGetProcedureAddress(HookModuleInfo->BaseAddress, &AnsiString, 0, &ProcAddress)))
+        {
+            SHIMENG_FAIL("Unable to retrieve %s!%s\n", HookApi->LibraryName, HookApi->FunctionName);
+            continue;
+        }
+
+        HookApi->OriginalFunction = ProcAddress;
+        if (HookApi->ApiLink)
+        {
+            SHIMENG_MSG("TODO: Figure out how to handle conflicting In/Exports with ApiLink!\n");
+        }
+        while (HookApi->ApiLink)
+        {
+            HookApi->ApiLink->OriginalFunction = HookApi->OriginalFunction;
+            HookApi->OriginalFunction = HookApi->ApiLink->ReplacementFunction;
+            HookApi = HookApi->ApiLink;
+        }
+    }
+}
+
 /* Walk all shim modules / enabled shims, and add their hooks */
 VOID SeiResolveAPIs(VOID)
+{
+    DWORD n;
+
+    for (n = 0; n < ARRAY_Size(&g_pHookArray); ++n)
+    {
+        PHOOKMODULEINFO pModuleInfo = ARRAY_At(&g_pHookArray, HOOKMODULEINFO, n);
+
+        /* Is this module loaded? */
+        if (pModuleInfo->BaseAddress)
+        {
+            SeiResolveAPI(pModuleInfo);
+        }
+    }
+}
+
+VOID SeiCombineHookInfo(VOID)
 {
     DWORD mod, n;
 
@@ -1249,6 +1296,7 @@ VOID SeiInit(PUNICODE_STRING ProcessImage, HSDB hsdb, SDBQUERYRESULT* pQuery)
     }
 
     SeiAddInternalHooks(dwTotalHooks);
+    SeiCombineHookInfo();
     SeiResolveAPIs();
     PatchNewModules(Peb);
 
@@ -1347,8 +1395,17 @@ VOID NTAPI SE_ProcessDying(VOID)
 
 VOID WINAPI SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry)
 {
+    PHOOKMODULEINFO HookModuleInfo;
     SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit ? "" : "AFTER ", &LdrEntry->BaseDllName);
 
+    HookModuleInfo = SeiFindHookModuleInfo(&LdrEntry->BaseDllName, NULL);
+    if (HookModuleInfo)
+    {
+        ASSERT(HookModuleInfo->BaseAddress == NULL);
+        HookModuleInfo->BaseAddress = LdrEntry->DllBase;
+        SeiResolveAPI(HookModuleInfo);
+    }
+
     SeiHookImports(LdrEntry);
 
     NotifyShims(SHIM_REASON_DLL_LOAD, LdrEntry);
index 0081c49..c6e3888 100644 (file)
@@ -23,6 +23,8 @@ typedef struct _ARRAY
 typedef struct _SHIMINFO *PSHIMINFO;
 typedef struct _SHIMMODULE *PSHIMMODULE;
 
+typedef struct tagHOOKAPIEX *PHOOKAPIEX;
+
 /* Shims know this structure as HOOKAPI, with 2 reserved members (the last 2). */
 typedef struct tagHOOKAPIEX
 {
@@ -31,8 +33,8 @@ typedef struct tagHOOKAPIEX
     PVOID ReplacementFunction;
     PVOID OriginalFunction;
     PSHIMINFO pShimInfo;
-    PVOID Unused;
-} HOOKAPIEX, *PHOOKAPIEX;
+    PHOOKAPIEX ApiLink;
+} HOOKAPIEX;
 
 C_ASSERT(sizeof(HOOKAPIEX) == sizeof(HOOKAPI));
 C_ASSERT(offsetof(HOOKAPIEX, pShimInfo) == offsetof(HOOKAPI, Reserved));