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