diff --git a/reactos/dll/ntdll/include/ntdllp.h b/reactos/dll/ntdll/include/ntdllp.h index b7b20ff7f92..dc24500068e 100644 --- a/reactos/dll/ntdll/include/ntdllp.h +++ b/reactos/dll/ntdll/include/ntdllp.h @@ -23,14 +23,42 @@ typedef BOOL /* Global data */ extern RTL_CRITICAL_SECTION LdrpLoaderLock; +extern BOOLEAN LdrpInLdrInit; /* ldrinit.c */ +NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL); NTSTATUS NTAPI LdrpInitializeTls(VOID); NTSTATUS NTAPI LdrpAllocateTls(VOID); VOID NTAPI LdrpFreeTls(VOID); VOID NTAPI LdrpTlsCallback(PVOID BaseAddress, ULONG Reason); BOOLEAN NTAPI LdrpCallDllEntry(PDLLMAIN_FUNC EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context); +/* ldrpe.c */ +NTSTATUS +NTAPI +LdrpSnapThunk(IN PVOID ExportBase, + IN PVOID ImportBase, + IN PIMAGE_THUNK_DATA OriginalThunk, + IN OUT PIMAGE_THUNK_DATA Thunk, + IN PIMAGE_EXPORT_DIRECTORY ExportEntry, + IN ULONG ExportSize, + IN BOOLEAN Static, + IN LPSTR DllName); + +/* ldrutils.c */ +NTSTATUS NTAPI +LdrpGetProcedureAddress(IN PVOID BaseAddress, + IN PANSI_STRING Name, + IN ULONG Ordinal, + OUT PVOID *ProcedureAddress, + IN BOOLEAN ExecuteInit); +NTSTATUS NTAPI +LdrpLoadDll(IN BOOLEAN Redirected, + IN PWSTR DllPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *BaseAddress, + IN BOOLEAN CallInit); /* FIXME: Cleanup this mess */ typedef NTSTATUS (NTAPI *PEPFUNC)(PPEB); diff --git a/reactos/dll/ntdll/ldr/ldrapi.c b/reactos/dll/ntdll/ldr/ldrapi.c index 55e1582a446..af898d035e5 100644 --- a/reactos/dll/ntdll/ldr/ldrapi.c +++ b/reactos/dll/ntdll/ldr/ldrapi.c @@ -109,8 +109,7 @@ LdrLockLoaderLock(IN ULONG Flags, { LONG OldCount; NTSTATUS Status = STATUS_SUCCESS; - BOOLEAN InInit = FALSE; // FIXME - //BOOLEAN InInit = LdrpInLdrInit; + BOOLEAN InInit = LdrpInLdrInit; DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Result, Cookie); @@ -378,4 +377,157 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle, return !Result ? STATUS_IMAGE_CHECKSUM_MISMATCH : Status; } +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrGetProcedureAddress_(IN PVOID BaseAddress, + IN PANSI_STRING Name, + IN ULONG Ordinal, + OUT PVOID *ProcedureAddress) +{ + /* Call the internal routine and tell it to execute DllInit */ + return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE); +} + + +NTSTATUS +NTAPI +LdrQueryProcessModuleInformationEx(IN ULONG ProcessId, + IN ULONG Reserved, + IN PRTL_PROCESS_MODULES ModuleInformation, + IN ULONG Size, + OUT PULONG ReturnedSize OPTIONAL) +{ + PLIST_ENTRY ModuleListHead, InitListHead; + PLIST_ENTRY Entry, InitEntry; + PLDR_DATA_TABLE_ENTRY Module, InitModule; + PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL; + NTSTATUS Status = STATUS_SUCCESS; + ULONG UsedSize = sizeof(ULONG); + ANSI_STRING AnsiString; + PCHAR p; + + DPRINT("LdrQueryProcessModuleInformation() called\n"); + + /* Acquire loader lock */ + RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); + + /* Check if we were given enough space */ + if (Size < UsedSize) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + ModuleInformation->NumberOfModules = 0; + ModulePtr = &ModuleInformation->Modules[0]; + Status = STATUS_SUCCESS; + } + + /* Traverse the list of modules */ + _SEH2_TRY + { + ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; + Entry = ModuleListHead->Flink; + + while (Entry != ModuleListHead) + { + Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + + DPRINT(" Module %wZ\n", &Module->FullDllName); + + /* Increase the used size */ + UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION); + + if (UsedSize > Size) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + ModulePtr->ImageBase = Module->DllBase; + ModulePtr->ImageSize = Module->SizeOfImage; + ModulePtr->Flags = Module->Flags; + ModulePtr->LoadCount = Module->LoadCount; + ModulePtr->MappedBase = NULL; + ModulePtr->InitOrderIndex = 0; + ModulePtr->LoadOrderIndex = ModuleInformation->NumberOfModules; + + /* Now get init order index by traversing init list */ + InitListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; + InitEntry = InitListHead->Flink; + + while (InitEntry != InitListHead) + { + InitModule = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); + + /* Increase the index */ + ModulePtr->InitOrderIndex++; + + /* Quit the loop if our module is found */ + if (InitModule == Module) break; + + /* Advance to the next entry */ + InitEntry = InitEntry->Flink; + } + + /* Prepare ANSI string with the module's name */ + AnsiString.Length = 0; + AnsiString.MaximumLength = sizeof(ModulePtr->FullPathName); + AnsiString.Buffer = ModulePtr->FullPathName; + RtlUnicodeStringToAnsiString(&AnsiString, + &Module->FullDllName, + FALSE); + + /* Calculate OffsetToFileName field */ + p = strrchr(ModulePtr->FullPathName, '\\'); + if (p != NULL) + ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1; + else + ModulePtr->OffsetToFileName = 0; + + /* Advance to the next module in the output list */ + ModulePtr++; + + /* Increase number of modules */ + if (ModuleInformation) + ModuleInformation->NumberOfModules++; + } + + /* Go to the next entry in the modules list */ + Entry = Entry->Flink; + } + + /* Set returned size if it was provided */ + if (ReturnedSize) + *ReturnedSize = UsedSize; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Ignoring the exception */ + } _SEH2_END; + + /* Release the lock */ + RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); + + DPRINT("LdrQueryProcessModuleInformation() done\n"); + + return Status; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation, + IN ULONG Size, + OUT PULONG ReturnedSize OPTIONAL) +{ + /* Call Ex version of the API */ + return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize); +} + /* EOF */ diff --git a/reactos/dll/ntdll/ldr/ldrinit.c b/reactos/dll/ntdll/ldr/ldrinit.c index 72e717beb33..bd15a66cbea 100644 --- a/reactos/dll/ntdll/ldr/ldrinit.c +++ b/reactos/dll/ntdll/ldr/ldrinit.c @@ -20,6 +20,10 @@ HKEY Wow64ExecOptionsKey; UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options"); UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L""); +BOOLEAN LdrpInLdrInit; + +PLDR_DATA_TABLE_ENTRY LdrpImageEntry; + //RTL_BITMAP TlsBitMap; //RTL_BITMAP TlsExpansionBitMap; //RTL_BITMAP FlsBitMap; @@ -329,6 +333,267 @@ LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey, FALSE); } +NTSTATUS +NTAPI +LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL) +{ +#if 0 + PLDR_DATA_TABLE_ENTRY LocalArray[16]; + PLIST_ENTRY ListHead; + PLIST_ENTRY NextEntry; + PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer; + PVOID EntryPoint; + ULONG Count, i; + //ULONG BreakOnInit; + NTSTATUS Status = STATUS_SUCCESS; + PPEB Peb = NtCurrentPeb(); + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; + ULONG BreakOnDllLoad; + PTEB OldTldTeb; + + DPRINT1("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry->BaseDllName); + + /* Check the Loader Lock */ + LdrpEnsureLoaderLockIsHeld(); + + /* Get the number of entries to call */ + if ((Count = LdrpClearLoadInProgress())) + { + /* Check if we can use our local buffer */ + if (Count > 16) + { + /* Allocate space for all the entries */ + LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + Count * sizeof(LdrRootEntry)); + if (!LdrRootEntry) return STATUS_NO_MEMORY; + } + else + { + /* Use our local array */ + LdrRootEntry = LocalArray; + } + } + else + { + /* Don't need one */ + LdrRootEntry = NULL; + } + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ pid %u %0x%x\n", + NtCurrentTeb()->RealClientId.UniqueThread, + NtCurrentTeb()->RealClientId.UniqueProcess, + Peb->ProcessParameters->ImagePathName, + NtCurrentTeb()->RealClientId.UniqueThread, + NtCurrentTeb()->RealClientId.UniqueProcess); + } + + /* Loop in order */ + ListHead = &Peb->Ldr->InInitializationOrderModuleList; + NextEntry = ListHead->Flink; + i = 0; + while (NextEntry != ListHead) + { + /* Get the Data Entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); + + /* Check if we have a Root Entry */ + if (LdrRootEntry) + { + /* Check flags */ + if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) + { + /* Setup the Cookie for the DLL */ + //LdrpInitSecurityCookie(LdrEntry); + UNIMPLEMENTED; + + /* Check for valid entrypoint */ + if (LdrEntry->EntryPoint) + { + /* Write in array */ + LdrRootEntry[i] = LdrEntry; + + /* Display debug message */ + if (ShowSnaps) + { + DPRINT1("[%x,%x] LDR: %wZ init routine %p\n", + NtCurrentTeb()->RealClientId.UniqueThread, + NtCurrentTeb()->RealClientId.UniqueProcess, + &LdrEntry->FullDllName, + LdrEntry->EntryPoint); + } + i++; + } + } + } + + /* Set the flag */ + LdrEntry->Flags |= LDRP_ENTRY_PROCESSED; + NextEntry = NextEntry->Flink; + } + + /* If we got a context, then we have to call Kernel32 for TS support */ + if (Context) + { + /* Check if we have one */ + //if (Kernel32ProcessInitPostImportfunction) + //{ + /* Call it */ + //Kernel32ProcessInitPostImportfunction(); + //} + + /* Clear it */ + //Kernel32ProcessInitPostImportfunction = NULL; + UNIMPLEMENTED; + } + + /* No root entry? return */ + if (!LdrRootEntry) return STATUS_SUCCESS; + + /* Set the TLD TEB */ + OldTldTeb = LdrpTopLevelDllBeingLoadedTeb; + LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb(); + + /* Loop */ + i = 0; + while (i < Count) + { + /* Get an entry */ + LdrEntry = LdrRootEntry[i]; + + /* FIXME: Verifiy NX Compat */ + + /* Move to next entry */ + i++; + + /* Get its entrypoint */ + EntryPoint = LdrEntry->EntryPoint; + + /* Are we being debugged? */ + BreakOnDllLoad = 0; + if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions) + { + /* Check if we should break on load */ + Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName, + L"BreakOnDllLoad", + REG_DWORD, + &BreakOnDllLoad, + sizeof(ULONG), + NULL); + if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0; + } + + /* Break if aksed */ + if (BreakOnDllLoad) + { + /* Check if we should show a message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName); + DPRINT1(" - About to call init routine at %lx\n", EntryPoint); + } + + /* Break in debugger */ + DbgBreakPoint(); + } + + /* Make sure we have an entrypoint */ + if (EntryPoint) + { + /* Save the old Dll Initializer and write the current one */ + OldInitializer = LdrpCurrentDllInitializer; + LdrpCurrentDllInitializer = LdrEntry; + + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID; + RtlZeroMemory(&ActCtx, sizeof(ActCtx)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Check if it has TLS */ + if (LdrEntry->TlsIndex && Context) + { + /* Call TLS */ + LdrpTlsCallback(LdrEntry->DllBase, DLL_PROCESS_ATTACH); + } + + /* Call the Entrypoint */ + DPRINT1("%wZ - Calling entry point at %x for thread attaching\n", + &LdrEntry->BaseDllName, EntryPoint); + LdrpCallDllEntry(EntryPoint, + LdrEntry->DllBase, + DLL_PROCESS_ATTACH, + Context); + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + + /* Save the Current DLL Initializer */ + LdrpCurrentDllInitializer = OldInitializer; + + /* Mark the entry as processed */ + LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED; + } + } + + /* Loop in order */ + ListHead = &Peb->Ldr->InInitializationOrderModuleList; + NextEntry = NextEntry->Flink; + while (NextEntry != ListHead) + { + /* Get the Data Entrry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); + + /* FIXME: Verify NX Compat */ + + /* Next entry */ + NextEntry = NextEntry->Flink; + } + + /* Check for TLS */ + if (LdrpImageHasTls && Context) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID; + RtlZeroMemory(&ActCtx, sizeof(ActCtx)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrpImageEntry->EntryPointActivationContext); + + /* Do TLS callbacks */ + LdrpTlsCallback(Peb->ImageBaseAddress, DLL_PROCESS_DETACH); + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + + /* Restore old TEB */ + LdrpTopLevelDllBeingLoadedTeb = OldTldTeb; + + /* Check if the array is in the heap */ + if (LdrRootEntry != LocalArray) + { + /* Free the array */ + RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry); + } + + /* Return to caller */ + DPRINT("LdrpAttachProcess() done\n"); + return Status; +#else + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +#endif +} + NTSTATUS NTAPI LdrpInitializeTls(VOID) diff --git a/reactos/dll/ntdll/ldr/ldrpe.c b/reactos/dll/ntdll/ldr/ldrpe.c new file mode 100644 index 00000000000..129f756c862 --- /dev/null +++ b/reactos/dll/ntdll/ldr/ldrpe.c @@ -0,0 +1,273 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/ntdll/ldr/ldrpe.c + * PURPOSE: Loader Functions dealing low-level PE Format structures + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ +ULONG LdrpFatalHardErrorCount; +PVOID LdrpManifestProberRoutine; + +/* PROTOTYPES ****************************************************************/ + +#define IMAGE_REL_BASED_HIGH3ADJ 11 + +NTSTATUS +NTAPI +LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL, + IN LPSTR ImportName, + IN PVOID DllBase, + OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry, + OUT PBOOLEAN Existing); + +/* FUNCTIONS *****************************************************************/ + +USHORT NTAPI +LdrpNameToOrdinal(LPSTR ImportName, + ULONG NumberOfNames, + PVOID ExportBase, + PULONG NameTable, + PUSHORT OrdinalTable) +{ + UNIMPLEMENTED; + return 0; +} + + +NTSTATUS +NTAPI +LdrpSnapThunk(IN PVOID ExportBase, + IN PVOID ImportBase, + IN PIMAGE_THUNK_DATA OriginalThunk, + IN OUT PIMAGE_THUNK_DATA Thunk, + IN PIMAGE_EXPORT_DIRECTORY ExportEntry, + IN ULONG ExportSize, + IN BOOLEAN Static, + IN LPSTR DllName) +{ + BOOLEAN IsOrdinal; + USHORT Ordinal; + ULONG OriginalOrdinal = 0; + PIMAGE_IMPORT_BY_NAME AddressOfData; + PULONG NameTable; + PUSHORT OrdinalTable; + LPSTR ImportName; + USHORT Hint; + NTSTATUS Status; + ULONG_PTR HardErrorParameters[3]; + UNICODE_STRING HardErrorDllName, HardErrorEntryPointName; + ANSI_STRING TempString; + ULONG Mask; + ULONG Response; + PULONG AddressOfFunctions; + UNICODE_STRING TempUString; + ANSI_STRING ForwarderName; + PANSI_STRING ForwardName; + PVOID ForwarderHandle; + ULONG ForwardOrdinal; + + /* Check if the snap is by ordinal */ + if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal))) + { + /* Get the ordinal number, and its normalized version */ + OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal); + Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base); + } + else + { + /* First get the data VA */ + AddressOfData = (PIMAGE_IMPORT_BY_NAME) + ((ULONG_PTR)ImportBase + + ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff)); + + /* Get the name */ + ImportName = (LPSTR)AddressOfData->Name; + + /* Now get the VA of the Name and Ordinal Tables */ + NameTable = (PULONG)((ULONG_PTR)ExportBase + + (ULONG_PTR)ExportEntry->AddressOfNames); + OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase + + (ULONG_PTR)ExportEntry->AddressOfNameOrdinals); + + /* Get the hint */ + Hint = AddressOfData->Hint; + + /* Try to get a match by using the hint */ + if (((ULONG)Hint < ExportEntry->NumberOfNames) && + (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint]))))) + { + /* We got a match, get the Ordinal from the hint */ + Ordinal = OrdinalTable[Hint]; + } + else + { + /* Well bummer, hint didn't work, do it the long way */ + Ordinal = LdrpNameToOrdinal(ImportName, + ExportEntry->NumberOfNames, + ExportBase, + NameTable, + OrdinalTable); + } + } + + /* Check if the ordinal is invalid */ + if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions) + { +FailurePath: + /* Is this a static snap? */ + if (Static) + { + /* These are critical errors. Setup a string for the DLL name */ + RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown"); + RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE); + + /* Set it as the parameter */ + HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName; + Mask = 2; + + /* Check if we have an ordinal */ + if (IsOrdinal) + { + /* Then set the ordinal as the 1st parameter */ + HardErrorParameters[0] = OriginalOrdinal; + } + else + { + /* We don't, use the entrypoint. Set up a string for it */ + RtlInitAnsiString(&TempString, ImportName); + RtlAnsiStringToUnicodeString(&HardErrorEntryPointName, + &TempString, + TRUE); + + /* Set it as the parameter */ + HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName; + Mask = 3; + } + + /* Raise the error */ + NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND : + STATUS_ENTRYPOINT_NOT_FOUND, + 2, + Mask, + HardErrorParameters, + OptionOk, + &Response); + + /* Increase the error count */ + if (LdrpInLdrInit) LdrpFatalHardErrorCount++; + + /* Free our string */ + RtlFreeUnicodeString(&HardErrorDllName); + if (!IsOrdinal) + { + /* Free our second string. Return entrypoint error */ + RtlFreeUnicodeString(&HardErrorEntryPointName); + RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND); + } + + /* Return ordinal error */ + RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND); + } + + /* Set this as a bad DLL */ + Thunk->u1.Function = (ULONG_PTR)0xffbadd11; + + /* Return the right error code */ + Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND : + STATUS_ENTRYPOINT_NOT_FOUND; + } + else + { + /* The ordinal seems correct, get the AddressOfFunctions VA */ + AddressOfFunctions = (PULONG) + ((ULONG_PTR)ExportBase + + (ULONG_PTR)ExportEntry->AddressOfFunctions); + + /* Write the function pointer*/ + Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal]; + + /* Make sure it's within the exports */ + if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) && + (Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize))) + { + /* Get the Import and Forwarder Names */ + ImportName = (LPSTR)Thunk->u1.Function; + ForwarderName.Buffer = ImportName; + ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName); + ForwarderName.MaximumLength = ForwarderName.Length; + Status = RtlAnsiStringToUnicodeString(&TempUString, + &ForwarderName, + TRUE); + + /* Make sure the conversion was OK */ + if (NT_SUCCESS(Status)) + { + /* Load the forwarder, free the temp string */ + Status = LdrpLoadDll(FALSE, + NULL, + NULL, + &TempUString, + &ForwarderHandle, + FALSE); + RtlFreeUnicodeString(&TempUString); + } + + /* If the load or conversion failed, use the failure path */ + if (!NT_SUCCESS(Status)) goto FailurePath; + + /* Now set up a name for the actual forwarder dll */ + RtlInitAnsiString(&ForwarderName, + ImportName + ForwarderName.Length + sizeof(CHAR)); + + /* Check if it's an ordinal forward */ + if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#')) + { + /* We don't have an actual function name */ + ForwardName = NULL; + + /* Convert the string into an ordinal */ + Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR), + 0, + &ForwardOrdinal); + + /* If this fails, then error out */ + if (!NT_SUCCESS(Status)) goto FailurePath; + } + else + { + /* Import by name */ + ForwardName = &ForwarderName; + } + + /* Get the pointer */ + Status = LdrpGetProcedureAddress(ForwarderHandle, + ForwardName, + ForwardOrdinal, + (PVOID*)&Thunk->u1.Function, + FALSE); + /* If this fails, then error out */ + if (!NT_SUCCESS(Status)) goto FailurePath; + } + else + { + /* It's not within the exports, let's hope it's valid */ + if (!AddressOfFunctions[Ordinal]) goto FailurePath; + } + + /* If we got here, then it's success */ + Status = STATUS_SUCCESS; + } + + /* Return status */ + return Status; +} + +/* EOF */ diff --git a/reactos/dll/ntdll/ldr/ldrutils.c b/reactos/dll/ntdll/ldr/ldrutils.c index 29534cdd992..5c37694807c 100644 --- a/reactos/dll/ntdll/ldr/ldrutils.c +++ b/reactos/dll/ntdll/ldr/ldrutils.c @@ -15,6 +15,8 @@ /* GLOBALS *******************************************************************/ +PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache; + /* FUNCTIONS *****************************************************************/ BOOLEAN @@ -80,4 +82,248 @@ LdrpTlsCallback(PVOID BaseAddress, ULONG Reason) _SEH2_END; } +BOOLEAN +NTAPI +LdrpCheckForLoadedDllHandle(IN PVOID Base, + OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) +{ + PLDR_DATA_TABLE_ENTRY Current; + PLIST_ENTRY ListHead, Next; + + /* Check the cache first */ + if (LdrpLoadedDllHandleCache && LdrpLoadedDllHandleCache->DllBase == Base) + { + /* We got lucky, return the cached entry */ + *LdrEntry = LdrpLoadedDllHandleCache; + return TRUE; + } + + /* Time for a lookup */ + ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; + Next = ListHead->Flink; + while(Next != ListHead) + { + /* Get the current entry */ + Current = CONTAINING_RECORD(Next, + LDR_DATA_TABLE_ENTRY, + InLoadOrderLinks); + + /* Make sure it's not unloading and check for a match */ + if ((Current->InMemoryOrderModuleList.Flink) && (Base == Current->DllBase)) + { + /* Save in cache */ + LdrpLoadedDllHandleCache = Current; + + /* Return it */ + *LdrEntry = Current; + return TRUE; + } + + /* Move to the next one */ + Next = Next->Flink; + } + + /* Nothing found */ + return FALSE; +} + +BOOLEAN +NTAPI +LdrpCheckForLoadedDll(IN PWSTR DllPath, + IN PUNICODE_STRING DllName, + IN BOOLEAN Flag, + IN BOOLEAN RedirectedDll, + OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) +{ + UNIMPLEMENTED; + return FALSE; +} + +NTSTATUS +NTAPI +LdrpGetProcedureAddress(IN PVOID BaseAddress, + IN PANSI_STRING Name, + IN ULONG Ordinal, + OUT PVOID *ProcedureAddress, + IN BOOLEAN ExecuteInit) +{ + NTSTATUS Status = STATUS_SUCCESS; + UCHAR ImportBuffer[64]; + PLDR_DATA_TABLE_ENTRY LdrEntry; + IMAGE_THUNK_DATA Thunk; + PVOID ImageBase; + PIMAGE_IMPORT_BY_NAME ImportName = NULL; + PIMAGE_EXPORT_DIRECTORY ExportDir; + ULONG ExportDirSize; + PLIST_ENTRY Entry; + + /* Show debug message */ + if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by "); + + /* Check if we got a name */ + if (Name) + { + /* Show debug message */ + if (ShowSnaps) DPRINT1("NAME - %s\n", Name->Buffer); + + /* Make sure it's not too long */ + if ((Name->Length + sizeof(CHAR) + sizeof(USHORT)) > MAXLONG) + { + /* Won't have enough space to add the hint */ + return STATUS_NAME_TOO_LONG; + } + + /* Check if our buffer is large enough */ + if (Name->Length >= (sizeof(ImportBuffer) - sizeof(CHAR))) + { + /* Allocate from heap, plus 2 bytes for the Hint */ + ImportName = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + Name->Length + sizeof(CHAR) + + sizeof(USHORT)); + } + else + { + /* Use our internal buffer */ + ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer; + } + + /* Clear the hint */ + ImportName->Hint = 0; + + /* Copy the name and null-terminate it */ + RtlMoveMemory(&ImportName->Name, Name->Buffer, Name->Length); + ImportName->Name[Name->Length + 1] = 0; + + /* Clear the high bit */ + ImageBase = ImportName; + Thunk.u1.AddressOfData = 0; + } + else + { + /* Do it by ordinal */ + ImageBase = NULL; + + /* Show debug message */ + if (ShowSnaps) DPRINT1("ORDINAL - %lx\n", Ordinal); + + if (Ordinal) + { + Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG; + } + else + { + /* No ordinal */ + DPRINT1("No ordinal and no name\n"); + return STATUS_INVALID_PARAMETER; + } + } + + /* Acquire lock unless we are initting */ + if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock); + + _SEH2_TRY + { + /* Try to find the loaded DLL */ + if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) + { + /* Invalid base */ + DPRINT1("Invalid base address\n"); + Status = STATUS_DLL_NOT_FOUND; + _SEH2_YIELD(goto Quickie;) + } + + /* Get the pointer to the export directory */ + ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &ExportDirSize); + + if (!ExportDir) + { + DPRINT1("Image has no exports\n"); + Status = STATUS_PROCEDURE_NOT_FOUND; + _SEH2_YIELD(goto Quickie;) + } + + /* Now get the thunk */ + Status = LdrpSnapThunk(LdrEntry->DllBase, + ImageBase, + &Thunk, + &Thunk, + ExportDir, + ExportDirSize, + FALSE, + NULL); + + /* Finally, see if we're supposed to run the init routines */ + if (ExecuteInit) + { + /* + * It's possible a forwarded entry had us load the DLL. In that case, + * then we will call its DllMain. Use the last loaded DLL for this. + */ + Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink; + LdrEntry = CONTAINING_RECORD(Entry, + LDR_DATA_TABLE_ENTRY, + InInitializationOrderModuleList); + + /* Make sure we didn't process it yet*/ + if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) + { + /* Call the init routine */ + _SEH2_TRY + { + Status = LdrpRunInitializeRoutines(NULL); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get the exception code */ + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + } + } + + /* Make sure we're OK till here */ + if (NT_SUCCESS(Status)) + { + /* Return the address */ + *ProcedureAddress = (PVOID)Thunk.u1.Function; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Just ignore exceptions */ + } + _SEH2_END; + +Quickie: + /* Cleanup */ + if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer)) + { + /* We allocated from heap, free it */ + RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName); + } + + /* Release the CS if we entered it */ + if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock); + + /* We're done */ + return Status; +} + +NTSTATUS +NTAPI +LdrpLoadDll(IN BOOLEAN Redirected, + IN PWSTR DllPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *BaseAddress, + IN BOOLEAN CallInit) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + /* EOF */ diff --git a/reactos/dll/ntdll/ldr/utils.c b/reactos/dll/ntdll/ldr/utils.c index e03cb12a3d2..232a6ef7f6b 100644 --- a/reactos/dll/ntdll/ldr/utils.c +++ b/reactos/dll/ntdll/ldr/utils.c @@ -2848,108 +2848,6 @@ LdrShutdownThread (VOID) return STATUS_SUCCESS; } - -/*************************************************************************** - * NAME EXPORTED - * LdrQueryProcessModuleInformation - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - * - * NOTE - * - * @implemented - */ -NTSTATUS NTAPI -LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL, - IN ULONG Size OPTIONAL, - OUT PULONG ReturnedSize) -{ - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL; - NTSTATUS Status = STATUS_SUCCESS; - ULONG UsedSize = sizeof(ULONG); - ANSI_STRING AnsiString; - PCHAR p; - - DPRINT("LdrQueryProcessModuleInformation() called\n"); -// FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c - RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock); - - if (ModuleInformation == NULL || Size == 0) - { - Status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - ModuleInformation->NumberOfModules = 0; - ModulePtr = &ModuleInformation->Modules[0]; - Status = STATUS_SUCCESS; - } - - ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; - Entry = ModuleListHead->Flink; - - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - - DPRINT(" Module %wZ\n", - &Module->FullDllName); - - if (UsedSize > Size) - { - Status = STATUS_INFO_LENGTH_MISMATCH; - } - else if (ModuleInformation != NULL) - { - ModulePtr->Section = 0; - ModulePtr->MappedBase = NULL; // FIXME: ?? - ModulePtr->ImageBase = Module->DllBase; - ModulePtr->ImageSize = Module->SizeOfImage; - ModulePtr->Flags = Module->Flags; - ModulePtr->LoadOrderIndex = 0; // FIXME: ?? - ModulePtr->InitOrderIndex = 0; // FIXME: ?? - ModulePtr->LoadCount = Module->LoadCount; - - AnsiString.Length = 0; - AnsiString.MaximumLength = 256; - AnsiString.Buffer = ModulePtr->FullPathName; - RtlUnicodeStringToAnsiString(&AnsiString, - &Module->FullDllName, - FALSE); - - p = strrchr(ModulePtr->FullPathName, '\\'); - if (p != NULL) - ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1; - else - ModulePtr->OffsetToFileName = 0; - - ModulePtr++; - ModuleInformation->NumberOfModules++; - } - UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION); - - Entry = Entry->Flink; - } - - RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); - - if (ReturnedSize != 0) - *ReturnedSize = UsedSize; - - DPRINT("LdrQueryProcessModuleInformation() done\n"); - - return(Status); -} - /* * Compute size of an image as it is actually present in virt memory * (i.e. excluding NEVER_LOAD sections) diff --git a/reactos/dll/ntdll/ntdll.rbuild b/reactos/dll/ntdll/ntdll.rbuild index 544a53b67ea..384a6c96ff6 100644 --- a/reactos/dll/ntdll/ntdll.rbuild +++ b/reactos/dll/ntdll/ntdll.rbuild @@ -49,6 +49,7 @@ ldrapi.c ldrinit.c + ldrpe.c ldrutils.c startup.c utils.c