https://git.reactos.org/?p=reactos.git;a=commitdiff;h=86e0d5e9b8ddbb620213f2adcdb131727af379bb

commit 86e0d5e9b8ddbb620213f2adcdb131727af379bb
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Tue Nov 29 00:49:33 2022 +0100
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Tue Aug 29 17:26:57 2023 +0200

    [NTOS:MM/PS] Remove code duplication between 
LookupEntryPoint/MiLocateExportName/MiFindExportedRoutineByName. (#4918)
    
    As it turns out, those three functions were duplicating the same code
    between each other. Reimplement these in terms of a common helper,
    RtlFindExportedRoutineByName().
    Indeed: MiFindExportedRoutineByName() was just MiLocateExportName()
    but taking a PANSI_STRING instead of a NULL-terminated string.
    
    A similar state of affairs also existed in Windows <= 2003, and the
    MS guys also noticed it. Both routines have been then merged and renamed
    to MiFindExportedRoutineByName() on Windows 8 (taking a PCSTR instead),
    and finally renamed and exported as RtlFindExportedRoutineByName()
    on Windows 10.
---
 ntoskrnl/include/internal/mm.h |  24 ++++-
 ntoskrnl/include/internal/ps.h |   6 --
 ntoskrnl/mm/ARM3/sysldr.c      | 221 +++++++++++++++++++++++++----------------
 ntoskrnl/ps/psmgr.c            |  80 ++-------------
 4 files changed, 168 insertions(+), 163 deletions(-)

diff --git a/ntoskrnl/include/internal/mm.h b/ntoskrnl/include/internal/mm.h
index 0d97244a7c9..f637014794a 100644
--- a/ntoskrnl/include/internal/mm.h
+++ b/ntoskrnl/include/internal/mm.h
@@ -1490,16 +1490,15 @@ VOID
 NTAPI
 MmFreeSectionSegments(PFILE_OBJECT FileObject);
 
-/* Exported from NT 6.2 Onward. We keep it internal. */
+/* Exported from NT 6.2 onward. We keep it internal. */
 NTSTATUS
 NTAPI
-MmMapViewInSystemSpaceEx (
+MmMapViewInSystemSpaceEx(
     _In_ PVOID Section,
     _Outptr_result_bytebuffer_ (*ViewSize) PVOID *MappedBase,
     _Inout_ PSIZE_T ViewSize,
     _Inout_ PLARGE_INTEGER SectionOffset,
-    _In_ ULONG_PTR Flags
-    );
+    _In_ ULONG_PTR Flags);
 
 BOOLEAN
 NTAPI
@@ -1661,6 +1660,23 @@ NTAPI
 MmFreeDriverInitialization(
     IN PLDR_DATA_TABLE_ENTRY LdrEntry);
 
+/* ReactOS-only, used by psmgr.c PspLookupSystemDllEntryPoint() as well */
+NTSTATUS
+NTAPI
+RtlpFindExportedRoutineByName(
+    _In_ PVOID ImageBase,
+    _In_ PCSTR ExportName,
+    _Out_ PVOID* Function,
+    _Out_opt_ PBOOLEAN IsForwarder,
+    _In_ NTSTATUS NotFoundStatus);
+
+/* Exported from NT 10.0 onward. We keep it internal. */
+PVOID
+NTAPI
+RtlFindExportedRoutineByName(
+    _In_ PVOID ImageBase,
+    _In_ PCSTR ExportName);
+
 /* procsup.c *****************************************************************/
 
 NTSTATUS
diff --git a/ntoskrnl/include/internal/ps.h b/ntoskrnl/include/internal/ps.h
index 7f55554f890..5be13cfc632 100644
--- a/ntoskrnl/include/internal/ps.h
+++ b/ntoskrnl/include/internal/ps.h
@@ -134,12 +134,6 @@ PsLocateSystemDll(
     VOID
 );
 
-NTSTATUS
-NTAPI
-PspGetSystemDllEntryPoints(
-    VOID
-);
-
 VOID
 NTAPI
 PsChangeQuantumTable(
diff --git a/ntoskrnl/mm/ARM3/sysldr.c b/ntoskrnl/mm/ARM3/sysldr.c
index c5f42ca582d..9a39b66d7ce 100644
--- a/ntoskrnl/mm/ARM3/sysldr.c
+++ b/ntoskrnl/mm/ARM3/sysldr.c
@@ -267,60 +267,163 @@ NameToOrdinal(
     return OrdinalTable[Mid];
 }
 
-PVOID
+/**
+ * @brief
+ * ReactOS-only helper routine for RtlFindExportedRoutineByName(),
+ * that provides a finer granularity regarding the nature of the
+ * export, and the failure reasons.
+ *
+ * @param[in]   ImageBase
+ * The base address of the loaded image.
+ *
+ * @param[in]   ExportName
+ * The name of the export, given as an ANSI NULL-terminated string.
+ *
+ * @param[out]  Function
+ * The address of the named exported routine, or NULL if not found.
+ * If the export is a forwarder (see @p IsForwarder below), this
+ * address points to the forwarder name.
+ *
+ * @param[out]  IsForwarder
+ * An optional pointer to a BOOLEAN variable, that is set to TRUE
+ * if the found export is a forwarder, and FALSE otherwise.
+ *
+ * @param[in]   NotFoundStatus
+ * The status code to return in case the export could not be found
+ * (examples: STATUS_ENTRYPOINT_NOT_FOUND, STATUS_PROCEDURE_NOT_FOUND).
+ *
+ * @return
+ * A status code as follows:
+ * - STATUS_SUCCESS if the named exported routine is found;
+ * - The custom @p NotFoundStatus if the export could not be found;
+ * - STATUS_INVALID_PARAMETER if the image is invalid or does not
+ *   contain an Export Directory.
+ *
+ * @note
+ * See RtlFindExportedRoutineByName() for more remarks.
+ * Used by psmgr.c PspLookupSystemDllEntryPoint() as well.
+ **/
+NTSTATUS
 NTAPI
-MiLocateExportName(IN PVOID DllBase,
-                   IN PCHAR ExportName)
+RtlpFindExportedRoutineByName(
+    _In_ PVOID ImageBase,
+    _In_ PCSTR ExportName,
+    _Out_ PVOID* Function,
+    _Out_opt_ PBOOLEAN IsForwarder,
+    _In_ NTSTATUS NotFoundStatus)
 {
+    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
     PULONG NameTable;
     PUSHORT OrdinalTable;
-    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
-    USHORT Ordinal;
-    PVOID Function;
     ULONG ExportSize;
+    USHORT Ordinal;
     PULONG ExportTable;
+    ULONG_PTR FunctionAddress;
+
     PAGED_CODE();
 
     /* Get the export directory */
-    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
+    ExportDirectory = RtlImageDirectoryEntryToData(ImageBase,
                                                    TRUE,
                                                    
IMAGE_DIRECTORY_ENTRY_EXPORT,
                                                    &ExportSize);
-    if (!ExportDirectory) return NULL;
+    if (!ExportDirectory)
+        return STATUS_INVALID_PARAMETER;
 
     /* Setup name tables */
-    NameTable = (PULONG)((ULONG_PTR)DllBase +
-                         ExportDirectory->AddressOfNames);
-    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
-                             ExportDirectory->AddressOfNameOrdinals);
+    NameTable = (PULONG)RVA(ImageBase, ExportDirectory->AddressOfNames);
+    OrdinalTable = (PUSHORT)RVA(ImageBase, 
ExportDirectory->AddressOfNameOrdinals);
 
     /* Get the ordinal */
     Ordinal = NameToOrdinal(ExportName,
-                            DllBase,
+                            ImageBase,
                             ExportDirectory->NumberOfNames,
                             NameTable,
                             OrdinalTable);
 
     /* Check if we couldn't find it */
-    if (Ordinal == -1) return NULL;
+    if (Ordinal == -1)
+        return NotFoundStatus;
 
     /* Validate the ordinal */
-    if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL;
+    if (Ordinal >= ExportDirectory->NumberOfFunctions)
+        return NotFoundStatus;
 
-    /* Resolve the address and write it */
-    ExportTable = (PULONG)((ULONG_PTR)DllBase +
-                           ExportDirectory->AddressOfFunctions);
-    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
+    /* Resolve the function's address */
+    ExportTable = (PULONG)RVA(ImageBase, ExportDirectory->AddressOfFunctions);
+    FunctionAddress = (ULONG_PTR)RVA(ImageBase, ExportTable[Ordinal]);
 
     /* Check if the function is actually a forwarder */
-    if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
-        ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+    if (IsForwarder)
     {
-        /* It is, fail */
+        *IsForwarder = FALSE;
+        if ((FunctionAddress > (ULONG_PTR)ExportDirectory) &&
+            (FunctionAddress < (ULONG_PTR)ExportDirectory + ExportSize))
+        {
+            /* It is, and points to the forwarder name */
+            *IsForwarder = TRUE;
+        }
+    }
+
+    /* We've found it */
+    *Function = (PVOID)FunctionAddress;
+    return STATUS_SUCCESS;
+}
+
+/**
+ * @brief
+ * Finds the address of a given named exported routine in a loaded image.
+ * Note that this function does not support forwarders.
+ *
+ * @param[in]   ImageBase
+ * The base address of the loaded image.
+ *
+ * @param[in]   ExportName
+ * The name of the export, given as an ANSI NULL-terminated string.
+ *
+ * @return
+ * The address of the named exported routine, or NULL if not found.
+ * If the export is a forwarder, this function returns NULL as well.
+ *
+ * @note
+ * This routine was originally named MiLocateExportName(), with a separate
+ * duplicated MiFindExportedRoutineByName() one (taking a PANSI_STRING)
+ * on Windows <= 2003. Both routines have been then merged and renamed
+ * to MiFindExportedRoutineByName() on Windows 8 (taking a PCSTR instead),
+ * and finally renamed and exported as RtlFindExportedRoutineByName() on
+ * Windows 10.
+ *
+ * @see 
https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/mm/sysload/mmgetsystemroutineaddress.htm
+ **/
+PVOID
+NTAPI
+RtlFindExportedRoutineByName(
+    _In_ PVOID ImageBase,
+    _In_ PCSTR ExportName)
+{
+    NTSTATUS Status;
+    BOOLEAN IsForwarder = FALSE;
+    PVOID Function;
+
+    PAGED_CODE();
+
+    /* Call the internal API */
+    Status = RtlpFindExportedRoutineByName(ImageBase,
+                                           ExportName,
+                                           &Function,
+                                           &IsForwarder,
+                                           STATUS_ENTRYPOINT_NOT_FOUND);
+    if (!NT_SUCCESS(Status))
+        return NULL;
+
+    /* If the export is actually a forwarder, log the error and fail */
+    if (IsForwarder)
+    {
+        DPRINT1("RtlFindExportedRoutineByName does not support forwarders!\n", 
FALSE);
         return NULL;
     }
 
-    /* We found it */
+    /* We've found the export */
     return Function;
 }
 
@@ -340,8 +443,8 @@ MmCallDllInitialize(
     PAGED_CODE();
 
     /* Try to see if the image exports a DllInitialize routine */
-    DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
-                                                     "DllInitialize");
+    DllInit = (PMM_DLL_INITIALIZE)
+        RtlFindExportedRoutineByName(LdrEntry->DllBase, "DllInitialize");
     if (!DllInit)
         return STATUS_SUCCESS;
 
@@ -399,7 +502,8 @@ MiCallDllUnloadAndUnloadDll(
     PAGED_CODE();
 
     /* Retrieve the DllUnload routine */
-    DllUnload = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, 
"DllUnload");
+    DllUnload = (PMM_DLL_UNLOAD)
+        RtlFindExportedRoutineByName(LdrEntry->DllBase, "DllUnload");
     if (!DllUnload)
         return FALSE;
 
@@ -512,58 +616,6 @@ MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
     LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
 }
 
-PVOID
-NTAPI
-MiFindExportedRoutineByName(IN PVOID DllBase,
-                            IN PANSI_STRING ExportName)
-{
-    PULONG NameTable;
-    PUSHORT OrdinalTable;
-    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
-    USHORT Ordinal;
-    PVOID Function;
-    ULONG ExportSize;
-    PULONG ExportTable;
-    PAGED_CODE();
-
-    /* Get the export directory */
-    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
-                                                   TRUE,
-                                                   
IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                                   &ExportSize);
-    if (!ExportDirectory) return NULL;
-
-    /* Setup name tables */
-    NameTable = (PULONG)((ULONG_PTR)DllBase +
-                         ExportDirectory->AddressOfNames);
-    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
-                             ExportDirectory->AddressOfNameOrdinals);
-
-    /* Get the ordinal */
-    Ordinal = NameToOrdinal(ExportName->Buffer,
-                            DllBase,
-                            ExportDirectory->NumberOfNames,
-                            NameTable,
-                            OrdinalTable);
-
-    /* Check if we couldn't find it */
-    if (Ordinal == -1) return NULL;
-
-    /* Validate the ordinal */
-    if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL;
-
-    /* Resolve the address and write it */
-    ExportTable = (PULONG)((ULONG_PTR)DllBase +
-                           ExportDirectory->AddressOfFunctions);
-    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
-
-    /* We found it! */
-    ASSERT((Function < (PVOID)ExportDirectory) ||
-           (Function > (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
-
-    return Function;
-}
-
 VOID
 NTAPI
 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
@@ -720,6 +772,7 @@ MiSnapThunk(IN PVOID DllBase,
     PIMAGE_IMPORT_BY_NAME ForwardName;
     SIZE_T ForwardLength;
     IMAGE_THUNK_DATA ForwardThunk;
+
     PAGED_CODE();
 
     /* Check if this is an ordinal */
@@ -740,7 +793,7 @@ MiSnapThunk(IN PVOID DllBase,
         /* Copy the procedure name */
         RtlStringCbCopyA(*MissingApi,
                          MAXIMUM_FILENAME_LENGTH,
-                         (PCHAR)&NameImport->Name[0]);
+                         (PCHAR)NameImport->Name);
 
         /* Setup name tables */
         DPRINT("Import name: %s\n", NameImport->Name);
@@ -775,10 +828,10 @@ MiSnapThunk(IN PVOID DllBase,
         }
     }
 
-    /* Check if the ordinal is invalid */
+    /* Check if the ordinal is valid */
     if (Ordinal >= ExportDirectory->NumberOfFunctions)
     {
-        /* Fail */
+        /* It's not, fail */
         Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
     }
     else
@@ -796,7 +849,7 @@ MiSnapThunk(IN PVOID DllBase,
 
         /* Check if the function is actually a forwarder */
         if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
-            (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+            (Address->u1.Function < (ULONG_PTR)ExportDirectory + ExportSize))
         {
             /* Now assume failure in case the forwarder doesn't exist */
             Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
@@ -3594,8 +3647,8 @@ MmGetSystemRoutineAddress(IN PUNICODE_STRING 
SystemRoutineName)
         if (Found)
         {
             /* Find the procedure name */
-            ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
-                                                      &AnsiRoutineName);
+            ProcAddress = RtlFindExportedRoutineByName(LdrEntry->DllBase,
+                                                       AnsiRoutineName.Buffer);
 
             /* Break out if we found it or if we already tried both modules */
             if (ProcAddress) break;
diff --git a/ntoskrnl/ps/psmgr.c b/ntoskrnl/ps/psmgr.c
index ad02cdfd82a..bd642375a88 100644
--- a/ntoskrnl/ps/psmgr.c
+++ b/ntoskrnl/ps/psmgr.c
@@ -62,80 +62,22 @@ BOOLEAN PspDoingGiveBacks;
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
-USHORT
-NTAPI
-NameToOrdinal(
-    _In_ PCSTR ExportName,
-    _In_ PVOID ImageBase,
-    _In_ ULONG NumberOfNames,
-    _In_ PULONG NameTable,
-    _In_ PUSHORT OrdinalTable);
-
-CODE_SEG("INIT")
+static CODE_SEG("INIT")
 NTSTATUS
-NTAPI
-LookupEntryPoint(IN PVOID DllBase,
-                 IN PCHAR Name,
-                 OUT PVOID *EntryPoint)
+PspLookupSystemDllEntryPoint(
+    _In_ PCSTR Name,
+    _Out_ PVOID* EntryPoint)
 {
-    PULONG NameTable;
-    PUSHORT OrdinalTable;
-    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
-    ULONG ExportSize;
-    CHAR Buffer[64];
-    USHORT Ordinal;
-    PULONG ExportTable;
-
-    /* Get the export directory */
-    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
-                                                   TRUE,
-                                                   
IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                                   &ExportSize);
-
-    /* Validate the name and copy it */
-    if (strlen(Name) > sizeof(Buffer) - 2) return STATUS_INVALID_PARAMETER;
-    strcpy(Buffer, Name);
-
-    /* Setup name tables */
-    NameTable = (PULONG)((ULONG_PTR)DllBase +
-                         ExportDirectory->AddressOfNames);
-    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
-                             ExportDirectory->AddressOfNameOrdinals);
-
-    /* Get the ordinal */
-    Ordinal = NameToOrdinal(Buffer,
-                            DllBase,
-                            ExportDirectory->NumberOfNames,
-                            NameTable,
-                            OrdinalTable);
-
-    /* Make sure the ordinal is valid */
-    if (Ordinal >= ExportDirectory->NumberOfFunctions)
-    {
-        /* It's not, fail */
-        return STATUS_PROCEDURE_NOT_FOUND;
-    }
-
-    /* Resolve the address and write it */
-    ExportTable = (PULONG)((ULONG_PTR)DllBase +
-                           ExportDirectory->AddressOfFunctions);
-    *EntryPoint = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
-    return STATUS_SUCCESS;
+    /* Call the internal API */
+    return RtlpFindExportedRoutineByName(PspSystemDllBase,
+                                         Name,
+                                         EntryPoint,
+                                         NULL,
+                                         STATUS_PROCEDURE_NOT_FOUND);
 }
 
-CODE_SEG("INIT")
+static CODE_SEG("INIT")
 NTSTATUS
-NTAPI
-PspLookupSystemDllEntryPoint(IN PCHAR Name,
-                             IN PVOID *EntryPoint)
-{
-    /* Call the LDR Routine */
-    return LookupEntryPoint(PspSystemDllBase, Name, EntryPoint);
-}
-
-CODE_SEG("INIT")
-NTSTATUS
-NTAPI
 PspLookupKernelUserEntryPoints(VOID)
 {
     NTSTATUS Status;

Reply via email to