/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS NT User-Mode Library * FILE: dll/ntdll/ldr/ldrinit.c * PURPOSE: User-Mode Process/Thread Startup * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) * Aleksey Bragin (aleksey@reactos.org) */ /* INCLUDES *****************************************************************/ #include #include #include #define NDEBUG #include /* GLOBALS *******************************************************************/ HANDLE ImageExecOptionsKey; HANDLE 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 LdrpShutdownInProgress; HANDLE LdrpShutdownThreadId; BOOLEAN LdrpDllValidation; PLDR_DATA_TABLE_ENTRY LdrpImageEntry; PUNICODE_STRING LdrpTopLevelDllBeingLoaded; WCHAR StringBuffer[156]; 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; BOOLEAN LdrpImageHasTls; LIST_ENTRY LdrpTlsList; ULONG LdrpNumberOfTlsEntries; ULONG LdrpNumberOfProcessors; PVOID NtDllBase; extern 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; 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; ULONG LdrpActiveUnloadCount; //extern LIST_ENTRY RtlCriticalSectionList; VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID); VOID NTAPI RtlpInitDeferedCriticalSection(VOID); VOID NTAPI RtlInitializeHeapManager(VOID); ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c ULONG RtlpShutdownProcessFlags; // TODO: Use it NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase); void actctx_init(void); extern BOOLEAN RtlpUse16ByteSLists; #ifdef _WIN64 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll #else #define DEFAULT_SECURITY_COOKIE 0xBB40E64E #endif /* FUNCTIONS *****************************************************************/ /* * @implemented */ NTSTATUS NTAPI LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey, IN BOOLEAN Wow64, OUT PHANDLE NewKeyHandle) { PHANDLE RootKeyLocation; HANDLE RootKey; UNICODE_STRING SubKeyString; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; PWCHAR p1; /* Check which root key to open */ if (Wow64) RootKeyLocation = &Wow64ExecOptionsKey; else RootKeyLocation = &ImageExecOptionsKey; /* Get the current key */ RootKey = *RootKeyLocation; /* Setup the object attributes */ InitializeObjectAttributes(&ObjectAttributes, Wow64 ? &Wow64OptionsString : &ImageExecOptionsString, OBJ_CASE_INSENSITIVE, NULL, NULL); /* Open the root key */ Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes); if (NT_SUCCESS(Status)) { /* Write the key handle */ if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0) { /* Someone already opened it, use it instead */ NtClose(RootKey); RootKey = *RootKeyLocation; } /* Extract the name */ SubKeyString = *SubKey; p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length); while (SubKeyString.Length) { if (p1[-1] == L'\\') break; p1--; SubKeyString.Length -= sizeof(*p1); } SubKeyString.Buffer = p1; SubKeyString.Length = SubKey->Length - SubKeyString.Length; /* Setup the object attributes */ InitializeObjectAttributes(&ObjectAttributes, &SubKeyString, OBJ_CASE_INSENSITIVE, RootKey, NULL); /* Open the setting key */ Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes); } /* Return to caller */ return Status; } /* * @implemented */ NTSTATUS NTAPI LdrQueryImageFileKeyOption(IN HANDLE KeyHandle, IN PCWSTR ValueName, IN ULONG Type, OUT PVOID Buffer, IN ULONG BufferSize, OUT PULONG ReturnedLength OPTIONAL) { ULONG KeyInfo[256]; UNICODE_STRING ValueNameString, IntegerString; ULONG KeyInfoSize, ResultSize; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo; BOOLEAN FreeHeap = FALSE; NTSTATUS Status; /* Build a string for the value name */ Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName); if (!NT_SUCCESS(Status)) return Status; /* Query the value */ Status = ZwQueryValueKey(KeyHandle, &ValueNameString, KeyValuePartialInformation, KeyValueInformation, sizeof(KeyInfo), &ResultSize); if (Status == STATUS_BUFFER_OVERFLOW) { /* Our local buffer wasn't enough, allocate one */ KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyValueInformation->DataLength; KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize); if (KeyValueInformation != NULL) { /* Try again */ Status = ZwQueryValueKey(KeyHandle, &ValueNameString, KeyValuePartialInformation, KeyValueInformation, KeyInfoSize, &ResultSize); FreeHeap = TRUE; } else { /* Give up this time */ Status = STATUS_NO_MEMORY; } } /* Check for success */ if (NT_SUCCESS(Status)) { /* Handle binary data */ if (KeyValueInformation->Type == REG_BINARY) { /* Check validity */ if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize)) { /* Copy into buffer */ RtlMoveMemory(Buffer, &KeyValueInformation->Data, KeyValueInformation->DataLength); } else { Status = STATUS_BUFFER_OVERFLOW; } /* Copy the result length */ if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength; } else if (KeyValueInformation->Type == REG_DWORD) { /* Check for valid type */ if (KeyValueInformation->Type != Type) { /* Error */ Status = STATUS_OBJECT_TYPE_MISMATCH; } else { /* Check validity */ if ((Buffer) && (BufferSize == sizeof(ULONG)) && (KeyValueInformation->DataLength <= BufferSize)) { /* Copy into buffer */ RtlMoveMemory(Buffer, &KeyValueInformation->Data, KeyValueInformation->DataLength); } else { Status = STATUS_BUFFER_OVERFLOW; } /* Copy the result length */ if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength; } } else if (KeyValueInformation->Type != REG_SZ) { /* We got something weird */ Status = STATUS_OBJECT_TYPE_MISMATCH; } else { /* String, check what you requested */ if (Type == REG_DWORD) { /* Validate */ if (BufferSize != sizeof(ULONG)) { /* Invalid size */ BufferSize = 0; Status = STATUS_INFO_LENGTH_MISMATCH; } else { /* OK, we know what you want... */ IntegerString.Buffer = (PWSTR)KeyValueInformation->Data; IntegerString.Length = (USHORT)KeyValueInformation->DataLength - sizeof(WCHAR); IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength; Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer); } } else { /* Validate */ if (KeyValueInformation->DataLength > BufferSize) { /* Invalid */ Status = STATUS_BUFFER_OVERFLOW; } else { /* Set the size */ BufferSize = KeyValueInformation->DataLength; } /* Copy the string */ RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize); } /* Copy the result length */ if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength; } } /* Check if buffer was in heap */ if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); /* Return status */ return Status; } /* * @implemented */ NTSTATUS NTAPI LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey, IN PCWSTR ValueName, IN ULONG Type, OUT PVOID Buffer, IN ULONG BufferSize, OUT PULONG ReturnedLength OPTIONAL, IN BOOLEAN Wow64) { NTSTATUS Status; HANDLE KeyHandle; /* Open a handle to the key */ Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle); /* Check for success */ if (NT_SUCCESS(Status)) { /* Query the data */ Status = LdrQueryImageFileKeyOption(KeyHandle, ValueName, Type, Buffer, BufferSize, ReturnedLength); /* Close the key */ NtClose(KeyHandle); } /* Return to caller */ return Status; } /* * @implemented */ NTSTATUS NTAPI LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey, IN PCWSTR ValueName, IN ULONG Type, OUT PVOID Buffer, IN ULONG BufferSize, OUT PULONG ReturnedLength OPTIONAL) { /* Call the newer function */ return LdrQueryImageFileExecutionOptionsEx(SubKey, ValueName, Type, Buffer, BufferSize, ReturnedLength, FALSE); } VOID NTAPI LdrpEnsureLoaderLockIsHeld(VOID) { // Ignored atm } PVOID NTAPI LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage) { PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir; ULONG DirSize; PVOID Cookie = NULL; /* Check NT header first */ if (!RtlImageNtHeader(BaseAddress)) return NULL; /* Get the pointer to the config directory */ ConfigDir = RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &DirSize); /* Check for sanity */ if (!ConfigDir || (DirSize != 64 && ConfigDir->Size != DirSize) || (ConfigDir->Size < 0x48)) return NULL; /* Now get the cookie */ Cookie = (PVOID)ConfigDir->SecurityCookie; /* Check this cookie */ if ((PCHAR)Cookie <= (PCHAR)BaseAddress || (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage) { Cookie = NULL; } /* Return validated security cookie */ return Cookie; } PVOID NTAPI LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry) { PULONG_PTR Cookie; LARGE_INTEGER Counter; ULONG_PTR NewCookie; /* Fetch address of the cookie */ Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage); if (Cookie) { /* Check if it's a default one */ if ((*Cookie == DEFAULT_SECURITY_COOKIE) || (*Cookie == 0xBB40)) { /* Make up a cookie from a bunch of values which may uniquely represent current moment of time, environment, etc */ NtQueryPerformanceCounter(&Counter, NULL); NewCookie = Counter.LowPart ^ Counter.HighPart; NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueProcess; NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueThread; /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */ while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time) { YieldProcessor(); }; /* Calculate the milliseconds value and xor it to the cookie */ NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) + (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8)); /* Make the cookie 16bit if necessary */ if (*Cookie == 0xBB40) NewCookie &= 0xFFFF; /* If the result is 0 or the same as we got, just subtract one from the existing value and that's it */ if ((NewCookie == 0) || (NewCookie == *Cookie)) { NewCookie = *Cookie - 1; } /* Set the new cookie value */ *Cookie = NewCookie; } } return Cookie; } VOID NTAPI LdrpInitializeThread(IN PCONTEXT Context) { PPEB Peb = NtCurrentPeb(); PLDR_DATA_TABLE_ENTRY LdrEntry; PLIST_ENTRY NextEntry, ListHead; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; NTSTATUS Status; PVOID EntryPoint; DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n", &LdrpImageEntry->BaseDllName, NtCurrentTeb()->RealClientId.UniqueProcess, NtCurrentTeb()->RealClientId.UniqueThread); /* Allocate an Activation Context Stack */ DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer); Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer); if (!NT_SUCCESS(Status)) { DPRINT1("Warning: Unable to allocate ActivationContextStack\n"); } /* Make sure we are not shutting down */ if (LdrpShutdownInProgress) return; /* Allocate TLS */ LdrpAllocateTls(); /* Start at the beginning */ ListHead = &Peb->Ldr->InMemoryOrderModuleList; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the current entry */ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); /* Make sure it's not ourselves */ if (Peb->ImageBaseAddress != LdrEntry->DllBase) { /* Check if we should call */ if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS)) { /* Get the entrypoint */ EntryPoint = LdrEntry->EntryPoint; /* Check if we are ready to call it */ if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) && (LdrEntry->Flags & LDRP_IMAGE_DLL)) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrEntry->EntryPointActivationContext); /* Check if it has TLS */ if (LdrEntry->TlsIndex) { /* Make sure we're not shutting down */ if (!LdrpShutdownInProgress) { /* Call TLS */ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH); } } /* Make sure we're not shutting down */ if (!LdrpShutdownInProgress) { /* Call the Entrypoint */ DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n", &LdrEntry->BaseDllName, LdrEntry->EntryPoint, NtCurrentTeb()->RealClientId.UniqueProcess, NtCurrentTeb()->RealClientId.UniqueThread); LdrpCallInitRoutine(LdrEntry->EntryPoint, LdrEntry->DllBase, DLL_THREAD_ATTACH, NULL); } /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } } } /* Next entry */ NextEntry = NextEntry->Flink; } /* Check for TLS */ if (LdrpImageHasTls && !LdrpShutdownInProgress) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrpImageEntry->EntryPointActivationContext); /* Do TLS callbacks */ LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH); /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } DPRINT("LdrpInitializeThread() done\n"); } NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL) { 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; BOOLEAN DllStatus; DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n", &LdrpImageEntry->BaseDllName, NtCurrentTeb()->RealClientId.UniqueProcess, NtCurrentTeb()->RealClientId.UniqueThread); /* 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("[%p,%p] LDR: Real INIT LIST for Process %wZ\n", NtCurrentTeb()->RealClientId.UniqueThread, NtCurrentTeb()->RealClientId.UniqueProcess, &Peb->ProcessParameters->ImagePathName); } /* 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, InInitializationOrderLinks); /* 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); /* Check for valid entrypoint */ if (LdrEntry->EntryPoint) { /* Write in array */ ASSERT(i < Count); LdrRootEntry[i] = LdrEntry; /* Display debug message */ if (ShowSnaps) { DPRINT1("[%p,%p] 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: Verify 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; /* Reset status back to STATUS_SUCCESS */ Status = STATUS_SUCCESS; } /* 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 %p\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.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrEntry->EntryPointActivationContext); /* Check if it has TLS */ if (LdrEntry->TlsIndex && Context) { /* Call TLS */ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH); } /* Call the Entrypoint */ if (ShowSnaps) { DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n", &LdrEntry->BaseDllName, EntryPoint); } DllStatus = LdrpCallInitRoutine(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; /* Fail if DLL init failed */ if (!DllStatus) { DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n", &LdrEntry->BaseDllName, EntryPoint); Status = STATUS_DLL_INIT_FAILED; goto Quickie; } } } /* Loop in order */ ListHead = &Peb->Ldr->InInitializationOrderModuleList; NextEntry = NextEntry->Flink; while (NextEntry != ListHead) { /* Get the Data Entry */ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); /* FIXME: Verify NX Compat */ // LdrpCheckNXCompatibility() /* Next entry */ NextEntry = NextEntry->Flink; } /* Check for TLS */ if (LdrpImageHasTls && Context) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrpImageEntry->EntryPointActivationContext); /* Do TLS callbacks */ LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH); /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } Quickie: /* 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("LdrpRunInitializeRoutines() done\n"); return Status; } /* * @implemented */ NTSTATUS NTAPI LdrShutdownProcess(VOID) { PPEB Peb = NtCurrentPeb(); PLDR_DATA_TABLE_ENTRY LdrEntry; PLIST_ENTRY NextEntry, ListHead; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; PVOID EntryPoint; DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName); if (LdrpShutdownInProgress) return STATUS_SUCCESS; /* Tell the Shim Engine */ if (g_ShimsEnabled) { VOID(NTAPI *SE_ProcessDying)(); SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying); SE_ProcessDying(); } /* Tell the world */ if (ShowSnaps) { DPRINT1("\n"); } /* Set the shutdown variables */ LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread; LdrpShutdownInProgress = TRUE; /* Enter the Loader Lock */ RtlEnterCriticalSection(&LdrpLoaderLock); /* Cleanup trace logging data (Etw) */ if (SharedUserData->TraceLogging) { /* FIXME */ DPRINT1("We don't support Etw yet.\n"); } /* Start at the end */ ListHead = &Peb->Ldr->InInitializationOrderModuleList; NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the current entry */ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); NextEntry = NextEntry->Blink; /* Make sure it's not ourselves */ if (Peb->ImageBaseAddress != LdrEntry->DllBase) { /* Get the entrypoint */ EntryPoint = LdrEntry->EntryPoint; /* Check if we are ready to call it */ if (EntryPoint && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) && LdrEntry->Flags) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrEntry->EntryPointActivationContext); /* Check if it has TLS */ if (LdrEntry->TlsIndex) { /* Call TLS */ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH); } /* Call the Entrypoint */ DPRINT("%wZ - Calling entry point at %p for thread detaching\n", &LdrEntry->BaseDllName, LdrEntry->EntryPoint); LdrpCallInitRoutine(EntryPoint, LdrEntry->DllBase, DLL_PROCESS_DETACH, (PVOID)1); /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } } } /* Check for TLS */ if (LdrpImageHasTls) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrpImageEntry->EntryPointActivationContext); /* Do TLS callbacks */ LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_DETACH); /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } /* FIXME: Do Heap detection and Etw final shutdown */ /* Release the lock */ RtlLeaveCriticalSection(&LdrpLoaderLock); DPRINT("LdrpShutdownProcess() done\n"); return STATUS_SUCCESS; } /* * @implemented */ NTSTATUS NTAPI LdrShutdownThread(VOID) { PPEB Peb = NtCurrentPeb(); PTEB Teb = NtCurrentTeb(); PLDR_DATA_TABLE_ENTRY LdrEntry; PLIST_ENTRY NextEntry, ListHead; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; PVOID EntryPoint; DPRINT("LdrShutdownThread() called for %wZ\n", &LdrpImageEntry->BaseDllName); /* Cleanup trace logging data (Etw) */ if (SharedUserData->TraceLogging) { /* FIXME */ DPRINT1("We don't support Etw yet.\n"); } /* Get the Ldr Lock */ RtlEnterCriticalSection(&LdrpLoaderLock); /* Start at the end */ ListHead = &Peb->Ldr->InInitializationOrderModuleList; NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the current entry */ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); NextEntry = NextEntry->Blink; /* Make sure it's not ourselves */ if (Peb->ImageBaseAddress != LdrEntry->DllBase) { /* Check if we should call */ if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) && (LdrEntry->Flags & LDRP_IMAGE_DLL)) { /* Get the entrypoint */ EntryPoint = LdrEntry->EntryPoint; /* Check if we are ready to call it */ if (EntryPoint) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrEntry->EntryPointActivationContext); /* Check if it has TLS */ if (LdrEntry->TlsIndex) { /* Make sure we're not shutting down */ if (!LdrpShutdownInProgress) { /* Call TLS */ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH); } } /* Make sure we're not shutting down */ if (!LdrpShutdownInProgress) { /* Call the Entrypoint */ DPRINT("%wZ - Calling entry point at %p for thread detaching\n", &LdrEntry->BaseDllName, LdrEntry->EntryPoint); LdrpCallInitRoutine(EntryPoint, LdrEntry->DllBase, DLL_THREAD_DETACH, NULL); } /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } } } } /* Check for TLS */ if (LdrpImageHasTls) { /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Activate the ActCtx */ RtlActivateActivationContextUnsafeFast(&ActCtx, LdrpImageEntry->EntryPointActivationContext); /* Do TLS callbacks */ LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_DETACH); /* Deactivate the ActCtx */ RtlDeactivateActivationContextUnsafeFast(&ActCtx); } /* Free TLS */ LdrpFreeTls(); RtlLeaveCriticalSection(&LdrpLoaderLock); /* Check for expansion slots */ if (Teb->TlsExpansionSlots) { /* Free expansion slots */ RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots); } /* Check for FLS Data */ if (Teb->FlsData) { /* FIXME */ DPRINT1("We don't support FLS Data yet\n"); } /* Check for Fiber data */ if (Teb->HasFiberData) { /* Free Fiber data*/ RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData); Teb->NtTib.FiberData = NULL; } /* Free the activation context stack */ RtlFreeThreadActivationContextStack(); DPRINT("LdrShutdownThread() done\n"); return STATUS_SUCCESS; } NTSTATUS NTAPI LdrpInitializeTls(VOID) { PLIST_ENTRY NextEntry, ListHead; PLDR_DATA_TABLE_ENTRY LdrEntry; PIMAGE_TLS_DIRECTORY TlsDirectory; PLDRP_TLS_DATA TlsData; ULONG Size; /* Initialize the TLS List */ InitializeListHead(&LdrpTlsList); /* Loop all the modules */ ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; NextEntry = ListHead->Flink; while (ListHead != NextEntry) { /* Get the entry */ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); NextEntry = NextEntry->Flink; /* Get the TLS directory */ TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &Size); /* Check if we have a directory */ if (!TlsDirectory) continue; /* Check if the image has TLS */ if (!LdrpImageHasTls) LdrpImageHasTls = TRUE; /* Show debug message */ if (ShowSnaps) { DPRINT1("LDR: Tls Found in %wZ at %p\n", &LdrEntry->BaseDllName, TlsDirectory); } /* Allocate an entry */ TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA)); if (!TlsData) return STATUS_NO_MEMORY; /* Lock the DLL and mark it for TLS Usage */ LdrEntry->LoadCount = -1; LdrEntry->TlsIndex = -1; /* Save the cached TLS data */ TlsData->TlsDirectory = *TlsDirectory; InsertTailList(&LdrpTlsList, &TlsData->TlsLinks); /* Update the index */ *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries; TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++; } /* Done setting up TLS, allocate entries */ return LdrpAllocateTls(); } NTSTATUS NTAPI LdrpAllocateTls(VOID) { PTEB Teb = NtCurrentTeb(); PLIST_ENTRY NextEntry, ListHead; PLDRP_TLS_DATA TlsData; SIZE_T TlsDataSize; PVOID *TlsVector; /* Check if we have any entries */ if (!LdrpNumberOfTlsEntries) return STATUS_SUCCESS; /* Allocate the vector array */ TlsVector = RtlAllocateHeap(RtlGetProcessHeap(), 0, LdrpNumberOfTlsEntries * sizeof(PVOID)); if (!TlsVector) return STATUS_NO_MEMORY; Teb->ThreadLocalStoragePointer = TlsVector; /* Loop the TLS Array */ ListHead = &LdrpTlsList; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the entry */ TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks); NextEntry = NextEntry->Flink; /* Allocate this vector */ TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData - TlsData->TlsDirectory.StartAddressOfRawData; TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(), 0, TlsDataSize); if (!TlsVector[TlsData->TlsDirectory.Characteristics]) { /* Out of memory */ return STATUS_NO_MEMORY; } /* Show debug message */ if (ShowSnaps) { DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n", TlsVector, TlsData->TlsDirectory.Characteristics, &TlsVector[TlsData->TlsDirectory.Characteristics], TlsData->TlsDirectory.StartAddressOfRawData, TlsVector[TlsData->TlsDirectory.Characteristics]); } /* Copy the data */ RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics], (PVOID)TlsData->TlsDirectory.StartAddressOfRawData, TlsDataSize); } /* Done */ return STATUS_SUCCESS; } VOID NTAPI LdrpFreeTls(VOID) { PLIST_ENTRY ListHead, NextEntry; PLDRP_TLS_DATA TlsData; PVOID *TlsVector; PTEB Teb = NtCurrentTeb(); /* Get a pointer to the vector array */ TlsVector = Teb->ThreadLocalStoragePointer; if (!TlsVector) return; /* Loop through it */ ListHead = &LdrpTlsList; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks); NextEntry = NextEntry->Flink; /* Free each entry */ if (TlsVector[TlsData->TlsDirectory.Characteristics]) { RtlFreeHeap(RtlGetProcessHeap(), 0, TlsVector[TlsData->TlsDirectory.Characteristics]); } } /* Free the array itself */ RtlFreeHeap(RtlGetProcessHeap(), 0, TlsVector); } NTSTATUS NTAPI LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey) { NTSTATUS Status; HANDLE KeyHandle; ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag; /* Return error if we were not provided a pointer where to save the options key handle */ if (!OptionsKey) return STATUS_INVALID_HANDLE; /* Zero initialize the options key pointer */ *OptionsKey = NULL; /* Open the options key */ Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle); /* Save it if it was opened successfully */ if (NT_SUCCESS(Status)) *OptionsKey = KeyHandle; if (KeyHandle) { /* There are image specific options, read them starting with NXCOMPAT */ Status = LdrQueryImageFileKeyOption(KeyHandle, L"ExecuteOptions", 4, &ExecuteOptions, sizeof(ExecuteOptions), 0); if (NT_SUCCESS(Status)) { /* TODO: Set execution options for the process */ /* if (ExecuteOptions == 0) ExecuteOptions = 1; else ExecuteOptions = 2; ZwSetInformationProcess(NtCurrentProcess(), ProcessExecuteFlags, &ExecuteOptions, sizeof(ULONG));*/ } /* Check if this image uses large pages */ if (Peb->ImageUsesLargePages) { /* TODO: If it does, open large page key */ UNIMPLEMENTED; } /* Get various option values */ LdrQueryImageFileKeyOption(KeyHandle, L"DisableHeapLookaside", REG_DWORD, &RtlpDisableHeapLookaside, sizeof(RtlpDisableHeapLookaside), NULL); LdrQueryImageFileKeyOption(KeyHandle, L"ShutdownFlags", REG_DWORD, &RtlpShutdownProcessFlags, sizeof(RtlpShutdownProcessFlags), NULL); LdrQueryImageFileKeyOption(KeyHandle, L"MinimumStackCommitInBytes", REG_DWORD, &MinimumStackCommit, sizeof(MinimumStackCommit), NULL); /* Update PEB's minimum stack commit if it's lower */ if (Peb->MinimumStackCommit < MinimumStackCommit) Peb->MinimumStackCommit = MinimumStackCommit; /* Set the global flag */ Status = LdrQueryImageFileKeyOption(KeyHandle, L"GlobalFlag", REG_DWORD, &GlobalFlag, sizeof(GlobalFlag), NULL); if (NT_SUCCESS(Status)) Peb->NtGlobalFlag = GlobalFlag; else GlobalFlag = 0; /* Call AVRF if necessary */ if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS)) { Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status); } } } else { /* There are no image-specific options, so perform global initialization */ if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS)) { /* Initialize app verifier package */ Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status); } } } return STATUS_SUCCESS; } VOID NTAPI LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry) { UNIMPLEMENTED; } VOID NTAPI LdrpInitializeProcessCompat(PVOID* pOldShimData) { static const GUID* GuidOrder[] = { &COMPAT_GUID_WIN10, &COMPAT_GUID_WIN81, &COMPAT_GUID_WIN8, &COMPAT_GUID_WIN7, &COMPAT_GUID_VISTA }; static const DWORD GuidVersions[] = { WINVER_WIN10, WINVER_WIN81, WINVER_WIN8, WINVER_WIN7, WINVER_VISTA }; ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)]; ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo; SIZE_T SizeRequired; NTSTATUS Status; DWORD n, cur; ReactOS_ShimData* pShimData = *pOldShimData; C_ASSERT(RTL_NUMBER_OF(GuidOrder) == RTL_NUMBER_OF(GuidVersions)); if (pShimData) { if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC || pShimData->dwSize != sizeof(ReactOS_ShimData)) { DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize); return; } if (pShimData->dwRosProcessCompatVersion) { DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion); return; } } SizeRequired = sizeof(Buffer); Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF, NULL, NULL, CompatibilityInformationInActivationContext, Buffer, sizeof(Buffer), &SizeRequired); if (!NT_SUCCESS(Status)) { DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status); return; } ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer; /* No Compatibility elements present, bail out */ if (ContextCompatInfo->ElementCount == 0) return; /* Search for known GUID's, starting from newest to oldest. */ for (cur = 0; cur < RTL_NUMBER_OF(GuidOrder); ++cur) { for (n = 0; n < ContextCompatInfo->ElementCount; ++n) { if (ContextCompatInfo->Elements[n].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS && RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, GuidOrder[cur], sizeof(GUID)) == sizeof(GUID)) { /* If this process did not need shim data before, allocate and store it */ if (pShimData == NULL) { PPEB Peb = NtCurrentPeb(); ASSERT(Peb->pShimData == NULL); pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData)); if (!pShimData) { DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData)); return; } pShimData->dwSize = sizeof(*pShimData); pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC; Peb->pShimData = pShimData; *pOldShimData = pShimData; } /* Store the highest found version, and bail out. */ pShimData->dwRosProcessCompatVersion = GuidVersions[cur]; DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x\n", GuidVersions[cur]); return; } } } } 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; //HANDLE CompatKey; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; //LPWSTR ImagePathBuffer; ULONG ConfigSize; UNICODE_STRING CurrentDirectory; HANDLE OptionsKey; ULONG HeapFlags; PIMAGE_NT_HEADERS NtHeader; LPWSTR NtDllName = NULL; NTSTATUS Status, ImportStatus; NLSTABLEINFO NlsTable; PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig; PTEB Teb = NtCurrentTeb(); PLIST_ENTRY ListHead; PLIST_ENTRY NextEntry; ULONG i; PWSTR ImagePath; ULONG DebugProcessHeapOnly = 0; PLDR_DATA_TABLE_ENTRY NtLdrEntry; PWCHAR Current; ULONG ExecuteOptions = 0; PVOID ViewBase; /* Set a NULL SEH Filter */ RtlSetUnhandledExceptionFilter(NULL); /* Get the image path */ ImagePath = Peb->ProcessParameters->ImagePathName.Buffer; /* Check if it's not 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, &OptionsKey); /* Check if this is a .NET executable */ if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &ComSectionSize)) { /* Remember 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; /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */ //Peb->pShimData = NULL; /* Save the number of processors and CS Timeout */ LdrpNumberOfProcessors = Peb->NumberOfProcessors; RtlpTimeout = Peb->CriticalSectionTimeout; /* Normalize the parameters */ ProcessParameters = RtlNormalizeProcessParams(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 = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS; /* Start verbose debugging messages right now if they were requested */ if (ShowSnaps) { DPRINT1("LDR: PID: 0x%p 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 */ // FIXME: What's the point of initing it manually, if two lines lower // a call to RtlInitializeCriticalSection() is being made anyway? //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList); //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock; RtlInitializeCriticalSection(&LdrpLoaderLock); 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(&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 */ if (OptionsKey) { /* Query the setting */ Status = LdrQueryImageFileKeyOption(OptionsKey, L"DebugProcessHeapOnly", REG_DWORD, &DebugProcessHeapOnly, sizeof(ULONG), NULL); if (NT_SUCCESS(Status)) { /* Reset DPH if requested */ if (RtlpPageHeapEnabled && DebugProcessHeapOnly) { RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY; RtlpPageHeapEnabled = FALSE; } } } /* Build the NTDLL Path */ FullPath.Buffer = StringBuffer; FullPath.Length = 0; FullPath.MaximumLength = sizeof(StringBuffer); 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)) { /* Open the Known DLLs Path */ RtlInitUnicodeString(&KnownDllString, L"KnownDllPath"); 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; } } } /* Check if we failed */ if (!NT_SUCCESS(Status)) { /* Assume System32 */ LdrpKnownDllObjectDirectory = NULL; RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer); LdrpKnownDllPath.Length -= sizeof(WCHAR); } /* 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 */ DPRINT1("No valid DllPath was given!\n"); 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)); if (!CurrentDirectory.Buffer) { DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n"); // FIXME: And what? } /* 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; DPRINT("Using dynamically allocd curdir\n"); } else { /* Use the local buffer */ DPRINT("Using local system root\n"); } } /* 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 = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress); /* Set it up */ LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase); LdrpImageEntry->LoadCount = -1; LdrpImageEntry->EntryPointActivationContext = 0; LdrpImageEntry->FullDllName = ImageFileName; if (IsDotNetImage) LdrpImageEntry->Flags = LDRP_COR_IMAGE; else LdrpImageEntry->Flags = 0; /* Check if the name is empty */ if (!ImageFileName.Buffer[0]) { /* Use the same Base name */ LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName; } 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 */ LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName; } else { /* Setup the name */ LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName); LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR); LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer + (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length)); } } /* Processing done, insert it */ LdrpInsertMemoryTableEntry(LdrpImageEntry); LdrpImageEntry->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->FullDllName.Length = FullPath.Length; NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength; NtLdrEntry->FullDllName.Buffer = StringBuffer; RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString); NtLdrEntry->BaseDllName.Length = NtDllString.Length; NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength; NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer; /* 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->InInitializationOrderLinks); /* Initialize Wine's active context implementation for the current process */ actctx_init(); /* ReactOS specific */ LdrpInitializeProcessCompat(&OldShimData); /* 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_APPLICATION_VERIFIER) { Status = AVrfInitializeVerifier(); if (!NT_SUCCESS(Status)) { DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status); return Status; } } 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... */ DPRINT("Unimplemented codepath!\n"); } /* Walk the IAT and load all the DLLs */ ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry); /* Check if relocation is needed */ if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase) { DPRINT1("LDR: Performing EXE relocation\n"); /* Change the protection to prepare for relocation */ ViewBase = Peb->ImageBaseAddress; Status = LdrpSetProtection(ViewBase, FALSE); if (!NT_SUCCESS(Status)) return Status; /* Do the relocation */ Status = LdrRelocateImageWithBias(ViewBase, 0LL, NULL, STATUS_SUCCESS, STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT); if (!NT_SUCCESS(Status)) { DPRINT1("LdrRelocateImageWithBias() failed\n"); return Status; } /* Check if a start context was provided */ if (Context) { DPRINT1("WARNING: Relocated EXE Context"); UNIMPLEMENTED; // We should support this return STATUS_INVALID_IMAGE_FORMAT; } /* Restore the protection */ Status = LdrpSetProtection(ViewBase, TRUE); if (!NT_SUCCESS(Status)) return Status; } /* 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; /* Check whether all static imports were properly loaded and return here */ if (!NT_SUCCESS(ImportStatus)) return ImportStatus; /* 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)); // FIXME: Should be done by Application Compatibility features, // by reading the registry, etc... // For now, this is the old code from ntdll!RtlGetVersion(). RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0); if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0) { WCHAR szCSDVersion[128]; LONG i; ULONG Length = ARRAYSIZE(szCSDVersion) - 1; i = _snwprintf(szCSDVersion, Length, L"Service Pack %d", ((Peb->OSCSDVersion >> 8) & 0xFF)); if (i < 0) { /* Null-terminate if it was overflowed */ szCSDVersion[Length] = UNICODE_NULL; } Length *= sizeof(WCHAR); Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length + sizeof(UNICODE_NULL)); if (Peb->CSDVersion.Buffer) { Peb->CSDVersion.Length = Length; Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL); RtlCopyMemory(Peb->CSDVersion.Buffer, szCSDVersion, Peb->CSDVersion.MaximumLength); Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL; } } /* Check if we had Shim Data */ if (OldShimData) { /* Load the Shim Engine */ Peb->AppCompatInfo = NULL; LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData); } else { /* Check for Application Compatibility Goo */ //LdrQueryApplicationCompatibilityGoo(hKey); DPRINT("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; } /* Notify Shim Engine */ if (g_ShimsEnabled) { VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID); SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit); SE_InstallAfterInit(&ImagePathName, OldShimData); } /* Check if we have a user-defined Post Process Routine */ if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine) { /* Call it */ Peb->PostProcessInitRoutine(); } /* Close the key if we have one opened */ if (OptionsKey) NtClose(OptionsKey); /* Return status */ return Status; } VOID NTAPI LdrpInitFailure(NTSTATUS Status) { ULONG Response; PPEB Peb = NtCurrentPeb(); /* Print a debug message */ DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n", &Peb->ProcessParameters->ImagePathName, Status); /* Raise a hard error */ if (!LdrpFatalHardErrorCount) { ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response); } } VOID NTAPI LdrpInit(PCONTEXT Context, PVOID SystemArgument1, PVOID SystemArgument2) { LARGE_INTEGER Timeout; PTEB Teb = NtCurrentTeb(); NTSTATUS Status, LoaderStatus = STATUS_SUCCESS; MEMORY_BASIC_INFORMATION MemoryBasicInfo; PPEB Peb = NtCurrentPeb(); DPRINT("LdrpInit() %p/%p\n", NtCurrentTeb()->RealClientId.UniqueProcess, NtCurrentTeb()->RealClientId.UniqueThread); #ifdef _WIN64 /* Set the SList header usage */ RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128]; #endif /* _WIN64 */ /* Check if we have a deallocation stack */ if (!Teb->DeallocationStack) { /* We don't, set one */ Status = NtQueryVirtualMemory(NtCurrentProcess(), Teb->NtTib.StackLimit, MemoryBasicInformation, &MemoryBasicInfo, sizeof(MEMORY_BASIC_INFORMATION), NULL); if (!NT_SUCCESS(Status)) { /* Fail */ LdrpInitFailure(Status); RtlRaiseStatus(Status); return; } /* Set the stack */ Teb->DeallocationStack = MemoryBasicInfo.AllocationBase; } /* Now check if the process is already being initialized */ while (_InterlockedCompareExchange(&LdrpProcessInitialized, 1, 0) == 1) { /* Set the timeout to 30 milliseconds */ Timeout.QuadPart = Int32x32To64(30, -10000); /* Make sure the status hasn't changed */ while (LdrpProcessInitialized == 1) { /* Do the wait */ ZwDelayExecution(FALSE, &Timeout); } } /* Check if we have already setup LDR data */ if (!Peb->Ldr) { /* Setup the Loader Lock */ Peb->LoaderLock = &LdrpLoaderLock; /* Let other code know we're initializing */ LdrpInLdrInit = TRUE; /* Protect with SEH */ _SEH2_TRY { /* Initialize the Process */ LoaderStatus = LdrpInitializeProcess(Context, SystemArgument1); /* Check for success and if MinimumStackCommit was requested */ if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit) { /* Enforce the limit */ //LdrpTouchThreadStack(Peb->MinimumStackCommit); UNIMPLEMENTED; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Fail with the SEH error */ LoaderStatus = _SEH2_GetExceptionCode(); } _SEH2_END; /* We're not initializing anymore */ LdrpInLdrInit = FALSE; /* Check if init worked */ if (NT_SUCCESS(LoaderStatus)) { /* Set the process as Initialized */ _InterlockedIncrement(&LdrpProcessInitialized); } } else { /* Loader data is there... is this a fork() ? */ if(Peb->InheritedAddressSpace) { /* Handle the fork() */ //LoaderStatus = LdrpForkProcess(); LoaderStatus = STATUS_NOT_IMPLEMENTED; UNIMPLEMENTED; } else { /* This is a new thread initializing */ LdrpInitializeThread(Context); } } /* All done, test alert the thread */ NtTestAlert(); /* Return */ if (!NT_SUCCESS(LoaderStatus)) { /* Fail */ LdrpInitFailure(LoaderStatus); RtlRaiseStatus(LoaderStatus); } } /* EOF */