https://git.reactos.org/?p=reactos.git;a=commitdiff;h=86e0d5e9b8ddbb620213f…
commit 86e0d5e9b8ddbb620213f2adcdb131727af379bb
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Tue Nov 29 00:49:33 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
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/mm…
+ **/
+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;