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