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