1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: lib/ntdll/ldr/ldrpe.c 5 * PURPOSE: Loader Functions dealing low-level PE Format structures 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntdll.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine; 19 ULONG LdrpNormalSnap; 20 21 /* FUNCTIONS *****************************************************************/ 22 23 24 NTSTATUS 25 NTAPI 26 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry, 27 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry, 28 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry, 29 IN BOOLEAN EntriesValid) 30 { 31 PVOID Iat; 32 NTSTATUS Status; 33 PIMAGE_THUNK_DATA OriginalThunk, FirstThunk; 34 PIMAGE_NT_HEADERS NtHeader; 35 PIMAGE_SECTION_HEADER SectionHeader; 36 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 37 LPSTR ImportName; 38 ULONG ForwarderChain, i, Rva, OldProtect, IatSize, ExportSize; 39 SIZE_T ImportSize; 40 DPRINT("LdrpSnapIAT(%wZ %wZ %p %u)\n", &ExportLdrEntry->BaseDllName, &ImportLdrEntry->BaseDllName, IatEntry, EntriesValid); 41 42 /* Get export directory */ 43 ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase, 44 TRUE, 45 IMAGE_DIRECTORY_ENTRY_EXPORT, 46 &ExportSize); 47 48 /* Make sure it has one */ 49 if (!ExportDirectory) 50 { 51 /* Fail */ 52 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n", 53 &ExportLdrEntry->BaseDllName); 54 return STATUS_INVALID_IMAGE_FORMAT; 55 } 56 57 /* Get the IAT */ 58 Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase, 59 TRUE, 60 IMAGE_DIRECTORY_ENTRY_IAT, 61 &IatSize); 62 ImportSize = IatSize; 63 64 /* Check if we don't have one */ 65 if (!Iat) 66 { 67 /* Get the NT Header and the first section */ 68 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase); 69 if (!NtHeader) return STATUS_INVALID_IMAGE_FORMAT; 70 SectionHeader = IMAGE_FIRST_SECTION(NtHeader); 71 72 /* Get the RVA of the import directory */ 73 Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 74 75 /* Make sure we got one */ 76 if (Rva) 77 { 78 /* Loop all the sections */ 79 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++) 80 { 81 /* Check if we are inside this section */ 82 if ((Rva >= SectionHeader->VirtualAddress) && 83 (Rva < (SectionHeader->VirtualAddress + 84 SectionHeader->SizeOfRawData))) 85 { 86 /* We are, so set the IAT here */ 87 Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) + 88 SectionHeader->VirtualAddress); 89 90 /* Set the size */ 91 IatSize = SectionHeader->Misc.VirtualSize; 92 93 /* Deal with Watcom and other retarded compilers */ 94 if (!IatSize) IatSize = SectionHeader->SizeOfRawData; 95 96 /* Found it, get out */ 97 break; 98 } 99 100 /* No match, move to the next section */ 101 SectionHeader++; 102 } 103 } 104 105 /* If we still don't have an IAT, that's bad */ 106 if (!Iat) 107 { 108 /* Fail */ 109 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n", 110 &ImportLdrEntry->BaseDllName, 111 ImportLdrEntry->DllBase); 112 return STATUS_INVALID_IMAGE_FORMAT; 113 } 114 115 /* Set the right size */ 116 ImportSize = IatSize; 117 } 118 119 /* Unprotect the IAT */ 120 Status = NtProtectVirtualMemory(NtCurrentProcess(), 121 &Iat, 122 &ImportSize, 123 PAGE_READWRITE, 124 &OldProtect); 125 if (!NT_SUCCESS(Status)) 126 { 127 /* Fail */ 128 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n", 129 &ImportLdrEntry->BaseDllName, 130 Status); 131 return Status; 132 } 133 134 /* Check if the Thunks are already valid */ 135 if (EntriesValid) 136 { 137 /* We'll only do forwarders. Get the import name */ 138 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name); 139 140 /* Get the list of forwarders */ 141 ForwarderChain = IatEntry->ForwarderChain; 142 143 /* Loop them */ 144 while (ForwarderChain != -1) 145 { 146 /* Get the cached thunk VA*/ 147 OriginalThunk = (PIMAGE_THUNK_DATA) 148 ((ULONG_PTR)ImportLdrEntry->DllBase + 149 IatEntry->OriginalFirstThunk + 150 (ForwarderChain * sizeof(IMAGE_THUNK_DATA))); 151 152 /* Get the first thunk */ 153 FirstThunk = (PIMAGE_THUNK_DATA) 154 ((ULONG_PTR)ImportLdrEntry->DllBase + 155 IatEntry->FirstThunk + 156 (ForwarderChain * sizeof(IMAGE_THUNK_DATA))); 157 158 /* Get the Forwarder from the thunk */ 159 ForwarderChain = (ULONG)FirstThunk->u1.Ordinal; 160 161 /* Snap the thunk */ 162 _SEH2_TRY 163 { 164 Status = LdrpSnapThunk(ExportLdrEntry->DllBase, 165 ImportLdrEntry->DllBase, 166 OriginalThunk, 167 FirstThunk, 168 ExportDirectory, 169 ExportSize, 170 TRUE, 171 ImportName); 172 173 /* Move to the next thunk */ 174 FirstThunk++; 175 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 176 { 177 /* Fail with the SEH error */ 178 Status = _SEH2_GetExceptionCode(); 179 } _SEH2_END; 180 181 /* If we messed up, exit */ 182 if (!NT_SUCCESS(Status)) break; 183 } 184 } 185 else if (IatEntry->FirstThunk) 186 { 187 /* Full snapping. Get the First thunk */ 188 FirstThunk = (PIMAGE_THUNK_DATA) 189 ((ULONG_PTR)ImportLdrEntry->DllBase + 190 IatEntry->FirstThunk); 191 192 /* Get the NT Header */ 193 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase); 194 195 /* Get the Original thunk VA, watch out for weird images */ 196 if ((IatEntry->Characteristics < NtHeader->OptionalHeader.SizeOfHeaders) || 197 (IatEntry->Characteristics >= NtHeader->OptionalHeader.SizeOfImage)) 198 { 199 /* Refuse it, this is a strange linked file */ 200 OriginalThunk = FirstThunk; 201 } 202 else 203 { 204 /* Get the address from the field and convert to VA */ 205 OriginalThunk = (PIMAGE_THUNK_DATA) 206 ((ULONG_PTR)ImportLdrEntry->DllBase + 207 IatEntry->OriginalFirstThunk); 208 } 209 210 /* Get the Import name VA */ 211 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + 212 IatEntry->Name); 213 214 /* Loop while it's valid */ 215 while (OriginalThunk->u1.AddressOfData) 216 { 217 /* Snap the Thunk */ 218 _SEH2_TRY 219 { 220 Status = LdrpSnapThunk(ExportLdrEntry->DllBase, 221 ImportLdrEntry->DllBase, 222 OriginalThunk, 223 FirstThunk, 224 ExportDirectory, 225 ExportSize, 226 TRUE, 227 ImportName); 228 229 /* Next thunks */ 230 OriginalThunk++; 231 FirstThunk++; 232 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 233 { 234 /* Fail with the SEH error */ 235 Status = _SEH2_GetExceptionCode(); 236 } _SEH2_END; 237 238 /* If we failed the snap, break out */ 239 if (!NT_SUCCESS(Status)) break; 240 } 241 } 242 243 /* Protect the IAT again */ 244 NtProtectVirtualMemory(NtCurrentProcess(), 245 &Iat, 246 &ImportSize, 247 OldProtect, 248 &OldProtect); 249 250 /* Also flush out the cache */ 251 NtFlushInstructionCache(NtCurrentProcess(), Iat, IatSize); 252 253 /* Return to Caller */ 254 return Status; 255 } 256 257 NTSTATUS 258 NTAPI 259 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, 260 IN PLDR_DATA_TABLE_ENTRY LdrEntry, 261 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR *BoundEntryPtr, 262 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry) 263 { 264 LPSTR ImportName = NULL, BoundImportName, ForwarderName; 265 NTSTATUS Status; 266 BOOLEAN AlreadyLoaded = FALSE, Stale; 267 PIMAGE_IMPORT_DESCRIPTOR ImportEntry; 268 PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry; 269 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry; 270 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry; 271 PPEB Peb = NtCurrentPeb(); 272 ULONG i, IatSize; 273 274 /* Get the pointer to the bound entry */ 275 BoundEntry = *BoundEntryPtr; 276 277 /* Get the name's VA */ 278 BoundImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName; 279 280 /* Show debug message */ 281 if (ShowSnaps) 282 { 283 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry->BaseDllName, BoundImportName); 284 } 285 286 /* Load the module for this entry */ 287 Status = LdrpLoadImportModule(DllPath, 288 BoundImportName, 289 &DllLdrEntry, 290 &AlreadyLoaded); 291 if (!NT_SUCCESS(Status)) 292 { 293 /* Show debug message */ 294 if (ShowSnaps) 295 { 296 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n", 297 &LdrEntry->BaseDllName, 298 BoundImportName, 299 Status); 300 } 301 goto Quickie; 302 } 303 304 /* Check if it wasn't already loaded */ 305 if (!AlreadyLoaded) 306 { 307 /* Add it to our list */ 308 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 309 &DllLdrEntry->InInitializationOrderLinks); 310 } 311 312 /* Check if the Bound Entry is now invalid */ 313 if ((BoundEntry->TimeDateStamp != DllLdrEntry->TimeDateStamp) || 314 (DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)) 315 { 316 /* Show debug message */ 317 if (ShowSnaps) 318 { 319 DPRINT1("LDR: %wZ has stale binding to %s\n", 320 &LdrEntry->BaseDllName, 321 BoundImportName); 322 } 323 324 /* Remember it's become stale */ 325 Stale = TRUE; 326 } 327 else 328 { 329 /* Show debug message */ 330 if (ShowSnaps) 331 { 332 DPRINT1("LDR: %wZ has correct binding to %s\n", 333 &LdrEntry->BaseDllName, 334 BoundImportName); 335 } 336 337 /* Remember it's valid */ 338 Stale = FALSE; 339 } 340 341 /* Get the forwarders */ 342 ForwarderEntry = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1); 343 344 /* Loop them */ 345 for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++) 346 { 347 /* Get the name */ 348 ForwarderName = (LPSTR)FirstEntry + ForwarderEntry->OffsetModuleName; 349 350 /* Show debug message */ 351 if (ShowSnaps) 352 { 353 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n", 354 &LdrEntry->BaseDllName, 355 ForwarderName, 356 &DllLdrEntry->BaseDllName); 357 } 358 359 /* Load the module */ 360 Status = LdrpLoadImportModule(DllPath, 361 ForwarderName, 362 &ForwarderLdrEntry, 363 &AlreadyLoaded); 364 if (NT_SUCCESS(Status)) 365 { 366 /* Loaded it, was it already loaded? */ 367 if (!AlreadyLoaded) 368 { 369 /* Add it to our list */ 370 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 371 &ForwarderLdrEntry->InInitializationOrderLinks); 372 } 373 } 374 375 /* Check if the Bound Entry is now invalid */ 376 if (!(NT_SUCCESS(Status)) || 377 (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) || 378 (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)) 379 { 380 /* Show debug message */ 381 if (ShowSnaps) 382 { 383 DPRINT1("LDR: %wZ has stale binding to %s\n", 384 &LdrEntry->BaseDllName, 385 ForwarderName); 386 } 387 388 /* Remember it's become stale */ 389 Stale = TRUE; 390 } 391 else 392 { 393 /* Show debug message */ 394 if (ShowSnaps) 395 { 396 DPRINT1("LDR: %wZ has correct binding to %s\n", 397 &LdrEntry->BaseDllName, 398 ForwarderName); 399 } 400 401 /* Remember it's valid */ 402 Stale = FALSE; 403 } 404 405 /* Move to the next one */ 406 ForwarderEntry++; 407 } 408 409 /* Set the next bound entry to the forwarder */ 410 FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry; 411 412 /* Check if the binding was stale */ 413 if (Stale) 414 { 415 /* It was, so find the IAT entry for it */ 416 ++LdrpNormalSnap; 417 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 418 TRUE, 419 IMAGE_DIRECTORY_ENTRY_IMPORT, 420 &IatSize); 421 422 /* Make sure it has a name */ 423 while (ImportEntry->Name) 424 { 425 /* Get the name */ 426 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name); 427 428 /* Compare it */ 429 if (!_stricmp(ImportName, BoundImportName)) break; 430 431 /* Move to next entry */ 432 ImportEntry++; 433 } 434 435 /* If we didn't find a name, fail */ 436 if (!ImportEntry->Name) 437 { 438 /* Show debug message */ 439 if (ShowSnaps) 440 { 441 DPRINT1("LDR: LdrpWalkImportTable - failing with" 442 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n"); 443 } 444 445 /* Return error */ 446 Status = STATUS_OBJECT_NAME_INVALID; 447 goto Quickie; 448 } 449 450 /* Show debug message */ 451 if (ShowSnaps) 452 { 453 DPRINT1("LDR: Stale Bind %s from %wZ\n", 454 ImportName, 455 &LdrEntry->BaseDllName); 456 } 457 458 /* Snap the IAT Entry*/ 459 Status = LdrpSnapIAT(DllLdrEntry, 460 LdrEntry, 461 ImportEntry, 462 FALSE); 463 464 /* Make sure we didn't fail */ 465 if (!NT_SUCCESS(Status)) 466 { 467 /* Show debug message */ 468 if (ShowSnaps) 469 { 470 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n", 471 &LdrEntry->BaseDllName, 472 BoundImportName, 473 Status); 474 } 475 476 /* Return */ 477 goto Quickie; 478 } 479 } 480 481 /* All done */ 482 Status = STATUS_SUCCESS; 483 484 Quickie: 485 /* Write where we are now and return */ 486 *BoundEntryPtr = FirstEntry; 487 return Status; 488 } 489 490 NTSTATUS 491 NTAPI 492 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL, 493 IN PLDR_DATA_TABLE_ENTRY LdrEntry, 494 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry) 495 { 496 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry; 497 NTSTATUS Status; 498 499 /* Make sure we have a name */ 500 while (BoundEntry->OffsetModuleName) 501 { 502 /* Parse this descriptor */ 503 Status = LdrpHandleOneNewFormatImportDescriptor(DllPath, 504 LdrEntry, 505 &BoundEntry, 506 FirstEntry); 507 if (!NT_SUCCESS(Status)) return Status; 508 } 509 510 /* Done */ 511 return STATUS_SUCCESS; 512 } 513 514 NTSTATUS 515 NTAPI 516 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, 517 IN PLDR_DATA_TABLE_ENTRY LdrEntry, 518 IN PIMAGE_IMPORT_DESCRIPTOR *ImportEntry) 519 { 520 LPSTR ImportName; 521 NTSTATUS Status; 522 BOOLEAN AlreadyLoaded = FALSE; 523 PLDR_DATA_TABLE_ENTRY DllLdrEntry; 524 PIMAGE_THUNK_DATA FirstThunk; 525 PPEB Peb = NtCurrentPeb(); 526 527 /* Get the import name's VA */ 528 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + (*ImportEntry)->Name); 529 530 /* Get the first thunk */ 531 FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase + 532 (*ImportEntry)->FirstThunk); 533 534 /* Make sure it's valid */ 535 if (!FirstThunk->u1.Function) goto SkipEntry; 536 537 /* Show debug message */ 538 if (ShowSnaps) 539 { 540 DPRINT1("LDR: %s used by %wZ\n", 541 ImportName, 542 &LdrEntry->BaseDllName); 543 } 544 545 /* Load the module associated to it */ 546 Status = LdrpLoadImportModule(DllPath, 547 ImportName, 548 &DllLdrEntry, 549 &AlreadyLoaded); 550 if (!NT_SUCCESS(Status)) 551 { 552 /* Fail */ 553 if (ShowSnaps) 554 { 555 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed " 556 "on import %s with status %x\n", 557 ImportName, 558 Status); 559 } 560 561 /* Return */ 562 return Status; 563 } 564 565 /* Show debug message */ 566 if (ShowSnaps) 567 { 568 DPRINT1("LDR: Snapping imports for %wZ from %s\n", 569 &LdrEntry->BaseDllName, 570 ImportName); 571 } 572 573 /* Check if it wasn't already loaded */ 574 ++LdrpNormalSnap; 575 if (!AlreadyLoaded) 576 { 577 /* Add the DLL to our list */ 578 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 579 &DllLdrEntry->InInitializationOrderLinks); 580 } 581 582 /* Now snap the IAT Entry */ 583 Status = LdrpSnapIAT(DllLdrEntry, LdrEntry, *ImportEntry, FALSE); 584 if (!NT_SUCCESS(Status)) 585 { 586 /* Fail */ 587 if (ShowSnaps) 588 { 589 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with " 590 "status %x\n", 591 Status); 592 } 593 594 /* Return */ 595 return Status; 596 } 597 598 SkipEntry: 599 /* Move on */ 600 (*ImportEntry)++; 601 return STATUS_SUCCESS; 602 } 603 604 NTSTATUS 605 NTAPI 606 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL, 607 IN PLDR_DATA_TABLE_ENTRY LdrEntry, 608 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry) 609 { 610 NTSTATUS Status; 611 612 /* Check for Name and Thunk */ 613 while ((ImportEntry->Name) && (ImportEntry->FirstThunk)) 614 { 615 /* Parse this descriptor */ 616 Status = LdrpHandleOneOldFormatImportDescriptor(DllPath, 617 LdrEntry, 618 &ImportEntry); 619 if (!NT_SUCCESS(Status)) return Status; 620 } 621 622 /* Done */ 623 return STATUS_SUCCESS; 624 } 625 626 USHORT 627 NTAPI 628 LdrpNameToOrdinal(IN LPSTR ImportName, 629 IN ULONG NumberOfNames, 630 IN PVOID ExportBase, 631 IN PULONG NameTable, 632 IN PUSHORT OrdinalTable) 633 { 634 LONG Start, End, Next, CmpResult; 635 636 /* Use classical binary search to find the ordinal */ 637 Start = Next = 0; 638 End = NumberOfNames - 1; 639 while (End >= Start) 640 { 641 /* Next will be exactly between Start and End */ 642 Next = (Start + End) >> 1; 643 644 /* Compare this name with the one we need to find */ 645 CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next])); 646 647 /* We found our entry if result is 0 */ 648 if (!CmpResult) break; 649 650 /* We didn't find, update our range then */ 651 if (CmpResult < 0) 652 { 653 End = Next - 1; 654 } 655 else if (CmpResult > 0) 656 { 657 Start = Next + 1; 658 } 659 } 660 661 /* If end is before start, then the search failed */ 662 if (End < Start) return -1; 663 664 /* Return found name */ 665 return OrdinalTable[Next]; 666 } 667 668 NTSTATUS 669 NTAPI 670 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL, 671 IN PLDR_DATA_TABLE_ENTRY LdrEntry) 672 { 673 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; 674 PPEB Peb = NtCurrentPeb(); 675 NTSTATUS Status = STATUS_SUCCESS, Status2; 676 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL; 677 PIMAGE_IMPORT_DESCRIPTOR ImportEntry; 678 ULONG BoundSize, IatSize; 679 680 DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry->BaseDllName, LdrEntry, DllPath); 681 682 /* Set up the Act Ctx */ 683 RtlZeroMemory(&ActCtx, sizeof(ActCtx)); 684 ActCtx.Size = sizeof(ActCtx); 685 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 686 687 /* Check if we have a manifest prober routine */ 688 if (LdrpManifestProberRoutine) 689 { 690 /* Probe the DLL for its manifest. Some details are omitted */ 691 Status2 = LdrpManifestProberRoutine(LdrEntry->DllBase, LdrEntry->FullDllName.Buffer, &LdrEntry->EntryPointActivationContext); 692 693 if (!NT_SUCCESS(Status2) && 694 Status2 != STATUS_NO_SUCH_FILE && 695 Status2 != STATUS_RESOURCE_DATA_NOT_FOUND && 696 Status2 != STATUS_RESOURCE_TYPE_NOT_FOUND && 697 Status2 != STATUS_RESOURCE_NAME_NOT_FOUND && 698 Status2 != STATUS_RESOURCE_LANG_NOT_FOUND) 699 { 700 /* Some serious issue */ 701 //Status = Status2; // FIXME: Ignore that error for now 702 DbgPrintEx(DPFLTR_SXS_ID, 703 DPFLTR_WARNING_LEVEL, 704 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its " 705 "manifest, ntstatus = 0x%08lx\n", 706 &LdrEntry->FullDllName, Status2); 707 } 708 } 709 710 /* Check if we failed above */ 711 if (!NT_SUCCESS(Status)) return Status; 712 713 /* Get the Active ActCtx */ 714 if (!LdrEntry->EntryPointActivationContext) 715 { 716 Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext); 717 718 if (!NT_SUCCESS(Status)) 719 { 720 /* Exit */ 721 DbgPrintEx(DPFLTR_SXS_ID, 722 DPFLTR_WARNING_LEVEL, 723 "LDR: RtlGetActiveActivationContext() failed; ntstatus = " 724 "0x%08lx\n", 725 Status); 726 return Status; 727 } 728 } 729 730 /* Activate the ActCtx */ 731 RtlActivateActivationContextUnsafeFast(&ActCtx, 732 LdrEntry->EntryPointActivationContext); 733 734 /* Check if we were redirected */ 735 if (!(LdrEntry->Flags & LDRP_REDIRECTED)) 736 { 737 /* Get the Bound IAT */ 738 BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 739 TRUE, 740 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, 741 &BoundSize); 742 } 743 744 /* Get the regular IAT, for fallback */ 745 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 746 TRUE, 747 IMAGE_DIRECTORY_ENTRY_IMPORT, 748 &IatSize); 749 750 /* Check if we got at least one */ 751 if ((BoundEntry) || (ImportEntry)) 752 { 753 /* Do we have a Bound IAT */ 754 if (BoundEntry) 755 { 756 /* Handle the descriptor */ 757 Status = LdrpHandleNewFormatImportDescriptors(DllPath, 758 LdrEntry, 759 BoundEntry); 760 } 761 else 762 { 763 /* Handle the descriptor */ 764 Status = LdrpHandleOldFormatImportDescriptors(DllPath, 765 LdrEntry, 766 ImportEntry); 767 } 768 769 /* Check the status of the handlers */ 770 if (NT_SUCCESS(Status)) 771 { 772 /* Check for Per-DLL Heap Tagging */ 773 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL) 774 { 775 /* FIXME */ 776 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n"); 777 } 778 779 /* Check if Page Heap was enabled */ 780 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS) 781 { 782 /* Initialize target DLL */ 783 AVrfPageHeapDllNotification(LdrEntry); 784 } 785 786 /* Check if Application Verifier was enabled */ 787 if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER) 788 { 789 AVrfDllLoadNotification(LdrEntry); 790 } 791 792 /* Just to be safe */ 793 Status = STATUS_SUCCESS; 794 } 795 } 796 797 /* Release the activation context */ 798 RtlDeactivateActivationContextUnsafeFast(&ActCtx); 799 800 DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry->BaseDllName, LdrEntry); 801 802 /* Return status */ 803 return Status; 804 } 805 806 NTSTATUS 807 NTAPI 808 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL, 809 IN LPSTR ImportName, 810 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry, 811 OUT PBOOLEAN Existing) 812 { 813 ANSI_STRING AnsiString; 814 PUNICODE_STRING ImpDescName; 815 const WCHAR *p; 816 BOOLEAN GotExtension; 817 WCHAR c; 818 NTSTATUS Status; 819 PPEB Peb = RtlGetCurrentPeb(); 820 PTEB Teb = NtCurrentTeb(); 821 UNICODE_STRING RedirectedImpDescName; 822 BOOLEAN RedirectedDll; 823 824 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p)\n", DllPath, ImportName, DataTableEntry, Existing); 825 826 RedirectedDll = FALSE; 827 RtlInitEmptyUnicodeString(&RedirectedImpDescName, NULL, 0); 828 829 /* Convert import descriptor name to unicode string */ 830 ImpDescName = &Teb->StaticUnicodeString; 831 RtlInitAnsiString(&AnsiString, ImportName); 832 Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE); 833 if (!NT_SUCCESS(Status)) return Status; 834 835 /* Find the extension, if present */ 836 p = ImpDescName->Buffer + ImpDescName->Length / sizeof(WCHAR) - 1; 837 GotExtension = FALSE; 838 while (p >= ImpDescName->Buffer) 839 { 840 c = *p--; 841 if (c == L'.') 842 { 843 GotExtension = TRUE; 844 break; 845 } 846 else if (c == L'\\') 847 { 848 break; 849 } 850 } 851 852 /* If no extension was found, add the default extension */ 853 if (!GotExtension) 854 { 855 /* Check that we have space to add one */ 856 if ((ImpDescName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >= 857 sizeof(Teb->StaticUnicodeBuffer)) 858 { 859 /* No space to add the extension */ 860 DbgPrintEx(DPFLTR_LDR_ID, 861 DPFLTR_ERROR_LEVEL, 862 "LDR: %s - Dll name missing extension; with extension " 863 "added the name is too long\n" 864 " ImpDescName: (@ %p) \"%wZ\"\n" 865 " ImpDescName->Length: %u\n", 866 __FUNCTION__, 867 ImpDescName, 868 ImpDescName, 869 ImpDescName->Length); 870 return STATUS_NAME_TOO_LONG; 871 } 872 873 /* Add it. Needs to be null terminated, thus the length check above */ 874 (VOID)RtlAppendUnicodeStringToString(ImpDescName, 875 &LdrApiDefaultExtension); 876 } 877 878 /* Check if the SxS Assemblies specify another file */ 879 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 880 ImpDescName, 881 &LdrApiDefaultExtension, 882 NULL, 883 &RedirectedImpDescName, 884 &ImpDescName, 885 NULL, 886 NULL, 887 NULL); 888 889 /* Check success */ 890 if (NT_SUCCESS(Status)) 891 { 892 /* Let Ldrp know */ 893 RedirectedDll = TRUE; 894 } 895 else if (Status != STATUS_SXS_KEY_NOT_FOUND) 896 { 897 /* Unrecoverable SxS failure */ 898 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status, ImpDescName); 899 goto done; 900 } 901 902 /* Check if it's loaded */ 903 if (LdrpCheckForLoadedDll(DllPath, 904 ImpDescName, 905 TRUE, 906 RedirectedDll, 907 DataTableEntry)) 908 { 909 /* It's already existing in the list */ 910 *Existing = TRUE; 911 Status = STATUS_SUCCESS; 912 goto done; 913 } 914 915 /* We're loading it for the first time */ 916 *Existing = FALSE; 917 918 /* Map it */ 919 Status = LdrpMapDll(DllPath, 920 NULL, 921 ImpDescName->Buffer, 922 NULL, 923 TRUE, 924 RedirectedDll, 925 DataTableEntry); 926 if (!NT_SUCCESS(Status)) 927 { 928 DPRINT1("LDR: LdrpMapDll failed with status %x for dll %wZ\n", Status, ImpDescName); 929 goto done; 930 } 931 932 /* Walk its import descriptor table */ 933 Status = LdrpWalkImportDescriptor(DllPath, 934 *DataTableEntry); 935 if (!NT_SUCCESS(Status)) 936 { 937 /* Add it to the in-init-order list in case of failure */ 938 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 939 &(*DataTableEntry)->InInitializationOrderLinks); 940 } 941 942 done: 943 RtlFreeUnicodeString(&RedirectedImpDescName); 944 945 return Status; 946 } 947 948 NTSTATUS 949 NTAPI 950 LdrpSnapThunk(IN PVOID ExportBase, 951 IN PVOID ImportBase, 952 IN PIMAGE_THUNK_DATA OriginalThunk, 953 IN OUT PIMAGE_THUNK_DATA Thunk, 954 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 955 IN ULONG ExportSize, 956 IN BOOLEAN Static, 957 IN LPSTR DllName) 958 { 959 BOOLEAN IsOrdinal; 960 USHORT Ordinal; 961 ULONG OriginalOrdinal = 0; 962 PIMAGE_IMPORT_BY_NAME AddressOfData; 963 PULONG NameTable; 964 PUSHORT OrdinalTable; 965 LPSTR ImportName = NULL, DotPosition; 966 USHORT Hint; 967 NTSTATUS Status; 968 ULONG_PTR HardErrorParameters[3]; 969 UNICODE_STRING HardErrorDllName, HardErrorEntryPointName; 970 ANSI_STRING TempString; 971 ULONG Mask; 972 ULONG Response; 973 PULONG AddressOfFunctions; 974 UNICODE_STRING TempUString; 975 ANSI_STRING ForwarderName; 976 PANSI_STRING ForwardName; 977 PVOID ForwarderHandle; 978 ULONG ForwardOrdinal; 979 980 /* Check if the snap is by ordinal */ 981 if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal))) 982 { 983 /* Get the ordinal number, and its normalized version */ 984 OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal); 985 Ordinal = (USHORT)(OriginalOrdinal - ExportDirectory->Base); 986 } 987 else 988 { 989 /* First get the data VA */ 990 AddressOfData = (PIMAGE_IMPORT_BY_NAME) 991 ((ULONG_PTR)ImportBase + 992 ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff)); 993 994 /* Get the name */ 995 ImportName = (LPSTR)AddressOfData->Name; 996 997 /* Now get the VA of the Name and Ordinal Tables */ 998 NameTable = (PULONG)((ULONG_PTR)ExportBase + 999 (ULONG_PTR)ExportDirectory->AddressOfNames); 1000 OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase + 1001 (ULONG_PTR)ExportDirectory->AddressOfNameOrdinals); 1002 1003 /* Get the hint */ 1004 Hint = AddressOfData->Hint; 1005 1006 /* Try to get a match by using the hint */ 1007 if (((ULONG)Hint < ExportDirectory->NumberOfNames) && 1008 (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint]))))) 1009 { 1010 /* We got a match, get the Ordinal from the hint */ 1011 Ordinal = OrdinalTable[Hint]; 1012 } 1013 else 1014 { 1015 /* Well bummer, hint didn't work, do it the long way */ 1016 Ordinal = LdrpNameToOrdinal(ImportName, 1017 ExportDirectory->NumberOfNames, 1018 ExportBase, 1019 NameTable, 1020 OrdinalTable); 1021 } 1022 } 1023 1024 /* Check if the ordinal is invalid */ 1025 if ((ULONG)Ordinal >= ExportDirectory->NumberOfFunctions) 1026 { 1027 FailurePath: 1028 /* Is this a static snap? */ 1029 if (Static) 1030 { 1031 UNICODE_STRING SnapTarget; 1032 PLDR_DATA_TABLE_ENTRY LdrEntry; 1033 1034 /* What was the module we were searching in */ 1035 RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown"); 1036 1037 /* What was the module we were searching for */ 1038 if (LdrpCheckForLoadedDllHandle(ImportBase, &LdrEntry)) 1039 SnapTarget = LdrEntry->BaseDllName; 1040 else 1041 RtlInitUnicodeString(&SnapTarget, L"Unknown"); 1042 1043 /* Inform the debug log */ 1044 if (IsOrdinal) 1045 DPRINT1("Failed to snap ordinal %Z!0x%x for %wZ\n", &TempString, OriginalOrdinal, &SnapTarget); 1046 else 1047 DPRINT1("Failed to snap %Z!%s for %wZ\n", &TempString, ImportName, &SnapTarget); 1048 1049 /* These are critical errors. Setup a string for the DLL name */ 1050 RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE); 1051 1052 /* Set it as the parameter */ 1053 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName; 1054 Mask = 2; 1055 1056 /* Check if we have an ordinal */ 1057 if (IsOrdinal) 1058 { 1059 /* Then set the ordinal as the 1st parameter */ 1060 HardErrorParameters[0] = OriginalOrdinal; 1061 } 1062 else 1063 { 1064 /* We don't, use the entrypoint. Set up a string for it */ 1065 RtlInitAnsiString(&TempString, ImportName); 1066 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName, 1067 &TempString, 1068 TRUE); 1069 1070 /* Set it as the parameter */ 1071 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName; 1072 Mask = 3; 1073 } 1074 1075 /* Raise the error */ 1076 NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND : 1077 STATUS_ENTRYPOINT_NOT_FOUND, 1078 2, 1079 Mask, 1080 HardErrorParameters, 1081 OptionOk, 1082 &Response); 1083 1084 /* Increase the error count */ 1085 if (LdrpInLdrInit) LdrpFatalHardErrorCount++; 1086 1087 /* Free our string */ 1088 RtlFreeUnicodeString(&HardErrorDllName); 1089 if (!IsOrdinal) 1090 { 1091 /* Free our second string. Return entrypoint error */ 1092 RtlFreeUnicodeString(&HardErrorEntryPointName); 1093 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND); 1094 } 1095 1096 /* Return ordinal error */ 1097 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND); 1098 } 1099 else 1100 { 1101 /* Inform the debug log */ 1102 if (IsOrdinal) 1103 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal); 1104 else 1105 DPRINT("Non-fatal: Failed to snap %s\n", ImportName); 1106 } 1107 1108 /* Set this as a bad DLL */ 1109 Thunk->u1.Function = (ULONG_PTR)0xffbadd11; 1110 1111 /* Return the right error code */ 1112 Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND : 1113 STATUS_ENTRYPOINT_NOT_FOUND; 1114 } 1115 else 1116 { 1117 /* The ordinal seems correct, get the AddressOfFunctions VA */ 1118 AddressOfFunctions = (PULONG) 1119 ((ULONG_PTR)ExportBase + 1120 (ULONG_PTR)ExportDirectory->AddressOfFunctions); 1121 1122 /* Write the function pointer*/ 1123 Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal]; 1124 1125 /* Make sure it's within the exports */ 1126 if ((Thunk->u1.Function > (ULONG_PTR)ExportDirectory) && 1127 (Thunk->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize))) 1128 { 1129 /* Get the Import and Forwarder Names */ 1130 ImportName = (LPSTR)Thunk->u1.Function; 1131 1132 DotPosition = strchr(ImportName, '.'); 1133 ASSERT(DotPosition != NULL); 1134 if (!DotPosition) 1135 goto FailurePath; 1136 1137 ForwarderName.Buffer = ImportName; 1138 ForwarderName.Length = (USHORT)(DotPosition - ImportName); 1139 ForwarderName.MaximumLength = ForwarderName.Length; 1140 Status = RtlAnsiStringToUnicodeString(&TempUString, 1141 &ForwarderName, 1142 TRUE); 1143 1144 /* Make sure the conversion was OK */ 1145 if (NT_SUCCESS(Status)) 1146 { 1147 WCHAR StringBuffer[MAX_PATH]; 1148 UNICODE_STRING StaticString, *RedirectedImportName; 1149 BOOLEAN Redirected = FALSE; 1150 1151 RtlInitEmptyUnicodeString(&StaticString, StringBuffer, sizeof(StringBuffer)); 1152 1153 /* Check if the SxS Assemblies specify another file */ 1154 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 1155 &TempUString, 1156 &LdrApiDefaultExtension, 1157 &StaticString, 1158 NULL, 1159 &RedirectedImportName, 1160 NULL, 1161 NULL, 1162 NULL); 1163 if (NT_SUCCESS(Status)) 1164 { 1165 if (ShowSnaps) 1166 { 1167 DPRINT1("LDR: %Z got redirected to %wZ\n", &ForwarderName, RedirectedImportName); 1168 } 1169 /* Let Ldrp know */ 1170 Redirected = TRUE; 1171 } 1172 else 1173 { 1174 RedirectedImportName = &TempUString; 1175 } 1176 1177 /* Load the forwarder */ 1178 Status = LdrpLoadDll(Redirected, 1179 NULL, 1180 NULL, 1181 RedirectedImportName, 1182 &ForwarderHandle, 1183 FALSE); 1184 1185 RtlFreeUnicodeString(&TempUString); 1186 } 1187 1188 /* If the load or conversion failed, use the failure path */ 1189 if (!NT_SUCCESS(Status)) goto FailurePath; 1190 1191 /* Now set up a name for the actual forwarder dll */ 1192 RtlInitAnsiString(&ForwarderName, 1193 ImportName + ForwarderName.Length + sizeof(CHAR)); 1194 1195 /* Check if it's an ordinal forward */ 1196 if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#')) 1197 { 1198 /* We don't have an actual function name */ 1199 ForwardName = NULL; 1200 1201 /* Convert the string into an ordinal */ 1202 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR), 1203 0, 1204 &ForwardOrdinal); 1205 1206 /* If this fails, then error out */ 1207 if (!NT_SUCCESS(Status)) goto FailurePath; 1208 } 1209 else 1210 { 1211 /* Import by name */ 1212 ForwardName = &ForwarderName; 1213 ForwardOrdinal = 0; 1214 } 1215 1216 /* Get the pointer */ 1217 Status = LdrpGetProcedureAddress(ForwarderHandle, 1218 ForwardName, 1219 ForwardOrdinal, 1220 (PVOID*)&Thunk->u1.Function, 1221 FALSE); 1222 /* If this fails, then error out */ 1223 if (!NT_SUCCESS(Status)) goto FailurePath; 1224 } 1225 else 1226 { 1227 /* It's not within the exports, let's hope it's valid */ 1228 if (!AddressOfFunctions[Ordinal]) goto FailurePath; 1229 } 1230 1231 /* If we got here, then it's success */ 1232 Status = STATUS_SUCCESS; 1233 } 1234 1235 /* Return status */ 1236 return Status; 1237 } 1238 1239 /* EOF */ 1240