From 7f3c5f09325c5e3b83d9a1c363e633aafb2abc97 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Mon, 1 Aug 2005 13:50:07 +0000 Subject: [PATCH] Various LdrGetProcedureAddress fixes: - Fix the binary search limits. - Fix the comparsion of names (previously "XXX" and "XXXyyy" would be considered identical) and make it case sensitive. - Remove non-binary search, it's not needed. - Don't use ULONG to store pointers. svn path=/trunk/; revision=16955 --- reactos/ntoskrnl/ldr/rtl.c | 128 ++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/reactos/ntoskrnl/ldr/rtl.c b/reactos/ntoskrnl/ldr/rtl.c index cd6a5429235..02e9e5a4369 100644 --- a/reactos/ntoskrnl/ldr/rtl.c +++ b/reactos/ntoskrnl/ldr/rtl.c @@ -24,83 +24,83 @@ LdrGetProcedureAddress (IN PVOID BaseAddress, OUT PVOID *ProcedureAddress) { PIMAGE_EXPORT_DIRECTORY ExportDir; + ULONG ExportDirSize = 0; PUSHORT OrdinalPtr; PULONG NamePtr; + PCHAR CurrentNamePtr; PULONG AddressPtr; - ULONG i = 0; + + if (ProcedureAddress == NULL) + return STATUS_INVALID_PARAMETER; /* get the pointer to the export directory */ - ExportDir = (PIMAGE_EXPORT_DIRECTORY) - RtlImageDirectoryEntryToData (BaseAddress, TRUE, - IMAGE_DIRECTORY_ENTRY_EXPORT, &i); + ExportDir = RtlImageDirectoryEntryToData(BaseAddress, TRUE, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &ExportDirSize); - if (!ExportDir || !i || !ProcedureAddress) - { - return(STATUS_INVALID_PARAMETER); - } + if (ExportDir == NULL || ExportDirSize == 0) + return STATUS_INVALID_PARAMETER; + + AddressPtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfFunctions); - AddressPtr = (PULONG)RVA((char*)BaseAddress, ExportDir->AddressOfFunctions); if (Name && Name->Length) - { - LONG minn, maxn; + { + LONG minn, maxn, mid, res; - /* by name */ - OrdinalPtr = - (PUSHORT)RVA((char*)BaseAddress, ExportDir->AddressOfNameOrdinals); - NamePtr = (PULONG)RVA((char*)BaseAddress, ExportDir->AddressOfNames); + /* Search for export by name */ - minn = 0; maxn = ExportDir->NumberOfNames; - while (minn <= maxn) - { - LONG mid; - LONG res; + /* + * NOTE: Exports are always sorted and so we can apply binary search. + * Also the function names are _case sensitive_, so respect that. + * -- Filip Navara, August 1st, 2005 + */ - mid = (minn + maxn) / 2; - res = _strnicmp(Name->Buffer, (PCH)RVA((char*)BaseAddress, NamePtr[mid]), - Name->Length); - if (res == 0) - { - *ProcedureAddress = - (PVOID)RVA((char*)BaseAddress, AddressPtr[OrdinalPtr[mid]]); - return(STATUS_SUCCESS); - } - else if (res > 0) - { - maxn = mid - 1; - } - else - { - minn = mid + 1; - } - } + OrdinalPtr = (PUSHORT)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals); + NamePtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfNames); - for (i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++) - { - if (!_strnicmp(Name->Buffer, - (char*)((char*)BaseAddress + *NamePtr), Name->Length)) - { - *ProcedureAddress = - (PVOID)((ULONG)BaseAddress + - (ULONG)AddressPtr[*OrdinalPtr]); - return STATUS_SUCCESS; - } - } - CPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name); - } + minn = 0; maxn = ExportDir->NumberOfNames - 1; + while (minn <= maxn) + { + mid = (minn + maxn) / 2; + CurrentNamePtr = (PCHAR)RVA(BaseAddress, NamePtr[mid]); + res = strncmp(CurrentNamePtr, Name->Buffer, Name->Length); + if (res == 0) + { + /* + * Check if the beginning of the name matched, but it's still + * not the whole name. + */ + if (CurrentNamePtr[Name->Length] != 0) + { + res = -1; + } + else + { + *ProcedureAddress = (PVOID)RVA(BaseAddress, AddressPtr[OrdinalPtr[mid]]); + return STATUS_SUCCESS; + } + } + if (res > 0) + maxn = mid - 1; + else + minn = mid + 1; + } + + CPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name); + } else - { - /* by ordinal */ - Ordinal &= 0x0000FFFF; - if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions) - { - *ProcedureAddress = - (PVOID)((ULONG)BaseAddress + - (ULONG)AddressPtr[Ordinal - ExportDir->Base]); - return STATUS_SUCCESS; - } - CPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", - Ordinal); - } + { + /* Search for export by ordinal */ + + Ordinal &= 0x0000FFFF; + if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions) + { + *ProcedureAddress = (PVOID)RVA(BaseAddress, AddressPtr[Ordinal - ExportDir->Base]); + return STATUS_SUCCESS; + } + + CPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal); + } return STATUS_PROCEDURE_NOT_FOUND; }