[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,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

View File

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

View File

@ -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;

View File

@ -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;