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