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