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