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