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