[NTDLL/LDR]
[reactos.git] / reactos / dll / ntdll / ldr / ldrinit.c
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 <win32k/callback.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* GLOBALS *******************************************************************/
20
21 HKEY ImageExecOptionsKey;
22 HKEY Wow64ExecOptionsKey;
23 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
24 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
25 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
26
27 BOOLEAN LdrpInLdrInit;
28 LONG LdrpProcessInitialized;
29 BOOLEAN LdrpLoaderLockInit;
30 BOOLEAN LdrpLdrDatabaseIsSetup;
31 BOOLEAN LdrpShutdownInProgress;
32 HANDLE LdrpShutdownThreadId;
33
34 BOOLEAN LdrpDllValidation;
35
36 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
37 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
38 WCHAR StringBuffer[156];
39 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
40 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
41 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
42
43 RTL_BITMAP TlsBitMap;
44 RTL_BITMAP TlsExpansionBitMap;
45 RTL_BITMAP FlsBitMap;
46 BOOLEAN LdrpImageHasTls;
47 LIST_ENTRY LdrpTlsList;
48 ULONG LdrpNumberOfTlsEntries;
49 ULONG LdrpNumberOfProcessors;
50 PVOID NtDllBase;
51 LARGE_INTEGER RtlpTimeout;
52 BOOLEAN RtlpTimeoutDisable;
53 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
54 LIST_ENTRY LdrpDllNotificationList;
55 HANDLE LdrpKnownDllObjectDirectory;
56 UNICODE_STRING LdrpKnownDllPath;
57 WCHAR LdrpKnownDllPathBuffer[128];
58 UNICODE_STRING LdrpDefaultPath;
59
60 PEB_LDR_DATA PebLdr;
61
62 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
63 RTL_CRITICAL_SECTION LdrpLoaderLock =
64 {
65 &LdrpLoaderLockDebug,
66 -1,
67 0,
68 0,
69 0,
70 0
71 };
72 RTL_CRITICAL_SECTION FastPebLock;
73
74 BOOLEAN ShowSnaps;
75
76 ULONG LdrpFatalHardErrorCount;
77 ULONG LdrpActiveUnloadCount;
78
79 //extern LIST_ENTRY RtlCriticalSectionList;
80
81 VOID RtlpInitializeVectoredExceptionHandling(VOID);
82 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
83 VOID RtlInitializeHeapManager(VOID);
84 extern BOOLEAN RtlpPageHeapEnabled;
85 extern ULONG RtlpDphGlobalFlags;
86
87 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
88 ULONG RtlpShutdownProcessFlags; // TODO: Use it
89
90 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
91
92 #ifdef _WIN64
93 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
94 #else
95 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
96 #endif
97
98 /* FUNCTIONS *****************************************************************/
99
100 /*
101 * @implemented
102 */
103 NTSTATUS
104 NTAPI
105 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
106 IN BOOLEAN Wow64,
107 OUT PHKEY NewKeyHandle)
108 {
109 PHKEY RootKeyLocation;
110 HANDLE RootKey;
111 UNICODE_STRING SubKeyString;
112 OBJECT_ATTRIBUTES ObjectAttributes;
113 NTSTATUS Status;
114 PWCHAR p1;
115
116 /* Check which root key to open */
117 if (Wow64)
118 RootKeyLocation = &Wow64ExecOptionsKey;
119 else
120 RootKeyLocation = &ImageExecOptionsKey;
121
122 /* Get the current key */
123 RootKey = *RootKeyLocation;
124
125 /* Setup the object attributes */
126 InitializeObjectAttributes(&ObjectAttributes,
127 Wow64 ?
128 &Wow64OptionsString : &ImageExecOptionsString,
129 OBJ_CASE_INSENSITIVE,
130 NULL,
131 NULL);
132
133 /* Open the root key */
134 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
135 if (NT_SUCCESS(Status))
136 {
137 /* Write the key handle */
138 if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0)
139 {
140 /* Someone already opened it, use it instead */
141 NtClose(RootKey);
142 RootKey = *RootKeyLocation;
143 }
144
145 /* Extract the name */
146 SubKeyString = *SubKey;
147 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
148 while (SubKey->Length)
149 {
150 if (p1[-1] == L'\\') break;
151 p1--;
152 SubKeyString.Length -= sizeof(*p1);
153 }
154 SubKeyString.Buffer = p1;
155 SubKeyString.Length = SubKeyString.MaximumLength - SubKeyString.Length - sizeof(WCHAR);
156
157 /* Setup the object attributes */
158 InitializeObjectAttributes(&ObjectAttributes,
159 &SubKeyString,
160 OBJ_CASE_INSENSITIVE,
161 RootKey,
162 NULL);
163
164 /* Open the setting key */
165 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
166 }
167
168 /* Return to caller */
169 return Status;
170 }
171
172 /*
173 * @implemented
174 */
175 NTSTATUS
176 NTAPI
177 LdrQueryImageFileKeyOption(IN HKEY KeyHandle,
178 IN PCWSTR ValueName,
179 IN ULONG Type,
180 OUT PVOID Buffer,
181 IN ULONG BufferSize,
182 OUT PULONG ReturnedLength OPTIONAL)
183 {
184 ULONG KeyInfo[256];
185 UNICODE_STRING ValueNameString, IntegerString;
186 ULONG KeyInfoSize, ResultSize;
187 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
188 BOOLEAN FreeHeap = FALSE;
189 NTSTATUS Status;
190
191 /* Build a string for the value name */
192 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
193 if (!NT_SUCCESS(Status)) return Status;
194
195 /* Query the value */
196 Status = NtQueryValueKey(KeyHandle,
197 &ValueNameString,
198 KeyValuePartialInformation,
199 KeyValueInformation,
200 sizeof(KeyInfo),
201 &ResultSize);
202 if (Status == STATUS_BUFFER_OVERFLOW)
203 {
204 /* Our local buffer wasn't enough, allocate one */
205 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
206 KeyValueInformation->DataLength;
207 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
208 0,
209 KeyInfoSize);
210 if (KeyInfo == NULL)
211 {
212 /* Give up this time */
213 Status = STATUS_NO_MEMORY;
214 }
215
216 /* Try again */
217 Status = NtQueryValueKey(KeyHandle,
218 &ValueNameString,
219 KeyValuePartialInformation,
220 KeyValueInformation,
221 KeyInfoSize,
222 &ResultSize);
223 FreeHeap = TRUE;
224 }
225
226 /* Check for success */
227 if (NT_SUCCESS(Status))
228 {
229 /* Handle binary data */
230 if (KeyValueInformation->Type == REG_BINARY)
231 {
232 /* Check validity */
233 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
234 {
235 /* Copy into buffer */
236 RtlMoveMemory(Buffer,
237 &KeyValueInformation->Data,
238 KeyValueInformation->DataLength);
239 }
240 else
241 {
242 Status = STATUS_BUFFER_OVERFLOW;
243 }
244
245 /* Copy the result length */
246 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
247 }
248 else if (KeyValueInformation->Type == REG_DWORD)
249 {
250 /* Check for valid type */
251 if (KeyValueInformation->Type != Type)
252 {
253 /* Error */
254 Status = STATUS_OBJECT_TYPE_MISMATCH;
255 }
256 else
257 {
258 /* Check validity */
259 if ((Buffer) &&
260 (BufferSize == sizeof(ULONG)) &&
261 (KeyValueInformation->DataLength <= BufferSize))
262 {
263 /* Copy into buffer */
264 RtlMoveMemory(Buffer,
265 &KeyValueInformation->Data,
266 KeyValueInformation->DataLength);
267 }
268 else
269 {
270 Status = STATUS_BUFFER_OVERFLOW;
271 }
272
273 /* Copy the result length */
274 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
275 }
276 }
277 else if (KeyValueInformation->Type != REG_SZ)
278 {
279 /* We got something weird */
280 Status = STATUS_OBJECT_TYPE_MISMATCH;
281 }
282 else
283 {
284 /* String, check what you requested */
285 if (Type == REG_DWORD)
286 {
287 /* Validate */
288 if (BufferSize != sizeof(ULONG))
289 {
290 /* Invalid size */
291 BufferSize = 0;
292 Status = STATUS_INFO_LENGTH_MISMATCH;
293 }
294 else
295 {
296 /* OK, we know what you want... */
297 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
298 IntegerString.Length = KeyValueInformation->DataLength -
299 sizeof(WCHAR);
300 IntegerString.MaximumLength = KeyValueInformation->DataLength;
301 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
302 }
303 }
304 else
305 {
306 /* Validate */
307 if (KeyValueInformation->DataLength > BufferSize)
308 {
309 /* Invalid */
310 Status = STATUS_BUFFER_OVERFLOW;
311 }
312 else
313 {
314 /* Set the size */
315 BufferSize = KeyValueInformation->DataLength;
316 }
317
318 /* Copy the string */
319 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
320 }
321
322 /* Copy the result length */
323 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
324 }
325 }
326
327 /* Check if buffer was in heap */
328 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
329
330 /* Close key and return */
331 NtClose(KeyHandle);
332 return Status;
333 }
334
335 /*
336 * @implemented
337 */
338 NTSTATUS
339 NTAPI
340 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
341 IN PCWSTR ValueName,
342 IN ULONG Type,
343 OUT PVOID Buffer,
344 IN ULONG BufferSize,
345 OUT PULONG ReturnedLength OPTIONAL,
346 IN BOOLEAN Wow64)
347 {
348 NTSTATUS Status;
349 HKEY KeyHandle;
350
351 /* Open a handle to the key */
352 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
353
354 /* Check for success */
355 if (NT_SUCCESS(Status))
356 {
357 /* Query the data */
358 Status = LdrQueryImageFileKeyOption(KeyHandle,
359 ValueName,
360 Type,
361 Buffer,
362 BufferSize,
363 ReturnedLength);
364
365 /* Close the key */
366 NtClose(KeyHandle);
367 }
368
369 /* Return to caller */
370 return Status;
371 }
372
373 /*
374 * @implemented
375 */
376 NTSTATUS
377 NTAPI
378 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
379 IN PCWSTR ValueName,
380 IN ULONG Type,
381 OUT PVOID Buffer,
382 IN ULONG BufferSize,
383 OUT PULONG ReturnedLength OPTIONAL)
384 {
385 /* Call the newer function */
386 return LdrQueryImageFileExecutionOptionsEx(SubKey,
387 ValueName,
388 Type,
389 Buffer,
390 BufferSize,
391 ReturnedLength,
392 FALSE);
393 }
394
395 VOID
396 NTAPI
397 LdrpEnsureLoaderLockIsHeld()
398 {
399 // Ignored atm
400 }
401
402 PVOID
403 NTAPI
404 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
405 {
406 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
407 ULONG DirSize;
408 PVOID Cookie = NULL;
409
410 /* Check NT header first */
411 if (!RtlImageNtHeader(BaseAddress)) return NULL;
412
413 /* Get the pointer to the config directory */
414 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
415 TRUE,
416 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
417 &DirSize);
418
419 /* Check for sanity */
420 if (!ConfigDir ||
421 (DirSize != 64 && ConfigDir->Size != DirSize) ||
422 (ConfigDir->Size < 0x48))
423 return NULL;
424
425 /* Now get the cookie */
426 Cookie = (PVOID)ConfigDir->SecurityCookie;
427
428 /* Check this cookie */
429 if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
430 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
431 {
432 Cookie = NULL;
433 }
434
435 /* Return validated security cookie */
436 return Cookie;
437 }
438
439 PVOID
440 NTAPI
441 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
442 {
443 PULONG_PTR Cookie;
444 LARGE_INTEGER Counter;
445 //ULONG NewCookie;
446
447 /* Fetch address of the cookie */
448 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
449
450 if (Cookie)
451 {
452 /* Check if it's a default one */
453 if (*Cookie == DEFAULT_SECURITY_COOKIE ||
454 *Cookie == 0xBB40)
455 {
456 /* We need to initialize it */
457
458 NtQueryPerformanceCounter(&Counter, NULL);
459 #if 0
460 GetSystemTimeAsFileTime (&systime.ft_struct);
461 #ifdef _WIN64
462 cookie = systime.ft_scalar;
463 #else
464 cookie = systime.ft_struct.dwLowDateTime;
465 cookie ^= systime.ft_struct.dwHighDateTime;
466 #endif
467
468 cookie ^= GetCurrentProcessId ();
469 cookie ^= GetCurrentThreadId ();
470 cookie ^= GetTickCount ();
471
472 QueryPerformanceCounter (&perfctr);
473 #ifdef _WIN64
474 cookie ^= perfctr.QuadPart;
475 #else
476 cookie ^= perfctr.LowPart;
477 cookie ^= perfctr.HighPart;
478 #endif
479
480 #ifdef _WIN64
481 cookie &= 0x0000ffffffffffffll;
482 #endif
483 #endif
484 *Cookie = Counter.LowPart;
485
486 //Cookie = NULL;
487 }
488 }
489
490 return Cookie;
491 }
492
493 VOID
494 NTAPI
495 LdrpInitializeThread(IN PCONTEXT Context)
496 {
497 PPEB Peb = NtCurrentPeb();
498 PLDR_DATA_TABLE_ENTRY LdrEntry;
499 PLIST_ENTRY NextEntry, ListHead;
500 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
501 NTSTATUS Status;
502 PVOID EntryPoint;
503
504 DPRINT("LdrpInitializeThread() called for %wZ\n",
505 &LdrpImageEntry->BaseDllName);
506
507 /* Allocate an Activation Context Stack */
508 /* FIXME: This is a hack for Wine's actctx stuff */
509 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
510 if (!(NtCurrentTeb()->ActivationContextStackPointer))
511 {
512 Status = RtlAllocateActivationContextStack((PVOID*)&NtCurrentTeb()->ActivationContextStackPointer);
513 if (NT_SUCCESS(Status))
514 {
515 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
516 DPRINT("ActiveFrame %p\n", ((PACTIVATION_CONTEXT_STACK)NtCurrentTeb()->ActivationContextStackPointer)->ActiveFrame);
517 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL;
518 }
519 else
520 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
521 }
522
523 /* Make sure we are not shutting down */
524 if (LdrpShutdownInProgress) return;
525
526 /* Allocate TLS */
527 LdrpAllocateTls();
528
529 /* Start at the beginning */
530 ListHead = &Peb->Ldr->InMemoryOrderModuleList;
531 NextEntry = ListHead->Flink;
532 while (NextEntry != ListHead)
533 {
534 /* Get the current entry */
535 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
536
537 /* Make sure it's not ourselves */
538 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
539 {
540 /* Check if we should call */
541 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
542 {
543 /* Get the entrypoint */
544 EntryPoint = LdrEntry->EntryPoint;
545
546 /* Check if we are ready to call it */
547 if ((EntryPoint) &&
548 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
549 (LdrEntry->Flags & LDRP_IMAGE_DLL))
550 {
551 /* Set up the Act Ctx */
552 ActCtx.Size = sizeof(ActCtx);
553 ActCtx.Format = 1;
554 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
555
556 /* Activate the ActCtx */
557 RtlActivateActivationContextUnsafeFast(&ActCtx,
558 LdrEntry->EntryPointActivationContext);
559
560 /* Check if it has TLS */
561 if (LdrEntry->TlsIndex)
562 {
563 /* Make sure we're not shutting down */
564 if (!LdrpShutdownInProgress)
565 {
566 /* Call TLS */
567 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
568 }
569 }
570
571 /* Make sure we're not shutting down */
572 if (!LdrpShutdownInProgress)
573 {
574 /* Call the Entrypoint */
575 DPRINT("%wZ - Calling entry point at %x for thread attaching\n",
576 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
577 LdrpCallInitRoutine(LdrEntry->EntryPoint,
578 LdrEntry->DllBase,
579 DLL_THREAD_ATTACH,
580 NULL);
581 }
582
583 /* Deactivate the ActCtx */
584 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
585 }
586 }
587 }
588
589 /* Next entry */
590 NextEntry = NextEntry->Flink;
591 }
592
593 /* Check for TLS */
594 if (LdrpImageHasTls && !LdrpShutdownInProgress)
595 {
596 /* Set up the Act Ctx */
597 ActCtx.Size = sizeof(ActCtx);
598 ActCtx.Format = 1;
599 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
600
601 /* Activate the ActCtx */
602 RtlActivateActivationContextUnsafeFast(&ActCtx,
603 LdrpImageEntry->EntryPointActivationContext);
604
605 /* Do TLS callbacks */
606 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
607
608 /* Deactivate the ActCtx */
609 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
610 }
611
612 DPRINT("LdrpInitializeThread() done\n");
613 }
614
615 NTSTATUS
616 NTAPI
617 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
618 {
619 PLDR_DATA_TABLE_ENTRY LocalArray[16];
620 PLIST_ENTRY ListHead;
621 PLIST_ENTRY NextEntry;
622 PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
623 PVOID EntryPoint;
624 ULONG Count, i;
625 //ULONG BreakOnInit;
626 NTSTATUS Status = STATUS_SUCCESS;
627 PPEB Peb = NtCurrentPeb();
628 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
629 ULONG BreakOnDllLoad;
630 PTEB OldTldTeb;
631 BOOLEAN DllStatus;
632
633 DPRINT("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry->BaseDllName);
634
635 /* Check the Loader Lock */
636 LdrpEnsureLoaderLockIsHeld();
637
638 /* Get the number of entries to call */
639 if ((Count = LdrpClearLoadInProgress()))
640 {
641 /* Check if we can use our local buffer */
642 if (Count > 16)
643 {
644 /* Allocate space for all the entries */
645 LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
646 0,
647 Count * sizeof(LdrRootEntry));
648 if (!LdrRootEntry) return STATUS_NO_MEMORY;
649 }
650 else
651 {
652 /* Use our local array */
653 LdrRootEntry = LocalArray;
654 }
655 }
656 else
657 {
658 /* Don't need one */
659 LdrRootEntry = NULL;
660 }
661
662 /* Show debug message */
663 if (ShowSnaps)
664 {
665 DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n",
666 NtCurrentTeb()->RealClientId.UniqueThread,
667 NtCurrentTeb()->RealClientId.UniqueProcess,
668 &Peb->ProcessParameters->ImagePathName);
669 }
670
671 /* Loop in order */
672 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
673 NextEntry = ListHead->Flink;
674 i = 0;
675 while (NextEntry != ListHead)
676 {
677 /* Get the Data Entry */
678 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
679
680 /* Check if we have a Root Entry */
681 if (LdrRootEntry)
682 {
683 /* Check flags */
684 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
685 {
686 /* Setup the Cookie for the DLL */
687 LdrpInitSecurityCookie(LdrEntry);
688
689 /* Check for valid entrypoint */
690 if (LdrEntry->EntryPoint)
691 {
692 /* Write in array */
693 LdrRootEntry[i] = LdrEntry;
694
695 /* Display debug message */
696 if (ShowSnaps)
697 {
698 DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
699 NtCurrentTeb()->RealClientId.UniqueThread,
700 NtCurrentTeb()->RealClientId.UniqueProcess,
701 &LdrEntry->FullDllName,
702 LdrEntry->EntryPoint);
703 }
704 i++;
705 }
706 }
707 }
708
709 /* Set the flag */
710 LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
711 NextEntry = NextEntry->Flink;
712 }
713
714 /* If we got a context, then we have to call Kernel32 for TS support */
715 if (Context)
716 {
717 /* Check if we have one */
718 //if (Kernel32ProcessInitPostImportfunction)
719 //{
720 /* Call it */
721 //Kernel32ProcessInitPostImportfunction();
722 //}
723
724 /* Clear it */
725 //Kernel32ProcessInitPostImportfunction = NULL;
726 UNIMPLEMENTED;
727 }
728
729 /* No root entry? return */
730 if (!LdrRootEntry) return STATUS_SUCCESS;
731
732 /* Set the TLD TEB */
733 OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
734 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
735
736 /* Loop */
737 i = 0;
738 while (i < Count)
739 {
740 /* Get an entry */
741 LdrEntry = LdrRootEntry[i];
742
743 /* FIXME: Verify NX Compat */
744
745 /* Move to next entry */
746 i++;
747
748 /* Get its entrypoint */
749 EntryPoint = LdrEntry->EntryPoint;
750
751 /* Are we being debugged? */
752 BreakOnDllLoad = 0;
753 if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
754 {
755 /* Check if we should break on load */
756 Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
757 L"BreakOnDllLoad",
758 REG_DWORD,
759 &BreakOnDllLoad,
760 sizeof(ULONG),
761 NULL);
762 if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
763
764 /* Reset status back to STATUS_SUCCESS */
765 Status = STATUS_SUCCESS;
766 }
767
768 /* Break if aksed */
769 if (BreakOnDllLoad)
770 {
771 /* Check if we should show a message */
772 if (ShowSnaps)
773 {
774 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
775 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
776 }
777
778 /* Break in debugger */
779 DbgBreakPoint();
780 }
781
782 /* Make sure we have an entrypoint */
783 if (EntryPoint)
784 {
785 /* Save the old Dll Initializer and write the current one */
786 OldInitializer = LdrpCurrentDllInitializer;
787 LdrpCurrentDllInitializer = LdrEntry;
788
789 /* Set up the Act Ctx */
790 ActCtx.Size = sizeof(ActCtx);
791 ActCtx.Format = 1;
792 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
793
794 /* Activate the ActCtx */
795 RtlActivateActivationContextUnsafeFast(&ActCtx,
796 LdrEntry->EntryPointActivationContext);
797
798 /* Check if it has TLS */
799 if (LdrEntry->TlsIndex && Context)
800 {
801 /* Call TLS */
802 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
803 }
804
805 /* Call the Entrypoint */
806 if (ShowSnaps)
807 {
808 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
809 &LdrEntry->BaseDllName, EntryPoint);
810 }
811 DllStatus = LdrpCallInitRoutine(EntryPoint,
812 LdrEntry->DllBase,
813 DLL_PROCESS_ATTACH,
814 Context);
815
816 /* Deactivate the ActCtx */
817 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
818
819 /* Save the Current DLL Initializer */
820 LdrpCurrentDllInitializer = OldInitializer;
821
822 /* Mark the entry as processed */
823 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
824
825 /* Fail if DLL init failed */
826 if (!DllStatus)
827 {
828 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
829 &LdrEntry->BaseDllName, EntryPoint);
830
831 Status = STATUS_DLL_INIT_FAILED;
832 goto Quickie;
833 }
834 }
835 }
836
837 /* Loop in order */
838 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
839 NextEntry = NextEntry->Flink;
840 while (NextEntry != ListHead)
841 {
842 /* Get the Data Entrry */
843 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
844
845 /* FIXME: Verify NX Compat */
846 // LdrpCheckNXCompatibility()
847
848 /* Next entry */
849 NextEntry = NextEntry->Flink;
850 }
851
852 /* Check for TLS */
853 if (LdrpImageHasTls && Context)
854 {
855 /* Set up the Act Ctx */
856 ActCtx.Size = sizeof(ActCtx);
857 ActCtx.Format = 1;
858 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
859
860 /* Activate the ActCtx */
861 RtlActivateActivationContextUnsafeFast(&ActCtx,
862 LdrpImageEntry->EntryPointActivationContext);
863
864 /* Do TLS callbacks */
865 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
866
867 /* Deactivate the ActCtx */
868 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
869 }
870
871 Quickie:
872 /* Restore old TEB */
873 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
874
875 /* Check if the array is in the heap */
876 if (LdrRootEntry != LocalArray)
877 {
878 /* Free the array */
879 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
880 }
881
882 /* Return to caller */
883 DPRINT("LdrpRunInitializeRoutines() done\n");
884 return Status;
885 }
886
887 /*
888 * @implemented
889 */
890 NTSTATUS
891 NTAPI
892 LdrShutdownProcess(VOID)
893 {
894 PPEB Peb = NtCurrentPeb();
895 PLDR_DATA_TABLE_ENTRY LdrEntry;
896 PLIST_ENTRY NextEntry, ListHead;
897 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
898 PVOID EntryPoint;
899
900 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
901 if (LdrpShutdownInProgress) return STATUS_SUCCESS;
902
903 /* Tell the Shim Engine */
904 //if (ShimsEnabled)
905 //{
906 /* FIXME */
907 //}
908
909 /* Tell the world */
910 if (ShowSnaps)
911 {
912 DPRINT1("\n");
913 }
914
915 /* Set the shutdown variables */
916 LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
917 LdrpShutdownInProgress = TRUE;
918
919 /* Enter the Loader Lock */
920 RtlEnterCriticalSection(&LdrpLoaderLock);
921
922 /* Cleanup trace logging data (Etw) */
923 if (SharedUserData->TraceLogging)
924 {
925 /* FIXME */
926 DPRINT1("We don't support Etw yet.\n");
927 }
928
929 /* Start at the end */
930 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
931 NextEntry = ListHead->Blink;
932 while (NextEntry != ListHead)
933 {
934 /* Get the current entry */
935 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
936 NextEntry = NextEntry->Blink;
937
938 /* Make sure it's not ourselves */
939 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
940 {
941 /* Get the entrypoint */
942 EntryPoint = LdrEntry->EntryPoint;
943
944 /* Check if we are ready to call it */
945 if (EntryPoint &&
946 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
947 LdrEntry->Flags)
948 {
949 /* Set up the Act Ctx */
950 ActCtx.Size = sizeof(ActCtx);
951 ActCtx.Format = 1;
952 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
953
954 /* Activate the ActCtx */
955 RtlActivateActivationContextUnsafeFast(&ActCtx,
956 LdrEntry->EntryPointActivationContext);
957
958 /* Check if it has TLS */
959 if (LdrEntry->TlsIndex)
960 {
961 /* Call TLS */
962 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH);
963 }
964
965 /* Call the Entrypoint */
966 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
967 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
968 LdrpCallInitRoutine(EntryPoint,
969 LdrEntry->DllBase,
970 DLL_PROCESS_DETACH,
971 (PVOID)1);
972
973 /* Deactivate the ActCtx */
974 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
975 }
976 }
977 }
978
979 /* Check for TLS */
980 if (LdrpImageHasTls)
981 {
982 /* Set up the Act Ctx */
983 ActCtx.Size = sizeof(ActCtx);
984 ActCtx.Format = 1;
985 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
986
987 /* Activate the ActCtx */
988 RtlActivateActivationContextUnsafeFast(&ActCtx,
989 LdrpImageEntry->EntryPointActivationContext);
990
991 /* Do TLS callbacks */
992 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_DETACH);
993
994 /* Deactivate the ActCtx */
995 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
996 }
997
998 /* FIXME: Do Heap detection and Etw final shutdown */
999
1000 /* Release the lock */
1001 RtlLeaveCriticalSection(&LdrpLoaderLock);
1002 DPRINT("LdrpShutdownProcess() done\n");
1003
1004 return STATUS_SUCCESS;
1005 }
1006
1007 /*
1008 * @implemented
1009 */
1010 NTSTATUS
1011 NTAPI
1012 LdrShutdownThread(VOID)
1013 {
1014 PPEB Peb = NtCurrentPeb();
1015 PTEB Teb = NtCurrentTeb();
1016 PLDR_DATA_TABLE_ENTRY LdrEntry;
1017 PLIST_ENTRY NextEntry, ListHead;
1018 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1019 PVOID EntryPoint;
1020
1021 DPRINT("LdrShutdownThread() called for %wZ\n",
1022 &LdrpImageEntry->BaseDllName);
1023
1024 /* Cleanup trace logging data (Etw) */
1025 if (SharedUserData->TraceLogging)
1026 {
1027 /* FIXME */
1028 DPRINT1("We don't support Etw yet.\n");
1029 }
1030
1031 /* Get the Ldr Lock */
1032 RtlEnterCriticalSection(&LdrpLoaderLock);
1033
1034 /* Start at the end */
1035 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1036 NextEntry = ListHead->Blink;
1037 while (NextEntry != ListHead)
1038 {
1039 /* Get the current entry */
1040 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
1041 NextEntry = NextEntry->Blink;
1042
1043 /* Make sure it's not ourselves */
1044 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1045 {
1046 /* Check if we should call */
1047 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1048 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1049 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1050 {
1051 /* Get the entrypoint */
1052 EntryPoint = LdrEntry->EntryPoint;
1053
1054 /* Check if we are ready to call it */
1055 if (EntryPoint)
1056 {
1057 /* Set up the Act Ctx */
1058 ActCtx.Size = sizeof(ActCtx);
1059 ActCtx.Format = 1;
1060 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1061
1062 /* Activate the ActCtx */
1063 RtlActivateActivationContextUnsafeFast(&ActCtx,
1064 LdrEntry->EntryPointActivationContext);
1065
1066 /* Check if it has TLS */
1067 if (LdrEntry->TlsIndex)
1068 {
1069 /* Make sure we're not shutting down */
1070 if (!LdrpShutdownInProgress)
1071 {
1072 /* Call TLS */
1073 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH);
1074 }
1075 }
1076
1077 /* Make sure we're not shutting down */
1078 if (!LdrpShutdownInProgress)
1079 {
1080 /* Call the Entrypoint */
1081 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
1082 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1083 LdrpCallInitRoutine(EntryPoint,
1084 LdrEntry->DllBase,
1085 DLL_THREAD_DETACH,
1086 NULL);
1087 }
1088
1089 /* Deactivate the ActCtx */
1090 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1091 }
1092 }
1093 }
1094 }
1095
1096 /* Check for TLS */
1097 if (LdrpImageHasTls)
1098 {
1099 /* Set up the Act Ctx */
1100 ActCtx.Size = sizeof(ActCtx);
1101 ActCtx.Format = 1;
1102 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1103
1104 /* Activate the ActCtx */
1105 RtlActivateActivationContextUnsafeFast(&ActCtx,
1106 LdrpImageEntry->EntryPointActivationContext);
1107
1108 /* Do TLS callbacks */
1109 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_DETACH);
1110
1111 /* Deactivate the ActCtx */
1112 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1113 }
1114
1115 /* Free TLS */
1116 LdrpFreeTls();
1117 RtlLeaveCriticalSection(&LdrpLoaderLock);
1118
1119 /* Check for expansion slots */
1120 if (Teb->TlsExpansionSlots)
1121 {
1122 /* Free expansion slots */
1123 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1124 }
1125
1126 /* Check for FLS Data */
1127 if (Teb->FlsData)
1128 {
1129 /* FIXME */
1130 DPRINT1("We don't support FLS Data yet\n");
1131 }
1132
1133 /* Check for Fiber data */
1134 if (Teb->HasFiberData)
1135 {
1136 /* Free Fiber data*/
1137 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1138 Teb->NtTib.FiberData = NULL;
1139 }
1140
1141 /* Free the activation context stack */
1142 RtlFreeThreadActivationContextStack();
1143 DPRINT("LdrShutdownThread() done\n");
1144
1145 return STATUS_SUCCESS;
1146 }
1147
1148 NTSTATUS
1149 NTAPI
1150 LdrpInitializeTls(VOID)
1151 {
1152 PLIST_ENTRY NextEntry, ListHead;
1153 PLDR_DATA_TABLE_ENTRY LdrEntry;
1154 PIMAGE_TLS_DIRECTORY TlsDirectory;
1155 PLDRP_TLS_DATA TlsData;
1156 ULONG Size;
1157
1158 /* Initialize the TLS List */
1159 InitializeListHead(&LdrpTlsList);
1160
1161 /* Loop all the modules */
1162 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1163 NextEntry = ListHead->Flink;
1164 while (ListHead != NextEntry)
1165 {
1166 /* Get the entry */
1167 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1168 NextEntry = NextEntry->Flink;
1169
1170 /* Get the TLS directory */
1171 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1172 TRUE,
1173 IMAGE_DIRECTORY_ENTRY_TLS,
1174 &Size);
1175
1176 /* Check if we have a directory */
1177 if (!TlsDirectory) continue;
1178
1179 /* Check if the image has TLS */
1180 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1181
1182 /* Show debug message */
1183 if (ShowSnaps)
1184 {
1185 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1186 &LdrEntry->BaseDllName,
1187 TlsDirectory);
1188 }
1189
1190 /* Allocate an entry */
1191 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1192 if (!TlsData) return STATUS_NO_MEMORY;
1193
1194 /* Lock the DLL and mark it for TLS Usage */
1195 LdrEntry->LoadCount = -1;
1196 LdrEntry->TlsIndex = -1;
1197
1198 /* Save the cached TLS data */
1199 TlsData->TlsDirectory = *TlsDirectory;
1200 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1201
1202 /* Update the index */
1203 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1204 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1205 }
1206
1207 /* Done setting up TLS, allocate entries */
1208 return LdrpAllocateTls();
1209 }
1210
1211 NTSTATUS
1212 NTAPI
1213 LdrpAllocateTls(VOID)
1214 {
1215 PTEB Teb = NtCurrentTeb();
1216 PLIST_ENTRY NextEntry, ListHead;
1217 PLDRP_TLS_DATA TlsData;
1218 ULONG TlsDataSize;
1219 PVOID *TlsVector;
1220
1221 /* Check if we have any entries */
1222 if (!LdrpNumberOfTlsEntries)
1223 return STATUS_SUCCESS;
1224
1225 /* Allocate the vector array */
1226 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1227 0,
1228 LdrpNumberOfTlsEntries * sizeof(PVOID));
1229 if (!TlsVector) return STATUS_NO_MEMORY;
1230 Teb->ThreadLocalStoragePointer = TlsVector;
1231
1232 /* Loop the TLS Array */
1233 ListHead = &LdrpTlsList;
1234 NextEntry = ListHead->Flink;
1235 while (NextEntry != ListHead)
1236 {
1237 /* Get the entry */
1238 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1239 NextEntry = NextEntry->Flink;
1240
1241 /* Allocate this vector */
1242 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1243 TlsData->TlsDirectory.StartAddressOfRawData;
1244 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1245 0,
1246 TlsDataSize);
1247 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1248 {
1249 /* Out of memory */
1250 return STATUS_NO_MEMORY;
1251 }
1252
1253 /* Show debug message */
1254 if (ShowSnaps)
1255 {
1256 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
1257 TlsVector,
1258 TlsData->TlsDirectory.Characteristics,
1259 &TlsVector[TlsData->TlsDirectory.Characteristics],
1260 TlsData->TlsDirectory.StartAddressOfRawData,
1261 TlsVector[TlsData->TlsDirectory.Characteristics]);
1262 }
1263
1264 /* Copy the data */
1265 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1266 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1267 TlsDataSize);
1268 }
1269
1270 /* Done */
1271 return STATUS_SUCCESS;
1272 }
1273
1274 VOID
1275 NTAPI
1276 LdrpFreeTls(VOID)
1277 {
1278 PLIST_ENTRY ListHead, NextEntry;
1279 PLDRP_TLS_DATA TlsData;
1280 PVOID *TlsVector;
1281 PTEB Teb = NtCurrentTeb();
1282
1283 /* Get a pointer to the vector array */
1284 TlsVector = Teb->ThreadLocalStoragePointer;
1285 if (!TlsVector) return;
1286
1287 /* Loop through it */
1288 ListHead = &LdrpTlsList;
1289 NextEntry = ListHead->Flink;
1290 while (NextEntry != ListHead)
1291 {
1292 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1293 NextEntry = NextEntry->Flink;
1294
1295 /* Free each entry */
1296 if (TlsVector[TlsData->TlsDirectory.Characteristics])
1297 {
1298 RtlFreeHeap(RtlGetProcessHeap(),
1299 0,
1300 TlsVector[TlsData->TlsDirectory.Characteristics]);
1301 }
1302 }
1303
1304 /* Free the array itself */
1305 RtlFreeHeap(RtlGetProcessHeap(),
1306 0,
1307 TlsVector);
1308 }
1309
1310 NTSTATUS
1311 NTAPI
1312 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHKEY OptionsKey)
1313 {
1314 NTSTATUS Status;
1315 HKEY KeyHandle;
1316 ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1317
1318 /* Return error if we were not provided a pointer where to save the options key handle */
1319 if (!OptionsKey) return STATUS_INVALID_HANDLE;
1320
1321 /* Zero initialize the optinos key pointer */
1322 *OptionsKey = NULL;
1323
1324 /* Open the options key */
1325 Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1326
1327 /* Save it if it was opened successfully */
1328 if (NT_SUCCESS(Status))
1329 *OptionsKey = KeyHandle;
1330
1331 if (KeyHandle)
1332 {
1333 /* There are image specific options, read them starting with NXCOMPAT */
1334 Status = LdrQueryImageFileKeyOption(KeyHandle,
1335 L"ExecuteOptions",
1336 4,
1337 &ExecuteOptions,
1338 sizeof(ExecuteOptions),
1339 0);
1340
1341 if (NT_SUCCESS(Status))
1342 {
1343 /* TODO: Set execution options for the process */
1344 /*
1345 if (ExecuteOptions == 0)
1346 ExecuteOptions = 1;
1347 else
1348 ExecuteOptions = 2;
1349 ZwSetInformationProcess(NtCurrentProcess(),
1350 ProcessExecuteFlags,
1351 &ExecuteOptions,
1352 sizeof(ULONG));*/
1353
1354 }
1355
1356 /* Check if this image uses large pages */
1357 if (Peb->ImageUsesLargePages)
1358 {
1359 /* TODO: If it does, open large page key */
1360 UNIMPLEMENTED;
1361 }
1362
1363 /* Get various option values */
1364 LdrQueryImageFileKeyOption(KeyHandle,
1365 L"DisableHeapLookaside",
1366 REG_DWORD,
1367 &RtlpDisableHeapLookaside,
1368 sizeof(RtlpDisableHeapLookaside),
1369 NULL);
1370
1371 LdrQueryImageFileKeyOption(KeyHandle,
1372 L"ShutdownFlags",
1373 REG_DWORD,
1374 &RtlpShutdownProcessFlags,
1375 sizeof(RtlpShutdownProcessFlags),
1376 NULL);
1377
1378 LdrQueryImageFileKeyOption(KeyHandle,
1379 L"MinimumStackCommitInBytes",
1380 REG_DWORD,
1381 &MinimumStackCommit,
1382 sizeof(MinimumStackCommit),
1383 NULL);
1384
1385 /* Update PEB's minimum stack commit if it's lower */
1386 if (Peb->MinimumStackCommit < MinimumStackCommit)
1387 Peb->MinimumStackCommit = MinimumStackCommit;
1388
1389 /* Set the global flag */
1390 Status = LdrQueryImageFileKeyOption(KeyHandle,
1391 L"GlobalFlag",
1392 REG_DWORD,
1393 &GlobalFlag,
1394 sizeof(GlobalFlag),
1395 NULL);
1396
1397 if (NT_SUCCESS(Status))
1398 Peb->NtGlobalFlag = GlobalFlag;
1399 else
1400 GlobalFlag = 0;
1401 }
1402 else
1403 {
1404 /* There are no image-specific options, so perform global initialization */
1405 if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
1406 {
1407 // TODO: Initialize app verifier package
1408 // Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, 1, FALSE);
1409 }
1410 }
1411
1412 return STATUS_SUCCESS;
1413 }
1414
1415 VOID
1416 NTAPI
1417 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1418 {
1419 UNIMPLEMENTED;
1420 }
1421
1422 NTSTATUS
1423 NTAPI
1424 LdrpInitializeProcess(IN PCONTEXT Context,
1425 IN PVOID SystemArgument1)
1426 {
1427 RTL_HEAP_PARAMETERS HeapParameters;
1428 ULONG ComSectionSize;
1429 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1430 PVOID OldShimData;
1431 OBJECT_ATTRIBUTES ObjectAttributes;
1432 //UNICODE_STRING LocalFileName, FullImageName;
1433 HANDLE SymLinkHandle;
1434 //ULONG DebugHeapOnly;
1435 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1436 PPEB Peb = NtCurrentPeb();
1437 BOOLEAN IsDotNetImage = FALSE;
1438 BOOLEAN FreeCurDir = FALSE;
1439 //HKEY CompatKey;
1440 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1441 //LPWSTR ImagePathBuffer;
1442 ULONG ConfigSize;
1443 UNICODE_STRING CurrentDirectory;
1444 HKEY OptionsKey;
1445 ULONG HeapFlags;
1446 PIMAGE_NT_HEADERS NtHeader;
1447 LPWSTR NtDllName = NULL;
1448 NTSTATUS Status;
1449 NLSTABLEINFO NlsTable;
1450 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1451 PTEB Teb = NtCurrentTeb();
1452 PLIST_ENTRY ListHead;
1453 PLIST_ENTRY NextEntry;
1454 ULONG i;
1455 PWSTR ImagePath;
1456 ULONG DebugProcessHeapOnly = 0;
1457 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1458 PWCHAR Current;
1459 ULONG ExecuteOptions = 0;
1460 PVOID ViewBase;
1461
1462 /* Set a NULL SEH Filter */
1463 RtlSetUnhandledExceptionFilter(NULL);
1464
1465 /* Get the image path */
1466 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1467
1468 /* Check if it's normalized */
1469 if (Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED)
1470 {
1471 /* Normalize it*/
1472 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1473 }
1474
1475 /* Create a unicode string for the Image Path */
1476 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1477 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1478 ImagePathName.Buffer = ImagePath;
1479
1480 /* Get the NT Headers */
1481 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1482
1483 /* Get the execution options */
1484 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1485
1486 /* Check if this is a .NET executable */
1487 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1488 TRUE,
1489 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1490 &ComSectionSize))
1491 {
1492 /* Remeber this for later */
1493 IsDotNetImage = TRUE;
1494 }
1495
1496 /* Save the NTDLL Base address */
1497 NtDllBase = SystemArgument1;
1498
1499 /* If this is a Native Image */
1500 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1501 {
1502 /* Then do DLL Validation */
1503 LdrpDllValidation = TRUE;
1504 }
1505
1506 /* Save the old Shim Data */
1507 OldShimData = Peb->pShimData;
1508
1509 /* Clear it */
1510 Peb->pShimData = NULL;
1511
1512 /* Save the number of processors and CS Timeout */
1513 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1514 RtlpTimeout = Peb->CriticalSectionTimeout;
1515
1516 /* Normalize the parameters */
1517 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1518 ProcessParameters = Peb->ProcessParameters;
1519 if (ProcessParameters)
1520 {
1521 /* Save the Image and Command Line Names */
1522 ImageFileName = ProcessParameters->ImagePathName;
1523 CommandLine = ProcessParameters->CommandLine;
1524 }
1525 else
1526 {
1527 /* It failed, initialize empty strings */
1528 RtlInitUnicodeString(&ImageFileName, NULL);
1529 RtlInitUnicodeString(&CommandLine, NULL);
1530 }
1531
1532 /* Initialize NLS data */
1533 RtlInitNlsTables(Peb->AnsiCodePageData,
1534 Peb->OemCodePageData,
1535 Peb->UnicodeCaseTableData,
1536 &NlsTable);
1537
1538 /* Reset NLS Translations */
1539 RtlResetRtlTranslations(&NlsTable);
1540
1541 /* Get the Image Config Directory */
1542 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1543 TRUE,
1544 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1545 &ConfigSize);
1546
1547 /* Setup the Heap Parameters */
1548 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1549 HeapFlags = HEAP_GROWABLE;
1550 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1551
1552 /* Check if we have Configuration Data */
1553 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1554 {
1555 /* FIXME: Custom heap settings and misc. */
1556 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1557 }
1558
1559 /* Check for custom affinity mask */
1560 if (Peb->ImageProcessAffinityMask)
1561 {
1562 /* Set it */
1563 Status = NtSetInformationProcess(NtCurrentProcess(),
1564 ProcessAffinityMask,
1565 &Peb->ImageProcessAffinityMask,
1566 sizeof(Peb->ImageProcessAffinityMask));
1567 }
1568
1569 /* Check if verbose debugging (ShowSnaps) was requested */
1570 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1571
1572 /* Start verbose debugging messages right now if they were requested */
1573 if (ShowSnaps)
1574 {
1575 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1576 Teb->ClientId.UniqueProcess,
1577 &CommandLine);
1578 }
1579
1580 /* If the timeout is too long */
1581 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1582 {
1583 /* Then disable CS Timeout */
1584 RtlpTimeoutDisable = TRUE;
1585 }
1586
1587 /* Initialize Critical Section Data */
1588 RtlpInitDeferedCriticalSection();
1589
1590 /* Initialize VEH Call lists */
1591 RtlpInitializeVectoredExceptionHandling();
1592
1593 /* Set TLS/FLS Bitmap data */
1594 Peb->FlsBitmap = &FlsBitMap;
1595 Peb->TlsBitmap = &TlsBitMap;
1596 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1597
1598 /* Initialize FLS Bitmap */
1599 RtlInitializeBitMap(&FlsBitMap,
1600 Peb->FlsBitmapBits,
1601 FLS_MAXIMUM_AVAILABLE);
1602 RtlSetBit(&FlsBitMap, 0);
1603
1604 /* Initialize TLS Bitmap */
1605 RtlInitializeBitMap(&TlsBitMap,
1606 Peb->TlsBitmapBits,
1607 TLS_MINIMUM_AVAILABLE);
1608 RtlSetBit(&TlsBitMap, 0);
1609 RtlInitializeBitMap(&TlsExpansionBitMap,
1610 Peb->TlsExpansionBitmapBits,
1611 TLS_EXPANSION_SLOTS);
1612 RtlSetBit(&TlsExpansionBitMap, 0);
1613
1614 /* Initialize the Hash Table */
1615 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1616 {
1617 InitializeListHead(&LdrpHashTable[i]);
1618 }
1619
1620 /* Initialize the Loader Lock */
1621 // FIXME: What's the point of initing it manually, if two lines lower
1622 // a call to RtlInitializeCriticalSection() is being made anyway?
1623 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1624 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1625 RtlInitializeCriticalSection(&LdrpLoaderLock);
1626 LdrpLoaderLockInit = TRUE;
1627
1628 /* Check if User Stack Trace Database support was requested */
1629 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1630 {
1631 DPRINT1("We don't support user stack trace databases yet\n");
1632 }
1633
1634 /* Setup Fast PEB Lock */
1635 RtlInitializeCriticalSection(&FastPebLock);
1636 Peb->FastPebLock = &FastPebLock;
1637 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1638 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1639
1640 /* Setup Callout Lock and Notification list */
1641 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1642 InitializeListHead(&LdrpDllNotificationList);
1643
1644 /* For old executables, use 16-byte aligned heap */
1645 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1646 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1647 {
1648 HeapFlags |= HEAP_CREATE_ALIGN_16;
1649 }
1650
1651 /* Setup the Heap */
1652 RtlInitializeHeapManager();
1653 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1654 NULL,
1655 NtHeader->OptionalHeader.SizeOfHeapReserve,
1656 NtHeader->OptionalHeader.SizeOfHeapCommit,
1657 NULL,
1658 &HeapParameters);
1659
1660 if (!Peb->ProcessHeap)
1661 {
1662 DPRINT1("Failed to create process heap\n");
1663 return STATUS_NO_MEMORY;
1664 }
1665
1666 // FIXME: Is it located properly?
1667 /* Initialize table of callbacks for the kernel. */
1668 Peb->KernelCallbackTable = RtlAllocateHeap(RtlGetProcessHeap(),
1669 0,
1670 sizeof(PVOID) *
1671 (USER32_CALLBACK_MAXIMUM + 1));
1672 if (!Peb->KernelCallbackTable)
1673 {
1674 DPRINT1("Failed to create callback table\n");
1675 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
1676 }
1677
1678 /* Allocate an Activation Context Stack */
1679 Status = RtlAllocateActivationContextStack((PVOID *)&Teb->ActivationContextStackPointer);
1680 if (!NT_SUCCESS(Status)) return Status;
1681
1682 // FIXME: Loader private heap is missing
1683 //DPRINT1("Loader private heap is missing\n");
1684
1685 /* Check for Debug Heap */
1686 if (OptionsKey)
1687 {
1688 /* Query the setting */
1689 Status = LdrQueryImageFileKeyOption(OptionsKey,
1690 L"DebugProcessHeapOnly",
1691 REG_DWORD,
1692 &DebugProcessHeapOnly,
1693 sizeof(ULONG),
1694 NULL);
1695
1696 if (NT_SUCCESS(Status))
1697 {
1698 /* Reset DPH if requested */
1699 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1700 {
1701 RtlpDphGlobalFlags &= ~0x40;
1702 RtlpPageHeapEnabled = FALSE;
1703 }
1704 }
1705 }
1706
1707 /* Build the NTDLL Path */
1708 FullPath.Buffer = StringBuffer;
1709 FullPath.Length = 0;
1710 FullPath.MaximumLength = sizeof(StringBuffer);
1711 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1712 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1713 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1714
1715 /* Open the Known DLLs directory */
1716 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1717 InitializeObjectAttributes(&ObjectAttributes,
1718 &KnownDllString,
1719 OBJ_CASE_INSENSITIVE,
1720 NULL,
1721 NULL);
1722 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1723 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1724 &ObjectAttributes);
1725
1726 /* Check if it exists */
1727 if (NT_SUCCESS(Status))
1728 {
1729 /* Open the Known DLLs Path */
1730 RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
1731 InitializeObjectAttributes(&ObjectAttributes,
1732 &KnownDllString,
1733 OBJ_CASE_INSENSITIVE,
1734 LdrpKnownDllObjectDirectory,
1735 NULL);
1736 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1737 SYMBOLIC_LINK_QUERY,
1738 &ObjectAttributes);
1739 if (NT_SUCCESS(Status))
1740 {
1741 /* Query the path */
1742 LdrpKnownDllPath.Length = 0;
1743 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1744 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1745 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1746 NtClose(SymLinkHandle);
1747 if (!NT_SUCCESS(Status))
1748 {
1749 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1750 return Status;
1751 }
1752 }
1753 }
1754
1755 /* Check if we failed */
1756 if (!NT_SUCCESS(Status))
1757 {
1758 /* Aassume System32 */
1759 LdrpKnownDllObjectDirectory = NULL;
1760 RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
1761 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1762 }
1763
1764 /* If we have process parameters, get the default path and current path */
1765 if (ProcessParameters)
1766 {
1767 /* Check if we have a Dll Path */
1768 if (ProcessParameters->DllPath.Length)
1769 {
1770 /* Get the path */
1771 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1772 }
1773 else
1774 {
1775 /* We need a valid path */
1776 DPRINT1("No valid DllPath was given!\n");
1777 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1778 }
1779
1780 /* Set the current directory */
1781 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1782
1783 /* Check if it's empty or invalid */
1784 if ((!CurrentDirectory.Buffer) ||
1785 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1786 (!CurrentDirectory.Length))
1787 {
1788 /* Allocate space for the buffer */
1789 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1790 0,
1791 3 * sizeof(WCHAR) +
1792 sizeof(UNICODE_NULL));
1793 if (!CurrentDirectory.Buffer)
1794 {
1795 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1796 // FIXME: And what?
1797 }
1798
1799 /* Copy the drive of the system root */
1800 RtlMoveMemory(CurrentDirectory.Buffer,
1801 SharedUserData->NtSystemRoot,
1802 3 * sizeof(WCHAR));
1803 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1804 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1805 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1806
1807 FreeCurDir = TRUE;
1808 DPRINT("Using dynamically allocd curdir\n");
1809 }
1810 else
1811 {
1812 /* Use the local buffer */
1813 DPRINT("Using local system root\n");
1814 }
1815 }
1816
1817 /* Setup Loader Data */
1818 Peb->Ldr = &PebLdr;
1819 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1820 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1821 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1822 PebLdr.Length = sizeof(PEB_LDR_DATA);
1823 PebLdr.Initialized = TRUE;
1824
1825 /* Allocate a data entry for the Image */
1826 LdrpImageEntry = NtLdrEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1827
1828 /* Set it up */
1829 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1830 NtLdrEntry->LoadCount = -1;
1831 NtLdrEntry->EntryPointActivationContext = 0;
1832 NtLdrEntry->FullDllName = ImageFileName;
1833
1834 if (IsDotNetImage)
1835 NtLdrEntry->Flags = LDRP_COR_IMAGE;
1836 else
1837 NtLdrEntry->Flags = 0;
1838
1839 /* Check if the name is empty */
1840 if (!ImageFileName.Buffer[0])
1841 {
1842 /* Use the same Base name */
1843 NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
1844 }
1845 else
1846 {
1847 /* Find the last slash */
1848 Current = ImageFileName.Buffer;
1849 while (*Current)
1850 {
1851 if (*Current++ == '\\')
1852 {
1853 /* Set this path */
1854 NtDllName = Current;
1855 }
1856 }
1857
1858 /* Did we find anything? */
1859 if (!NtDllName)
1860 {
1861 /* Use the same Base name */
1862 NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
1863 }
1864 else
1865 {
1866 /* Setup the name */
1867 NtLdrEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
1868 NtLdrEntry->BaseDllName.MaximumLength = NtLdrEntry->BaseDllName.Length + sizeof(WCHAR);
1869 NtLdrEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
1870 (ImageFileName.Length - NtLdrEntry->BaseDllName.Length));
1871 }
1872 }
1873
1874 /* Processing done, insert it */
1875 LdrpInsertMemoryTableEntry(NtLdrEntry);
1876 NtLdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
1877
1878 /* Now add an entry for NTDLL */
1879 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
1880 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
1881 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1882 NtLdrEntry->LoadCount = -1;
1883 NtLdrEntry->EntryPointActivationContext = 0;
1884
1885 NtLdrEntry->FullDllName.Length = FullPath.Length;
1886 NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
1887 NtLdrEntry->FullDllName.Buffer = StringBuffer;
1888 RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
1889
1890 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
1891 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
1892 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
1893
1894 /* Processing done, insert it */
1895 LdrpNtDllDataTableEntry = NtLdrEntry;
1896 LdrpInsertMemoryTableEntry(NtLdrEntry);
1897
1898 /* Let the world know */
1899 if (ShowSnaps)
1900 {
1901 DPRINT1("LDR: NEW PROCESS\n");
1902 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
1903 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
1904 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
1905 }
1906
1907 /* Link the Init Order List */
1908 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
1909 &LdrpNtDllDataTableEntry->InInitializationOrderModuleList);
1910
1911 /* Set the current directory */
1912 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
1913 if (!NT_SUCCESS(Status))
1914 {
1915 /* We failed, check if we should free it */
1916 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1917
1918 /* Set it to the NT Root */
1919 CurrentDirectory = NtSystemRoot;
1920 RtlSetCurrentDirectory_U(&CurrentDirectory);
1921 }
1922 else
1923 {
1924 /* We're done with it, free it */
1925 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1926 }
1927
1928 /* Check if we should look for a .local file */
1929 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
1930 {
1931 /* FIXME */
1932 DPRINT1("We don't support .local overrides yet\n");
1933 }
1934
1935 /* Check if the Application Verifier was enabled */
1936 if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK)
1937 {
1938 /* FIXME */
1939 DPRINT1("We don't support Application Verifier yet\n");
1940 }
1941
1942 if (IsDotNetImage)
1943 {
1944 /* FIXME */
1945 DPRINT1("We don't support .NET applications yet\n");
1946 }
1947
1948 /* FIXME: Load support for Terminal Services */
1949 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1950 {
1951 /* Load kernel32 and call BasePostImportInit... */
1952 DPRINT1("Unimplemented codepath!\n");
1953 }
1954
1955 /* Walk the IAT and load all the DLLs */
1956 LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
1957
1958 /* Check if relocation is needed */
1959 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
1960 {
1961 DPRINT1("LDR: Performing EXE relocation\n");
1962
1963 /* Change the protection to prepare for relocation */
1964 ViewBase = Peb->ImageBaseAddress;
1965 Status = LdrpSetProtection(ViewBase, FALSE);
1966 if (!NT_SUCCESS(Status)) return Status;
1967
1968 /* Do the relocation */
1969 Status = LdrRelocateImageWithBias(ViewBase,
1970 0LL,
1971 NULL,
1972 STATUS_SUCCESS,
1973 STATUS_CONFLICTING_ADDRESSES,
1974 STATUS_INVALID_IMAGE_FORMAT);
1975 if (!NT_SUCCESS(Status))
1976 {
1977 DPRINT1("LdrRelocateImageWithBias() failed\n");
1978 return Status;
1979 }
1980
1981 /* Check if a start context was provided */
1982 if (Context)
1983 {
1984 DPRINT1("WARNING: Relocated EXE Context");
1985 UNIMPLEMENTED; // We should support this
1986 return STATUS_INVALID_IMAGE_FORMAT;
1987 }
1988
1989 /* Restore the protection */
1990 Status = LdrpSetProtection(ViewBase, TRUE);
1991 if (!NT_SUCCESS(Status)) return Status;
1992 }
1993
1994 /* Lock the DLLs */
1995 ListHead = &Peb->Ldr->InLoadOrderModuleList;
1996 NextEntry = ListHead->Flink;
1997 while (ListHead != NextEntry)
1998 {
1999 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2000 NtLdrEntry->LoadCount = -1;
2001 NextEntry = NextEntry->Flink;
2002 }
2003
2004 /* Phase 0 is done */
2005 LdrpLdrDatabaseIsSetup = TRUE;
2006
2007 /* Initialize TLS */
2008 Status = LdrpInitializeTls();
2009 if (!NT_SUCCESS(Status))
2010 {
2011 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2012 Status);
2013 return Status;
2014 }
2015
2016 /* FIXME Mark the DLL Ranges for Stack Traces later */
2017
2018 /* Notify the debugger now */
2019 if (Peb->BeingDebugged)
2020 {
2021 /* Break */
2022 DbgBreakPoint();
2023
2024 /* Update show snaps again */
2025 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2026 }
2027
2028 /* Validate the Image for MP Usage */
2029 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2030
2031 /* Check NX Options */
2032 if (SharedUserData->NXSupportPolicy == 1)
2033 {
2034 ExecuteOptions = 0xD;
2035 }
2036 else if (!SharedUserData->NXSupportPolicy)
2037 {
2038 ExecuteOptions = 0xA;
2039 }
2040
2041 /* Let Mm know */
2042 ZwSetInformationProcess(NtCurrentProcess(),
2043 ProcessExecuteFlags,
2044 &ExecuteOptions,
2045 sizeof(ULONG));
2046
2047 /* Check if we had Shim Data */
2048 if (OldShimData)
2049 {
2050 /* Load the Shim Engine */
2051 Peb->AppCompatInfo = NULL;
2052 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
2053 DPRINT1("We do not support shims yet\n");
2054 }
2055 else
2056 {
2057 /* Check for Application Compatibility Goo */
2058 //LdrQueryApplicationCompatibilityGoo(hKey);
2059 DPRINT1("Querying app compat hacks is missing!\n");
2060 }
2061
2062 /*
2063 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2064 * incompatible images.
2065 */
2066
2067 /* Now call the Init Routines */
2068 Status = LdrpRunInitializeRoutines(Context);
2069 if (!NT_SUCCESS(Status))
2070 {
2071 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2072 Status);
2073 return Status;
2074 }
2075
2076 /* FIXME: Unload the Shim Engine if it was loaded */
2077
2078 /* Check if we have a user-defined Post Process Routine */
2079 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2080 {
2081 /* Call it */
2082 Peb->PostProcessInitRoutine();
2083 }
2084
2085 ///* Close the key if we have one opened */
2086 if (OptionsKey) NtClose(OptionsKey);
2087
2088 /* Return status */
2089 return Status;
2090 }
2091
2092 VOID
2093 NTAPI
2094 LdrpInitFailure(NTSTATUS Status)
2095 {
2096 ULONG Response;
2097 PPEB Peb = NtCurrentPeb();
2098
2099 /* Print a debug message */
2100 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2101 &Peb->ProcessParameters->ImagePathName, Status);
2102
2103 /* Raise a hard error */
2104 if (!LdrpFatalHardErrorCount)
2105 {
2106 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2107 }
2108 }
2109
2110 VOID
2111 NTAPI
2112 LdrpInit(PCONTEXT Context,
2113 PVOID SystemArgument1,
2114 PVOID SystemArgument2)
2115 {
2116 LARGE_INTEGER Timeout;
2117 PTEB Teb = NtCurrentTeb();
2118 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2119 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2120 PPEB Peb = NtCurrentPeb();
2121
2122 DPRINT("LdrpInit()\n");
2123
2124 /* Check if we have a deallocation stack */
2125 if (!Teb->DeallocationStack)
2126 {
2127 /* We don't, set one */
2128 Status = NtQueryVirtualMemory(NtCurrentProcess(),
2129 Teb->NtTib.StackLimit,
2130 MemoryBasicInformation,
2131 &MemoryBasicInfo,
2132 sizeof(MEMORY_BASIC_INFORMATION),
2133 NULL);
2134 if (!NT_SUCCESS(Status))
2135 {
2136 /* Fail */
2137 LdrpInitFailure(Status);
2138 RtlRaiseStatus(Status);
2139 return;
2140 }
2141
2142 /* Set the stack */
2143 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2144 }
2145
2146 /* Now check if the process is already being initialized */
2147 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2148 1,
2149 0) == 1)
2150 {
2151 /* Set the timeout to 30 seconds */
2152 Timeout.QuadPart = Int32x32To64(30, -10000);
2153
2154 /* Make sure the status hasn't changed */
2155 while (!LdrpProcessInitialized)
2156 {
2157 /* Do the wait */
2158 ZwDelayExecution(FALSE, &Timeout);
2159 }
2160 }
2161
2162 /* Check if we have already setup LDR data */
2163 if (!Peb->Ldr)
2164 {
2165 /* Setup the Loader Lock */
2166 Peb->LoaderLock = &LdrpLoaderLock;
2167
2168 /* Let other code know we're initializing */
2169 LdrpInLdrInit = TRUE;
2170
2171 /* Protect with SEH */
2172 _SEH2_TRY
2173 {
2174 /* Initialize the Process */
2175 LoaderStatus = LdrpInitializeProcess(Context,
2176 SystemArgument1);
2177
2178 /* Check for success and if MinimumStackCommit was requested */
2179 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2180 {
2181 /* Enforce the limit */
2182 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2183 UNIMPLEMENTED;
2184 }
2185 }
2186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2187 {
2188 /* Fail with the SEH error */
2189 LoaderStatus = _SEH2_GetExceptionCode();
2190 }
2191 _SEH2_END;
2192
2193 /* We're not initializing anymore */
2194 LdrpInLdrInit = FALSE;
2195
2196 /* Check if init worked */
2197 if (NT_SUCCESS(LoaderStatus))
2198 {
2199 /* Set the process as Initialized */
2200 _InterlockedIncrement(&LdrpProcessInitialized);
2201 }
2202 }
2203 else
2204 {
2205 /* Loader data is there... is this a fork() ? */
2206 if(Peb->InheritedAddressSpace)
2207 {
2208 /* Handle the fork() */
2209 //LoaderStatus = LdrpForkProcess();
2210 LoaderStatus = STATUS_NOT_IMPLEMENTED;
2211 UNIMPLEMENTED;
2212 }
2213 else
2214 {
2215 /* This is a new thread initializing */
2216 LdrpInitializeThread(Context);
2217 }
2218 }
2219
2220 /* All done, test alert the thread */
2221 NtTestAlert();
2222
2223 /* Return */
2224 if (!NT_SUCCESS(LoaderStatus))
2225 {
2226 /* Fail */
2227 LdrpInitFailure(LoaderStatus);
2228 RtlRaiseStatus(LoaderStatus);
2229 }
2230 }
2231
2232 /* EOF */