[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.
This commit is contained in:
Hermès Bélusca-Maïto 2022-11-29 00:49:33 +01:00
parent d8695eee1e
commit 86e0d5e9b8
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
4 changed files with 168 additions and 163 deletions

View file

@ -1490,7 +1490,7 @@ VOID
NTAPI NTAPI
MmFreeSectionSegments(PFILE_OBJECT FileObject); 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 NTSTATUS
NTAPI NTAPI
MmMapViewInSystemSpaceEx( MmMapViewInSystemSpaceEx(
@ -1498,8 +1498,7 @@ MmMapViewInSystemSpaceEx (
_Outptr_result_bytebuffer_ (*ViewSize) PVOID *MappedBase, _Outptr_result_bytebuffer_ (*ViewSize) PVOID *MappedBase,
_Inout_ PSIZE_T ViewSize, _Inout_ PSIZE_T ViewSize,
_Inout_ PLARGE_INTEGER SectionOffset, _Inout_ PLARGE_INTEGER SectionOffset,
_In_ ULONG_PTR Flags _In_ ULONG_PTR Flags);
);
BOOLEAN BOOLEAN
NTAPI NTAPI
@ -1661,6 +1660,23 @@ NTAPI
MmFreeDriverInitialization( MmFreeDriverInitialization(
IN PLDR_DATA_TABLE_ENTRY LdrEntry); 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 *****************************************************************/ /* procsup.c *****************************************************************/
NTSTATUS NTSTATUS

View file

@ -134,12 +134,6 @@ PsLocateSystemDll(
VOID VOID
); );
NTSTATUS
NTAPI
PspGetSystemDllEntryPoints(
VOID
);
VOID VOID
NTAPI NTAPI
PsChangeQuantumTable( PsChangeQuantumTable(

View file

@ -267,60 +267,163 @@ NameToOrdinal(
return OrdinalTable[Mid]; 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 NTAPI
MiLocateExportName(IN PVOID DllBase, RtlpFindExportedRoutineByName(
IN PCHAR ExportName) _In_ PVOID ImageBase,
_In_ PCSTR ExportName,
_Out_ PVOID* Function,
_Out_opt_ PBOOLEAN IsForwarder,
_In_ NTSTATUS NotFoundStatus)
{ {
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PULONG NameTable; PULONG NameTable;
PUSHORT OrdinalTable; PUSHORT OrdinalTable;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
USHORT Ordinal;
PVOID Function;
ULONG ExportSize; ULONG ExportSize;
USHORT Ordinal;
PULONG ExportTable; PULONG ExportTable;
ULONG_PTR FunctionAddress;
PAGED_CODE(); PAGED_CODE();
/* Get the export directory */ /* Get the export directory */
ExportDirectory = RtlImageDirectoryEntryToData(DllBase, ExportDirectory = RtlImageDirectoryEntryToData(ImageBase,
TRUE, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize); &ExportSize);
if (!ExportDirectory) return NULL; if (!ExportDirectory)
return STATUS_INVALID_PARAMETER;
/* Setup name tables */ /* Setup name tables */
NameTable = (PULONG)((ULONG_PTR)DllBase + NameTable = (PULONG)RVA(ImageBase, ExportDirectory->AddressOfNames);
ExportDirectory->AddressOfNames); OrdinalTable = (PUSHORT)RVA(ImageBase, ExportDirectory->AddressOfNameOrdinals);
OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
ExportDirectory->AddressOfNameOrdinals);
/* Get the ordinal */ /* Get the ordinal */
Ordinal = NameToOrdinal(ExportName, Ordinal = NameToOrdinal(ExportName,
DllBase, ImageBase,
ExportDirectory->NumberOfNames, ExportDirectory->NumberOfNames,
NameTable, NameTable,
OrdinalTable); OrdinalTable);
/* Check if we couldn't find it */ /* Check if we couldn't find it */
if (Ordinal == -1) return NULL; if (Ordinal == -1)
return NotFoundStatus;
/* Validate the ordinal */ /* Validate the ordinal */
if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL; if (Ordinal >= ExportDirectory->NumberOfFunctions)
return NotFoundStatus;
/* Resolve the address and write it */ /* Resolve the function's address */
ExportTable = (PULONG)((ULONG_PTR)DllBase + ExportTable = (PULONG)RVA(ImageBase, ExportDirectory->AddressOfFunctions);
ExportDirectory->AddressOfFunctions); FunctionAddress = (ULONG_PTR)RVA(ImageBase, ExportTable[Ordinal]);
Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
/* Check if the function is actually a forwarder */ /* Check if the function is actually a forwarder */
if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) && if (IsForwarder)
((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
{ {
/* 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; return NULL;
} }
/* We found it */ /* We've found the export */
return Function; return Function;
} }
@ -340,8 +443,8 @@ MmCallDllInitialize(
PAGED_CODE(); PAGED_CODE();
/* Try to see if the image exports a DllInitialize routine */ /* Try to see if the image exports a DllInitialize routine */
DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase, DllInit = (PMM_DLL_INITIALIZE)
"DllInitialize"); RtlFindExportedRoutineByName(LdrEntry->DllBase, "DllInitialize");
if (!DllInit) if (!DllInit)
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -399,7 +502,8 @@ MiCallDllUnloadAndUnloadDll(
PAGED_CODE(); PAGED_CODE();
/* Retrieve the DllUnload routine */ /* Retrieve the DllUnload routine */
DllUnload = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload"); DllUnload = (PMM_DLL_UNLOAD)
RtlFindExportedRoutineByName(LdrEntry->DllBase, "DllUnload");
if (!DllUnload) if (!DllUnload)
return FALSE; return FALSE;
@ -512,58 +616,6 @@ MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 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 VOID
NTAPI NTAPI
MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry, MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
@ -720,6 +772,7 @@ MiSnapThunk(IN PVOID DllBase,
PIMAGE_IMPORT_BY_NAME ForwardName; PIMAGE_IMPORT_BY_NAME ForwardName;
SIZE_T ForwardLength; SIZE_T ForwardLength;
IMAGE_THUNK_DATA ForwardThunk; IMAGE_THUNK_DATA ForwardThunk;
PAGED_CODE(); PAGED_CODE();
/* Check if this is an ordinal */ /* Check if this is an ordinal */
@ -740,7 +793,7 @@ MiSnapThunk(IN PVOID DllBase,
/* Copy the procedure name */ /* Copy the procedure name */
RtlStringCbCopyA(*MissingApi, RtlStringCbCopyA(*MissingApi,
MAXIMUM_FILENAME_LENGTH, MAXIMUM_FILENAME_LENGTH,
(PCHAR)&NameImport->Name[0]); (PCHAR)NameImport->Name);
/* Setup name tables */ /* Setup name tables */
DPRINT("Import name: %s\n", NameImport->Name); 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) if (Ordinal >= ExportDirectory->NumberOfFunctions)
{ {
/* Fail */ /* It's not, fail */
Status = STATUS_DRIVER_ORDINAL_NOT_FOUND; Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
} }
else else
@ -796,7 +849,7 @@ MiSnapThunk(IN PVOID DllBase,
/* Check if the function is actually a forwarder */ /* Check if the function is actually a forwarder */
if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) && 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 */ /* Now assume failure in case the forwarder doesn't exist */
Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
@ -3594,8 +3647,8 @@ MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
if (Found) if (Found)
{ {
/* Find the procedure name */ /* Find the procedure name */
ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase, ProcAddress = RtlFindExportedRoutineByName(LdrEntry->DllBase,
&AnsiRoutineName); AnsiRoutineName.Buffer);
/* Break out if we found it or if we already tried both modules */ /* Break out if we found it or if we already tried both modules */
if (ProcAddress) break; if (ProcAddress) break;

View file

@ -62,80 +62,22 @@ BOOLEAN PspDoingGiveBacks;
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
USHORT static CODE_SEG("INIT")
NTAPI
NameToOrdinal(
_In_ PCSTR ExportName,
_In_ PVOID ImageBase,
_In_ ULONG NumberOfNames,
_In_ PULONG NameTable,
_In_ PUSHORT OrdinalTable);
CODE_SEG("INIT")
NTSTATUS NTSTATUS
NTAPI PspLookupSystemDllEntryPoint(
LookupEntryPoint(IN PVOID DllBase, _In_ PCSTR Name,
IN PCHAR Name, _Out_ PVOID* EntryPoint)
OUT PVOID *EntryPoint)
{ {
PULONG NameTable; /* Call the internal API */
PUSHORT OrdinalTable; return RtlpFindExportedRoutineByName(PspSystemDllBase,
PIMAGE_EXPORT_DIRECTORY ExportDirectory; Name,
ULONG ExportSize; EntryPoint,
CHAR Buffer[64]; NULL,
USHORT Ordinal; STATUS_PROCEDURE_NOT_FOUND);
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 */ static CODE_SEG("INIT")
ExportTable = (PULONG)((ULONG_PTR)DllBase +
ExportDirectory->AddressOfFunctions);
*EntryPoint = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
return STATUS_SUCCESS;
}
CODE_SEG("INIT")
NTSTATUS 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) PspLookupKernelUserEntryPoints(VOID)
{ {
NTSTATUS Status; NTSTATUS Status;