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