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