diff --git a/reactos/dll/ntdll/include/ntdllp.h b/reactos/dll/ntdll/include/ntdllp.h index 097f8522d1c..a01a960cef2 100644 --- a/reactos/dll/ntdll/include/ntdllp.h +++ b/reactos/dll/ntdll/include/ntdllp.h @@ -26,6 +26,7 @@ extern RTL_CRITICAL_SECTION LdrpLoaderLock; extern BOOLEAN LdrpInLdrInit; extern LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES]; extern BOOLEAN ShowSnaps; +extern UNICODE_STRING LdrpDefaultPath; /* ldrinit.c */ NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL); diff --git a/reactos/dll/ntdll/ldr/ldrinit.c b/reactos/dll/ntdll/ldr/ldrinit.c index 535bce90b8c..cccaa4ee4f3 100644 --- a/reactos/dll/ntdll/ldr/ldrinit.c +++ b/reactos/dll/ntdll/ldr/ldrinit.c @@ -19,31 +19,69 @@ HKEY ImageExecOptionsKey; 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""); +UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll"); BOOLEAN LdrpInLdrInit; LONG LdrpProcessInitialized; +BOOLEAN LdrpLoaderLockInit; +BOOLEAN LdrpLdrDatabaseIsSetup; + +BOOLEAN LdrpDllValidation; PLDR_DATA_TABLE_ENTRY LdrpImageEntry; PUNICODE_STRING LdrpTopLevelDllBeingLoaded; extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c! PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer; +PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry; -//RTL_BITMAP TlsBitMap; -//RTL_BITMAP TlsExpansionBitMap; -//RTL_BITMAP FlsBitMap; +RTL_BITMAP TlsBitMap; +RTL_BITMAP TlsExpansionBitMap; +RTL_BITMAP FlsBitMap; BOOLEAN LdrpImageHasTls; LIST_ENTRY LdrpTlsList; ULONG LdrpNumberOfTlsEntries; ULONG LdrpNumberOfProcessors; +PVOID NtDllBase; +LARGE_INTEGER RtlpTimeout; +BOOLEAN RtlpTimeoutDisable; +LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES]; +LIST_ENTRY LdrpDllNotificationList; +HANDLE LdrpKnownDllObjectDirectory; +UNICODE_STRING LdrpKnownDllPath; +WCHAR LdrpKnownDllPathBuffer[128]; +UNICODE_STRING LdrpDefaultPath; -RTL_CRITICAL_SECTION LdrpLoaderLock; +PEB_LDR_DATA PebLdr; + +RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug; +RTL_CRITICAL_SECTION LdrpLoaderLock = +{ + &LdrpLoaderLockDebug, + -1, + 0, + 0, + 0, + 0 +}; +RTL_CRITICAL_SECTION FastPebLock; BOOLEAN ShowSnaps; ULONG LdrpFatalHardErrorCount; +//extern LIST_ENTRY RtlCriticalSectionList; + VOID RtlpInitializeVectoredExceptionHandling(VOID); VOID NTAPI RtlpInitDeferedCriticalSection(VOID); +VOID RtlInitializeHeapManager(VOID); +extern BOOLEAN RtlpPageHeapEnabled; +extern ULONG RtlpDphGlobalFlags; + +NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase); +NTSTATUS NTAPI +LdrpInitializeProcess_(PCONTEXT Context, + PVOID SystemArgument1); + /* FUNCTIONS *****************************************************************/ @@ -455,12 +493,10 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL) /* Show debug message */ if (ShowSnaps) { - DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ pid %u %0x%x\n", + DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n", NtCurrentTeb()->RealClientId.UniqueThread, NtCurrentTeb()->RealClientId.UniqueProcess, - Peb->ProcessParameters->ImagePathName, - NtCurrentTeb()->RealClientId.UniqueThread, - NtCurrentTeb()->RealClientId.UniqueProcess); + &Peb->ProcessParameters->ImagePathName); } /* Loop in order */ @@ -838,6 +874,644 @@ LdrpFreeTls(VOID) TlsVector); } +NTSTATUS +NTAPI +LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PULONG Options) +{ + UNIMPLEMENTED; + *Options = 0; + return STATUS_SUCCESS; +} + +VOID +NTAPI +LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry) +{ + UNIMPLEMENTED; +} + +NTSTATUS +NTAPI +LdrpInitializeProcess(IN PCONTEXT Context, + IN PVOID SystemArgument1) +{ + RTL_HEAP_PARAMETERS HeapParameters; + ULONG ComSectionSize; + //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData"); + PVOID OldShimData; + OBJECT_ATTRIBUTES ObjectAttributes; + //UNICODE_STRING LocalFileName, FullImageName; + HANDLE SymLinkHandle; + //ULONG DebugHeapOnly; + UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString; + PPEB Peb = NtCurrentPeb(); + BOOLEAN IsDotNetImage = FALSE; + BOOLEAN FreeCurDir = FALSE; + //HKEY CompatKey; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + //LPWSTR ImagePathBuffer; + ULONG ConfigSize; + UNICODE_STRING CurrentDirectory; + ULONG ExecuteOptions; + ULONG HeapFlags; + PIMAGE_NT_HEADERS NtHeader; + LPWSTR NtDllName = NULL; + NTSTATUS Status; + NLSTABLEINFO NlsTable; + PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig; + PTEB Teb = NtCurrentTeb(); + PLIST_ENTRY ListHead; + PLIST_ENTRY NextEntry; + ULONG i; + PWSTR ImagePath; + ULONG DebugProcessHeapOnly = 0; + WCHAR FullNtDllPath[MAX_PATH]; + PLDR_DATA_TABLE_ENTRY NtLdrEntry; + PWCHAR Current; + + /* Set a NULL SEH Filter */ + RtlSetUnhandledExceptionFilter(NULL); + + /* Get the image path */ + ImagePath = Peb->ProcessParameters->ImagePathName.Buffer; + + /* Check if it's normalized */ + if (Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED) + { + /* Normalize it*/ + ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters); + } + + /* Create a unicode string for the Image Path */ + ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length; + ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR); + ImagePathName.Buffer = ImagePath; + + /* Get the NT Headers */ + NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress); + + /* Get the execution options */ + Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &ExecuteOptions); + + /* Check if this is a .NET executable */ + if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, + TRUE, + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, + &ComSectionSize)) + { + /* Remeber this for later */ + IsDotNetImage = TRUE; + } + + /* Save the NTDLL Base address */ + NtDllBase = SystemArgument1; + + /* If this is a Native Image */ + if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE) + { + /* Then do DLL Validation */ + LdrpDllValidation = TRUE; + } + + /* Save the old Shim Data */ + OldShimData = Peb->pShimData; + + /* Clear it */ + Peb->pShimData = NULL; + + /* Save the number of processors and CS Timeout */ + LdrpNumberOfProcessors = Peb->NumberOfProcessors; + RtlpTimeout = Peb->CriticalSectionTimeout; + + /* Normalize the parameters */ + ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters); + ProcessParameters = Peb->ProcessParameters; + if (ProcessParameters) + { + /* Save the Image and Command Line Names */ + ImageFileName = ProcessParameters->ImagePathName; + CommandLine = ProcessParameters->CommandLine; + } + else + { + /* It failed, initialize empty strings */ + RtlInitUnicodeString(&ImageFileName, NULL); + RtlInitUnicodeString(&CommandLine, NULL); + } + + /* Initialize NLS data */ + RtlInitNlsTables(Peb->AnsiCodePageData, + Peb->OemCodePageData, + Peb->UnicodeCaseTableData, + &NlsTable); + + /* Reset NLS Translations */ + RtlResetRtlTranslations(&NlsTable); + + /* Get the Image Config Directory */ + LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, + TRUE, + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, + &ConfigSize); + + /* Setup the Heap Parameters */ + RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS)); + HeapFlags = HEAP_GROWABLE; + HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS); + + /* Check if we have Configuration Data */ + if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY))) + { + /* FIXME: Custom heap settings and misc. */ + DPRINT1("We don't support LOAD_CONFIG data yet\n"); + } + + /* Check for custom affinity mask */ + if (Peb->ImageProcessAffinityMask) + { + /* Set it */ + Status = NtSetInformationProcess(NtCurrentProcess(), + ProcessAffinityMask, + &Peb->ImageProcessAffinityMask, + sizeof(Peb->ImageProcessAffinityMask)); + } + + /* Check if verbose debugging (ShowSnaps) was requested */ + ShowSnaps = TRUE;//Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS; + + /* Start verbose debugging messages right now if they were requested */ + if (ShowSnaps) + { + DPRINT1("LDR: PID: 0x%x started - '%wZ'\n", + Teb->ClientId.UniqueProcess, + &CommandLine); + } + + /* If the timeout is too long */ + if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000)) + { + /* Then disable CS Timeout */ + RtlpTimeoutDisable = TRUE; + } + + /* Initialize Critical Section Data */ + RtlpInitDeferedCriticalSection(); + + /* Initialize VEH Call lists */ + RtlpInitializeVectoredExceptionHandling(); + + /* Set TLS/FLS Bitmap data */ + Peb->FlsBitmap = &FlsBitMap; + Peb->TlsBitmap = &TlsBitMap; + Peb->TlsExpansionBitmap = &TlsExpansionBitMap; + + /* Initialize FLS Bitmap */ + RtlInitializeBitMap(&FlsBitMap, + Peb->FlsBitmapBits, + FLS_MAXIMUM_AVAILABLE); + RtlSetBit(&FlsBitMap, 0); + + /* Initialize TLS Bitmap */ + RtlInitializeBitMap(&TlsBitMap, + Peb->TlsBitmapBits, + TLS_MINIMUM_AVAILABLE); + RtlSetBit(&TlsBitMap, 0); + RtlInitializeBitMap(&TlsExpansionBitMap, + Peb->TlsExpansionBitmapBits, + TLS_EXPANSION_SLOTS); + RtlSetBit(&TlsExpansionBitMap, 0); + + /* Initialize the Hash Table */ + for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++) + { + InitializeListHead(&LdrpHashTable[i]); + } + + /* Initialize the Loader Lock */ + //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList); + //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock; + UNIMPLEMENTED; + LdrpLoaderLockInit = TRUE; + + /* Check if User Stack Trace Database support was requested */ + if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB) + { + DPRINT1("We don't support user stack trace databases yet\n"); + } + + /* Setup Fast PEB Lock */ + RtlInitializeCriticalSection(&FastPebLock); + Peb->FastPebLock = &FastPebLock; + //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection; + //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection; + + /* Setup Callout Lock and Notification list */ + //RtlInitializeCriticalSection(&RtlpCalloutEntryLock); + InitializeListHead(&LdrpDllNotificationList); + + /* For old executables, use 16-byte aligned heap */ + if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) && + (NtHeader->OptionalHeader.MinorSubsystemVersion < 51)) + { + HeapFlags |= HEAP_CREATE_ALIGN_16; + } + + /* Setup the Heap */ + RtlInitializeHeapManager(); + Peb->ProcessHeap = RtlCreateHeap(HeapFlags, + NULL, + NtHeader->OptionalHeader.SizeOfHeapReserve, + NtHeader->OptionalHeader.SizeOfHeapCommit, + NULL, + &HeapParameters); + + if (!Peb->ProcessHeap) + { + DPRINT1("Failed to create process heap\n"); + return STATUS_NO_MEMORY; + } + + /* Allocate an Activation Context Stack */ + Status = RtlAllocateActivationContextStack((PVOID *)&Teb->ActivationContextStackPointer); + if (!NT_SUCCESS(Status)) return Status; + + // FIXME: Loader private heap is missing + DPRINT1("Loader private heap is missing\n"); + + /* Check for Debug Heap */ + DPRINT1("Check for a debug heap is missing\n"); + if (FALSE) + { + /* Query the setting */ + Status = LdrQueryImageFileKeyOption(NULL,//hKey + L"DebugProcessHeapOnly", + REG_DWORD, + &DebugProcessHeapOnly, + sizeof(ULONG), + NULL); + + if (NT_SUCCESS(Status)) + { + /* Reset DPH if requested */ + if (RtlpPageHeapEnabled && DebugProcessHeapOnly) + { + RtlpDphGlobalFlags &= ~0x40; + RtlpPageHeapEnabled = FALSE; + } + } + } + + /* Build the NTDLL Path */ + FullPath.Buffer = FullNtDllPath; + FullPath.Length = 0; + FullPath.MaximumLength = sizeof(FullNtDllPath); + RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot); + RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot); + RtlAppendUnicodeToString(&FullPath, L"\\System32\\"); + + /* Open the Known DLLs directory */ + RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls"); + InitializeObjectAttributes(&ObjectAttributes, + &KnownDllString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory, + DIRECTORY_QUERY | DIRECTORY_TRAVERSE, + &ObjectAttributes); + + /* Check if it exists */ + if (!NT_SUCCESS(Status)) + { + /* It doesn't, so assume System32 */ + LdrpKnownDllObjectDirectory = NULL; + RtlInitUnicodeString(&LdrpKnownDllPath, FullPath.Buffer); + LdrpKnownDllPath.Length -= sizeof(WCHAR); + } + else + { + /* Open the Known DLLs Path */ + InitializeObjectAttributes(&ObjectAttributes, + &KnownDllString, + OBJ_CASE_INSENSITIVE, + LdrpKnownDllObjectDirectory, + NULL); + Status = NtOpenSymbolicLinkObject(&SymLinkHandle, + SYMBOLIC_LINK_QUERY, + &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Query the path */ + LdrpKnownDllPath.Length = 0; + LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer); + LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer; + Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL); + NtClose(SymLinkHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status); + return Status; + } + } + } + + /* If we have process parameters, get the default path and current path */ + if (ProcessParameters) + { + /* Check if we have a Dll Path */ + if (ProcessParameters->DllPath.Length) + { + /* Get the path */ + LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath; + } + else + { + /* We need a valid path */ + LdrpInitFailure(STATUS_INVALID_PARAMETER); + } + + /* Set the current directory */ + CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath; + + /* Check if it's empty or invalid */ + if ((!CurrentDirectory.Buffer) || + (CurrentDirectory.Buffer[0] == UNICODE_NULL) || + (!CurrentDirectory.Length)) + { + /* Allocate space for the buffer */ + CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap, + 0, + 3 * sizeof(WCHAR) + + sizeof(UNICODE_NULL)); + + /* Copy the drive of the system root */ + RtlMoveMemory(CurrentDirectory.Buffer, + SharedUserData->NtSystemRoot, + 3 * sizeof(WCHAR)); + CurrentDirectory.Buffer[3] = UNICODE_NULL; + CurrentDirectory.Length = 3 * sizeof(WCHAR); + CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR); + + FreeCurDir = TRUE; + } + else + { + /* Use the local buffer */ + CurrentDirectory.Length = NtSystemRoot.Length; + CurrentDirectory.Buffer = NtSystemRoot.Buffer; + } + } + + /* Setup Loader Data */ + Peb->Ldr = &PebLdr; + InitializeListHead(&PebLdr.InLoadOrderModuleList); + InitializeListHead(&PebLdr.InMemoryOrderModuleList); + InitializeListHead(&PebLdr.InInitializationOrderModuleList); + PebLdr.Length = sizeof(PEB_LDR_DATA); + PebLdr.Initialized = TRUE; + + /* Allocate a data entry for the Image */ + LdrpImageEntry = NtLdrEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress); + + /* Set it up */ + NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase); + NtLdrEntry->LoadCount = -1; + NtLdrEntry->EntryPointActivationContext = 0; + NtLdrEntry->FullDllName.Length = ImageFileName.Length; + NtLdrEntry->FullDllName.Buffer = ImageFileName.Buffer; + if (IsDotNetImage) + NtLdrEntry->Flags = LDRP_COR_IMAGE; + else + NtLdrEntry->Flags = 0; + + /* Check if the name is empty */ + if (!ImageFileName.Buffer[0]) + { + /* Use the same Base name */ + NtLdrEntry->BaseDllName = NtLdrEntry->BaseDllName; + } + else + { + /* Find the last slash */ + Current = ImageFileName.Buffer; + while (*Current) + { + if (*Current++ == '\\') + { + /* Set this path */ + NtDllName = Current; + } + } + + /* Did we find anything? */ + if (!NtDllName) + { + /* Use the same Base name */ + NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName; + } + else + { + /* Setup the name */ + NtLdrEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName); + NtLdrEntry->BaseDllName.MaximumLength = NtLdrEntry->BaseDllName.Length + sizeof(WCHAR); + NtLdrEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer + + (ImageFileName.Length - NtLdrEntry->BaseDllName.Length)); + } + } + + /* Processing done, insert it */ + LdrpInsertMemoryTableEntry(NtLdrEntry); + NtLdrEntry->Flags |= LDRP_ENTRY_PROCESSED; + + /* Now add an entry for NTDLL */ + NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1); + NtLdrEntry->Flags = LDRP_IMAGE_DLL; + NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase); + NtLdrEntry->LoadCount = -1; + NtLdrEntry->EntryPointActivationContext = 0; + //NtLdrEntry->BaseDllName.Length = NtSystemRoot.Length; + //RtlAppendUnicodeStringToString(&NtSystemRoot, &NtDllString); + NtLdrEntry->BaseDllName.Length = NtDllString.Length; + NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength; + NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer; + + // FIXME: Full DLL name?! + + /* Processing done, insert it */ + LdrpNtDllDataTableEntry = NtLdrEntry; + LdrpInsertMemoryTableEntry(NtLdrEntry); + + /* Let the world know */ + if (ShowSnaps) + { + DPRINT1("LDR: NEW PROCESS\n"); + DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName); + DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory); + DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath); + } + + /* Link the Init Order List */ + InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList, + &LdrpNtDllDataTableEntry->InInitializationOrderModuleList); + + /* Set the current directory */ + Status = RtlSetCurrentDirectory_U(&CurrentDirectory); + if (!NT_SUCCESS(Status)) + { + /* We failed, check if we should free it */ + if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory); + + /* Set it to the NT Root */ + CurrentDirectory = NtSystemRoot; + RtlSetCurrentDirectory_U(&CurrentDirectory); + } + else + { + /* We're done with it, free it */ + if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory); + } + + /* Check if we should look for a .local file */ + if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH) + { + /* FIXME */ + DPRINT1("We don't support .local overrides yet\n"); + } + + /* Check if the Application Verifier was enabled */ + if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK) + { + /* FIXME */ + DPRINT1("We don't support Application Verifier yet\n"); + } + + if (IsDotNetImage) + { + /* FIXME */ + DPRINT1("We don't support .NET applications yet\n"); + } + + /* FIXME: Load support for Terminal Services */ + if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) + { + /* Load kernel32 and call BasePostImportInit... */ + DPRINT1("Unimplemented codepath!\n"); + } + + /* Walk the IAT and load all the DLLs */ + LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry); + + /* Check if relocation is needed */ + if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase) + { + DPRINT("LDR: Performing relocations\n"); + Status = LdrPerformRelocations(NtHeader, Peb->ImageBaseAddress); + if (!NT_SUCCESS(Status)) + { + DPRINT1("LdrPerformRelocations() failed\n"); + return STATUS_INVALID_IMAGE_FORMAT; + } + } + + /* Lock the DLLs */ + ListHead = &Peb->Ldr->InLoadOrderModuleList; + NextEntry = ListHead->Flink; + while (ListHead != NextEntry) + { + NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + NtLdrEntry->LoadCount = -1; + NextEntry = NextEntry->Flink; + } + + /* Phase 0 is done */ + LdrpLdrDatabaseIsSetup = TRUE; + + /* Initialize TLS */ + Status = LdrpInitializeTls(); + if (!NT_SUCCESS(Status)) + { + DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n", + Status); + return Status; + } + + /* FIXME Mark the DLL Ranges for Stack Traces later */ + + /* Notify the debugger now */ + if (Peb->BeingDebugged) + { + /* Break */ + DbgBreakPoint(); + + /* Update show snaps again */ + ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS; + } + + /* Validate the Image for MP Usage */ + if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry); + + /* Check NX Options */ + if (SharedUserData->NXSupportPolicy == 1) + { + ExecuteOptions = 0xD; + } + else if (!SharedUserData->NXSupportPolicy) + { + ExecuteOptions = 0xA; + } + + /* Let Mm know */ + ZwSetInformationProcess(NtCurrentProcess(), + ProcessExecuteFlags, + &ExecuteOptions, + sizeof(ULONG)); + + /* Check if we had Shim Data */ + if (OldShimData) + { + /* Load the Shim Engine */ + Peb->AppCompatInfo = NULL; + //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData); + DPRINT1("We do not support shims yet\n"); + } + else + { + /* Check for Application Compatibility Goo */ + //LdrQueryApplicationCompatibilityGoo(hKey); + DPRINT1("Querying app compat hacks is missing!\n"); + } + + /* + * FIXME: Check for special images, SecuROM, SafeDisc and other NX- + * incompatible images. + */ + + /* Now call the Init Routines */ + Status = LdrpRunInitializeRoutines(Context); + if (!NT_SUCCESS(Status)) + { + DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n", + Status); + return Status; + } + + /* FIXME: Unload the Shim Engine if it was loaded */ + + /* Check if we have a user-defined Post Process Routine */ + if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine) + { + DPRINT1("CP\n"); + /* Call it */ + Peb->PostProcessInitRoutine(); + } + + ///* Close the key if we have one opened */ + //if (hKey) NtClose(hKey); +DbgBreakPoint(); + /* Return status */ + return Status; +} + VOID NTAPI LdrpInitFailure(NTSTATUS Status) @@ -915,17 +1589,11 @@ LdrpInit(PCONTEXT Context, /* Let other code know we're initializing */ LdrpInLdrInit = TRUE; - /* Initialize Critical Section Data */ - RtlpInitDeferedCriticalSection(); - - /* Initialize VEH Call lists */ - RtlpInitializeVectoredExceptionHandling(); - /* Protect with SEH */ _SEH2_TRY { /* Initialize the Process */ - LoaderStatus = LdrpInitializeProcess(Context, + LoaderStatus = LdrpInitializeProcess_(Context, SystemArgument1); /* Check for success and if MinimumStackCommit was requested */ diff --git a/reactos/dll/ntdll/ldr/ldrpe.c b/reactos/dll/ntdll/ldr/ldrpe.c index 4e72d91e908..ddcaf617e50 100644 --- a/reactos/dll/ntdll/ldr/ldrpe.c +++ b/reactos/dll/ntdll/ldr/ldrpe.c @@ -30,6 +30,595 @@ LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL, /* FUNCTIONS *****************************************************************/ +NTSTATUS +NTAPI +LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry, + IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry, + IN PIMAGE_IMPORT_DESCRIPTOR IatEntry, + IN BOOLEAN EntriesValid) +{ + PIMAGE_EXPORT_DIRECTORY ExportDirectory; + ULONG ExportSize; + PVOID Iat; + SIZE_T ImportSize; + ULONG IatSize; + //PPEB Peb = NtCurrentPeb(); + NTSTATUS Status; + PIMAGE_THUNK_DATA Thunk, OriginalThunk, FirstThunk; + LPSTR ImportName; + ULONG ForwarderChain; + PIMAGE_NT_HEADERS NtHeader; + PIMAGE_SECTION_HEADER SectionHeader; + ULONG i, Rva; + ULONG OldProtect; + + /* Get export directory */ + ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &ExportSize); + + /* Make sure it has one */ + if (!ExportDirectory) return STATUS_INVALID_IMAGE_FORMAT; + + /* Get the IAT */ + Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_IAT, + &IatSize); + ImportSize = IatSize; + + /* Check if we don't have one */ + if (!Iat) + { + /* Get the NT Header and the first section */ + NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase); + SectionHeader = IMAGE_FIRST_SECTION(NtHeader); + + /* Get the RVA of the import directory */ + Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + + /* Make sure we got one */ + if (Rva) + { + /* Loop all the sections */ + for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++) + { + /* Check if we are inside this section */ + if ((Rva >= SectionHeader->VirtualAddress) && + (Rva < (SectionHeader->VirtualAddress + + SectionHeader->SizeOfRawData))) + { + /* We are, so set the IAT here */ + Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) + + SectionHeader->VirtualAddress); + + /* Set the size */ + IatSize = SectionHeader->Misc.VirtualSize; + + /* Deal with Watcom and other retarded compilers */ + if (!IatSize) + { + IatSize = SectionHeader->SizeOfRawData; + } + + /* Found it, get out */ + break; + } + + /* No match, move to the next section */ + ++SectionHeader; + } + } + + /* If we still don't have an IAT, that's bad */ + if (!Iat) return STATUS_INVALID_IMAGE_FORMAT; + + /* Set the right size */ + ImportSize = IatSize; + } + + /* Unprotect the IAT */ + Status = NtProtectVirtualMemory(NtCurrentProcess(), + &Iat, + &ImportSize, + PAGE_READWRITE, + &OldProtect); + if (!NT_SUCCESS(Status)) return Status; + + /* Check if the Thunks are already valid */ + if (EntriesValid) + { + /* We'll only do forwarders. Get the import name */ + ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name); + + /* Get the list of forwaders */ + ForwarderChain = IatEntry->ForwarderChain; + + /* Loop them */ + while (ForwarderChain != -1) + { + /* Get the cached thunk VA*/ + OriginalThunk = (PIMAGE_THUNK_DATA) + ((ULONG_PTR)ImportLdrEntry->DllBase + + IatEntry->OriginalFirstThunk + + (ForwarderChain * sizeof(IMAGE_THUNK_DATA))); + + /* Get the first thunk */ + FirstThunk = (PIMAGE_THUNK_DATA) + ((ULONG_PTR)ImportLdrEntry->DllBase + + IatEntry->FirstThunk + + (ForwarderChain * sizeof(IMAGE_THUNK_DATA))); + + /* Get the Forwarder from the thunk */ + ForwarderChain = (ULONG)FirstThunk->u1.Ordinal; + + /* Snap the thunk */ + Status = LdrpSnapThunk(ExportLdrEntry->DllBase, + ImportLdrEntry->DllBase, + OriginalThunk, + FirstThunk, + ExportDirectory, + ExportSize, + TRUE, + ImportName); + + /* Move to the next thunk */ + FirstThunk++; + + /* If we messed up, exit */ + if (!NT_SUCCESS(Status)) break; + } + } + else if (IatEntry->FirstThunk) + { + /* Full snapping. Get the First thunk */ + FirstThunk = (PIMAGE_THUNK_DATA) + ((ULONG_PTR)ImportLdrEntry->DllBase + + IatEntry->FirstThunk); + + /* Get the NT Header */ + NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase); + + /* Get the Original thunk VA, watch out for weird images */ + if ((IatEntry->Characteristics < NtHeader->OptionalHeader.SizeOfHeaders) || + (IatEntry->Characteristics >= NtHeader->OptionalHeader.SizeOfImage)) + { + /* Reuse it, this is a strange linked file */ + OriginalThunk = FirstThunk; + } + else + { + /* Get the address from the field and convert to VA */ + OriginalThunk = (PIMAGE_THUNK_DATA) + ((ULONG_PTR)ImportLdrEntry->DllBase + + IatEntry->OriginalFirstThunk); + } + + /* Get the Import name VA */ + ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + + IatEntry->Name); + + /* Loop while it's valid */ + while (OriginalThunk->u1.AddressOfData) + { + /* Snap the Thunk */ + Status = LdrpSnapThunk(ExportLdrEntry->DllBase, + ImportLdrEntry->DllBase, + OriginalThunk, + FirstThunk, + ExportDirectory, + ExportSize, + TRUE, + ImportName); + + /* Next thunks */ + OriginalThunk++; + Thunk++; + + /* If we failed the snap, break out */ + if (!NT_SUCCESS(Status)) break; + } + } + + /* Protect the IAT again */ + NtProtectVirtualMemory(NtCurrentProcess(), + &Iat, + &ImportSize, + OldProtect, + &OldProtect); + + /* Also flush out the cache */ + NtFlushInstructionCache(NtCurrentProcess(), Iat, IatSize); + + /* Return to Caller */ + return Status; +} + +NTSTATUS +NTAPI +LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry, + IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry) +{ + LPSTR ImportName = NULL, BoundImportName, ForwarderName; + NTSTATUS Status; + BOOLEAN AlreadyLoaded = FALSE, Stale; + PIMAGE_IMPORT_DESCRIPTOR ImportEntry; + PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry; + PIMAGE_BOUND_FORWARDER_REF ForwarderEntry; + PPEB Peb = NtCurrentPeb(); + ULONG i, IatSize; + + /* Get the name's VA */ + BoundImportName = (LPSTR)(BoundEntry + BoundEntry->OffsetModuleName); + + /* Show debug mesage */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry->BaseDllName, BoundImportName); + } + + /* Load the module for this entry */ + Status = LdrpLoadImportModule(DllPath, + BoundImportName, + LdrEntry->DllBase, + &DllLdrEntry, + &AlreadyLoaded); + if (!NT_SUCCESS(Status)) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n", + &LdrEntry->BaseDllName, + BoundImportName, + Status); + } + goto Quickie; + } + + /* Check if it wasn't already loaded */ + if (!AlreadyLoaded) + { + /* Add it to our list */ + InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, + &DllLdrEntry->InInitializationOrderModuleList); + } + + /* Check if the Bound Entry is now invalid */ + if ((BoundEntry->TimeDateStamp != DllLdrEntry->TimeDateStamp) || + (DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ has stale binding to %s\n", + &DllLdrEntry->BaseDllName, + BoundImportName); + } + + /* Remember it's become stale */ + Stale = TRUE; + } + else + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ has correct binding to %s\n", + &DllLdrEntry->BaseDllName, + BoundImportName); + } + + /* Remember it's valid */ + Stale = FALSE; + } + + /* Get the forwarders */ + ForwarderEntry = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1); + + /* Loop them */ + for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++) + { + /* Get the name */ + ForwarderName = (LPSTR)(FirstEntry + ForwarderEntry->OffsetModuleName); + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n", + &LdrEntry->BaseDllName, + ForwarderName, + &DllLdrEntry->BaseDllName); + } + + /* Load the module */ + Status = LdrpLoadImportModule(DllPath, + ForwarderName, + LdrEntry->DllBase, + &ForwarderLdrEntry, + &AlreadyLoaded); + if (NT_SUCCESS(Status)) + { + /* Loaded it, was it already loaded? */ + if (!AlreadyLoaded) + { + /* Add it to our list */ + InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, + &ForwarderLdrEntry->InInitializationOrderModuleList); + } + } + + /* Check if the Bound Entry is now invalid */ + if (!(NT_SUCCESS(Status)) || + (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) || + (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ has stale binding to %s\n", + &ForwarderLdrEntry->BaseDllName, + ForwarderName); + } + + /* Remember it's become stale */ + Stale = TRUE; + } + else + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ has correct binding to %s\n", + &ForwarderLdrEntry->BaseDllName, + ForwarderName); + } + + /* Remember it's valid */ + Stale = FALSE; + } + + /* Move to the next one */ + ForwarderEntry++; + } + + /* Set the next bound entry to the forwarder */ + FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry; + + /* Check if the binding was stale */ + if (Stale) + { + /* It was, so find the IAT entry for it */ + ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &IatSize); + + /* Make sure it has a name */ + while (ImportEntry->Name) + { + /* Get the name */ + ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name); + + /* Compare it */ + if (!_stricmp(ImportName, BoundImportName)) break; + + /* Move to next entry */ + ImportEntry += 1; + } + + /* If we didn't find a name, fail */ + if (!ImportEntry->Name) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: LdrpWalkImportTable - failing with" + "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n"); + } + + /* Return error */ + Status = STATUS_OBJECT_NAME_INVALID; + goto Quickie; + } + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: Stale Bind %s from %wZ\n", + ImportName, + &LdrEntry->BaseDllName); + } + + /* Snap the IAT Entry*/ + Status = LdrpSnapIAT(DllLdrEntry, + LdrEntry, + ImportEntry, + FALSE); + + /* Make sure we didn't fail */ + if (!NT_SUCCESS(Status)) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n", + &LdrEntry->BaseDllName, + BoundImportName, + Status); + } + + /* Return */ + goto Quickie; + } + } + + /* All done */ + Status = STATUS_SUCCESS; + +Quickie: + /* Write where we are now and return */ + *BoundEntry = *FirstEntry; + return Status; +} + +NTSTATUS +NTAPI +LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry) +{ + PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry; + NTSTATUS Status; + + /* Make sure we have a name */ + while (BoundEntry->OffsetModuleName) + { + /* Parse this descriptor */ + Status = LdrpHandleOneNewFormatImportDescriptor(DllPath, + LdrEntry, + BoundEntry, + FirstEntry); + if (!NT_SUCCESS(Status)) return Status; + } + + /* Done */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry) +{ + //ULONG IatSize, i; + LPSTR ImportName; + NTSTATUS Status; + BOOLEAN AlreadyLoaded = FALSE, StaticEntriesValid = FALSE, SkipSnap = TRUE; + PLDR_DATA_TABLE_ENTRY DllLdrEntry; + PIMAGE_THUNK_DATA FirstThunk; + PPEB Peb = NtCurrentPeb(); + + /* Get the import name's VA */ + ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name); + + /* Get the first thunk */ + FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase + + ImportEntry->FirstThunk); + + /* Make sure it's valid */ + if (!FirstThunk->u1.Function) goto SkipEntry; + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: %s used by %wZ\n", + ImportName, + &LdrEntry->BaseDllName); + } + + /* Load the module associated to it */ + Status = LdrpLoadImportModule(DllPath, + ImportName, + LdrEntry->DllBase, + &DllLdrEntry, + &AlreadyLoaded); + if (!NT_SUCCESS(Status)) return Status; + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: Snapping imports for %wZ from %s\n", + &LdrEntry->BaseDllName, + ImportName); + } + + /* Check if the image was bound when compiled */ + if (ImportEntry->OriginalFirstThunk) + { + /* It was, so check if the static IAT entries are still valid */ + if ((ImportEntry->TimeDateStamp) && + (ImportEntry->TimeDateStamp == DllLdrEntry->TimeDateStamp) && + (!(DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: Snap bypass %s from %wZ\n", + ImportName, + &LdrEntry->BaseDllName); + } + + /* + * They are still valid, so we can skip snapping them. + * Additionally, if we have no forwarders, we are totally + * done. + */ + if (ImportEntry->ForwarderChain == -1) + { + /* Totally skip LdrpSnapIAT */ + SkipSnap = TRUE; + } + else + { + /* Set this so LdrpSnapIAT will only do forwarders */ + StaticEntriesValid = TRUE; + } + } + } + + /* Check if it wasn't already loaded */ + if (!AlreadyLoaded) + { + /* Add the DLL to our list */ + InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, + &DllLdrEntry->InInitializationOrderModuleList); + } + + /* Check if we should snap at all */ + if (!SkipSnap) + { + /* Now snap the IAT Entry */ + Status = LdrpSnapIAT(DllLdrEntry, + LdrEntry, + ImportEntry, + StaticEntriesValid); + if (!NT_SUCCESS(Status)) return Status; + } + +SkipEntry: + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry) +{ + NTSTATUS Status; + + /* Check for Name and Thunk */ + while (ImportEntry->Name && ImportEntry->FirstThunk) + { + /* Parse this descriptor */ + Status = LdrpHandleOneOldFormatImportDescriptor(DllPath, + LdrEntry, + ImportEntry); + if (!NT_SUCCESS(Status)) return Status; + + /* Move to the next entry */ + ImportEntry++; + } + + /* Done */ + return STATUS_SUCCESS; +} + USHORT NTAPI LdrpNameToOrdinal(LPSTR ImportName, ULONG NumberOfNames, @@ -41,6 +630,169 @@ LdrpNameToOrdinal(LPSTR ImportName, return 0; } +NTSTATUS +NTAPI +LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL, + IN PLDR_DATA_TABLE_ENTRY LdrEntry) +{ + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; + PPEB Peb = NtCurrentPeb(); + NTSTATUS Status = STATUS_SUCCESS; + PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL; + PIMAGE_IMPORT_DESCRIPTOR ImportEntry; + ULONG BoundSize, IatSize; +DPRINT1("LdrpWalkImportDescriptor('%S' %x)\n", DllPath, LdrEntry); + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID; + RtlZeroMemory(&ActCtx, sizeof(ActCtx)); + + /* Check if we have a manifest prober routine */ + if (LdrpManifestProberRoutine) + { + DPRINT1("We don't support manifests yet, much less prober routines\n"); + } + + /* Check if we failed above */ + if (!NT_SUCCESS(Status)) return Status; + + /* Get the Active ActCtx */ + Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext); + if (!NT_SUCCESS(Status)) return Status; + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Check if we were directed */ + if (!(LdrEntry->Flags & LDRP_REDIRECTED)) + { + /* Get the Bound IAT */ + BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, + &BoundSize); + } + + /* Get the regular IAT, for fallback */ + ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &IatSize); + + /* Check if we got at least one */ + if (BoundEntry || ImportEntry) + { + /* Do we have a Bound IAT */ + if (BoundEntry) + { + /* Handle the descriptor */ + Status = LdrpHandleNewFormatImportDescriptors(DllPath, + LdrEntry, + BoundEntry); + } + else + { + /* Handle the descriptor */ + Status = LdrpHandleOldFormatImportDescriptors(DllPath, + LdrEntry, + ImportEntry); + } + + /* Check the status of the handlers */ + if (NT_SUCCESS(Status)) + { + /* Check for Per-DLL Heap Tagging */ + if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL) + { + /* FIXME */ + DPRINT1("We don't support Per-DLL Heap Tagging yet!\n"); + } + + /* Check if Page Heap was enabled */ + if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS) + { + /* FIXME */ + DPRINT1("We don't support Page Heaps yet!\n"); + } + + /* Check if Application Verifier was enabled */ + if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) + { + /* FIXME */ + DPRINT1("We don't support Application Verifier yet!\n"); + } + + /* Just to be safe */ + Status = STATUS_SUCCESS; + } + } + + /* Release the activation context */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL, + IN LPSTR ImportName, + IN PVOID DllBase, + OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry, + OUT PBOOLEAN Existing) +{ + ANSI_STRING AnsiString; + PUNICODE_STRING ImpDescName; + NTSTATUS Status; + PPEB Peb = RtlGetCurrentPeb(); + PTEB Teb = NtCurrentTeb(); +DPRINT1("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath, ImportName, DllBase, DataTableEntry, Existing); + /* Convert import descriptor name to unicode string */ + ImpDescName = &Teb->StaticUnicodeString; + RtlInitAnsiString(&AnsiString, ImportName); + Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE); + if (!NT_SUCCESS(Status)) return Status; + + /* Check if it's loaded */ + if (LdrpCheckForLoadedDll(DllPath, + ImpDescName, + TRUE, + FALSE, + DataTableEntry)) + { + /* It's already existing in the list */ + *Existing = TRUE; + return STATUS_SUCCESS; + } + + /* We're loading it for the first time */ + *Existing = FALSE; + + /* Map it */ + Status = LdrpMapDll(DllPath, + ImpDescName->Buffer, + NULL, + NULL, + TRUE, + FALSE, + DataTableEntry); + + if (!NT_SUCCESS(Status)) return Status; + + /* Walk its import descriptor table */ + Status = LdrpWalkImportDescriptor(DllPath, + *DataTableEntry); + if (!NT_SUCCESS(Status)) + { + /* Add it to the in-init-order list in case of failure */ + InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, + &(*DataTableEntry)->InInitializationOrderModuleList); + } + + return Status; +} NTSTATUS NTAPI diff --git a/reactos/dll/ntdll/ldr/ldrutils.c b/reactos/dll/ntdll/ldr/ldrutils.c index b45ca1a21ae..8c2783755ae 100644 --- a/reactos/dll/ntdll/ldr/ldrutils.c +++ b/reactos/dll/ntdll/ldr/ldrutils.c @@ -16,7 +16,6 @@ /* GLOBALS *******************************************************************/ PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache; -LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES]; #define LDR_GET_HASH_ENTRY(x) (RtlUpcaseUnicodeChar((x)) & (LDR_HASH_TABLE_ENTRIES - 1)) @@ -217,7 +216,261 @@ LdrpCheckForLoadedDll(IN PWSTR DllPath, IN BOOLEAN RedirectedDll, OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) { - UNIMPLEMENTED; + ULONG HashIndex; + PLIST_ENTRY ListHead, ListEntry; + PLDR_DATA_TABLE_ENTRY CurEntry; + BOOLEAN FullPath = FALSE; + PWCHAR wc; + WCHAR NameBuf[266]; + UNICODE_STRING FullDllName, NtPathName; + ULONG Length; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE FileHandle, SectionHandle; + IO_STATUS_BLOCK Iosb; + PVOID ViewBase = NULL; + SIZE_T ViewSize = 0; + PIMAGE_NT_HEADERS NtHeader, NtHeader2; +DPRINT1("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath, DllName, Flag, RedirectedDll, LdrEntry); + /* Check if a dll name was provided */ + if (!DllName->Buffer || !DllName->Buffer[0]) return FALSE; + + /* Look in the hash table if flag was set */ +lookinhash: + if (Flag) + { + /* Get hash index */ + HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]); + + /* Traverse that list */ + ListHead = &LdrpHashTable[HashIndex]; + ListEntry = ListHead->Flink; + while (ListEntry != ListHead) + { + /* Get the current entry */ + CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks); + + /* Check base name of that module */ + if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE)) + { + /* It matches, return it */ + *LdrEntry = CurEntry; + return TRUE; + } + + /* Advance to the next entry */ + ListEntry = ListEntry->Flink; + } + + /* Module was not found, return failure */ + return FALSE; + } + + /* Check if there is a full path in this DLL */ + wc = DllName->Buffer; + while (*wc) + { + /* Check for a slash in the current position*/ + if (*wc == L'\\' || *wc == L'/') + { + /* Found the slash, so dll name contains path */ + FullPath = TRUE; + + /* Setup full dll name string */ + FullDllName.Buffer = NameBuf; + + Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer, + DllName->Buffer, + NULL, + sizeof(NameBuf) - sizeof(UNICODE_NULL), + FullDllName.Buffer, + NULL); + + /* Check if that was successful */ + if (!Length || Length > sizeof(NameBuf) - sizeof(UNICODE_NULL)) + { + if (ShowSnaps) + { + DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n", + DllName->Buffer, Length); + } + + /* Return failure */ + return FALSE; + } + + /* Full dll name is found */ + FullDllName.Length = Length; + FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL); + break; + } + + wc++; + } + + /* Go check the hash table */ + if (!FullPath) + { + Flag = TRUE; + goto lookinhash; + } + + /* Now go through the InLoadOrder module list */ + ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; + ListEntry = ListHead->Flink; + + while (ListEntry != ListHead) + { + /* Get the containing record of the current entry and advance to the next one */ + CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + ListEntry = ListEntry->Flink; + + /* Check if it's already being unloaded */ + if (!CurEntry->InMemoryOrderModuleList.Flink) continue; + + /* Check if name matches */ + if (RtlEqualUnicodeString(&FullDllName, + &CurEntry->FullDllName, + TRUE)) + { + /* Found it */ + *LdrEntry = CurEntry; + + /* Find activation context */ + Status = RtlFindActivationContextSectionString(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, DllName, NULL); + if (!NT_SUCCESS(Status)) + return FALSE; + else + return TRUE; + } + } + + /* The DLL was not found in the load order modules list. Perform a complex check */ + + /* Convert given path to NT path */ + if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer, + &NtPathName, + NULL, + NULL)) + { + /* Fail if conversion failed */ + return FALSE; + } + + /* Initialize object attributes and open it */ + InitializeObjectAttributes(&ObjectAttributes, + &NtPathName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + SYNCHRONIZE | FILE_EXECUTE, + &ObjectAttributes, + &Iosb, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + + /* Free NT path name */ + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer); + + /* If opening the file failed - return failure */ + if (!NT_SUCCESS(Status)) return FALSE; + + /* Create a section for this file */ + Status = NtCreateSection(&SectionHandle, + SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, + NULL, + NULL, + PAGE_EXECUTE, + SEC_COMMIT, + FileHandle); + + /* Close file handle */ + NtClose(FileHandle); + + /* If creating section failed - return failure */ + if (!NT_SUCCESS(Status)) return FALSE; + + /* Map view of this section */ + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &ViewBase, + 0, + 0, + NULL, + &ViewSize, + ViewShare, + 0, + PAGE_EXECUTE); + /* Close section handle */ + NtClose(SectionHandle); + + /* If section mapping failed - return failure */ + if (!NT_SUCCESS(Status)) return FALSE; + + /* Get pointer to the NT header of this section */ + NtHeader = RtlImageNtHeader(ViewBase); + if (!NtHeader) + { + /* Unmap the section and fail */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + return FALSE; + } + + /* Go through the list of modules */ + ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; + ListEntry = ListHead->Flink; + + while (ListEntry != ListHead) + { + CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + ListEntry = ListEntry->Flink; + + /* Check if it's already being unloaded */ + if (!CurEntry->InMemoryOrderModuleList.Flink) continue; + + _SEH2_TRY + { + /* Check if timedate stamp and sizes match */ + if (CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp && + CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage) + { + /* Time, date and size match. Let's compare their headers */ + NtHeader2 = RtlImageNtHeader(CurEntry->DllBase); + + if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS))) + { + /* Headers match too! Finally ask the kernel to compare mapped files */ + Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase); + + if (!NT_SUCCESS(Status)) + { + _SEH2_YIELD(continue;) + } + else + { + /* This is our entry! */ + *LdrEntry = CurEntry; + + /* Unmap the section */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + + _SEH2_YIELD(return TRUE;) + } + } + } + } + _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(break;) + } + _SEH2_END; + } + + /* Unmap the section */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + return FALSE; } diff --git a/reactos/dll/ntdll/ldr/startup.c b/reactos/dll/ntdll/ldr/startup.c index 731842ac26e..f063aefdc0d 100644 --- a/reactos/dll/ntdll/ldr/startup.c +++ b/reactos/dll/ntdll/ldr/startup.c @@ -17,13 +17,15 @@ VOID RtlInitializeHeapManager(VOID); VOID LdrpInitLoader(VOID); extern PTEB LdrpTopLevelDllBeingLoadedTeb; +VOID NTAPI RtlpInitDeferedCriticalSection(VOID); +VOID RtlpInitializeVectoredExceptionHandling(VOID); /* GLOBALS *******************************************************************/ extern PLDR_DATA_TABLE_ENTRY LdrpImageEntry; -static RTL_CRITICAL_SECTION PebLock; -static RTL_BITMAP TlsBitMap; -static RTL_BITMAP TlsExpansionBitMap; +extern RTL_CRITICAL_SECTION FastPebLock; +extern RTL_BITMAP TlsBitMap; +extern RTL_BITMAP TlsExpansionBitMap; #define VALUE_BUFFER_SIZE 256 @@ -309,7 +311,7 @@ finish: NTSTATUS NTAPI -LdrpInitializeProcess(PCONTEXT Context, +LdrpInitializeProcess_(PCONTEXT Context, PVOID SystemArgument1) { PIMAGE_NT_HEADERS NTHeaders; @@ -372,6 +374,9 @@ LdrpInitializeProcess(PCONTEXT Context, Peb->NumberOfProcessors = SystemInformation.NumberOfProcessors; + /* Initialize Critical Section Data */ + RtlpInitDeferedCriticalSection(); + /* Load execution options */ LoadImageFileExecutionOptions(Peb); @@ -430,9 +435,12 @@ LdrpInitializeProcess(PCONTEXT Context, ZwTerminateProcess(NtCurrentProcess(), STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE); } + /* initialized vectored exception handling */ + RtlpInitializeVectoredExceptionHandling(); + /* initalize peb lock support */ - RtlInitializeCriticalSection(&PebLock); - Peb->FastPebLock = &PebLock; + RtlInitializeCriticalSection(&FastPebLock); + Peb->FastPebLock = &FastPebLock; /* initialize tls bitmaps */ RtlInitializeBitMap(&TlsBitMap, Peb->TlsBitmapBits, TLS_MINIMUM_AVAILABLE); diff --git a/reactos/dll/ntdll/ldr/utils.c b/reactos/dll/ntdll/ldr/utils.c index 2f660dacdbe..c9bb89bbb51 100644 --- a/reactos/dll/ntdll/ldr/utils.c +++ b/reactos/dll/ntdll/ldr/utils.c @@ -32,8 +32,8 @@ #endif static BOOLEAN LdrpDllShutdownInProgress = FALSE; -static HANDLE LdrpKnownDllsDirHandle = NULL; -static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL}; +extern HANDLE LdrpKnownDllObjectDirectory; +extern UNICODE_STRING LdrpKnownDllPath; static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL; extern PLDR_DATA_TABLE_ENTRY LdrpImageEntry; @@ -231,13 +231,13 @@ LdrpInitLoader(VOID) OBJ_CASE_INSENSITIVE, NULL, NULL); - Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle, + Status = NtOpenDirectoryObject(&LdrpKnownDllObjectDirectory, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status); - LdrpKnownDllsDirHandle = NULL; + LdrpKnownDllObjectDirectory = NULL; return; } @@ -249,8 +249,8 @@ LdrpInitLoader(VOID) MAX_PATH * sizeof(WCHAR)); if (LinkTarget.Buffer == NULL) { - NtClose(LdrpKnownDllsDirHandle); - LdrpKnownDllsDirHandle = NULL; + NtClose(LdrpKnownDllObjectDirectory); + LdrpKnownDllObjectDirectory = NULL; return; } @@ -259,7 +259,7 @@ LdrpInitLoader(VOID) InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, - LdrpKnownDllsDirHandle, + LdrpKnownDllObjectDirectory, NULL); Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, @@ -267,8 +267,8 @@ LdrpInitLoader(VOID) if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&LinkTarget); - NtClose(LdrpKnownDllsDirHandle); - LdrpKnownDllsDirHandle = NULL; + NtClose(LdrpKnownDllObjectDirectory); + LdrpKnownDllObjectDirectory = NULL; return; } @@ -279,8 +279,8 @@ LdrpInitLoader(VOID) if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&LinkTarget); - NtClose(LdrpKnownDllsDirHandle); - LdrpKnownDllsDirHandle = NULL; + NtClose(LdrpKnownDllObjectDirectory); + LdrpKnownDllObjectDirectory = NULL; } RtlCreateUnicodeString(&LdrpKnownDllPath, @@ -431,7 +431,7 @@ LdrpMapKnownDll(IN PUNICODE_STRING DllName, DPRINT("LdrpMapKnownDll() called\n"); - if (LdrpKnownDllsDirHandle == NULL) + if (LdrpKnownDllObjectDirectory == NULL) { DPRINT("Invalid 'KnownDlls' directory\n"); return STATUS_UNSUCCESSFUL; @@ -442,7 +442,7 @@ LdrpMapKnownDll(IN PUNICODE_STRING DllName, InitializeObjectAttributes(&ObjectAttributes, DllName, OBJ_CASE_INSENSITIVE, - LdrpKnownDllsDirHandle, + LdrpKnownDllObjectDirectory, NULL); Status = NtOpenSection(SectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, @@ -1189,7 +1189,7 @@ LdrGetExportByName(PVOID BaseAddress, * NOTE * */ -static NTSTATUS +NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase) {