1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NT User Mode Library 4 * FILE: dll/ntdll/ldr/ldrapi.c 5 * PURPOSE: PE Loader Public APIs 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Aleksey Bragin (aleksey@reactos.org) 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntdll.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 /* GLOBALS *******************************************************************/ 18 19 LIST_ENTRY LdrpUnloadHead; 20 LONG LdrpLoaderLockAcquisitionCount; 21 BOOLEAN LdrpShowRecursiveLoads, LdrpBreakOnRecursiveDllLoads; 22 UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL"); 23 ULONG AlternateResourceModuleCount; 24 extern PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine; 25 26 /* FUNCTIONS *****************************************************************/ 27 28 NTSTATUS 29 NTAPI 30 LdrFindCreateProcessManifest(IN ULONG Flags, 31 IN PVOID Image, 32 IN PVOID IdPath, 33 IN ULONG IdPathLength, 34 IN PVOID OutDataEntry) 35 { 36 UNIMPLEMENTED; 37 return STATUS_NOT_IMPLEMENTED; 38 } 39 40 NTSTATUS 41 NTAPI 42 LdrDestroyOutOfProcessImage(IN PVOID Image) 43 { 44 UNIMPLEMENTED; 45 return STATUS_NOT_IMPLEMENTED; 46 } 47 48 NTSTATUS 49 NTAPI 50 LdrCreateOutOfProcessImage(IN ULONG Flags, 51 IN HANDLE ProcessHandle, 52 IN HANDLE DllHandle, 53 IN PVOID Unknown3) 54 { 55 UNIMPLEMENTED; 56 return STATUS_NOT_IMPLEMENTED; 57 } 58 59 NTSTATUS 60 NTAPI 61 LdrAccessOutOfProcessResource(IN PVOID Unknown, 62 IN PVOID Image, 63 IN PVOID Unknown1, 64 IN PVOID Unknown2, 65 IN PVOID Unknown3) 66 { 67 UNIMPLEMENTED; 68 return STATUS_NOT_IMPLEMENTED; 69 } 70 71 VOID 72 NTAPI 73 LdrSetDllManifestProber( 74 _In_ PLDR_MANIFEST_PROBER_ROUTINE Routine) 75 { 76 LdrpManifestProberRoutine = Routine; 77 } 78 79 BOOLEAN 80 NTAPI 81 LdrAlternateResourcesEnabled(VOID) 82 { 83 /* ReactOS does not support this */ 84 return FALSE; 85 } 86 87 FORCEINLINE 88 ULONG_PTR 89 LdrpMakeCookie(VOID) 90 { 91 /* Generate a cookie */ 92 return (((ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | 93 (_InterlockedIncrement(&LdrpLoaderLockAcquisitionCount) & 0xFFFF); 94 } 95 96 /* 97 * @implemented 98 */ 99 NTSTATUS 100 NTAPI 101 LdrUnlockLoaderLock( 102 _In_ ULONG Flags, 103 _In_opt_ ULONG_PTR Cookie) 104 { 105 NTSTATUS Status = STATUS_SUCCESS; 106 107 DPRINT("LdrUnlockLoaderLock(%x %Ix)\n", Flags, Cookie); 108 109 /* Check for valid flags */ 110 if (Flags & ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 111 { 112 /* Flags are invalid, check how to fail */ 113 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 114 { 115 /* The caller wants us to raise status */ 116 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1); 117 } 118 119 /* A normal failure */ 120 return STATUS_INVALID_PARAMETER_1; 121 } 122 123 /* If we don't have a cookie, just return */ 124 if (!Cookie) return STATUS_SUCCESS; 125 126 /* Validate the cookie */ 127 if ((Cookie & 0xF0000000) || 128 ((Cookie >> 16) ^ (HandleToUlong(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF))) 129 { 130 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n"); 131 132 /* Invalid cookie, check how to fail */ 133 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 134 { 135 /* The caller wants us to raise status */ 136 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2); 137 } 138 139 /* A normal failure */ 140 return STATUS_INVALID_PARAMETER_2; 141 } 142 143 /* Ready to release the lock */ 144 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 145 { 146 /* Do a direct leave */ 147 RtlLeaveCriticalSection(&LdrpLoaderLock); 148 } 149 else 150 { 151 /* Wrap this in SEH, since we're not supposed to raise */ 152 _SEH2_TRY 153 { 154 /* Leave the lock */ 155 RtlLeaveCriticalSection(&LdrpLoaderLock); 156 } 157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 158 { 159 /* We should use the LDR Filter instead */ 160 Status = _SEH2_GetExceptionCode(); 161 } 162 _SEH2_END; 163 } 164 165 /* All done */ 166 return Status; 167 } 168 169 /* 170 * @implemented 171 */ 172 NTSTATUS 173 NTAPI 174 LdrLockLoaderLock( 175 _In_ ULONG Flags, 176 _Out_opt_ PULONG Disposition, 177 _Out_opt_ PULONG_PTR Cookie) 178 { 179 NTSTATUS Status = STATUS_SUCCESS; 180 BOOLEAN InInit = LdrpInLdrInit; 181 182 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Disposition, Cookie); 183 184 /* Zero out the outputs */ 185 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID; 186 if (Cookie) *Cookie = 0; 187 188 /* Validate the flags */ 189 if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS | 190 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)) 191 { 192 /* Flags are invalid, check how to fail */ 193 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 194 { 195 /* The caller wants us to raise status */ 196 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1); 197 } 198 199 /* A normal failure */ 200 return STATUS_INVALID_PARAMETER_1; 201 } 202 203 /* Make sure we got a cookie */ 204 if (!Cookie) 205 { 206 /* No cookie check how to fail */ 207 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 208 { 209 /* The caller wants us to raise status */ 210 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3); 211 } 212 213 /* A normal failure */ 214 return STATUS_INVALID_PARAMETER_3; 215 } 216 217 /* If the flag is set, make sure we have a valid pointer to use */ 218 if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Disposition)) 219 { 220 /* No pointer to return the data to */ 221 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 222 { 223 /* The caller wants us to raise status */ 224 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2); 225 } 226 227 /* Fail */ 228 return STATUS_INVALID_PARAMETER_2; 229 } 230 231 /* Return now if we are in the init phase */ 232 if (InInit) return STATUS_SUCCESS; 233 234 /* Check what locking semantic to use */ 235 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 236 { 237 /* Check if we should enter or simply try */ 238 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) 239 { 240 /* Do a try */ 241 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock)) 242 { 243 /* It's locked */ 244 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED; 245 } 246 else 247 { 248 /* It worked */ 249 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 250 *Cookie = LdrpMakeCookie(); 251 } 252 } 253 else 254 { 255 /* Do a enter */ 256 RtlEnterCriticalSection(&LdrpLoaderLock); 257 258 /* See if result was requested */ 259 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 260 *Cookie = LdrpMakeCookie(); 261 } 262 } 263 else 264 { 265 /* Wrap this in SEH, since we're not supposed to raise */ 266 _SEH2_TRY 267 { 268 /* Check if we should enter or simply try */ 269 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) 270 { 271 /* Do a try */ 272 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock)) 273 { 274 /* It's locked */ 275 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED; 276 } 277 else 278 { 279 /* It worked */ 280 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 281 *Cookie = LdrpMakeCookie(); 282 } 283 } 284 else 285 { 286 /* Do an enter */ 287 RtlEnterCriticalSection(&LdrpLoaderLock); 288 289 /* See if result was requested */ 290 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 291 *Cookie = LdrpMakeCookie(); 292 } 293 } 294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 295 { 296 /* We should use the LDR Filter instead */ 297 Status = _SEH2_GetExceptionCode(); 298 } 299 _SEH2_END; 300 } 301 302 /* Return status */ 303 return Status; 304 } 305 306 /* 307 * @implemented 308 */ 309 NTSTATUS 310 NTAPI 311 DECLSPEC_HOTPATCH 312 LdrLoadDll( 313 _In_opt_ PWSTR SearchPath, 314 _In_opt_ PULONG DllCharacteristics, 315 _In_ PUNICODE_STRING DllName, 316 _Out_ PVOID *BaseAddress) 317 { 318 WCHAR StringBuffer[MAX_PATH]; 319 UNICODE_STRING DllString1, DllString2; 320 BOOLEAN RedirectedDll = FALSE; 321 NTSTATUS Status; 322 ULONG_PTR Cookie; 323 PUNICODE_STRING OldTldDll; 324 PTEB Teb = NtCurrentTeb(); 325 326 /* Initialize the strings */ 327 RtlInitEmptyUnicodeString(&DllString1, StringBuffer, sizeof(StringBuffer)); 328 RtlInitEmptyUnicodeString(&DllString2, NULL, 0); 329 330 /* Check if the SxS Assemblies specify another file */ 331 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 332 DllName, 333 &LdrApiDefaultExtension, 334 &DllString1, 335 &DllString2, 336 &DllName, 337 NULL, 338 NULL, 339 NULL); 340 341 /* Check success */ 342 if (NT_SUCCESS(Status)) 343 { 344 /* Let Ldrp know */ 345 RedirectedDll = TRUE; 346 } 347 else if (Status != STATUS_SXS_KEY_NOT_FOUND) 348 { 349 /* Unrecoverable SxS failure; did we get a string? */ 350 if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2); 351 return Status; 352 } 353 354 /* Lock the loader lock */ 355 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie); 356 357 /* Check if there's a TLD DLL being loaded */ 358 OldTldDll = LdrpTopLevelDllBeingLoaded; 359 _SEH2_TRY 360 { 361 362 if (OldTldDll) 363 { 364 /* This is a recursive load, do something about it? */ 365 if ((ShowSnaps) || (LdrpShowRecursiveLoads) || (LdrpBreakOnRecursiveDllLoads)) 366 { 367 /* Print out debug messages */ 368 DPRINT1("[%p, %p] LDR: Recursive DLL Load\n", 369 Teb->RealClientId.UniqueProcess, 370 Teb->RealClientId.UniqueThread); 371 DPRINT1("[%p, %p] Previous DLL being loaded \"%wZ\"\n", 372 Teb->RealClientId.UniqueProcess, 373 Teb->RealClientId.UniqueThread, 374 OldTldDll); 375 DPRINT1("[%p, %p] DLL being requested \"%wZ\"\n", 376 Teb->RealClientId.UniqueProcess, 377 Teb->RealClientId.UniqueThread, 378 DllName); 379 380 /* Was it initializing too? */ 381 if (!LdrpCurrentDllInitializer) 382 { 383 DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n", 384 Teb->RealClientId.UniqueProcess, 385 Teb->RealClientId.UniqueThread); 386 } 387 else 388 { 389 DPRINT1("[%p, %p] DLL whose initializer was currently running \"%wZ\"\n", 390 Teb->ClientId.UniqueProcess, 391 Teb->ClientId.UniqueThread, 392 &LdrpCurrentDllInitializer->BaseDllName); 393 } 394 } 395 } 396 397 /* Set this one as the TLD DLL being loaded*/ 398 LdrpTopLevelDllBeingLoaded = DllName; 399 400 /* Load the DLL */ 401 Status = LdrpLoadDll(RedirectedDll, 402 SearchPath, 403 DllCharacteristics, 404 DllName, 405 BaseAddress, 406 TRUE); 407 if (NT_SUCCESS(Status)) 408 { 409 Status = STATUS_SUCCESS; 410 } 411 else if ((Status != STATUS_NO_SUCH_FILE) && 412 (Status != STATUS_DLL_NOT_FOUND) && 413 (Status != STATUS_OBJECT_NAME_NOT_FOUND) && 414 (Status != STATUS_DLL_INIT_FAILED)) 415 { 416 DbgPrintEx(DPFLTR_LDR_ID, 417 DPFLTR_WARNING_LEVEL, 418 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n", 419 __FUNCTION__, 420 DllName, 421 Status); 422 } 423 } 424 _SEH2_FINALLY 425 { 426 /* Restore the old TLD DLL */ 427 LdrpTopLevelDllBeingLoaded = OldTldDll; 428 429 /* Release the lock */ 430 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 431 } 432 _SEH2_END; 433 434 /* Do we have a redirect string? */ 435 if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2); 436 437 /* Return */ 438 return Status; 439 } 440 441 /* 442 * @implemented 443 */ 444 NTSTATUS 445 NTAPI 446 LdrFindEntryForAddress( 447 _In_ PVOID Address, 448 _Out_ PLDR_DATA_TABLE_ENTRY *Module) 449 { 450 PLIST_ENTRY ListHead, NextEntry; 451 PLDR_DATA_TABLE_ENTRY LdrEntry; 452 PIMAGE_NT_HEADERS NtHeader; 453 PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr; 454 ULONG_PTR DllBase, DllEnd; 455 456 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address); 457 458 /* Nothing to do */ 459 if (!Ldr) return STATUS_NO_MORE_ENTRIES; 460 461 /* Get the current entry */ 462 LdrEntry = Ldr->EntryInProgress; 463 if (LdrEntry) 464 { 465 /* Get the NT Headers */ 466 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 467 if (NtHeader) 468 { 469 /* Get the Image Base */ 470 DllBase = (ULONG_PTR)LdrEntry->DllBase; 471 DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage; 472 473 /* Check if they match */ 474 if (((ULONG_PTR)Address >= DllBase) && 475 ((ULONG_PTR)Address < DllEnd)) 476 { 477 /* Return it */ 478 *Module = LdrEntry; 479 return STATUS_SUCCESS; 480 } 481 } 482 } 483 484 /* Loop the module list */ 485 ListHead = &Ldr->InMemoryOrderModuleList; 486 NextEntry = ListHead->Flink; 487 while (NextEntry != ListHead) 488 { 489 /* Get the entry and NT Headers */ 490 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); 491 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 492 if (NtHeader) 493 { 494 /* Get the Image Base */ 495 DllBase = (ULONG_PTR)LdrEntry->DllBase; 496 DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage; 497 498 /* Check if they match */ 499 if (((ULONG_PTR)Address >= DllBase) && 500 ((ULONG_PTR)Address < DllEnd)) 501 { 502 /* Return it */ 503 *Module = LdrEntry; 504 return STATUS_SUCCESS; 505 } 506 507 /* Next Entry */ 508 NextEntry = NextEntry->Flink; 509 } 510 } 511 512 /* Nothing found */ 513 DbgPrintEx(DPFLTR_LDR_ID, 514 DPFLTR_WARNING_LEVEL, 515 "LDR: %s() exiting 0x%08lx\n", 516 __FUNCTION__, 517 STATUS_NO_MORE_ENTRIES); 518 return STATUS_NO_MORE_ENTRIES; 519 } 520 521 /* 522 * @implemented 523 */ 524 NTSTATUS 525 NTAPI 526 LdrGetDllHandleEx( 527 _In_ ULONG Flags, 528 _In_opt_ PWSTR DllPath, 529 _In_opt_ PULONG DllCharacteristics, 530 _In_ PUNICODE_STRING DllName, 531 _Out_opt_ PVOID *DllHandle) 532 { 533 NTSTATUS Status; 534 PLDR_DATA_TABLE_ENTRY LdrEntry; 535 UNICODE_STRING RedirectName, DllString1, RawDllName; 536 PUNICODE_STRING pRedirectName, CompareName; 537 PWCHAR p1, p2, p3; 538 BOOLEAN Locked, RedirectedDll; 539 ULONG_PTR Cookie; 540 ULONG LoadFlag, Length; 541 542 /* Initialize the strings */ 543 RtlInitEmptyUnicodeString(&DllString1, NULL, 0); 544 RtlInitEmptyUnicodeString(&RawDllName, NULL, 0); 545 RedirectName = *DllName; 546 pRedirectName = &RedirectName; 547 548 /* Initialize state */ 549 RedirectedDll = Locked = FALSE; 550 LdrEntry = NULL; 551 Cookie = 0; 552 553 /* Clear the handle */ 554 if (DllHandle) *DllHandle = NULL; 555 556 /* Check for a valid flag combination */ 557 if ((Flags & ~(LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) || 558 (!DllHandle && !(Flags & LDR_GET_DLL_HANDLE_EX_PIN))) 559 { 560 DPRINT1("Flags are invalid or no DllHandle given\n"); 561 Status = STATUS_INVALID_PARAMETER; 562 goto Quickie; 563 } 564 565 /* If not initializing */ 566 if (!LdrpInLdrInit) 567 { 568 /* Acquire the lock */ 569 Status = LdrLockLoaderLock(0, NULL, &Cookie); 570 if (!NT_SUCCESS(Status)) goto Quickie; 571 572 /* Remember we own it */ 573 Locked = TRUE; 574 } 575 576 /* Check if the SxS Assemblies specify another file */ 577 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 578 pRedirectName, 579 &LdrApiDefaultExtension, 580 NULL, 581 &DllString1, 582 &pRedirectName, 583 NULL, 584 NULL, 585 NULL); 586 587 /* Check success */ 588 if (NT_SUCCESS(Status)) 589 { 590 /* Let Ldrp know */ 591 RedirectedDll = TRUE; 592 } 593 else if (Status != STATUS_SXS_KEY_NOT_FOUND) 594 { 595 /* Unrecoverable SxS failure */ 596 goto Quickie; 597 } 598 else 599 { 600 ASSERT(pRedirectName == &RedirectName); 601 } 602 603 /* Set default failure code */ 604 Status = STATUS_DLL_NOT_FOUND; 605 606 /* Use the cache if we can */ 607 if (LdrpGetModuleHandleCache) 608 { 609 /* Check if we were redirected */ 610 if (RedirectedDll) 611 { 612 /* Check the flag */ 613 if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)) 614 { 615 goto DontCompare; 616 } 617 618 /* Use the right name */ 619 CompareName = &LdrpGetModuleHandleCache->FullDllName; 620 } 621 else 622 { 623 /* Check the flag */ 624 if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED) 625 { 626 goto DontCompare; 627 } 628 629 /* Use the right name */ 630 CompareName = &LdrpGetModuleHandleCache->BaseDllName; 631 } 632 633 /* Check if the name matches */ 634 if (RtlEqualUnicodeString(pRedirectName, 635 CompareName, 636 TRUE)) 637 { 638 /* Skip the rest */ 639 LdrEntry = LdrpGetModuleHandleCache; 640 641 /* Return success */ 642 Status = STATUS_SUCCESS; 643 goto Quickie; 644 } 645 } 646 647 DontCompare: 648 /* Find the name without the extension */ 649 p1 = pRedirectName->Buffer; 650 p2 = NULL; 651 p3 = &p1[pRedirectName->Length / sizeof(WCHAR)]; 652 while (p1 != p3) 653 { 654 if (*p1++ == L'.') 655 { 656 p2 = p1; 657 } 658 else if (*p1 == L'\\') 659 { 660 p2 = NULL; 661 } 662 } 663 664 /* Check if no extension was found or if we got a slash */ 665 if (!(p2) || (*p2 == L'\\') || (*p2 == L'/')) 666 { 667 /* Check that we have space to add one */ 668 Length = pRedirectName->Length + 669 LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL); 670 if (Length >= UNICODE_STRING_MAX_BYTES) 671 { 672 /* No space to add the extension */ 673 Status = STATUS_NAME_TOO_LONG; 674 goto Quickie; 675 } 676 677 /* Setup the string */ 678 RawDllName.MaximumLength = Length; 679 ASSERT(Length >= sizeof(UNICODE_NULL)); 680 RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 681 0, 682 RawDllName.MaximumLength); 683 if (!RawDllName.Buffer) 684 { 685 Status = STATUS_NO_MEMORY; 686 goto Quickie; 687 } 688 689 /* Copy the string and add extension */ 690 RtlCopyUnicodeString(&RawDllName, pRedirectName); 691 RtlAppendUnicodeStringToString(&RawDllName, &LdrApiDefaultExtension); 692 } 693 else 694 { 695 /* Check if there's something in the name */ 696 Length = pRedirectName->Length; 697 if (Length) 698 { 699 /* Check and remove trailing period */ 700 if (pRedirectName->Buffer[Length / sizeof(WCHAR) - sizeof(ANSI_NULL)] == '.') 701 { 702 /* Decrease the size */ 703 pRedirectName->Length -= sizeof(WCHAR); 704 } 705 } 706 707 /* Setup the string */ 708 RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR); 709 RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 710 0, 711 RawDllName.MaximumLength); 712 if (!RawDllName.Buffer) 713 { 714 Status = STATUS_NO_MEMORY; 715 goto Quickie; 716 } 717 718 /* Copy the string */ 719 RtlCopyUnicodeString(&RawDllName, pRedirectName); 720 } 721 722 /* Display debug string */ 723 if (ShowSnaps) 724 { 725 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n", 726 &RawDllName, 727 DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L""); 728 } 729 730 /* Do the lookup */ 731 if (LdrpCheckForLoadedDll(DllPath, 732 &RawDllName, 733 ((ULONG_PTR)DllPath == 1) ? TRUE : FALSE, 734 RedirectedDll, 735 &LdrEntry)) 736 { 737 /* Update cached entry */ 738 LdrpGetModuleHandleCache = LdrEntry; 739 740 /* Return success */ 741 Status = STATUS_SUCCESS; 742 } 743 else 744 { 745 /* Make sure to NULL this */ 746 LdrEntry = NULL; 747 } 748 Quickie: 749 /* The success path must have a valid loader entry */ 750 ASSERT((LdrEntry != NULL) == NT_SUCCESS(Status)); 751 752 /* Check if we got an entry and success */ 753 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL); 754 if ((LdrEntry) && (NT_SUCCESS(Status))) 755 { 756 /* Check if the DLL is locked */ 757 if ((LdrEntry->LoadCount != 0xFFFF) && 758 !(Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) 759 { 760 /* Check what to do with the load count */ 761 if (Flags & LDR_GET_DLL_HANDLE_EX_PIN) 762 { 763 /* Pin it */ 764 LdrEntry->LoadCount = 0xFFFF; 765 LoadFlag = LDRP_UPDATE_PIN; 766 } 767 else 768 { 769 /* Increase the load count */ 770 LdrEntry->LoadCount++; 771 LoadFlag = LDRP_UPDATE_REFCOUNT; 772 } 773 774 /* Update the load count now */ 775 LdrpUpdateLoadCount2(LdrEntry, LoadFlag); 776 LdrpClearLoadInProgress(); 777 } 778 779 /* Check if the caller is requesting the handle */ 780 if (DllHandle) *DllHandle = LdrEntry->DllBase; 781 } 782 783 /* Free string if needed */ 784 if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1); 785 786 /* Free the raw DLL Name if needed */ 787 if (RawDllName.Buffer) 788 { 789 /* Free the heap-allocated buffer */ 790 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer); 791 RawDllName.Buffer = NULL; 792 } 793 794 /* Release lock */ 795 if (Locked) 796 { 797 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, 798 Cookie); 799 } 800 801 /* Return */ 802 return Status; 803 } 804 805 /* 806 * @implemented 807 */ 808 NTSTATUS 809 NTAPI 810 LdrGetDllHandle( 811 _In_opt_ PWSTR DllPath, 812 _In_opt_ PULONG DllCharacteristics, 813 _In_ PUNICODE_STRING DllName, 814 _Out_ PVOID *DllHandle) 815 { 816 /* Call the newer API */ 817 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT, 818 DllPath, 819 DllCharacteristics, 820 DllName, 821 DllHandle); 822 } 823 824 /* 825 * @implemented 826 */ 827 NTSTATUS 828 NTAPI 829 LdrGetProcedureAddress( 830 _In_ PVOID BaseAddress, 831 _In_opt_ _When_(Ordinal == 0, _Notnull_) PANSI_STRING Name, 832 _In_opt_ _When_(Name == NULL, _In_range_(>, 0)) ULONG Ordinal, 833 _Out_ PVOID *ProcedureAddress) 834 { 835 /* Call the internal routine and tell it to execute DllInit */ 836 return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE); 837 } 838 839 /* 840 * @implemented 841 */ 842 NTSTATUS 843 NTAPI 844 LdrVerifyImageMatchesChecksum( 845 _In_ HANDLE FileHandle, 846 _In_ PLDR_CALLBACK Callback, 847 _In_ PVOID CallbackContext, 848 _Out_ PUSHORT ImageCharacteristics) 849 { 850 FILE_STANDARD_INFORMATION FileStandardInfo; 851 PIMAGE_IMPORT_DESCRIPTOR ImportData; 852 PIMAGE_SECTION_HEADER LastSection = NULL; 853 IO_STATUS_BLOCK IoStatusBlock; 854 PIMAGE_NT_HEADERS NtHeader; 855 HANDLE SectionHandle; 856 SIZE_T ViewSize; 857 PVOID ViewBase; 858 BOOLEAN Result, NoActualCheck; 859 NTSTATUS Status; 860 PVOID ImportName; 861 ULONG Size; 862 DPRINT("LdrVerifyImageMatchesChecksum() called\n"); 863 864 /* If the handle has the magic KnownDll flag, skip actual checksums */ 865 NoActualCheck = ((ULONG_PTR)FileHandle & 1); 866 867 /* Create the section */ 868 Status = NtCreateSection(&SectionHandle, 869 SECTION_MAP_EXECUTE, 870 NULL, 871 NULL, 872 PAGE_EXECUTE, 873 SEC_COMMIT, 874 FileHandle); 875 if (!NT_SUCCESS(Status)) 876 { 877 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status); 878 return Status; 879 } 880 881 /* Map the section */ 882 ViewSize = 0; 883 ViewBase = NULL; 884 Status = NtMapViewOfSection(SectionHandle, 885 NtCurrentProcess(), 886 &ViewBase, 887 0, 888 0, 889 NULL, 890 &ViewSize, 891 ViewShare, 892 0, 893 PAGE_EXECUTE); 894 if (!NT_SUCCESS(Status)) 895 { 896 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status); 897 NtClose(SectionHandle); 898 return Status; 899 } 900 901 /* Get the file information */ 902 Status = NtQueryInformationFile(FileHandle, 903 &IoStatusBlock, 904 &FileStandardInfo, 905 sizeof(FILE_STANDARD_INFORMATION), 906 FileStandardInformation); 907 if (!NT_SUCCESS(Status)) 908 { 909 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status); 910 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 911 NtClose(SectionHandle); 912 return Status; 913 } 914 915 /* Protect with SEH */ 916 _SEH2_TRY 917 { 918 /* Check if this is the KnownDll hack */ 919 if (NoActualCheck) 920 { 921 /* Don't actually do it */ 922 Result = TRUE; 923 } 924 else 925 { 926 /* Verify the checksum */ 927 Result = LdrVerifyMappedImageMatchesChecksum(ViewBase, 928 FileStandardInfo.EndOfFile.LowPart, 929 FileStandardInfo.EndOfFile.LowPart); 930 } 931 932 /* Check if a callback was supplied */ 933 if ((Result) && (Callback)) 934 { 935 /* Get the NT Header */ 936 NtHeader = RtlImageNtHeader(ViewBase); 937 938 /* Check if caller requested this back */ 939 if (ImageCharacteristics) 940 { 941 /* Return to caller */ 942 *ImageCharacteristics = NtHeader->FileHeader.Characteristics; 943 } 944 945 /* Get the Import Directory Data */ 946 ImportData = RtlImageDirectoryEntryToData(ViewBase, 947 FALSE, 948 IMAGE_DIRECTORY_ENTRY_IMPORT, 949 &Size); 950 951 /* Make sure there is one */ 952 if (ImportData) 953 { 954 /* Loop the imports */ 955 while (ImportData->Name) 956 { 957 /* Get the name */ 958 ImportName = RtlImageRvaToVa(NtHeader, 959 ViewBase, 960 ImportData->Name, 961 &LastSection); 962 963 /* Notify the callback */ 964 Callback(CallbackContext, ImportName); 965 ImportData++; 966 } 967 } 968 } 969 } 970 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 971 { 972 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */ 973 Result = FALSE; 974 } 975 _SEH2_END; 976 977 /* Unmap file and close handle */ 978 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 979 NtClose(SectionHandle); 980 981 /* Return status */ 982 return Result ? Status : STATUS_IMAGE_CHECKSUM_MISMATCH; 983 } 984 985 NTSTATUS 986 NTAPI 987 LdrQueryProcessModuleInformationEx( 988 _In_opt_ ULONG ProcessId, 989 _Reserved_ ULONG Reserved, 990 _Out_writes_bytes_to_(Size, *ReturnedSize) PRTL_PROCESS_MODULES ModuleInformation, 991 _In_ ULONG Size, 992 _Out_opt_ PULONG ReturnedSize) 993 { 994 PLIST_ENTRY ModuleListHead, InitListHead; 995 PLIST_ENTRY Entry, InitEntry; 996 PLDR_DATA_TABLE_ENTRY Module, InitModule; 997 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL; 998 NTSTATUS Status = STATUS_SUCCESS; 999 ULONG UsedSize = FIELD_OFFSET(RTL_PROCESS_MODULES, Modules); 1000 ANSI_STRING AnsiString; 1001 PCHAR p; 1002 1003 DPRINT("LdrQueryProcessModuleInformation() called\n"); 1004 1005 /* Acquire loader lock */ 1006 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); 1007 1008 _SEH2_TRY 1009 { 1010 /* Check if we were given enough space */ 1011 if (Size < UsedSize) 1012 { 1013 Status = STATUS_INFO_LENGTH_MISMATCH; 1014 } 1015 else 1016 { 1017 ModuleInformation->NumberOfModules = 0; 1018 ModulePtr = &ModuleInformation->Modules[0]; 1019 Status = STATUS_SUCCESS; 1020 } 1021 1022 /* Traverse the list of modules */ 1023 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 1024 Entry = ModuleListHead->Flink; 1025 1026 while (Entry != ModuleListHead) 1027 { 1028 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 1029 1030 DPRINT(" Module %wZ\n", &Module->FullDllName); 1031 1032 /* Increase the used size */ 1033 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION); 1034 1035 if (UsedSize > Size) 1036 { 1037 Status = STATUS_INFO_LENGTH_MISMATCH; 1038 } 1039 else 1040 { 1041 ModulePtr->ImageBase = Module->DllBase; 1042 ModulePtr->ImageSize = Module->SizeOfImage; 1043 ModulePtr->Flags = Module->Flags; 1044 ModulePtr->LoadCount = Module->LoadCount; 1045 ModulePtr->MappedBase = NULL; 1046 ModulePtr->InitOrderIndex = 0; 1047 ModulePtr->LoadOrderIndex = ModuleInformation->NumberOfModules; 1048 1049 /* Now get init order index by traversing init list */ 1050 InitListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; 1051 InitEntry = InitListHead->Flink; 1052 1053 while (InitEntry != InitListHead) 1054 { 1055 InitModule = CONTAINING_RECORD(InitEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); 1056 1057 /* Increase the index */ 1058 ModulePtr->InitOrderIndex++; 1059 1060 /* Quit the loop if our module is found */ 1061 if (InitModule == Module) break; 1062 1063 /* Advance to the next entry */ 1064 InitEntry = InitEntry->Flink; 1065 } 1066 1067 /* Prepare ANSI string with the module's name */ 1068 AnsiString.Length = 0; 1069 AnsiString.MaximumLength = sizeof(ModulePtr->FullPathName); 1070 AnsiString.Buffer = ModulePtr->FullPathName; 1071 RtlUnicodeStringToAnsiString(&AnsiString, 1072 &Module->FullDllName, 1073 FALSE); 1074 1075 /* Calculate OffsetToFileName field */ 1076 p = strrchr(ModulePtr->FullPathName, '\\'); 1077 if (p != NULL) 1078 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1; 1079 else 1080 ModulePtr->OffsetToFileName = 0; 1081 1082 /* Advance to the next module in the output list */ 1083 ModulePtr++; 1084 1085 /* Increase number of modules */ 1086 if (ModuleInformation) 1087 ModuleInformation->NumberOfModules++; 1088 } 1089 1090 /* Go to the next entry in the modules list */ 1091 Entry = Entry->Flink; 1092 } 1093 1094 /* Set returned size if it was provided */ 1095 if (ReturnedSize) 1096 *ReturnedSize = UsedSize; 1097 } 1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1099 { 1100 /* Ignoring the exception */ 1101 } _SEH2_END; 1102 1103 /* Release the lock */ 1104 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); 1105 1106 DPRINT("LdrQueryProcessModuleInformation() done\n"); 1107 1108 return Status; 1109 } 1110 1111 /* 1112 * @implemented 1113 */ 1114 NTSTATUS 1115 NTAPI 1116 LdrQueryProcessModuleInformation( 1117 _Out_writes_bytes_to_(Size, *ReturnedSize) PRTL_PROCESS_MODULES ModuleInformation, 1118 _In_ ULONG Size, 1119 _Out_opt_ PULONG ReturnedSize) 1120 { 1121 /* Call Ex version of the API */ 1122 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize); 1123 } 1124 1125 /* 1126 * @implemented 1127 */ 1128 NTSTATUS 1129 NTAPI 1130 LdrEnumerateLoadedModules( 1131 _Reserved_ ULONG ReservedFlag, 1132 _In_ PLDR_ENUM_CALLBACK EnumProc, 1133 _In_opt_ PVOID Context) 1134 { 1135 PLIST_ENTRY ListHead, ListEntry; 1136 PLDR_DATA_TABLE_ENTRY LdrEntry; 1137 NTSTATUS Status; 1138 ULONG_PTR Cookie; 1139 BOOLEAN Stop = FALSE; 1140 1141 /* Check parameters */ 1142 if ((ReservedFlag) || !(EnumProc)) return STATUS_INVALID_PARAMETER; 1143 1144 /* Acquire the loader lock */ 1145 Status = LdrLockLoaderLock(0, NULL, &Cookie); 1146 if (!NT_SUCCESS(Status)) return Status; 1147 1148 /* Loop all the modules and call enum proc */ 1149 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 1150 ListEntry = ListHead->Flink; 1151 while (ListHead != ListEntry) 1152 { 1153 /* Get the entry */ 1154 LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 1155 1156 /* Call the enumeration proc inside SEH */ 1157 _SEH2_TRY 1158 { 1159 EnumProc(LdrEntry, Context, &Stop); 1160 } 1161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1162 { 1163 /* Ignoring the exception */ 1164 } _SEH2_END; 1165 1166 /* Break if we were asked to stop enumeration */ 1167 if (Stop) 1168 { 1169 break; 1170 } 1171 1172 /* Advance to the next module */ 1173 ListEntry = ListEntry->Flink; 1174 } 1175 1176 /* Release loader lock */ 1177 Status = LdrUnlockLoaderLock(0, Cookie); 1178 ASSERT(NT_SUCCESS(Status)); 1179 1180 /* Reset any successful status to STATUS_SUCCESS, 1181 * but leave failure to the caller */ 1182 if (NT_SUCCESS(Status)) 1183 Status = STATUS_SUCCESS; 1184 1185 /* Return any possible failure status */ 1186 return Status; 1187 } 1188 1189 /* 1190 * @implemented 1191 */ 1192 NTSTATUS 1193 NTAPI 1194 LdrDisableThreadCalloutsForDll( 1195 _In_ PVOID BaseAddress) 1196 { 1197 PLDR_DATA_TABLE_ENTRY LdrEntry; 1198 NTSTATUS Status; 1199 BOOLEAN LockHeld; 1200 ULONG_PTR Cookie; 1201 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress); 1202 1203 /* Don't do it during shutdown */ 1204 if (LdrpShutdownInProgress) return STATUS_SUCCESS; 1205 1206 /* Check if we should grab the lock */ 1207 LockHeld = FALSE; 1208 if (!LdrpInLdrInit) 1209 { 1210 /* Grab the lock */ 1211 Status = LdrLockLoaderLock(0, NULL, &Cookie); 1212 if (!NT_SUCCESS(Status)) return Status; 1213 LockHeld = TRUE; 1214 } 1215 1216 /* Make sure the DLL is valid and get its entry */ 1217 Status = STATUS_DLL_NOT_FOUND; 1218 if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 1219 { 1220 /* Get if it has a TLS slot */ 1221 if (!LdrEntry->TlsIndex) 1222 { 1223 /* It doesn't, so you're allowed to call this */ 1224 LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS; 1225 Status = STATUS_SUCCESS; 1226 } 1227 } 1228 1229 /* Check if the lock was held */ 1230 if (LockHeld) 1231 { 1232 /* Release it */ 1233 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 1234 } 1235 1236 /* Return the status */ 1237 return Status; 1238 } 1239 1240 /* 1241 * @implemented 1242 */ 1243 NTSTATUS 1244 NTAPI 1245 LdrAddRefDll( 1246 _In_ ULONG Flags, 1247 _In_ PVOID BaseAddress) 1248 { 1249 PLDR_DATA_TABLE_ENTRY LdrEntry; 1250 NTSTATUS Status = STATUS_SUCCESS; 1251 ULONG_PTR Cookie; 1252 BOOLEAN Locked = FALSE; 1253 1254 /* Check for invalid flags */ 1255 if (Flags & ~(LDR_ADDREF_DLL_PIN)) 1256 { 1257 /* Fail with invalid parameter status if so */ 1258 Status = STATUS_INVALID_PARAMETER; 1259 goto quickie; 1260 } 1261 1262 /* Acquire the loader lock if not in init phase */ 1263 if (!LdrpInLdrInit) 1264 { 1265 /* Acquire the lock */ 1266 Status = LdrLockLoaderLock(0, NULL, &Cookie); 1267 if (!NT_SUCCESS(Status)) goto quickie; 1268 Locked = TRUE; 1269 } 1270 1271 /* Get this module's data table entry */ 1272 if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 1273 { 1274 if (!LdrEntry) 1275 { 1276 /* Shouldn't happen */ 1277 Status = STATUS_INTERNAL_ERROR; 1278 goto quickie; 1279 } 1280 1281 /* If this is not a pinned module */ 1282 if (LdrEntry->LoadCount != 0xFFFF) 1283 { 1284 /* Update its load count */ 1285 if (Flags & LDR_ADDREF_DLL_PIN) 1286 { 1287 /* Pin it by setting load count to -1 */ 1288 LdrEntry->LoadCount = 0xFFFF; 1289 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN); 1290 } 1291 else 1292 { 1293 /* Increase its load count by one */ 1294 LdrEntry->LoadCount++; 1295 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 1296 } 1297 1298 /* Clear load in progress */ 1299 LdrpClearLoadInProgress(); 1300 } 1301 } 1302 else 1303 { 1304 /* There was an error getting this module's handle, return invalid param status */ 1305 Status = STATUS_INVALID_PARAMETER; 1306 } 1307 1308 quickie: 1309 /* Check for error case */ 1310 if (!NT_SUCCESS(Status)) 1311 { 1312 /* Print debug information */ 1313 if ((ShowSnaps) || ((Status != STATUS_NO_SUCH_FILE) && 1314 (Status != STATUS_DLL_NOT_FOUND) && 1315 (Status != STATUS_OBJECT_NAME_NOT_FOUND))) 1316 { 1317 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress, Status); 1318 } 1319 } 1320 1321 /* Release the lock if needed */ 1322 if (Locked) LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 1323 return Status; 1324 } 1325 1326 /* 1327 * @implemented 1328 */ 1329 NTSTATUS 1330 NTAPI 1331 LdrUnloadDll( 1332 _In_ PVOID BaseAddress) 1333 { 1334 NTSTATUS Status = STATUS_SUCCESS; 1335 PPEB Peb = NtCurrentPeb(); 1336 PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry; 1337 PVOID EntryPoint; 1338 PLIST_ENTRY NextEntry; 1339 LIST_ENTRY UnloadList; 1340 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; 1341 PVOID CorImageData; 1342 ULONG ComSectionSize; 1343 1344 /* Get the LDR Lock */ 1345 if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock); 1346 1347 /* Increase the unload count */ 1348 LdrpActiveUnloadCount++; 1349 1350 /* Skip unload */ 1351 if (LdrpShutdownInProgress) goto Quickie; 1352 1353 /* Make sure the DLL is valid and get its entry */ 1354 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 1355 { 1356 Status = STATUS_DLL_NOT_FOUND; 1357 goto Quickie; 1358 } 1359 1360 /* Check the current Load Count */ 1361 if (LdrEntry->LoadCount != 0xFFFF) 1362 { 1363 /* Decrease it */ 1364 LdrEntry->LoadCount--; 1365 1366 /* If it's a dll */ 1367 if (LdrEntry->Flags & LDRP_IMAGE_DLL) 1368 { 1369 /* Set up the Act Ctx */ 1370 ActCtx.Size = sizeof(ActCtx); 1371 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 1372 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); 1373 1374 /* Activate the ActCtx */ 1375 RtlActivateActivationContextUnsafeFast(&ActCtx, 1376 LdrEntry->EntryPointActivationContext); 1377 1378 /* Update the load count */ 1379 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT); 1380 1381 /* Release the context */ 1382 RtlDeactivateActivationContextUnsafeFast(&ActCtx); 1383 } 1384 } 1385 else 1386 { 1387 /* The DLL is locked */ 1388 goto Quickie; 1389 } 1390 1391 /* Show debug message */ 1392 if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n"); 1393 1394 /* Check if this is our only unload and initialize the list if so */ 1395 if (LdrpActiveUnloadCount == 1) InitializeListHead(&LdrpUnloadHead); 1396 1397 /* Loop the modules to build the list */ 1398 NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink; 1399 while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList) 1400 { 1401 /* Get the entry */ 1402 LdrEntry = CONTAINING_RECORD(NextEntry, 1403 LDR_DATA_TABLE_ENTRY, 1404 InInitializationOrderLinks); 1405 NextEntry = NextEntry->Blink; 1406 1407 /* Remove flag */ 1408 LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS; 1409 1410 /* If the load count is now 0 */ 1411 if (!LdrEntry->LoadCount) 1412 { 1413 /* Show message */ 1414 if (ShowSnaps) 1415 { 1416 DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n", 1417 LdrpActiveUnloadCount, 1418 LdrEntry->BaseDllName.Buffer, 1419 LdrEntry->FullDllName.Buffer, 1420 (ULONG)LdrEntry->LoadCount, 1421 LdrEntry->EntryPoint); 1422 } 1423 1424 /* Call Shim Engine and notify */ 1425 if (g_ShimsEnabled) 1426 { 1427 VOID (NTAPI* SE_DllUnloaded)(PVOID) = RtlDecodeSystemPointer(g_pfnSE_DllUnloaded); 1428 SE_DllUnloaded(LdrEntry); 1429 } 1430 1431 /* Unlink it */ 1432 CurrentEntry = LdrEntry; 1433 RemoveEntryList(&CurrentEntry->InInitializationOrderLinks); 1434 RemoveEntryList(&CurrentEntry->InMemoryOrderLinks); 1435 RemoveEntryList(&CurrentEntry->HashLinks); 1436 1437 /* If there's more then one active unload */ 1438 if (LdrpActiveUnloadCount > 1) 1439 { 1440 /* Flush the cached DLL handle and clear the list */ 1441 LdrpLoadedDllHandleCache = NULL; 1442 CurrentEntry->InMemoryOrderLinks.Flink = NULL; 1443 } 1444 1445 /* Add the entry on the unload list */ 1446 InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks); 1447 } 1448 } 1449 1450 /* Only call the entrypoints once */ 1451 if (LdrpActiveUnloadCount > 1) goto Quickie; 1452 1453 /* Now loop the unload list and create our own */ 1454 InitializeListHead(&UnloadList); 1455 CurrentEntry = NULL; 1456 NextEntry = LdrpUnloadHead.Flink; 1457 while (NextEntry != &LdrpUnloadHead) 1458 { 1459 /* Get the current entry */ 1460 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 1461 1462 LdrpRecordUnloadEvent(LdrEntry); 1463 1464 /* Set the entry and clear it from the list */ 1465 CurrentEntry = LdrEntry; 1466 LdrpLoadedDllHandleCache = NULL; 1467 CurrentEntry->InMemoryOrderLinks.Flink = NULL; 1468 1469 /* Move it from the global to the local list */ 1470 RemoveEntryList(&CurrentEntry->HashLinks); 1471 InsertTailList(&UnloadList, &CurrentEntry->HashLinks); 1472 1473 /* Get the entrypoint */ 1474 EntryPoint = LdrEntry->EntryPoint; 1475 1476 /* Check if we should call it */ 1477 if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED)) 1478 { 1479 /* Show message */ 1480 if (ShowSnaps) 1481 { 1482 DPRINT1("LDR: Calling deinit %p\n", EntryPoint); 1483 } 1484 1485 /* Set up the Act Ctx */ 1486 ActCtx.Size = sizeof(ActCtx); 1487 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 1488 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); 1489 1490 /* Activate the ActCtx */ 1491 RtlActivateActivationContextUnsafeFast(&ActCtx, 1492 LdrEntry->EntryPointActivationContext); 1493 1494 /* Call the entrypoint */ 1495 _SEH2_TRY 1496 { 1497 LdrpCallInitRoutine(LdrEntry->EntryPoint, 1498 LdrEntry->DllBase, 1499 DLL_PROCESS_DETACH, 1500 NULL); 1501 } 1502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1503 { 1504 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n", 1505 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName); 1506 } 1507 _SEH2_END; 1508 1509 /* Release the context */ 1510 RtlDeactivateActivationContextUnsafeFast(&ActCtx); 1511 } 1512 1513 /* Remove it from the list */ 1514 RemoveEntryList(&CurrentEntry->InLoadOrderLinks); 1515 CurrentEntry = NULL; 1516 NextEntry = LdrpUnloadHead.Flink; 1517 } 1518 1519 /* Now loop our local list */ 1520 NextEntry = UnloadList.Flink; 1521 while (NextEntry != &UnloadList) 1522 { 1523 /* Get the entry */ 1524 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 1525 NextEntry = NextEntry->Flink; 1526 CurrentEntry = LdrEntry; 1527 1528 /* Notify Application Verifier */ 1529 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) 1530 { 1531 AVrfDllUnloadNotification(LdrEntry); 1532 } 1533 1534 /* Show message */ 1535 if (ShowSnaps) 1536 { 1537 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer); 1538 } 1539 1540 /* Check if this is a .NET executable */ 1541 CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 1542 TRUE, 1543 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, 1544 &ComSectionSize); 1545 if (CorImageData) 1546 { 1547 /* FIXME */ 1548 DPRINT1(".NET Images are not supported yet\n"); 1549 } 1550 1551 /* Check if we should unmap*/ 1552 if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP)) 1553 { 1554 /* Unmap the DLL */ 1555 Status = NtUnmapViewOfSection(NtCurrentProcess(), 1556 CurrentEntry->DllBase); 1557 ASSERT(NT_SUCCESS(Status)); 1558 } 1559 1560 /* Unload the alternate resource module, if any */ 1561 LdrUnloadAlternateResourceModule(CurrentEntry->DllBase); 1562 1563 /* FIXME: Send shutdown notification */ 1564 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress); 1565 1566 /* Check if a Hotpatch is active */ 1567 if (LdrEntry->PatchInformation) 1568 { 1569 /* FIXME */ 1570 DPRINT1("We don't support Hotpatching yet\n"); 1571 } 1572 1573 /* Deallocate the Entry */ 1574 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry); 1575 1576 /* If this is the cached entry, invalidate it */ 1577 if (LdrpGetModuleHandleCache == CurrentEntry) 1578 { 1579 LdrpGetModuleHandleCache = NULL; 1580 } 1581 } 1582 1583 Quickie: 1584 /* Decrease unload count */ 1585 LdrpActiveUnloadCount--; 1586 if (!LdrpInLdrInit) RtlLeaveCriticalSection(Peb->LoaderLock); 1587 1588 /* Return to caller */ 1589 return Status; 1590 } 1591 1592 /* 1593 * @implemented 1594 */ 1595 BOOLEAN 1596 NTAPI 1597 RtlDllShutdownInProgress(VOID) 1598 { 1599 /* Return the internal global */ 1600 return LdrpShutdownInProgress; 1601 } 1602 1603 /* 1604 * @implemented 1605 */ 1606 PIMAGE_BASE_RELOCATION 1607 NTAPI 1608 LdrProcessRelocationBlock( 1609 _In_ ULONG_PTR Address, 1610 _In_ ULONG Count, 1611 _In_ PUSHORT TypeOffset, 1612 _In_ LONG_PTR Delta) 1613 { 1614 return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta); 1615 } 1616 1617 /* FIXME: Add to ntstatus.mc */ 1618 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L) 1619 1620 /* 1621 * @implemented 1622 */ 1623 NTSTATUS 1624 NTAPI 1625 LdrLoadAlternateResourceModule( 1626 _In_ PVOID Module, 1627 _In_ PWSTR Buffer) 1628 { 1629 /* Is MUI Support enabled? */ 1630 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS; 1631 1632 UNIMPLEMENTED; 1633 return STATUS_MUI_FILE_NOT_FOUND; 1634 } 1635 1636 /* 1637 * @implemented 1638 */ 1639 BOOLEAN 1640 NTAPI 1641 LdrUnloadAlternateResourceModule( 1642 _In_ PVOID BaseAddress) 1643 { 1644 ULONG_PTR Cookie; 1645 1646 /* Acquire the loader lock */ 1647 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie); 1648 1649 /* Check if there's any alternate resources loaded */ 1650 if (AlternateResourceModuleCount) 1651 { 1652 UNIMPLEMENTED; 1653 } 1654 1655 /* Release the loader lock */ 1656 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 1657 1658 /* All done */ 1659 return TRUE; 1660 } 1661 1662 /* 1663 * @unimplemented 1664 */ 1665 BOOLEAN 1666 NTAPI 1667 LdrFlushAlternateResourceModules(VOID) 1668 { 1669 UNIMPLEMENTED; 1670 return FALSE; 1671 } 1672 1673 /* 1674 * @unimplemented 1675 * See https://www.kernelmode.info/forum/viewtopic.php?t=991 1676 */ 1677 NTSTATUS 1678 NTAPI 1679 LdrSetAppCompatDllRedirectionCallback( 1680 _In_ ULONG Flags, 1681 _In_ PLDR_APP_COMPAT_DLL_REDIRECTION_CALLBACK_FUNCTION CallbackFunction, 1682 _In_opt_ PVOID CallbackData) 1683 { 1684 UNIMPLEMENTED; 1685 return STATUS_NOT_IMPLEMENTED; 1686 } 1687 1688 BOOLEAN 1689 NTAPI 1690 LdrInitShimEngineDynamic(IN PVOID BaseAddress) 1691 { 1692 ULONG_PTR Cookie; 1693 NTSTATUS Status = LdrLockLoaderLock(0, NULL, &Cookie); 1694 if (NT_SUCCESS(Status)) 1695 { 1696 if (!g_pShimEngineModule) 1697 { 1698 g_pShimEngineModule = BaseAddress; 1699 LdrpGetShimEngineInterface(); 1700 } 1701 LdrUnlockLoaderLock(0, Cookie); 1702 return TRUE; 1703 } 1704 return FALSE; 1705 } 1706 1707 /* EOF */ 1708