xref: /reactos/dll/ntdll/ldr/ldrinit.c (revision d58a040e)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS NT User-Mode Library
4  * FILE:            dll/ntdll/ldr/ldrinit.c
5  * PURPOSE:         User-Mode Process/Thread Startup
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  *                  Aleksey Bragin (aleksey@reactos.org)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ntdll.h>
13 #include <compat_undoc.h>
14 #include <compatguid_undoc.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 
20 /* GLOBALS *******************************************************************/
21 
22 HANDLE ImageExecOptionsKey;
23 HANDLE Wow64ExecOptionsKey;
24 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
25 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
26 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
27 UNICODE_STRING Kernel32String = RTL_CONSTANT_STRING(L"kernel32.dll");
28 const UNICODE_STRING LdrpDotLocal = RTL_CONSTANT_STRING(L".Local");
29 
30 BOOLEAN LdrpInLdrInit;
31 LONG LdrpProcessInitialized;
32 BOOLEAN LdrpLoaderLockInit;
33 BOOLEAN LdrpLdrDatabaseIsSetup;
34 BOOLEAN LdrpShutdownInProgress;
35 HANDLE LdrpShutdownThreadId;
36 
37 BOOLEAN LdrpDllValidation;
38 
39 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
40 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
41 WCHAR StringBuffer[156];
42 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
43 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
44 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
45 
46 static NTSTATUS (WINAPI *Kernel32ProcessInitPostImportFunction)(VOID);
47 static BOOL (WINAPI *Kernel32BaseQueryModuleData)(IN LPSTR ModuleName, IN LPSTR Unk1, IN PVOID Unk2, IN PVOID Unk3, IN PVOID Unk4);
48 
49 RTL_BITMAP TlsBitMap;
50 RTL_BITMAP TlsExpansionBitMap;
51 RTL_BITMAP FlsBitMap;
52 BOOLEAN LdrpImageHasTls;
53 LIST_ENTRY LdrpTlsList;
54 ULONG LdrpNumberOfTlsEntries;
55 ULONG LdrpNumberOfProcessors;
56 PVOID NtDllBase;
57 extern LARGE_INTEGER RtlpTimeout;
58 extern BOOLEAN RtlpTimeoutDisable;
59 PVOID LdrpHeap;
60 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
61 LIST_ENTRY LdrpDllNotificationList;
62 HANDLE LdrpKnownDllObjectDirectory;
63 UNICODE_STRING LdrpKnownDllPath;
64 WCHAR LdrpKnownDllPathBuffer[128];
65 UNICODE_STRING LdrpDefaultPath;
66 
67 PEB_LDR_DATA PebLdr;
68 
69 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
70 RTL_CRITICAL_SECTION LdrpLoaderLock =
71 {
72     &LdrpLoaderLockDebug,
73     -1,
74     0,
75     0,
76     0,
77     0
78 };
79 RTL_CRITICAL_SECTION FastPebLock;
80 
81 BOOLEAN ShowSnaps;
82 
83 ULONG LdrpFatalHardErrorCount;
84 ULONG LdrpActiveUnloadCount;
85 
86 //extern LIST_ENTRY RtlCriticalSectionList;
87 
88 VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
89 VOID NTAPI RtlpInitDeferredCriticalSection(VOID);
90 VOID NTAPI RtlInitializeHeapManager(VOID);
91 
92 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
93 ULONG RtlpShutdownProcessFlags; // TODO: Use it
94 
95 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
96 NTSTATUS NTAPI RtlpInitializeActCtx(PVOID* pOldShimData);
97 extern BOOLEAN RtlpUse16ByteSLists;
98 
99 #ifdef _WIN64
100 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
101 #else
102 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
103 #endif
104 
105 /* FUNCTIONS *****************************************************************/
106 
107 /*
108  * @implemented
109  */
110 NTSTATUS
111 NTAPI
LdrOpenImageFileOptionsKey(_In_ PUNICODE_STRING SubKey,_In_ BOOLEAN Wow64,_Out_ PHANDLE NewKeyHandle)112 LdrOpenImageFileOptionsKey(
113     _In_ PUNICODE_STRING SubKey,
114     _In_ BOOLEAN Wow64,
115     _Out_ PHANDLE NewKeyHandle)
116 {
117     PHANDLE RootKeyLocation;
118     HANDLE RootKey;
119     UNICODE_STRING SubKeyString;
120     OBJECT_ATTRIBUTES ObjectAttributes;
121     NTSTATUS Status;
122     PWCHAR p1;
123 
124     /* Check which root key to open */
125     if (Wow64)
126         RootKeyLocation = &Wow64ExecOptionsKey;
127     else
128         RootKeyLocation = &ImageExecOptionsKey;
129 
130     /* Get the current key */
131     RootKey = *RootKeyLocation;
132 
133     /* Setup the object attributes */
134     InitializeObjectAttributes(&ObjectAttributes,
135                                Wow64 ?
136                                &Wow64OptionsString : &ImageExecOptionsString,
137                                OBJ_CASE_INSENSITIVE,
138                                NULL,
139                                NULL);
140 
141     /* Open the root key */
142     Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
143     if (NT_SUCCESS(Status))
144     {
145         /* Write the key handle */
146         if (InterlockedCompareExchangePointer(RootKeyLocation, RootKey, NULL) != NULL)
147         {
148             /* Someone already opened it, use it instead */
149             NtClose(RootKey);
150             RootKey = *RootKeyLocation;
151         }
152 
153         /* Extract the name */
154         SubKeyString = *SubKey;
155         p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
156         while (SubKeyString.Length)
157         {
158             if (p1[-1] == L'\\') break;
159             p1--;
160             SubKeyString.Length -= sizeof(*p1);
161         }
162         SubKeyString.Buffer = p1;
163         SubKeyString.Length = SubKey->Length - SubKeyString.Length;
164 
165         /* Setup the object attributes */
166         InitializeObjectAttributes(&ObjectAttributes,
167                                    &SubKeyString,
168                                    OBJ_CASE_INSENSITIVE,
169                                    RootKey,
170                                    NULL);
171 
172         /* Open the setting key */
173         Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
174     }
175 
176     /* Return to caller */
177     return Status;
178 }
179 
180 /*
181  * @implemented
182  */
183 NTSTATUS
184 NTAPI
LdrQueryImageFileKeyOption(_In_ HANDLE KeyHandle,_In_ PCWSTR ValueName,_In_ ULONG Type,_Out_ PVOID Buffer,_In_ ULONG BufferSize,_Out_opt_ PULONG ReturnedLength)185 LdrQueryImageFileKeyOption(
186     _In_ HANDLE KeyHandle,
187     _In_ PCWSTR ValueName,
188     _In_ ULONG Type,
189     _Out_ PVOID Buffer,
190     _In_ ULONG BufferSize,
191     _Out_opt_ PULONG ReturnedLength)
192 {
193     ULONG KeyInfo[256];
194     UNICODE_STRING ValueNameString, IntegerString;
195     ULONG KeyInfoSize, ResultSize;
196     PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
197     BOOLEAN FreeHeap = FALSE;
198     NTSTATUS Status;
199 
200     /* Build a string for the value name */
201     Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
202     if (!NT_SUCCESS(Status)) return Status;
203 
204     /* Query the value */
205     Status = ZwQueryValueKey(KeyHandle,
206                              &ValueNameString,
207                              KeyValuePartialInformation,
208                              KeyValueInformation,
209                              sizeof(KeyInfo),
210                              &ResultSize);
211     if (Status == STATUS_BUFFER_OVERFLOW)
212     {
213         /* Our local buffer wasn't enough, allocate one */
214         KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
215                       KeyValueInformation->DataLength;
216         KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
217                                               0,
218                                               KeyInfoSize);
219         if (KeyValueInformation != NULL)
220         {
221             /* Try again */
222             Status = ZwQueryValueKey(KeyHandle,
223                                      &ValueNameString,
224                                      KeyValuePartialInformation,
225                                      KeyValueInformation,
226                                      KeyInfoSize,
227                                      &ResultSize);
228             FreeHeap = TRUE;
229         }
230         else
231         {
232             /* Give up this time */
233             Status = STATUS_NO_MEMORY;
234         }
235     }
236 
237     /* Check for success */
238     if (NT_SUCCESS(Status))
239     {
240         /* Handle binary data */
241         if (KeyValueInformation->Type == REG_BINARY)
242         {
243             /* Check validity */
244             if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
245             {
246                 /* Copy into buffer */
247                 RtlMoveMemory(Buffer,
248                               &KeyValueInformation->Data,
249                               KeyValueInformation->DataLength);
250             }
251             else
252             {
253                 Status = STATUS_BUFFER_OVERFLOW;
254             }
255 
256             /* Copy the result length */
257             if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
258         }
259         else if (KeyValueInformation->Type == REG_DWORD)
260         {
261             /* Check for valid type */
262             if (KeyValueInformation->Type != Type)
263             {
264                 /* Error */
265                 Status = STATUS_OBJECT_TYPE_MISMATCH;
266             }
267             else
268             {
269                 /* Check validity */
270                 if ((Buffer) &&
271                     (BufferSize == sizeof(ULONG)) &&
272                     (KeyValueInformation->DataLength <= BufferSize))
273                 {
274                     /* Copy into buffer */
275                     RtlMoveMemory(Buffer,
276                                   &KeyValueInformation->Data,
277                                   KeyValueInformation->DataLength);
278                 }
279                 else
280                 {
281                     Status = STATUS_BUFFER_OVERFLOW;
282                 }
283 
284                 /* Copy the result length */
285                 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
286             }
287         }
288         else if (KeyValueInformation->Type != REG_SZ)
289         {
290             /* We got something weird */
291             Status = STATUS_OBJECT_TYPE_MISMATCH;
292         }
293         else
294         {
295             /*  String, check what you requested */
296             if (Type == REG_DWORD)
297             {
298                 /* Validate */
299                 if (BufferSize != sizeof(ULONG))
300                 {
301                     /* Invalid size */
302                     BufferSize = 0;
303                     Status = STATUS_INFO_LENGTH_MISMATCH;
304                 }
305                 else
306                 {
307                     /* OK, we know what you want... */
308                     IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
309                     IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
310                                            sizeof(WCHAR);
311                     IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
312                     Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
313                 }
314             }
315             else
316             {
317                 /* Validate */
318                 if (KeyValueInformation->DataLength > BufferSize)
319                 {
320                     /* Invalid */
321                     Status = STATUS_BUFFER_OVERFLOW;
322                 }
323                 else
324                 {
325                     /* Set the size */
326                     BufferSize = KeyValueInformation->DataLength;
327                 }
328 
329                 /* Copy the string */
330                 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
331             }
332 
333             /* Copy the result length */
334             if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
335         }
336     }
337 
338     /* Check if buffer was in heap */
339     if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
340 
341     /* Return status */
342     return Status;
343 }
344 
345 /*
346  * @implemented
347  */
348 NTSTATUS
349 NTAPI
LdrQueryImageFileExecutionOptionsEx(_In_ PUNICODE_STRING SubKey,_In_ PCWSTR ValueName,_In_ ULONG Type,_Out_ PVOID Buffer,_In_ ULONG BufferSize,_Out_opt_ PULONG ReturnedLength,_In_ BOOLEAN Wow64)350 LdrQueryImageFileExecutionOptionsEx(
351     _In_ PUNICODE_STRING SubKey,
352     _In_ PCWSTR ValueName,
353     _In_ ULONG Type,
354     _Out_ PVOID Buffer,
355     _In_ ULONG BufferSize,
356     _Out_opt_ PULONG ReturnedLength,
357     _In_ BOOLEAN Wow64)
358 {
359     NTSTATUS Status;
360     HANDLE KeyHandle;
361 
362     /* Open a handle to the key */
363     Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
364 
365     /* Check for success */
366     if (NT_SUCCESS(Status))
367     {
368         /* Query the data */
369         Status = LdrQueryImageFileKeyOption(KeyHandle,
370                                             ValueName,
371                                             Type,
372                                             Buffer,
373                                             BufferSize,
374                                             ReturnedLength);
375 
376         /* Close the key */
377         NtClose(KeyHandle);
378     }
379 
380     /* Return to caller */
381     return Status;
382 }
383 
384 /*
385  * @implemented
386  */
387 NTSTATUS
388 NTAPI
LdrQueryImageFileExecutionOptions(_In_ PUNICODE_STRING SubKey,_In_ PCWSTR ValueName,_In_ ULONG Type,_Out_ PVOID Buffer,_In_ ULONG BufferSize,_Out_opt_ PULONG ReturnedLength)389 LdrQueryImageFileExecutionOptions(
390     _In_ PUNICODE_STRING SubKey,
391     _In_ PCWSTR ValueName,
392     _In_ ULONG Type,
393     _Out_ PVOID Buffer,
394     _In_ ULONG BufferSize,
395     _Out_opt_ PULONG ReturnedLength)
396 {
397     /* Call the newer function */
398     return LdrQueryImageFileExecutionOptionsEx(SubKey,
399                                                ValueName,
400                                                Type,
401                                                Buffer,
402                                                BufferSize,
403                                                ReturnedLength,
404                                                FALSE);
405 }
406 
407 VOID
408 NTAPI
LdrpEnsureLoaderLockIsHeld(VOID)409 LdrpEnsureLoaderLockIsHeld(VOID)
410 {
411     // Ignored atm
412 }
413 
414 PVOID
415 NTAPI
LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress,ULONG SizeOfImage)416 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
417 {
418     PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
419     ULONG DirSize;
420     PVOID Cookie = NULL;
421 
422     /* Check NT header first */
423     if (!RtlImageNtHeader(BaseAddress)) return NULL;
424 
425     /* Get the pointer to the config directory */
426     ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
427                                              TRUE,
428                                              IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
429                                              &DirSize);
430 
431     /* Check for sanity */
432     if (!ConfigDir ||
433         (DirSize != 64 && ConfigDir->Size != DirSize) ||
434         (ConfigDir->Size < 0x48))
435         return NULL;
436 
437     /* Now get the cookie */
438     Cookie = (PVOID)ConfigDir->SecurityCookie;
439 
440     /* Check this cookie */
441     if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
442         (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
443     {
444         Cookie = NULL;
445     }
446 
447     /* Return validated security cookie */
448     return Cookie;
449 }
450 
451 PVOID
452 NTAPI
LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)453 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
454 {
455     PULONG_PTR Cookie;
456     LARGE_INTEGER Counter;
457     ULONG_PTR NewCookie;
458 
459     /* Fetch address of the cookie */
460     Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
461 
462     if (Cookie)
463     {
464         /* Check if it's a default one */
465         if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
466             (*Cookie == 0xBB40))
467         {
468             /* Make up a cookie from a bunch of values which may uniquely represent
469                current moment of time, environment, etc */
470             NtQueryPerformanceCounter(&Counter, NULL);
471 
472             NewCookie = Counter.LowPart ^ Counter.HighPart;
473             NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
474             NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueThread;
475 
476             /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
477             while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
478             {
479                 YieldProcessor();
480             };
481 
482             /* Calculate the milliseconds value and xor it to the cookie */
483             NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
484                 (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
485 
486             /* Make the cookie 16bit if necessary */
487             if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
488 
489             /* If the result is 0 or the same as we got, just subtract one from the existing value
490                and that's it */
491             if ((NewCookie == 0) || (NewCookie == *Cookie))
492             {
493                 NewCookie = *Cookie - 1;
494             }
495 
496             /* Set the new cookie value */
497             *Cookie = NewCookie;
498         }
499     }
500 
501     return Cookie;
502 }
503 
504 VOID
505 NTAPI
LdrpInitializeThread(IN PCONTEXT Context)506 LdrpInitializeThread(IN PCONTEXT Context)
507 {
508     PPEB Peb = NtCurrentPeb();
509     PLDR_DATA_TABLE_ENTRY LdrEntry;
510     PLIST_ENTRY NextEntry, ListHead;
511     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
512     NTSTATUS Status;
513     PVOID EntryPoint;
514 
515     DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n",
516             &LdrpImageEntry->BaseDllName,
517             NtCurrentTeb()->RealClientId.UniqueProcess,
518             NtCurrentTeb()->RealClientId.UniqueThread);
519 
520     /* Allocate an Activation Context Stack */
521     DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
522     Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
523     if (!NT_SUCCESS(Status))
524     {
525         DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
526     }
527 
528     /* Make sure we are not shutting down */
529     if (LdrpShutdownInProgress) return;
530 
531     /* Allocate TLS */
532     LdrpAllocateTls();
533 
534     /* Start at the beginning */
535     ListHead = &Peb->Ldr->InMemoryOrderModuleList;
536     NextEntry = ListHead->Flink;
537     while (NextEntry != ListHead)
538     {
539         /* Get the current entry */
540         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
541 
542         /* Make sure it's not ourselves */
543         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
544         {
545             /* Check if we should call */
546             if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
547             {
548                 /* Get the entrypoint */
549                 EntryPoint = LdrEntry->EntryPoint;
550 
551                 /* Check if we are ready to call it */
552                 if ((EntryPoint) &&
553                     (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
554                     (LdrEntry->Flags & LDRP_IMAGE_DLL))
555                 {
556                     /* Set up the Act Ctx */
557                     ActCtx.Size = sizeof(ActCtx);
558                     ActCtx.Format = 1;
559                     RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
560 
561                     /* Activate the ActCtx */
562                     RtlActivateActivationContextUnsafeFast(&ActCtx,
563                                                            LdrEntry->EntryPointActivationContext);
564 
565                     _SEH2_TRY
566                     {
567                         /* Check if it has TLS */
568                         if (LdrEntry->TlsIndex)
569                         {
570                             /* Make sure we're not shutting down */
571                             if (!LdrpShutdownInProgress)
572                             {
573                                 /* Call TLS */
574                                 LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_ATTACH);
575                             }
576                         }
577 
578                         /* Make sure we're not shutting down */
579                         if (!LdrpShutdownInProgress)
580                         {
581                             /* Call the Entrypoint */
582                             DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
583                                    &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
584                                    NtCurrentTeb()->RealClientId.UniqueProcess,
585                                    NtCurrentTeb()->RealClientId.UniqueThread);
586                             LdrpCallInitRoutine(LdrEntry->EntryPoint,
587                                                 LdrEntry->DllBase,
588                                                 DLL_THREAD_ATTACH,
589                                                 NULL);
590                         }
591                     }
592                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
593                     {
594                         DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_ATTACH) for %wZ\n",
595                                 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
596                     }
597                     _SEH2_END;
598 
599                     /* Deactivate the ActCtx */
600                     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
601                 }
602             }
603         }
604 
605         /* Next entry */
606         NextEntry = NextEntry->Flink;
607     }
608 
609     /* Check for TLS */
610     if (LdrpImageHasTls && !LdrpShutdownInProgress)
611     {
612         /* Set up the Act Ctx */
613         ActCtx.Size = sizeof(ActCtx);
614         ActCtx.Format = 1;
615         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
616 
617         /* Activate the ActCtx */
618         RtlActivateActivationContextUnsafeFast(&ActCtx,
619                                                LdrpImageEntry->EntryPointActivationContext);
620 
621         _SEH2_TRY
622         {
623             /* Do TLS callbacks */
624             LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_ATTACH);
625         }
626         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
627         {
628             /* Do nothing */
629         }
630         _SEH2_END;
631 
632         /* Deactivate the ActCtx */
633         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
634     }
635 
636     DPRINT("LdrpInitializeThread() done\n");
637 }
638 
639 NTSTATUS
640 NTAPI
LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)641 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
642 {
643     PLDR_DATA_TABLE_ENTRY LocalArray[16];
644     PLIST_ENTRY ListHead;
645     PLIST_ENTRY NextEntry;
646     PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
647     PVOID EntryPoint;
648     ULONG Count, i;
649     //ULONG BreakOnInit;
650     NTSTATUS Status = STATUS_SUCCESS;
651     PPEB Peb = NtCurrentPeb();
652     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
653     ULONG BreakOnDllLoad;
654     PTEB OldTldTeb;
655     BOOLEAN DllStatus;
656 
657     DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
658         &LdrpImageEntry->BaseDllName,
659         NtCurrentTeb()->RealClientId.UniqueProcess,
660         NtCurrentTeb()->RealClientId.UniqueThread);
661 
662     /* Check the Loader Lock */
663     LdrpEnsureLoaderLockIsHeld();
664 
665      /* Get the number of entries to call */
666     if ((Count = LdrpClearLoadInProgress()))
667     {
668         /* Check if we can use our local buffer */
669         if (Count > 16)
670         {
671             /* Allocate space for all the entries */
672             LdrRootEntry = RtlAllocateHeap(LdrpHeap,
673                                            0,
674                                            Count * sizeof(*LdrRootEntry));
675             if (!LdrRootEntry) return STATUS_NO_MEMORY;
676         }
677         else
678         {
679             /* Use our local array */
680             LdrRootEntry = LocalArray;
681         }
682     }
683     else
684     {
685         /* Don't need one */
686         LdrRootEntry = NULL;
687     }
688 
689     /* Show debug message */
690     if (ShowSnaps)
691     {
692         DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
693                 NtCurrentTeb()->RealClientId.UniqueThread,
694                 NtCurrentTeb()->RealClientId.UniqueProcess,
695                 &Peb->ProcessParameters->ImagePathName);
696     }
697 
698     /* Loop in order */
699     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
700     NextEntry = ListHead->Flink;
701     i = 0;
702     while (NextEntry != ListHead)
703     {
704         /* Get the Data Entry */
705         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
706 
707         /* Check if we have a Root Entry */
708         if (LdrRootEntry)
709         {
710             /* Check flags */
711             if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
712             {
713                 /* Setup the Cookie for the DLL */
714                 LdrpInitSecurityCookie(LdrEntry);
715 
716                 /* Check for valid entrypoint */
717                 if (LdrEntry->EntryPoint)
718                 {
719                     /* Write in array */
720                     ASSERT(i < Count);
721                     LdrRootEntry[i] = LdrEntry;
722 
723                     /* Display debug message */
724                     if (ShowSnaps)
725                     {
726                         DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
727                                 NtCurrentTeb()->RealClientId.UniqueThread,
728                                 NtCurrentTeb()->RealClientId.UniqueProcess,
729                                 &LdrEntry->FullDllName,
730                                 LdrEntry->EntryPoint);
731                     }
732                     i++;
733                 }
734             }
735         }
736 
737         /* Set the flag */
738         LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
739         NextEntry = NextEntry->Flink;
740     }
741 
742     Status = STATUS_SUCCESS;
743 
744     /* If we got a context, then we have to call Kernel32 for TS support */
745     if (Context)
746     {
747         /* Check if we have one */
748         if (Kernel32ProcessInitPostImportFunction)
749         {
750             /* Call it */
751             Status = Kernel32ProcessInitPostImportFunction();
752             if (!NT_SUCCESS(Status))
753             {
754                 DPRINT1("LDR: LdrpRunInitializeRoutines - Failed running kernel32 post-import function, Status=0x%08lx\n", Status);
755             }
756         }
757         /* Clear it */
758         Kernel32ProcessInitPostImportFunction = NULL;
759     }
760 
761     /* No root entry? return */
762     if (!LdrRootEntry)
763         return Status;
764 
765     /* Set the TLD TEB */
766     OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
767     LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
768 
769     /* Loop */
770     i = 0;
771     while (i < Count)
772     {
773         /* Get an entry */
774         LdrEntry = LdrRootEntry[i];
775 
776         /* FIXME: Verify NX Compat */
777 
778         /* Move to next entry */
779         i++;
780 
781         /* Get its entrypoint */
782         EntryPoint = LdrEntry->EntryPoint;
783 
784         /* Are we being debugged? */
785         BreakOnDllLoad = 0;
786         if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
787         {
788             /* Check if we should break on load */
789             Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
790                                                        L"BreakOnDllLoad",
791                                                        REG_DWORD,
792                                                        &BreakOnDllLoad,
793                                                        sizeof(ULONG),
794                                                        NULL);
795             if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
796 
797             /* Reset status back to STATUS_SUCCESS */
798             Status = STATUS_SUCCESS;
799         }
800 
801         /* Break if aksed */
802         if (BreakOnDllLoad)
803         {
804             /* Check if we should show a message */
805             if (ShowSnaps)
806             {
807                 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
808                 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
809             }
810 
811             /* Break in debugger */
812             DbgBreakPoint();
813         }
814 
815         /* Make sure we have an entrypoint */
816         if (EntryPoint)
817         {
818             /* Save the old Dll Initializer and write the current one */
819             OldInitializer = LdrpCurrentDllInitializer;
820             LdrpCurrentDllInitializer = LdrEntry;
821 
822             /* Set up the Act Ctx */
823             ActCtx.Size = sizeof(ActCtx);
824             ActCtx.Format = 1;
825             RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
826 
827             /* Activate the ActCtx */
828             RtlActivateActivationContextUnsafeFast(&ActCtx,
829                                                    LdrEntry->EntryPointActivationContext);
830 
831             _SEH2_TRY
832             {
833                 /* Check if it has TLS */
834                 if (LdrEntry->TlsIndex && Context)
835                 {
836                     /* Call TLS */
837                     LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_ATTACH);
838                 }
839 
840                 /* Call the Entrypoint */
841                 if (ShowSnaps)
842                 {
843                     DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
844                             &LdrEntry->BaseDllName, EntryPoint);
845                 }
846                 DllStatus = LdrpCallInitRoutine(EntryPoint,
847                                                 LdrEntry->DllBase,
848                                                 DLL_PROCESS_ATTACH,
849                                                 Context);
850             }
851             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
852             {
853                 DllStatus = FALSE;
854                 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_ATTACH) for %wZ\n",
855                         _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
856             }
857             _SEH2_END;
858 
859             /* Deactivate the ActCtx */
860             RtlDeactivateActivationContextUnsafeFast(&ActCtx);
861 
862             /* Save the Current DLL Initializer */
863             LdrpCurrentDllInitializer = OldInitializer;
864 
865             /* Mark the entry as processed */
866             LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
867 
868             /* Fail if DLL init failed */
869             if (!DllStatus)
870             {
871                 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
872                     &LdrEntry->BaseDllName, EntryPoint);
873 
874                 Status = STATUS_DLL_INIT_FAILED;
875                 goto Quickie;
876             }
877         }
878     }
879 
880     /* Loop in order */
881     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
882     NextEntry = NextEntry->Flink;
883     while (NextEntry != ListHead)
884     {
885         /* Get the Data Entry */
886         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
887 
888         /* FIXME: Verify NX Compat */
889         // LdrpCheckNXCompatibility()
890 
891         /* Next entry */
892         NextEntry = NextEntry->Flink;
893     }
894 
895     /* Check for TLS */
896     if (LdrpImageHasTls && Context)
897     {
898         /* Set up the Act Ctx */
899         ActCtx.Size = sizeof(ActCtx);
900         ActCtx.Format = 1;
901         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
902 
903         /* Activate the ActCtx */
904         RtlActivateActivationContextUnsafeFast(&ActCtx,
905                                                LdrpImageEntry->EntryPointActivationContext);
906 
907         _SEH2_TRY
908         {
909             /* Do TLS callbacks */
910             LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_ATTACH);
911         }
912         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
913         {
914             /* Do nothing */
915         }
916         _SEH2_END;
917 
918         /* Deactivate the ActCtx */
919         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
920     }
921 
922 Quickie:
923     /* Restore old TEB */
924     LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
925 
926     /* Check if the array is in the heap */
927     if (LdrRootEntry != LocalArray)
928     {
929         /* Free the array */
930         RtlFreeHeap(LdrpHeap, 0, LdrRootEntry);
931     }
932 
933     /* Return to caller */
934     DPRINT("LdrpRunInitializeRoutines() done\n");
935     return Status;
936 }
937 
938 /*
939  * @implemented
940  */
941 NTSTATUS
942 NTAPI
LdrShutdownProcess(VOID)943 LdrShutdownProcess(VOID)
944 {
945     PPEB Peb = NtCurrentPeb();
946     PLDR_DATA_TABLE_ENTRY LdrEntry;
947     PLIST_ENTRY NextEntry, ListHead;
948     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
949     PVOID EntryPoint;
950 
951     DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
952     if (LdrpShutdownInProgress) return STATUS_SUCCESS;
953 
954     /* Tell the Shim Engine */
955     if (g_ShimsEnabled)
956     {
957         VOID(NTAPI *SE_ProcessDying)();
958         SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying);
959         SE_ProcessDying();
960     }
961 
962     /* Tell the world */
963     if (ShowSnaps)
964     {
965         DPRINT1("\n");
966     }
967 
968     /* Set the shutdown variables */
969     LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
970     LdrpShutdownInProgress = TRUE;
971 
972     /* Enter the Loader Lock */
973     RtlEnterCriticalSection(&LdrpLoaderLock);
974 
975     /* Cleanup trace logging data (Etw) */
976     if (SharedUserData->TraceLogging)
977     {
978         /* FIXME */
979         DPRINT1("We don't support Etw yet.\n");
980     }
981 
982     /* Start at the end */
983     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
984     NextEntry = ListHead->Blink;
985     while (NextEntry != ListHead)
986     {
987         /* Get the current entry */
988         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
989         NextEntry = NextEntry->Blink;
990 
991         /* Make sure it's not ourselves */
992         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
993         {
994             /* Get the entrypoint */
995             EntryPoint = LdrEntry->EntryPoint;
996 
997             /* Check if we are ready to call it */
998             if (EntryPoint &&
999                 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1000                 LdrEntry->Flags)
1001             {
1002                 /* Set up the Act Ctx */
1003                 ActCtx.Size = sizeof(ActCtx);
1004                 ActCtx.Format = 1;
1005                 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1006 
1007                 /* Activate the ActCtx */
1008                 RtlActivateActivationContextUnsafeFast(&ActCtx,
1009                                                        LdrEntry->EntryPointActivationContext);
1010 
1011                 _SEH2_TRY
1012                 {
1013                     /* Check if it has TLS */
1014                     if (LdrEntry->TlsIndex)
1015                     {
1016                         /* Call TLS */
1017                         LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_DETACH);
1018                     }
1019 
1020                     /* Call the Entrypoint */
1021                     DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1022                            &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1023                     LdrpCallInitRoutine(EntryPoint,
1024                                         LdrEntry->DllBase,
1025                                         DLL_PROCESS_DETACH,
1026                                         (PVOID)1);
1027                 }
1028                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1029                 {
1030                     DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n",
1031                             _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1032                 }
1033                 _SEH2_END;
1034 
1035                 /* Deactivate the ActCtx */
1036                 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1037             }
1038         }
1039     }
1040 
1041     /* Check for TLS */
1042     if (LdrpImageHasTls)
1043     {
1044         /* Set up the Act Ctx */
1045         ActCtx.Size = sizeof(ActCtx);
1046         ActCtx.Format = 1;
1047         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1048 
1049         /* Activate the ActCtx */
1050         RtlActivateActivationContextUnsafeFast(&ActCtx,
1051                                                LdrpImageEntry->EntryPointActivationContext);
1052 
1053         _SEH2_TRY
1054         {
1055             /* Do TLS callbacks */
1056             LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_DETACH);
1057         }
1058         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1059         {
1060             /* Do nothing */
1061         }
1062         _SEH2_END;
1063 
1064         /* Deactivate the ActCtx */
1065         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1066     }
1067 
1068     /* FIXME: Do Heap detection and Etw final shutdown */
1069 
1070     /* Release the lock */
1071     RtlLeaveCriticalSection(&LdrpLoaderLock);
1072     DPRINT("LdrpShutdownProcess() done\n");
1073 
1074     return STATUS_SUCCESS;
1075 }
1076 
1077 /*
1078  * @implemented
1079  */
1080 NTSTATUS
1081 NTAPI
LdrShutdownThread(VOID)1082 LdrShutdownThread(VOID)
1083 {
1084     PPEB Peb = NtCurrentPeb();
1085     PTEB Teb = NtCurrentTeb();
1086     PLDR_DATA_TABLE_ENTRY LdrEntry;
1087     PLIST_ENTRY NextEntry, ListHead;
1088     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1089     PVOID EntryPoint;
1090 
1091     DPRINT("LdrShutdownThread() called for %wZ\n",
1092             &LdrpImageEntry->BaseDllName);
1093 
1094     /* Cleanup trace logging data (Etw) */
1095     if (SharedUserData->TraceLogging)
1096     {
1097         /* FIXME */
1098         DPRINT1("We don't support Etw yet.\n");
1099     }
1100 
1101     /* Get the Ldr Lock */
1102     RtlEnterCriticalSection(&LdrpLoaderLock);
1103 
1104     /* Start at the end */
1105     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1106     NextEntry = ListHead->Blink;
1107     while (NextEntry != ListHead)
1108     {
1109         /* Get the current entry */
1110         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
1111         NextEntry = NextEntry->Blink;
1112 
1113         /* Make sure it's not ourselves */
1114         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1115         {
1116             /* Check if we should call */
1117             if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1118                 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1119                 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1120             {
1121                 /* Get the entrypoint */
1122                 EntryPoint = LdrEntry->EntryPoint;
1123 
1124                 /* Check if we are ready to call it */
1125                 if (EntryPoint)
1126                 {
1127                     /* Set up the Act Ctx */
1128                     ActCtx.Size = sizeof(ActCtx);
1129                     ActCtx.Format = 1;
1130                     RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1131 
1132                     /* Activate the ActCtx */
1133                     RtlActivateActivationContextUnsafeFast(&ActCtx,
1134                                                            LdrEntry->EntryPointActivationContext);
1135 
1136                     _SEH2_TRY
1137                     {
1138                         /* Check if it has TLS */
1139                         if (LdrEntry->TlsIndex)
1140                         {
1141                             /* Make sure we're not shutting down */
1142                             if (!LdrpShutdownInProgress)
1143                             {
1144                                 /* Call TLS */
1145                                 LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_DETACH);
1146                             }
1147                         }
1148 
1149                         /* Make sure we're not shutting down */
1150                         if (!LdrpShutdownInProgress)
1151                         {
1152                             /* Call the Entrypoint */
1153                             DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1154                                    &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1155                             LdrpCallInitRoutine(EntryPoint,
1156                                                 LdrEntry->DllBase,
1157                                                 DLL_THREAD_DETACH,
1158                                                 NULL);
1159                         }
1160                     }
1161                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1162                     {
1163                         DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_DETACH) for %wZ\n",
1164                                 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1165                     }
1166                     _SEH2_END;
1167 
1168                     /* Deactivate the ActCtx */
1169                     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1170                 }
1171             }
1172         }
1173     }
1174 
1175     /* Check for TLS */
1176     if (LdrpImageHasTls)
1177     {
1178         /* Set up the Act Ctx */
1179         ActCtx.Size = sizeof(ActCtx);
1180         ActCtx.Format = 1;
1181         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1182 
1183         /* Activate the ActCtx */
1184         RtlActivateActivationContextUnsafeFast(&ActCtx,
1185                                                LdrpImageEntry->EntryPointActivationContext);
1186 
1187         _SEH2_TRY
1188         {
1189             /* Do TLS callbacks */
1190             LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_DETACH);
1191         }
1192         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1193         {
1194             /* Do nothing */
1195         }
1196         _SEH2_END;
1197 
1198         /* Deactivate the ActCtx */
1199         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1200     }
1201 
1202     /* Free TLS */
1203     LdrpFreeTls();
1204     RtlLeaveCriticalSection(&LdrpLoaderLock);
1205 
1206     /* Check for expansion slots */
1207     if (Teb->TlsExpansionSlots)
1208     {
1209         /* Free expansion slots */
1210         RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1211     }
1212 
1213     /* Check for FLS Data */
1214     if (Teb->FlsData)
1215     {
1216         /* Mimic BaseRundownFls */
1217         ULONG n, FlsHighIndex;
1218         PRTL_FLS_DATA pFlsData;
1219         PFLS_CALLBACK_FUNCTION lpCallback;
1220 
1221         pFlsData = Teb->FlsData;
1222 
1223         RtlAcquirePebLock();
1224         FlsHighIndex = NtCurrentPeb()->FlsHighIndex;
1225         RemoveEntryList(&pFlsData->ListEntry);
1226         RtlReleasePebLock();
1227 
1228         for (n = 1; n <= FlsHighIndex; ++n)
1229         {
1230             lpCallback = NtCurrentPeb()->FlsCallback[n];
1231             if (lpCallback && pFlsData->Data[n])
1232             {
1233                 lpCallback(pFlsData->Data[n]);
1234             }
1235         }
1236 
1237         RtlFreeHeap(RtlGetProcessHeap(), 0, pFlsData);
1238         Teb->FlsData = NULL;
1239     }
1240 
1241     /* Check for Fiber data */
1242     if (Teb->HasFiberData)
1243     {
1244         /* Free Fiber data*/
1245         RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1246         Teb->NtTib.FiberData = NULL;
1247     }
1248 
1249     /* Free the activation context stack */
1250     RtlFreeThreadActivationContextStack();
1251     DPRINT("LdrShutdownThread() done\n");
1252 
1253     return STATUS_SUCCESS;
1254 }
1255 
1256 NTSTATUS
1257 NTAPI
LdrpInitializeTls(VOID)1258 LdrpInitializeTls(VOID)
1259 {
1260     PLIST_ENTRY NextEntry, ListHead;
1261     PLDR_DATA_TABLE_ENTRY LdrEntry;
1262     PIMAGE_TLS_DIRECTORY TlsDirectory;
1263     PLDRP_TLS_DATA TlsData;
1264     ULONG Size;
1265 
1266     /* Initialize the TLS List */
1267     InitializeListHead(&LdrpTlsList);
1268 
1269     /* Loop all the modules */
1270     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1271     NextEntry = ListHead->Flink;
1272     while (ListHead != NextEntry)
1273     {
1274         /* Get the entry */
1275         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1276         NextEntry = NextEntry->Flink;
1277 
1278         /* Get the TLS directory */
1279         TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1280                                                     TRUE,
1281                                                     IMAGE_DIRECTORY_ENTRY_TLS,
1282                                                     &Size);
1283 
1284         /* Check if we have a directory */
1285         if (!TlsDirectory) continue;
1286 
1287         /* Check if the image has TLS */
1288         if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1289 
1290         /* Show debug message */
1291         if (ShowSnaps)
1292         {
1293             DPRINT1("LDR: Tls Found in %wZ at %p\n",
1294                     &LdrEntry->BaseDllName,
1295                     TlsDirectory);
1296         }
1297 
1298         /* Allocate an entry */
1299         TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1300         if (!TlsData) return STATUS_NO_MEMORY;
1301 
1302         /* Lock the DLL and mark it for TLS Usage */
1303         LdrEntry->LoadCount = -1;
1304         LdrEntry->TlsIndex = -1;
1305 
1306         /* Save the cached TLS data */
1307         TlsData->TlsDirectory = *TlsDirectory;
1308         InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1309 
1310         /* Update the index */
1311         *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1312         TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1313     }
1314 
1315     /* Done setting up TLS, allocate entries */
1316     return LdrpAllocateTls();
1317 }
1318 
1319 NTSTATUS
1320 NTAPI
LdrpAllocateTls(VOID)1321 LdrpAllocateTls(VOID)
1322 {
1323     PTEB Teb = NtCurrentTeb();
1324     PLIST_ENTRY NextEntry, ListHead;
1325     PLDRP_TLS_DATA TlsData;
1326     SIZE_T TlsDataSize;
1327     PVOID *TlsVector;
1328 
1329     /* Check if we have any entries */
1330     if (!LdrpNumberOfTlsEntries)
1331         return STATUS_SUCCESS;
1332 
1333     /* Allocate the vector array */
1334     TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1335                                     0,
1336                                     LdrpNumberOfTlsEntries * sizeof(PVOID));
1337     if (!TlsVector) return STATUS_NO_MEMORY;
1338     Teb->ThreadLocalStoragePointer = TlsVector;
1339 
1340     /* Loop the TLS Array */
1341     ListHead = &LdrpTlsList;
1342     NextEntry = ListHead->Flink;
1343     while (NextEntry != ListHead)
1344     {
1345         /* Get the entry */
1346         TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1347         NextEntry = NextEntry->Flink;
1348 
1349         /* Allocate this vector */
1350         TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1351                       TlsData->TlsDirectory.StartAddressOfRawData;
1352         TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1353                                                                            0,
1354                                                                            TlsDataSize);
1355         if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1356         {
1357             /* Out of memory */
1358             return STATUS_NO_MEMORY;
1359         }
1360 
1361         /* Show debug message */
1362         if (ShowSnaps)
1363         {
1364             DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1365                     TlsVector,
1366                     TlsData->TlsDirectory.Characteristics,
1367                     &TlsVector[TlsData->TlsDirectory.Characteristics],
1368                     TlsData->TlsDirectory.StartAddressOfRawData,
1369                     TlsVector[TlsData->TlsDirectory.Characteristics]);
1370         }
1371 
1372         /* Copy the data */
1373         RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1374                       (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1375                       TlsDataSize);
1376     }
1377 
1378     /* Done */
1379     return STATUS_SUCCESS;
1380 }
1381 
1382 VOID
1383 NTAPI
LdrpFreeTls(VOID)1384 LdrpFreeTls(VOID)
1385 {
1386     PLIST_ENTRY ListHead, NextEntry;
1387     PLDRP_TLS_DATA TlsData;
1388     PVOID *TlsVector;
1389     PTEB Teb = NtCurrentTeb();
1390 
1391     /* Get a pointer to the vector array */
1392     TlsVector = Teb->ThreadLocalStoragePointer;
1393     if (!TlsVector) return;
1394 
1395     /* Loop through it */
1396     ListHead = &LdrpTlsList;
1397     NextEntry = ListHead->Flink;
1398     while (NextEntry != ListHead)
1399     {
1400         TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1401         NextEntry = NextEntry->Flink;
1402 
1403         /* Free each entry */
1404         if (TlsVector[TlsData->TlsDirectory.Characteristics])
1405         {
1406             RtlFreeHeap(RtlGetProcessHeap(),
1407                         0,
1408                         TlsVector[TlsData->TlsDirectory.Characteristics]);
1409         }
1410     }
1411 
1412     /* Free the array itself */
1413     RtlFreeHeap(RtlGetProcessHeap(),
1414                 0,
1415                 TlsVector);
1416 }
1417 
1418 NTSTATUS
1419 NTAPI
LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName,PPEB Peb,PHANDLE OptionsKey)1420 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
1421 {
1422     NTSTATUS Status;
1423     HANDLE KeyHandle;
1424     ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1425 
1426     /* Return error if we were not provided a pointer where to save the options key handle */
1427     if (!OptionsKey) return STATUS_INVALID_HANDLE;
1428 
1429     /* Zero initialize the options key pointer */
1430     *OptionsKey = NULL;
1431 
1432     /* Open the options key */
1433     Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1434 
1435     /* Save it if it was opened successfully */
1436     if (NT_SUCCESS(Status))
1437         *OptionsKey = KeyHandle;
1438 
1439     if (KeyHandle)
1440     {
1441         /* There are image specific options, read them starting with NXCOMPAT */
1442         Status = LdrQueryImageFileKeyOption(KeyHandle,
1443                                             L"ExecuteOptions",
1444                                             4,
1445                                             &ExecuteOptions,
1446                                             sizeof(ExecuteOptions),
1447                                             0);
1448 
1449         if (NT_SUCCESS(Status))
1450         {
1451             /* TODO: Set execution options for the process */
1452             /*
1453             if (ExecuteOptions == 0)
1454                 ExecuteOptions = 1;
1455             else
1456                 ExecuteOptions = 2;
1457             ZwSetInformationProcess(NtCurrentProcess(),
1458                                     ProcessExecuteFlags,
1459                                     &ExecuteOptions,
1460                                     sizeof(ULONG));*/
1461 
1462         }
1463 
1464         /* Check if this image uses large pages */
1465         if (Peb->ImageUsesLargePages)
1466         {
1467             /* TODO: If it does, open large page key */
1468             UNIMPLEMENTED;
1469         }
1470 
1471         /* Get various option values */
1472         LdrQueryImageFileKeyOption(KeyHandle,
1473                                    L"DisableHeapLookaside",
1474                                    REG_DWORD,
1475                                    &RtlpDisableHeapLookaside,
1476                                    sizeof(RtlpDisableHeapLookaside),
1477                                    NULL);
1478 
1479         LdrQueryImageFileKeyOption(KeyHandle,
1480                                    L"ShutdownFlags",
1481                                    REG_DWORD,
1482                                    &RtlpShutdownProcessFlags,
1483                                    sizeof(RtlpShutdownProcessFlags),
1484                                    NULL);
1485 
1486         LdrQueryImageFileKeyOption(KeyHandle,
1487                                    L"MinimumStackCommitInBytes",
1488                                    REG_DWORD,
1489                                    &MinimumStackCommit,
1490                                    sizeof(MinimumStackCommit),
1491                                    NULL);
1492 
1493         /* Update PEB's minimum stack commit if it's lower */
1494         if (Peb->MinimumStackCommit < MinimumStackCommit)
1495             Peb->MinimumStackCommit = MinimumStackCommit;
1496 
1497         /* Set the global flag */
1498         Status = LdrQueryImageFileKeyOption(KeyHandle,
1499                                             L"GlobalFlag",
1500                                             REG_DWORD,
1501                                             &GlobalFlag,
1502                                             sizeof(GlobalFlag),
1503                                             NULL);
1504 
1505         if (NT_SUCCESS(Status))
1506             Peb->NtGlobalFlag = GlobalFlag;
1507         else
1508             GlobalFlag = 0;
1509 
1510         /* Call AVRF if necessary */
1511         if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1512         {
1513             Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1514             if (!NT_SUCCESS(Status))
1515             {
1516                 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1517             }
1518         }
1519     }
1520     else
1521     {
1522         /* There are no image-specific options, so perform global initialization */
1523         if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1524         {
1525             /* Initialize app verifier package */
1526             Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1527             if (!NT_SUCCESS(Status))
1528             {
1529                 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1530             }
1531         }
1532     }
1533 
1534     return STATUS_SUCCESS;
1535 }
1536 
1537 VOID
1538 NTAPI
LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)1539 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1540 {
1541     UNIMPLEMENTED;
1542 }
1543 
1544 BOOLEAN
1545 NTAPI
LdrpDisableProcessCompatGuidDetection(VOID)1546 LdrpDisableProcessCompatGuidDetection(VOID)
1547 {
1548     UNICODE_STRING PolicyKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\Software\\Policies\\Microsoft\\Windows\\AppCompat");
1549     UNICODE_STRING DisableDetection = RTL_CONSTANT_STRING(L"DisableCompatGuidDetection");
1550     OBJECT_ATTRIBUTES PolicyKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&PolicyKey, OBJ_CASE_INSENSITIVE);
1551     KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
1552     ULONG ResultLength;
1553     NTSTATUS Status;
1554     HANDLE KeyHandle;
1555 
1556     Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &PolicyKeyAttributes);
1557     if (NT_SUCCESS(Status))
1558     {
1559         Status = NtQueryValueKey(KeyHandle,
1560                                  &DisableDetection,
1561                                  KeyValuePartialInformation,
1562                                  &KeyInfo,
1563                                  sizeof(KeyInfo),
1564                                  &ResultLength);
1565         NtClose(KeyHandle);
1566         if ((NT_SUCCESS(Status)) &&
1567             (KeyInfo.Type == REG_DWORD) &&
1568             (KeyInfo.DataLength == sizeof(ULONG)) &&
1569             (KeyInfo.Data[0] == TRUE))
1570         {
1571             return TRUE;
1572         }
1573     }
1574     return FALSE;
1575 }
1576 
1577 
1578 VOID
1579 NTAPI
LdrpInitializeProcessCompat(PVOID pProcessActctx,PVOID * pOldShimData)1580 LdrpInitializeProcessCompat(PVOID pProcessActctx, PVOID* pOldShimData)
1581 {
1582     static const struct
1583     {
1584         const GUID* Guid;
1585         const DWORD Version;
1586     } KnownCompatGuids[] = {
1587         { &COMPAT_GUID_WIN10, _WIN32_WINNT_WIN10 },
1588         { &COMPAT_GUID_WIN81, _WIN32_WINNT_WINBLUE },
1589         { &COMPAT_GUID_WIN8, _WIN32_WINNT_WIN8 },
1590         { &COMPAT_GUID_WIN7, _WIN32_WINNT_WIN7 },
1591         { &COMPAT_GUID_VISTA, _WIN32_WINNT_VISTA },
1592     };
1593 
1594     ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1595     ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1596     SIZE_T SizeRequired;
1597     NTSTATUS Status;
1598     DWORD n, cur;
1599     ReactOS_ShimData* pShimData = *pOldShimData;
1600 
1601     if (pShimData)
1602     {
1603         if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1604             pShimData->dwSize != sizeof(ReactOS_ShimData))
1605         {
1606             DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1607             return;
1608         }
1609         if (pShimData->dwRosProcessCompatVersion)
1610         {
1611             if (pShimData->dwRosProcessCompatVersion == REACTOS_COMPATVERSION_IGNOREMANIFEST)
1612             {
1613                 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion set to ignore manifest\n");
1614             }
1615             else
1616             {
1617                 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1618             }
1619             return;
1620         }
1621     }
1622 
1623     SizeRequired = sizeof(Buffer);
1624     Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1625                                                   pProcessActctx,
1626                                                   NULL,
1627                                                   CompatibilityInformationInActivationContext,
1628                                                   Buffer,
1629                                                   sizeof(Buffer),
1630                                                   &SizeRequired);
1631 
1632     if (!NT_SUCCESS(Status))
1633     {
1634         DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1635         return;
1636     }
1637 
1638     ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1639     /* No Compatibility elements present, bail out */
1640     if (ContextCompatInfo->ElementCount == 0)
1641         return;
1642 
1643     /* Search for known GUIDs, starting from oldest to newest.
1644        Note that on Windows it is somewhat reversed, starting from the latest known
1645        version, going down. But we are not Windows, trying to allow a lower version,
1646        we are ReactOS trying to fake a higher version. So we interpret what Windows
1647        does as "try the closest version to the actual version", so we start with the
1648        lowest version, which is closest to Windows 2003, which we mostly are. */
1649     for (cur = RTL_NUMBER_OF(KnownCompatGuids) - 1; cur != -1; --cur)
1650     {
1651         for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1652         {
1653             if (ContextCompatInfo->Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1654                 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, KnownCompatGuids[cur].Guid, sizeof(GUID)) == sizeof(GUID))
1655             {
1656                 if (LdrpDisableProcessCompatGuidDetection())
1657                 {
1658                     DPRINT1("LdrpInitializeProcessCompat: Not applying automatic fix for winver 0x%x due to policy\n", KnownCompatGuids[cur].Version);
1659                     return;
1660                 }
1661 
1662                 /* If this process did not need shim data before, allocate and store it */
1663                 if (pShimData == NULL)
1664                 {
1665                     PPEB Peb = NtCurrentPeb();
1666 
1667                     ASSERT(Peb->pShimData == NULL);
1668                     pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1669 
1670                     if (!pShimData)
1671                     {
1672                         DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1673                         return;
1674                     }
1675 
1676                     pShimData->dwSize = sizeof(*pShimData);
1677                     pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1678 
1679                     Peb->pShimData = pShimData;
1680                     *pOldShimData = pShimData;
1681                 }
1682 
1683                 /* Store the lowest found version, and bail out. */
1684                 pShimData->dwRosProcessCompatVersion = KnownCompatGuids[cur].Version;
1685                 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x in manifest from %wZ\n",
1686                         KnownCompatGuids[cur].Version,
1687                         &(NtCurrentPeb()->ProcessParameters->ImagePathName));
1688                 return;
1689             }
1690         }
1691     }
1692 }
1693 
1694 VOID
1695 NTAPI
LdrpInitializeDotLocalSupport(PRTL_USER_PROCESS_PARAMETERS ProcessParameters)1696 LdrpInitializeDotLocalSupport(PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
1697 {
1698     UNICODE_STRING ImagePathName = ProcessParameters->ImagePathName;
1699     WCHAR LocalBuffer[MAX_PATH];
1700     UNICODE_STRING DotLocal;
1701     NTSTATUS Status;
1702     ULONG RequiredSize;
1703 
1704     RequiredSize = ImagePathName.Length + LdrpDotLocal.Length + sizeof(UNICODE_NULL);
1705     if (RequiredSize <= sizeof(LocalBuffer))
1706     {
1707         RtlInitEmptyUnicodeString(&DotLocal, LocalBuffer, sizeof(LocalBuffer));
1708     }
1709     else if (RequiredSize <= UNICODE_STRING_MAX_BYTES)
1710     {
1711         DotLocal.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, RequiredSize);
1712         DotLocal.Length = 0;
1713         DotLocal.MaximumLength = RequiredSize;
1714         if (!DotLocal.Buffer)
1715             DPRINT1("LDR: Failed to allocate memory for .local check\n");
1716     }
1717     else
1718     {
1719         DotLocal.Buffer = NULL;
1720         DotLocal.Length = 0;
1721         DotLocal.MaximumLength = 0;
1722         DPRINT1("LDR: String too big for .local check\n");
1723     }
1724 
1725     if (DotLocal.Buffer)
1726     {
1727         Status = RtlAppendUnicodeStringToString(&DotLocal, &ImagePathName);
1728         ASSERT(NT_SUCCESS(Status));
1729         if (NT_SUCCESS(Status))
1730         {
1731             Status = RtlAppendUnicodeStringToString(&DotLocal, &LdrpDotLocal);
1732             ASSERT(NT_SUCCESS(Status));
1733         }
1734 
1735         if (NT_SUCCESS(Status))
1736         {
1737             if (RtlDoesFileExists_UStr(&DotLocal))
1738             {
1739                 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_PRIVATE_DLL_PATH;
1740             }
1741         }
1742         else
1743         {
1744             DPRINT1("LDR: Failed to append: 0x%lx\n", Status);
1745         }
1746 
1747         if (DotLocal.Buffer != LocalBuffer)
1748         {
1749             RtlFreeHeap(RtlGetProcessHeap(), 0, DotLocal.Buffer);
1750         }
1751     }
1752 }
1753 
1754 
1755 NTSTATUS
1756 NTAPI
LdrpInitializeProcess(IN PCONTEXT Context,IN PVOID SystemArgument1)1757 LdrpInitializeProcess(IN PCONTEXT Context,
1758                       IN PVOID SystemArgument1)
1759 {
1760     RTL_HEAP_PARAMETERS HeapParameters;
1761     ULONG ComSectionSize;
1762     ANSI_STRING BaseProcessInitPostImportName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");
1763     ANSI_STRING BaseQueryModuleDataName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1764     PVOID OldShimData;
1765     OBJECT_ATTRIBUTES ObjectAttributes;
1766     //UNICODE_STRING LocalFileName, FullImageName;
1767     HANDLE SymLinkHandle;
1768     //ULONG DebugHeapOnly;
1769     UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1770     PPEB Peb = NtCurrentPeb();
1771     BOOLEAN IsDotNetImage = FALSE;
1772     BOOLEAN FreeCurDir = FALSE;
1773     //HANDLE CompatKey;
1774     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1775     //LPWSTR ImagePathBuffer;
1776     ULONG ConfigSize;
1777     UNICODE_STRING CurrentDirectory;
1778     HANDLE OptionsKey;
1779     ULONG HeapFlags;
1780     PIMAGE_NT_HEADERS NtHeader;
1781     LPWSTR NtDllName = NULL;
1782     NTSTATUS Status, ImportStatus;
1783     NLSTABLEINFO NlsTable;
1784     PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1785     PTEB Teb = NtCurrentTeb();
1786     PLIST_ENTRY ListHead;
1787     PLIST_ENTRY NextEntry;
1788     ULONG i;
1789     PWSTR ImagePath;
1790     ULONG DebugProcessHeapOnly = 0;
1791     PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1792     PWCHAR Current;
1793     ULONG ExecuteOptions = 0;
1794     PVOID ViewBase;
1795 
1796     /* Set a NULL SEH Filter */
1797     RtlSetUnhandledExceptionFilter(NULL);
1798 
1799     /* Get the image path */
1800     ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1801 
1802     /* Check if it's not normalized */
1803     if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1804     {
1805         /* Normalize it*/
1806         ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1807     }
1808 
1809     /* Create a unicode string for the Image Path */
1810     ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1811     ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1812     ImagePathName.Buffer = ImagePath;
1813 
1814     /* Get the NT Headers */
1815     NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1816 
1817     /* Get the execution options */
1818     Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1819 
1820     /* Check if this is a .NET executable */
1821     if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1822                                      TRUE,
1823                                      IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1824                                      &ComSectionSize))
1825     {
1826         /* Remember this for later */
1827         IsDotNetImage = TRUE;
1828     }
1829 
1830     /* Save the NTDLL Base address */
1831     NtDllBase = SystemArgument1;
1832 
1833     /* If this is a Native Image */
1834     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1835     {
1836         /* Then do DLL Validation */
1837         LdrpDllValidation = TRUE;
1838     }
1839 
1840     /* Save the old Shim Data */
1841     OldShimData = Peb->pShimData;
1842 
1843     /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1844     //Peb->pShimData = NULL;
1845 
1846     /* Save the number of processors and CS timeout */
1847     LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1848     RtlpTimeout = Peb->CriticalSectionTimeout;
1849 
1850     /* Normalize the parameters */
1851     ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1852     if (ProcessParameters)
1853     {
1854         /* Save the Image and Command Line Names */
1855         ImageFileName = ProcessParameters->ImagePathName;
1856         CommandLine = ProcessParameters->CommandLine;
1857     }
1858     else
1859     {
1860         /* It failed, initialize empty strings */
1861         RtlInitUnicodeString(&ImageFileName, NULL);
1862         RtlInitUnicodeString(&CommandLine, NULL);
1863     }
1864 
1865     /* Initialize NLS data */
1866     RtlInitNlsTables(Peb->AnsiCodePageData,
1867                      Peb->OemCodePageData,
1868                      Peb->UnicodeCaseTableData,
1869                      &NlsTable);
1870 
1871     /* Reset NLS Translations */
1872     RtlResetRtlTranslations(&NlsTable);
1873 
1874     /* Get the Image Config Directory */
1875     LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1876                                               TRUE,
1877                                               IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1878                                               &ConfigSize);
1879 
1880     /* Setup the Heap Parameters */
1881     RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
1882     HeapFlags = HEAP_GROWABLE;
1883     HeapParameters.Length = sizeof(HeapParameters);
1884 
1885     /* Check if we have Configuration Data */
1886 #define VALID_CONFIG_FIELD(Name) (ConfigSize >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, Name))
1887     /* The 'original' load config ends after SecurityCookie */
1888     if ((LoadConfig) && ConfigSize && (VALID_CONFIG_FIELD(SecurityCookie) || ConfigSize == LoadConfig->Size))
1889     {
1890         if (ConfigSize != sizeof(IMAGE_LOAD_CONFIG_DIRECTORY))
1891             DPRINT1("WARN: Accepting different LOAD_CONFIG size!\n");
1892         else
1893             DPRINT1("Applying LOAD_CONFIG\n");
1894 
1895         if (VALID_CONFIG_FIELD(GlobalFlagsSet) && LoadConfig->GlobalFlagsSet)
1896             Peb->NtGlobalFlag |= LoadConfig->GlobalFlagsSet;
1897 
1898         if (VALID_CONFIG_FIELD(GlobalFlagsClear) && LoadConfig->GlobalFlagsClear)
1899             Peb->NtGlobalFlag &= ~LoadConfig->GlobalFlagsClear;
1900 
1901         /* Convert the default CS timeout from milliseconds to 100ns units */
1902         if (VALID_CONFIG_FIELD(CriticalSectionDefaultTimeout) && LoadConfig->CriticalSectionDefaultTimeout)
1903             RtlpTimeout.QuadPart = Int32x32To64(LoadConfig->CriticalSectionDefaultTimeout, -10000);
1904 
1905         if (VALID_CONFIG_FIELD(DeCommitFreeBlockThreshold) && LoadConfig->DeCommitFreeBlockThreshold)
1906             HeapParameters.DeCommitFreeBlockThreshold = LoadConfig->DeCommitFreeBlockThreshold;
1907 
1908         if (VALID_CONFIG_FIELD(DeCommitTotalFreeThreshold) && LoadConfig->DeCommitTotalFreeThreshold)
1909             HeapParameters.DeCommitTotalFreeThreshold = LoadConfig->DeCommitTotalFreeThreshold;
1910 
1911         if (VALID_CONFIG_FIELD(MaximumAllocationSize) && LoadConfig->MaximumAllocationSize)
1912             HeapParameters.MaximumAllocationSize = LoadConfig->MaximumAllocationSize;
1913 
1914         if (VALID_CONFIG_FIELD(VirtualMemoryThreshold) && LoadConfig->VirtualMemoryThreshold)
1915             HeapParameters.VirtualMemoryThreshold = LoadConfig->VirtualMemoryThreshold;
1916 
1917         if (VALID_CONFIG_FIELD(ProcessHeapFlags) && LoadConfig->ProcessHeapFlags)
1918             HeapFlags = LoadConfig->ProcessHeapFlags;
1919     }
1920 #undef VALID_CONFIG_FIELD
1921 
1922     /* Check for custom affinity mask */
1923     if (Peb->ImageProcessAffinityMask)
1924     {
1925         /* Set it */
1926         Status = NtSetInformationProcess(NtCurrentProcess(),
1927                                          ProcessAffinityMask,
1928                                          &Peb->ImageProcessAffinityMask,
1929                                          sizeof(Peb->ImageProcessAffinityMask));
1930     }
1931 
1932     /* Check if verbose debugging (ShowSnaps) was requested */
1933     ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1934 
1935     /* Start verbose debugging messages right now if they were requested */
1936     if (ShowSnaps)
1937     {
1938         DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1939                 Teb->ClientId.UniqueProcess,
1940                 &CommandLine);
1941     }
1942 
1943     /* If the CS timeout is longer than 1 hour, disable it */
1944     if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1945         RtlpTimeoutDisable = TRUE;
1946 
1947     /* Initialize Critical Section Data */
1948     RtlpInitDeferredCriticalSection();
1949 
1950     /* Initialize VEH Call lists */
1951     RtlpInitializeVectoredExceptionHandling();
1952 
1953     /* Set TLS/FLS Bitmap data */
1954     Peb->FlsBitmap = &FlsBitMap;
1955     Peb->TlsBitmap = &TlsBitMap;
1956     Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1957 
1958     /* Initialize FLS Bitmap */
1959     RtlInitializeBitMap(&FlsBitMap,
1960                         Peb->FlsBitmapBits,
1961                         FLS_MAXIMUM_AVAILABLE);
1962     RtlSetBit(&FlsBitMap, 0);
1963     InitializeListHead(&Peb->FlsListHead);
1964 
1965     /* Initialize TLS Bitmap */
1966     RtlInitializeBitMap(&TlsBitMap,
1967                         Peb->TlsBitmapBits,
1968                         TLS_MINIMUM_AVAILABLE);
1969     RtlSetBit(&TlsBitMap, 0);
1970     RtlInitializeBitMap(&TlsExpansionBitMap,
1971                         Peb->TlsExpansionBitmapBits,
1972                         TLS_EXPANSION_SLOTS);
1973     RtlSetBit(&TlsExpansionBitMap, 0);
1974 
1975     /* Initialize the Hash Table */
1976     for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1977     {
1978         InitializeListHead(&LdrpHashTable[i]);
1979     }
1980 
1981     /* Initialize the Loader Lock */
1982     // FIXME: What's the point of initing it manually, if two lines lower
1983     //        a call to RtlInitializeCriticalSection() is being made anyway?
1984     //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1985     //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1986     RtlInitializeCriticalSection(&LdrpLoaderLock);
1987     LdrpLoaderLockInit = TRUE;
1988 
1989     /* Check if User Stack Trace Database support was requested */
1990     if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1991     {
1992         DPRINT1("We don't support user stack trace databases yet\n");
1993     }
1994 
1995     /* Setup Fast PEB Lock */
1996     RtlInitializeCriticalSection(&FastPebLock);
1997     Peb->FastPebLock = &FastPebLock;
1998     //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1999     //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
2000 
2001     /* Setup Callout Lock and Notification list */
2002     //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
2003     InitializeListHead(&LdrpDllNotificationList);
2004 
2005     /* For old executables, use 16-byte aligned heap */
2006     if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
2007         (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
2008     {
2009         HeapFlags |= HEAP_CREATE_ALIGN_16;
2010     }
2011 
2012     /* Setup the Heap */
2013     RtlInitializeHeapManager();
2014     Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
2015                                      NULL,
2016                                      NtHeader->OptionalHeader.SizeOfHeapReserve,
2017                                      NtHeader->OptionalHeader.SizeOfHeapCommit,
2018                                      NULL,
2019                                      &HeapParameters);
2020 
2021     if (!Peb->ProcessHeap)
2022     {
2023         DPRINT1("Failed to create process heap\n");
2024         return STATUS_NO_MEMORY;
2025     }
2026 
2027     /* Allocate an Activation Context Stack */
2028     Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
2029     if (!NT_SUCCESS(Status)) return Status;
2030 
2031     RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
2032     HeapFlags = HEAP_GROWABLE | HEAP_CLASS_1;
2033     HeapParameters.Length = sizeof(HeapParameters);
2034     LdrpHeap = RtlCreateHeap(HeapFlags, 0, 0x10000, 0x6000, 0, &HeapParameters);
2035     if (!LdrpHeap)
2036     {
2037         DPRINT1("Failed to create loader private heap\n");
2038         return STATUS_NO_MEMORY;
2039     }
2040 
2041     /* Check for Debug Heap */
2042     if (OptionsKey)
2043     {
2044         /* Query the setting */
2045         Status = LdrQueryImageFileKeyOption(OptionsKey,
2046                                             L"DebugProcessHeapOnly",
2047                                             REG_DWORD,
2048                                             &DebugProcessHeapOnly,
2049                                             sizeof(ULONG),
2050                                             NULL);
2051 
2052         if (NT_SUCCESS(Status))
2053         {
2054             /* Reset DPH if requested */
2055             if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
2056             {
2057                 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
2058                 RtlpPageHeapEnabled = FALSE;
2059             }
2060         }
2061     }
2062 
2063     /* Build the NTDLL Path */
2064     FullPath.Buffer = StringBuffer;
2065     FullPath.Length = 0;
2066     FullPath.MaximumLength = sizeof(StringBuffer);
2067     RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
2068     RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
2069     RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
2070 
2071     /* Open the Known DLLs directory */
2072     RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
2073     InitializeObjectAttributes(&ObjectAttributes,
2074                                &KnownDllString,
2075                                OBJ_CASE_INSENSITIVE,
2076                                NULL,
2077                                NULL);
2078     Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
2079                                    DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
2080                                    &ObjectAttributes);
2081 
2082     /* Check if it exists */
2083     if (NT_SUCCESS(Status))
2084     {
2085         /* Open the Known DLLs Path */
2086         RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
2087         InitializeObjectAttributes(&ObjectAttributes,
2088                                    &KnownDllString,
2089                                    OBJ_CASE_INSENSITIVE,
2090                                    LdrpKnownDllObjectDirectory,
2091                                    NULL);
2092         Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
2093                                           SYMBOLIC_LINK_QUERY,
2094                                           &ObjectAttributes);
2095         if (NT_SUCCESS(Status))
2096         {
2097             /* Query the path */
2098             LdrpKnownDllPath.Length = 0;
2099             LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
2100             LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
2101             Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
2102             NtClose(SymLinkHandle);
2103             if (!NT_SUCCESS(Status))
2104             {
2105                 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
2106                 return Status;
2107             }
2108         }
2109     }
2110 
2111     /* Check if we failed */
2112     if (!NT_SUCCESS(Status))
2113     {
2114         /* Assume System32 */
2115         LdrpKnownDllObjectDirectory = NULL;
2116         RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
2117         LdrpKnownDllPath.Length -= sizeof(WCHAR);
2118     }
2119 
2120     /* If we have process parameters, get the default path and current path */
2121     if (ProcessParameters)
2122     {
2123         /* Check if we have a Dll Path */
2124         if (ProcessParameters->DllPath.Length)
2125         {
2126             /* Get the path */
2127             LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
2128         }
2129         else
2130         {
2131             /* We need a valid path */
2132             DPRINT1("No valid DllPath was given!\n");
2133             LdrpInitFailure(STATUS_INVALID_PARAMETER);
2134         }
2135 
2136         /* Set the current directory */
2137         CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
2138 
2139         /* Check if it's empty or invalid */
2140         if ((!CurrentDirectory.Buffer) ||
2141             (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
2142             (!CurrentDirectory.Length))
2143         {
2144             /* Allocate space for the buffer */
2145             CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
2146                                                       0,
2147                                                       3 * sizeof(WCHAR) +
2148                                                       sizeof(UNICODE_NULL));
2149             if (!CurrentDirectory.Buffer)
2150             {
2151                 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
2152                 // FIXME: And what?
2153             }
2154 
2155             /* Copy the drive of the system root */
2156             RtlMoveMemory(CurrentDirectory.Buffer,
2157                           SharedUserData->NtSystemRoot,
2158                           3 * sizeof(WCHAR));
2159             CurrentDirectory.Buffer[3] = UNICODE_NULL;
2160             CurrentDirectory.Length = 3 * sizeof(WCHAR);
2161             CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
2162 
2163             FreeCurDir = TRUE;
2164             DPRINT("Using dynamically allocd curdir\n");
2165         }
2166         else
2167         {
2168             /* Use the local buffer */
2169             DPRINT("Using local system root\n");
2170         }
2171     }
2172 
2173     /* Setup Loader Data */
2174     Peb->Ldr = &PebLdr;
2175     InitializeListHead(&PebLdr.InLoadOrderModuleList);
2176     InitializeListHead(&PebLdr.InMemoryOrderModuleList);
2177     InitializeListHead(&PebLdr.InInitializationOrderModuleList);
2178     PebLdr.Length = sizeof(PEB_LDR_DATA);
2179     PebLdr.Initialized = TRUE;
2180 
2181     /* Allocate a data entry for the Image */
2182     LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
2183 
2184     /* Set it up */
2185     LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
2186     LdrpImageEntry->LoadCount = -1;
2187     LdrpImageEntry->EntryPointActivationContext = 0;
2188     LdrpImageEntry->FullDllName = ImageFileName;
2189 
2190     if (IsDotNetImage)
2191         LdrpImageEntry->Flags = LDRP_COR_IMAGE;
2192     else
2193         LdrpImageEntry->Flags = 0;
2194 
2195     /* Check if the name is empty */
2196     if (!ImageFileName.Buffer[0])
2197     {
2198         /* Use the same Base name */
2199         LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2200     }
2201     else
2202     {
2203         /* Find the last slash */
2204         Current = ImageFileName.Buffer;
2205         while (*Current)
2206         {
2207             if (*Current++ == '\\')
2208             {
2209                 /* Set this path */
2210                 NtDllName = Current;
2211             }
2212         }
2213 
2214         /* Did we find anything? */
2215         if (!NtDllName)
2216         {
2217             /* Use the same Base name */
2218             LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2219         }
2220         else
2221         {
2222             /* Setup the name */
2223             LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
2224             LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
2225             LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
2226                                                      (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
2227         }
2228     }
2229 
2230     /* Processing done, insert it */
2231     LdrpInsertMemoryTableEntry(LdrpImageEntry);
2232     LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
2233 
2234     /* Now add an entry for NTDLL */
2235     NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
2236     NtLdrEntry->Flags = LDRP_IMAGE_DLL;
2237     NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
2238     NtLdrEntry->LoadCount = -1;
2239     NtLdrEntry->EntryPointActivationContext = 0;
2240 
2241     NtLdrEntry->FullDllName.Length = FullPath.Length;
2242     NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
2243     NtLdrEntry->FullDllName.Buffer = StringBuffer;
2244     RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
2245 
2246     NtLdrEntry->BaseDllName.Length = NtDllString.Length;
2247     NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
2248     NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
2249 
2250     /* Processing done, insert it */
2251     LdrpNtDllDataTableEntry = NtLdrEntry;
2252     LdrpInsertMemoryTableEntry(NtLdrEntry);
2253 
2254     /* Let the world know */
2255     if (ShowSnaps)
2256     {
2257         DPRINT1("LDR: NEW PROCESS\n");
2258         DPRINT1("     Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
2259         DPRINT1("     Current Directory: %wZ\n", &CurrentDirectory);
2260         DPRINT1("     Search Path: %wZ\n", &LdrpDefaultPath);
2261     }
2262 
2263     /* Link the Init Order List */
2264     InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2265                    &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2266 
2267     /* Initialize Wine's active context implementation for the current process */
2268     RtlpInitializeActCtx(&OldShimData);
2269 
2270     /* Set the current directory */
2271     Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2272     if (!NT_SUCCESS(Status))
2273     {
2274         /* We failed, check if we should free it */
2275         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2276 
2277         /* Set it to the NT Root */
2278         CurrentDirectory = NtSystemRoot;
2279         RtlSetCurrentDirectory_U(&CurrentDirectory);
2280     }
2281     else
2282     {
2283         /* We're done with it, free it */
2284         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2285     }
2286 
2287     /* Check if we should look for a .local file */
2288     if (ProcessParameters && !(ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH))
2289     {
2290         LdrpInitializeDotLocalSupport(ProcessParameters);
2291     }
2292 
2293     /* Check if the Application Verifier was enabled */
2294     if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2295     {
2296         Status = AVrfInitializeVerifier();
2297         if (!NT_SUCCESS(Status))
2298         {
2299             DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2300             return Status;
2301         }
2302 
2303     }
2304 
2305     if (IsDotNetImage)
2306     {
2307         /* FIXME */
2308         DPRINT1("We don't support .NET applications yet\n");
2309     }
2310 
2311     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
2312         NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2313     {
2314         PVOID Kernel32BaseAddress;
2315         PVOID FunctionAddress;
2316 
2317         Status = LdrLoadDll(NULL, NULL, &Kernel32String, &Kernel32BaseAddress);
2318 
2319         if (!NT_SUCCESS(Status))
2320         {
2321             if (ShowSnaps)
2322                 DPRINT1("LDR: Unable to load %wZ, Status=0x%08lx\n", &Kernel32String, Status);
2323             return Status;
2324         }
2325 
2326         Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2327                                         &BaseProcessInitPostImportName,
2328                                         0,
2329                                         &FunctionAddress);
2330 
2331         if (!NT_SUCCESS(Status))
2332         {
2333             if (ShowSnaps)
2334                 DPRINT1("LDR: Unable to find post-import process init function, Status=0x%08lx\n", Status);
2335             return Status;
2336         }
2337         Kernel32ProcessInitPostImportFunction = FunctionAddress;
2338 
2339         Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2340                                         &BaseQueryModuleDataName,
2341                                         0,
2342                                         &FunctionAddress);
2343 
2344         if (!NT_SUCCESS(Status))
2345         {
2346             if (ShowSnaps)
2347                 DPRINT1("LDR: Unable to find BaseQueryModuleData, Status=0x%08lx\n", Status);
2348             return Status;
2349         }
2350         Kernel32BaseQueryModuleData = FunctionAddress;
2351     }
2352 
2353     /* Walk the IAT and load all the DLLs */
2354     ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2355 
2356     /* Check if relocation is needed */
2357     if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2358     {
2359         DPRINT1("LDR: Performing EXE relocation\n");
2360 
2361         /* Change the protection to prepare for relocation */
2362         ViewBase = Peb->ImageBaseAddress;
2363         Status = LdrpSetProtection(ViewBase, FALSE);
2364         if (!NT_SUCCESS(Status)) return Status;
2365 
2366         /* Do the relocation */
2367         Status = LdrRelocateImageWithBias(ViewBase,
2368                                           0LL,
2369                                           NULL,
2370                                           STATUS_SUCCESS,
2371                                           STATUS_CONFLICTING_ADDRESSES,
2372                                           STATUS_INVALID_IMAGE_FORMAT);
2373         if (!NT_SUCCESS(Status))
2374         {
2375             DPRINT1("LdrRelocateImageWithBias() failed\n");
2376             return Status;
2377         }
2378 
2379         /* Check if a start context was provided */
2380         if (Context)
2381         {
2382             DPRINT1("WARNING: Relocated EXE Context");
2383             UNIMPLEMENTED; // We should support this
2384             return STATUS_INVALID_IMAGE_FORMAT;
2385         }
2386 
2387         /* Restore the protection */
2388         Status = LdrpSetProtection(ViewBase, TRUE);
2389         if (!NT_SUCCESS(Status)) return Status;
2390     }
2391 
2392     /* Lock the DLLs */
2393     ListHead = &Peb->Ldr->InLoadOrderModuleList;
2394     NextEntry = ListHead->Flink;
2395     while (ListHead != NextEntry)
2396     {
2397         NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2398         NtLdrEntry->LoadCount = -1;
2399         NextEntry = NextEntry->Flink;
2400     }
2401 
2402     /* Phase 0 is done */
2403     LdrpLdrDatabaseIsSetup = TRUE;
2404 
2405     /* Check whether all static imports were properly loaded and return here */
2406     if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2407 
2408 #if (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
2409     /* Initialize the keyed event for condition variables */
2410     RtlpInitializeKeyedEvent();
2411 #endif
2412 
2413     /* Initialize TLS */
2414     Status = LdrpInitializeTls();
2415     if (!NT_SUCCESS(Status))
2416     {
2417         DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2418                 Status);
2419         return Status;
2420     }
2421 
2422     /* FIXME Mark the DLL Ranges for Stack Traces later */
2423 
2424     /* Notify the debugger now */
2425     if (Peb->BeingDebugged)
2426     {
2427         /* Break */
2428         DbgBreakPoint();
2429 
2430         /* Update show snaps again */
2431         ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2432     }
2433 
2434     /* Validate the Image for MP Usage */
2435     if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2436 
2437     /* Check NX options and set them */
2438     if (SharedUserData->NXSupportPolicy == NX_SUPPORT_POLICY_ALWAYSON)
2439     {
2440         ExecuteOptions = MEM_EXECUTE_OPTION_DISABLE |
2441                          MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION |
2442                          MEM_EXECUTE_OPTION_PERMANENT;
2443     }
2444     else if (SharedUserData->NXSupportPolicy == NX_SUPPORT_POLICY_ALWAYSOFF)
2445     {
2446         ExecuteOptions = MEM_EXECUTE_OPTION_ENABLE | MEM_EXECUTE_OPTION_PERMANENT;
2447     }
2448     Status = NtSetInformationProcess(NtCurrentProcess(),
2449                                      ProcessExecuteFlags,
2450                                      &ExecuteOptions,
2451                                      sizeof(ExecuteOptions));
2452     if (!NT_SUCCESS(Status))
2453     {
2454         DPRINT1("LDR: Could not set process execute flags 0x%x; status %x\n",
2455                 ExecuteOptions, Status);
2456     }
2457 
2458     // FIXME: Should be done by Application Compatibility features,
2459     // by reading the registry, etc...
2460     // For now, this is the old code from ntdll!RtlGetVersion().
2461     RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2462     if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2463     {
2464         WCHAR szCSDVersion[128];
2465         LONG i;
2466         USHORT Length = (USHORT)ARRAYSIZE(szCSDVersion) - 1;
2467         i = _snwprintf(szCSDVersion, Length,
2468                        L"Service Pack %d",
2469                        ((Peb->OSCSDVersion >> 8) & 0xFF));
2470         if (i < 0)
2471         {
2472             /* Null-terminate if it was overflowed */
2473             szCSDVersion[Length] = UNICODE_NULL;
2474         }
2475 
2476         Length *= sizeof(WCHAR);
2477         Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2478                                                  0,
2479                                                  Length + sizeof(UNICODE_NULL));
2480         if (Peb->CSDVersion.Buffer)
2481         {
2482             Peb->CSDVersion.Length = Length;
2483             Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2484 
2485             RtlCopyMemory(Peb->CSDVersion.Buffer,
2486                           szCSDVersion,
2487                           Peb->CSDVersion.MaximumLength);
2488             Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2489         }
2490     }
2491 
2492     /* Check if we had Shim Data */
2493     if (OldShimData)
2494     {
2495         /* Load the Shim Engine */
2496         Peb->AppCompatInfo = NULL;
2497         LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2498     }
2499     else
2500     {
2501         /* Check for Application Compatibility Goo */
2502         //LdrQueryApplicationCompatibilityGoo(hKey);
2503         DPRINT("Querying app compat hacks is missing!\n");
2504     }
2505 
2506     /*
2507      * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2508      * incompatible images.
2509      */
2510 
2511     /* Now call the Init Routines */
2512     Status = LdrpRunInitializeRoutines(Context);
2513     if (!NT_SUCCESS(Status))
2514     {
2515         DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2516                 Status);
2517         return Status;
2518     }
2519 
2520     /* Notify Shim Engine */
2521     if (g_ShimsEnabled)
2522     {
2523         VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2524         SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2525         SE_InstallAfterInit(&ImagePathName, OldShimData);
2526     }
2527 
2528     /* Check if we have a user-defined Post Process Routine */
2529     if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2530     {
2531         /* Call it */
2532         Peb->PostProcessInitRoutine();
2533     }
2534 
2535     /* Close the key if we have one opened */
2536     if (OptionsKey) NtClose(OptionsKey);
2537 
2538     /* Return status */
2539     return Status;
2540 }
2541 
2542 VOID
2543 NTAPI
LdrpInitFailure(NTSTATUS Status)2544 LdrpInitFailure(NTSTATUS Status)
2545 {
2546     ULONG Response;
2547     PPEB Peb = NtCurrentPeb();
2548 
2549     /* Print a debug message */
2550     DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2551             &Peb->ProcessParameters->ImagePathName, Status);
2552 
2553     /* Raise a hard error */
2554     if (!LdrpFatalHardErrorCount)
2555     {
2556         ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2557     }
2558 }
2559 
2560 VOID
2561 NTAPI
LdrpInit(PCONTEXT Context,PVOID SystemArgument1,PVOID SystemArgument2)2562 LdrpInit(PCONTEXT Context,
2563          PVOID SystemArgument1,
2564          PVOID SystemArgument2)
2565 {
2566     LARGE_INTEGER Timeout;
2567     PTEB Teb = NtCurrentTeb();
2568     NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2569     MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2570     PPEB Peb = NtCurrentPeb();
2571 
2572     DPRINT("LdrpInit() %p/%p\n",
2573         NtCurrentTeb()->RealClientId.UniqueProcess,
2574         NtCurrentTeb()->RealClientId.UniqueThread);
2575 
2576 #ifdef _WIN64
2577     /* Set the SList header usage */
2578     RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2579 #endif /* _WIN64 */
2580 
2581     /* Check if we have a deallocation stack */
2582     if (!Teb->DeallocationStack)
2583     {
2584         /* We don't, set one */
2585         Status = NtQueryVirtualMemory(NtCurrentProcess(),
2586                                       Teb->NtTib.StackLimit,
2587                                       MemoryBasicInformation,
2588                                       &MemoryBasicInfo,
2589                                       sizeof(MEMORY_BASIC_INFORMATION),
2590                                       NULL);
2591         if (!NT_SUCCESS(Status))
2592         {
2593             /* Fail */
2594             LdrpInitFailure(Status);
2595             RtlRaiseStatus(Status);
2596             return;
2597         }
2598 
2599         /* Set the stack */
2600         Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2601     }
2602 
2603     /* Now check if the process is already being initialized */
2604     while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2605                                       1,
2606                                       0) == 1)
2607     {
2608         /* Set the timeout to 30 milliseconds */
2609         Timeout.QuadPart = Int32x32To64(30, -10000);
2610 
2611         /* Make sure the status hasn't changed */
2612         while (LdrpProcessInitialized == 1)
2613         {
2614             /* Do the wait */
2615             ZwDelayExecution(FALSE, &Timeout);
2616         }
2617     }
2618 
2619     /* Check if we have already setup LDR data */
2620     if (!Peb->Ldr)
2621     {
2622         /* Setup the Loader Lock */
2623         Peb->LoaderLock = &LdrpLoaderLock;
2624 
2625         /* Let other code know we're initializing */
2626         LdrpInLdrInit = TRUE;
2627 
2628         /* Protect with SEH */
2629         _SEH2_TRY
2630         {
2631             /* Initialize the Process */
2632             LoaderStatus = LdrpInitializeProcess(Context,
2633                                                  SystemArgument1);
2634 
2635             /* Check for success and if MinimumStackCommit was requested */
2636             if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2637             {
2638                 /* Enforce the limit */
2639                 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2640                 UNIMPLEMENTED;
2641             }
2642         }
2643         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2644         {
2645             /* Fail with the SEH error */
2646             LoaderStatus = _SEH2_GetExceptionCode();
2647         }
2648         _SEH2_END;
2649 
2650         /* We're not initializing anymore */
2651         LdrpInLdrInit = FALSE;
2652 
2653         /* Check if init worked */
2654         if (NT_SUCCESS(LoaderStatus))
2655         {
2656             /* Set the process as Initialized */
2657             _InterlockedIncrement(&LdrpProcessInitialized);
2658         }
2659     }
2660     else
2661     {
2662         /* Loader data is there... is this a fork() ? */
2663         if(Peb->InheritedAddressSpace)
2664         {
2665             /* Handle the fork() */
2666             //LoaderStatus = LdrpForkProcess();
2667             LoaderStatus = STATUS_NOT_IMPLEMENTED;
2668             UNIMPLEMENTED;
2669         }
2670         else
2671         {
2672             /* This is a new thread initializing */
2673             LdrpInitializeThread(Context);
2674         }
2675     }
2676 
2677     /* All done, test alert the thread */
2678     NtTestAlert();
2679 
2680     /* Return */
2681     if (!NT_SUCCESS(LoaderStatus))
2682     {
2683         /* Fail */
2684         LdrpInitFailure(LoaderStatus);
2685         RtlRaiseStatus(LoaderStatus);
2686     }
2687 }
2688 
2689 /* EOF */
2690