1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NT User-Mode Library 4 * FILE: dll/ntdll/ldr/ldrutils.c 5 * PURPOSE: Internal Loader Utility Functions 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 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache, LdrpGetModuleHandleCache; 20 21 BOOLEAN g_ShimsEnabled; 22 PVOID g_pShimEngineModule; 23 PVOID g_pfnSE_DllLoaded; 24 PVOID g_pfnSE_DllUnloaded; 25 PVOID g_pfnSE_InstallBeforeInit; 26 PVOID g_pfnSE_InstallAfterInit; 27 PVOID g_pfnSE_ProcessDying; 28 29 /* FUNCTIONS *****************************************************************/ 30 31 NTSTATUS 32 NTAPI 33 LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut, 34 IN ULONG Length) 35 { 36 /* Sanity checks */ 37 ASSERT(StringOut); 38 ASSERT(Length <= UNICODE_STRING_MAX_BYTES); 39 40 /* Assume failure */ 41 StringOut->Length = 0; 42 43 /* Make sure it's not mis-aligned */ 44 if (Length & 1) 45 { 46 /* Fail */ 47 StringOut->Buffer = NULL; 48 StringOut->MaximumLength = 0; 49 return STATUS_INVALID_PARAMETER; 50 } 51 52 /* Allocate the string*/ 53 StringOut->Buffer = RtlAllocateHeap(LdrpHeap, 54 0, 55 Length + sizeof(WCHAR)); 56 if (!StringOut->Buffer) 57 { 58 /* Fail */ 59 StringOut->MaximumLength = 0; 60 return STATUS_NO_MEMORY; 61 } 62 63 /* Null-terminate it */ 64 StringOut->Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL; 65 66 /* Check if this is a maximum-sized string */ 67 if (Length != UNICODE_STRING_MAX_BYTES) 68 { 69 /* It's not, so set the maximum length to be one char more */ 70 StringOut->MaximumLength = (USHORT)Length + sizeof(UNICODE_NULL); 71 } 72 else 73 { 74 /* The length is already the maximum possible */ 75 StringOut->MaximumLength = UNICODE_STRING_MAX_BYTES; 76 } 77 78 /* Return success */ 79 return STATUS_SUCCESS; 80 } 81 82 VOID 83 NTAPI 84 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn) 85 { 86 ASSERT(StringIn != NULL); 87 88 /* If Buffer is not NULL - free it */ 89 if (StringIn->Buffer) 90 { 91 RtlFreeHeap(LdrpHeap, 0, StringIn->Buffer); 92 } 93 94 /* Zero it out */ 95 RtlInitEmptyUnicodeString(StringIn, NULL, 0); 96 } 97 98 BOOLEAN 99 NTAPI 100 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint, 101 IN PVOID BaseAddress, 102 IN ULONG Reason, 103 IN PVOID Context) 104 { 105 /* Call the entry */ 106 return EntryPoint(BaseAddress, Reason, Context); 107 } 108 109 /* NOTE: This function is broken */ 110 VOID 111 NTAPI 112 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 113 IN ULONG Flags, 114 OUT PUNICODE_STRING UpdateString) 115 { 116 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder; 117 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry; 118 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry; 119 PIMAGE_IMPORT_DESCRIPTOR ImportEntry; 120 PIMAGE_THUNK_DATA FirstThunk; 121 PLDR_DATA_TABLE_ENTRY Entry; 122 PUNICODE_STRING ImportNameUnic, RedirectedImportName; 123 ANSI_STRING ImportNameAnsi; 124 LPSTR ImportName; 125 ULONG ImportSize; 126 NTSTATUS Status; 127 ULONG i; 128 BOOLEAN RedirectedDll; 129 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; 130 131 /* Set up the Act Ctx */ 132 ActCtx.Size = sizeof(ActCtx); 133 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 134 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); 135 136 /* Activate the ActCtx */ 137 RtlActivateActivationContextUnsafeFast(&ActCtx, 138 LdrEntry->EntryPointActivationContext); 139 140 /* Check the action we need to perform */ 141 if ((Flags == LDRP_UPDATE_REFCOUNT) || (Flags == LDRP_UPDATE_PIN)) 142 { 143 /* Make sure entry is not being loaded already */ 144 if (LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS) 145 goto done; 146 147 LdrEntry->Flags |= LDRP_LOAD_IN_PROGRESS; 148 } 149 else if (Flags == LDRP_UPDATE_DEREFCOUNT) 150 { 151 /* Make sure the entry is not being unloaded already */ 152 if (LdrEntry->Flags & LDRP_UNLOAD_IN_PROGRESS) 153 goto done; 154 155 LdrEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS; 156 } 157 158 /* Go through all bound DLLs and dereference them */ 159 ImportNameUnic = &NtCurrentTeb()->StaticUnicodeString; 160 161 /* Try to get the new import entry */ 162 FirstEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 163 TRUE, 164 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, 165 &ImportSize); 166 167 if (FirstEntry) 168 { 169 /* Set entry flags if refing/derefing */ 170 if (Flags == LDRP_UPDATE_REFCOUNT) 171 LdrEntry->Flags |= LDRP_LOAD_IN_PROGRESS; 172 else if (Flags == LDRP_UPDATE_DEREFCOUNT) 173 LdrEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS; 174 175 BoundEntry = FirstEntry; 176 while (BoundEntry->OffsetModuleName) 177 { 178 /* Get pointer to the current import name */ 179 ImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName; 180 181 RtlInitAnsiString(&ImportNameAnsi, ImportName); 182 Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE); 183 184 if (NT_SUCCESS(Status)) 185 { 186 RedirectedDll = FALSE; 187 RedirectedImportName = ImportNameUnic; 188 189 /* Check if the SxS Assemblies specify another file */ 190 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 191 ImportNameUnic, 192 &LdrApiDefaultExtension, 193 UpdateString, 194 NULL, 195 &RedirectedImportName, 196 NULL, 197 NULL, 198 NULL); 199 200 /* Check success */ 201 if (NT_SUCCESS(Status)) 202 { 203 /* Let Ldrp know */ 204 if (ShowSnaps) 205 { 206 DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi, RedirectedImportName); 207 } 208 209 RedirectedDll = TRUE; 210 } 211 212 if (RedirectedDll || Status == STATUS_SXS_KEY_NOT_FOUND) 213 { 214 if (LdrpCheckForLoadedDll(NULL, 215 RedirectedImportName, 216 TRUE, 217 RedirectedDll, 218 &Entry)) 219 { 220 if (Entry->LoadCount != 0xFFFF) 221 { 222 /* Perform the required action */ 223 switch (Flags) 224 { 225 case LDRP_UPDATE_REFCOUNT: 226 Entry->LoadCount++; 227 break; 228 case LDRP_UPDATE_DEREFCOUNT: 229 Entry->LoadCount--; 230 break; 231 case LDRP_UPDATE_PIN: 232 Entry->LoadCount = 0xFFFF; 233 break; 234 } 235 236 /* Show snaps */ 237 if (ShowSnaps) 238 { 239 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags, RedirectedImportName, Entry->LoadCount); 240 } 241 } 242 243 /* Recurse into this entry */ 244 LdrpUpdateLoadCount3(Entry, Flags, UpdateString); 245 } 246 else if (RedirectedDll) 247 { 248 DPRINT1("LDR: LdrpCheckForLoadedDll failed for redirected dll %wZ\n", RedirectedImportName); 249 } 250 } 251 else 252 { 253 /* Unrecoverable SxS failure */ 254 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status, ImportNameUnic); 255 } 256 257 } 258 259 /* Go through forwarders */ 260 NewImportForwarder = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1); 261 for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++) 262 { 263 ImportName = (LPSTR)FirstEntry + NewImportForwarder->OffsetModuleName; 264 265 RtlInitAnsiString(&ImportNameAnsi, ImportName); 266 Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE); 267 if (NT_SUCCESS(Status)) 268 { 269 RedirectedDll = FALSE; 270 RedirectedImportName = ImportNameUnic; 271 272 /* Check if the SxS Assemblies specify another file */ 273 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 274 ImportNameUnic, 275 &LdrApiDefaultExtension, 276 UpdateString, 277 NULL, 278 &RedirectedImportName, 279 NULL, 280 NULL, 281 NULL); 282 /* Check success */ 283 if (NT_SUCCESS(Status)) 284 { 285 if (ShowSnaps) 286 { 287 DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi, RedirectedImportName); 288 } 289 /* Let Ldrp know */ 290 RedirectedDll = TRUE; 291 } 292 293 if (RedirectedDll || Status == STATUS_SXS_KEY_NOT_FOUND) 294 { 295 if (LdrpCheckForLoadedDll(NULL, 296 RedirectedImportName, 297 TRUE, 298 RedirectedDll, 299 &Entry)) 300 { 301 if (Entry->LoadCount != 0xFFFF) 302 { 303 /* Perform the required action */ 304 switch (Flags) 305 { 306 case LDRP_UPDATE_REFCOUNT: 307 Entry->LoadCount++; 308 break; 309 case LDRP_UPDATE_DEREFCOUNT: 310 Entry->LoadCount--; 311 break; 312 case LDRP_UPDATE_PIN: 313 Entry->LoadCount = 0xFFFF; 314 break; 315 } 316 317 /* Show snaps */ 318 if (ShowSnaps) 319 { 320 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags, RedirectedImportName, Entry->LoadCount); 321 } 322 } 323 324 /* Recurse into this entry */ 325 LdrpUpdateLoadCount3(Entry, Flags, UpdateString); 326 } 327 else if (RedirectedDll) 328 { 329 DPRINT1("LDR: LdrpCheckForLoadedDll failed with status %x for redirected dll %wZ\n", Status, RedirectedImportName); 330 } 331 } 332 else 333 { 334 /* Unrecoverable SxS failure */ 335 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status, ImportNameUnic); 336 } 337 338 } 339 340 NewImportForwarder++; 341 } 342 343 BoundEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewImportForwarder; 344 } 345 346 /* We're done */ 347 goto done; 348 } 349 350 /* Check oldstyle import descriptor */ 351 ImportEntry = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(LdrEntry->DllBase, 352 TRUE, 353 IMAGE_DIRECTORY_ENTRY_IMPORT, 354 &ImportSize); 355 if (ImportEntry) 356 { 357 /* There is old one, so go through its entries */ 358 while (ImportEntry->Name && ImportEntry->FirstThunk) 359 { 360 FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->FirstThunk); 361 362 /* Skip this entry if needed */ 363 if (!FirstThunk->u1.Function) 364 { 365 ImportEntry++; 366 continue; 367 } 368 369 ImportName = (PSZ)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name); 370 371 RtlInitAnsiString(&ImportNameAnsi, ImportName); 372 Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE); 373 if (NT_SUCCESS(Status)) 374 { 375 RedirectedDll = FALSE; 376 RedirectedImportName = ImportNameUnic; 377 378 /* Check if the SxS Assemblies specify another file */ 379 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 380 ImportNameUnic, 381 &LdrApiDefaultExtension, 382 UpdateString, 383 NULL, 384 &RedirectedImportName, 385 NULL, 386 NULL, 387 NULL); 388 /* Check success */ 389 if (NT_SUCCESS(Status)) 390 { 391 if (ShowSnaps) 392 { 393 DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi, RedirectedImportName); 394 } 395 396 /* Let Ldrp know */ 397 RedirectedDll = TRUE; 398 } 399 400 if (RedirectedDll || Status == STATUS_SXS_KEY_NOT_FOUND) 401 { 402 if (LdrpCheckForLoadedDll(NULL, 403 RedirectedImportName, 404 TRUE, 405 RedirectedDll, 406 &Entry)) 407 { 408 if (Entry->LoadCount != 0xFFFF) 409 { 410 /* Perform the required action */ 411 switch (Flags) 412 { 413 case LDRP_UPDATE_REFCOUNT: 414 Entry->LoadCount++; 415 break; 416 case LDRP_UPDATE_DEREFCOUNT: 417 Entry->LoadCount--; 418 break; 419 case LDRP_UPDATE_PIN: 420 Entry->LoadCount = 0xFFFF; 421 break; 422 } 423 424 /* Show snaps */ 425 if (ShowSnaps) 426 { 427 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags, RedirectedImportName, Entry->LoadCount); 428 } 429 } 430 431 /* Recurse */ 432 LdrpUpdateLoadCount3(Entry, Flags, UpdateString); 433 } 434 else if (RedirectedDll) 435 { 436 DPRINT1("LDR: LdrpCheckForLoadedDll failed for redirected dll %wZ\n", RedirectedImportName); 437 } 438 439 } 440 else 441 { 442 /* Unrecoverable SxS failure */ 443 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed for dll %wZ\n", ImportNameUnic); 444 } 445 446 } 447 448 /* Go to the next entry */ 449 ImportEntry++; 450 } 451 } 452 453 done: 454 /* Release the context */ 455 RtlDeactivateActivationContextUnsafeFast(&ActCtx); 456 } 457 458 VOID 459 NTAPI 460 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 461 IN ULONG Flags) 462 { 463 WCHAR Buffer[MAX_PATH]; 464 UNICODE_STRING UpdateString; 465 466 /* Setup the string and call the extended API */ 467 RtlInitEmptyUnicodeString(&UpdateString, Buffer, sizeof(Buffer)); 468 LdrpUpdateLoadCount3(LdrEntry, Flags, &UpdateString); 469 } 470 471 VOID 472 NTAPI 473 LdrpCallTlsInitializers(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 474 IN ULONG Reason) 475 { 476 PIMAGE_TLS_DIRECTORY TlsDirectory; 477 PIMAGE_TLS_CALLBACK *Array, Callback; 478 ULONG Size; 479 480 /* Get the TLS Directory */ 481 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 482 TRUE, 483 IMAGE_DIRECTORY_ENTRY_TLS, 484 &Size); 485 486 /* Protect against invalid pointers */ 487 _SEH2_TRY 488 { 489 /* Make sure it's valid */ 490 if (TlsDirectory) 491 { 492 /* Get the array */ 493 Array = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks; 494 if (Array) 495 { 496 /* Display debug */ 497 if (ShowSnaps) 498 { 499 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n", 500 LdrEntry->DllBase, TlsDirectory, Array); 501 } 502 503 /* Loop the array */ 504 while (*Array) 505 { 506 /* Get the TLS Entrypoint */ 507 Callback = *Array++; 508 509 /* Display debug */ 510 if (ShowSnaps) 511 { 512 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n", 513 LdrEntry->DllBase, Callback); 514 } 515 516 /* Call it */ 517 LdrpCallInitRoutine((PDLL_INIT_ROUTINE)Callback, 518 LdrEntry->DllBase, 519 Reason, 520 NULL); 521 } 522 } 523 } 524 } 525 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 526 { 527 DPRINT1("LDR: Exception 0x%x during Tls Callback(%u) for %wZ\n", 528 _SEH2_GetExceptionCode(), Reason, &LdrEntry->BaseDllName); 529 } 530 _SEH2_END; 531 } 532 533 NTSTATUS 534 NTAPI 535 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName, 536 IN HANDLE DllHandle) 537 { 538 /* Not implemented */ 539 return STATUS_SUCCESS; 540 } 541 542 NTSTATUS 543 NTAPI 544 LdrpCreateDllSection(IN PUNICODE_STRING FullName, 545 IN HANDLE DllHandle, 546 IN PULONG DllCharacteristics OPTIONAL, 547 OUT PHANDLE SectionHandle) 548 { 549 HANDLE FileHandle; 550 NTSTATUS Status; 551 OBJECT_ATTRIBUTES ObjectAttributes; 552 IO_STATUS_BLOCK IoStatusBlock; 553 ULONG_PTR HardErrorParameters[1]; 554 ULONG Response; 555 SECTION_IMAGE_INFORMATION SectionImageInfo; 556 557 /* Check if we don't already have a handle */ 558 if (!DllHandle) 559 { 560 /* Create the object attributes */ 561 InitializeObjectAttributes(&ObjectAttributes, 562 FullName, 563 OBJ_CASE_INSENSITIVE, 564 NULL, 565 NULL); 566 567 /* Open the DLL */ 568 Status = NtOpenFile(&FileHandle, 569 SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA, 570 &ObjectAttributes, 571 &IoStatusBlock, 572 FILE_SHARE_READ | FILE_SHARE_DELETE, 573 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 574 575 /* Check if we failed */ 576 if (!NT_SUCCESS(Status)) 577 { 578 /* Attempt to open for execute only */ 579 Status = NtOpenFile(&FileHandle, 580 SYNCHRONIZE | FILE_EXECUTE, 581 &ObjectAttributes, 582 &IoStatusBlock, 583 FILE_SHARE_READ | FILE_SHARE_DELETE, 584 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 585 586 /* Check if this failed too */ 587 if (!NT_SUCCESS(Status)) 588 { 589 /* Show debug message */ 590 if (ShowSnaps) 591 { 592 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n", 593 Status); 594 } 595 596 /* Make sure to return an expected status code */ 597 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 598 { 599 /* Callers expect this instead */ 600 Status = STATUS_DLL_NOT_FOUND; 601 } 602 603 /* Return an empty section handle */ 604 *SectionHandle = NULL; 605 return Status; 606 } 607 } 608 } 609 else 610 { 611 /* Use the handle we already have */ 612 FileHandle = DllHandle; 613 } 614 615 /* Create a section for the DLL */ 616 Status = NtCreateSection(SectionHandle, 617 SECTION_MAP_READ | SECTION_MAP_EXECUTE | 618 SECTION_MAP_WRITE | SECTION_QUERY, 619 NULL, 620 NULL, 621 PAGE_EXECUTE, 622 SEC_IMAGE, 623 FileHandle); 624 625 /* If mapping failed, raise a hard error */ 626 if (!NT_SUCCESS(Status)) 627 { 628 /* Forget the handle */ 629 *SectionHandle = NULL; 630 631 /* Give the DLL name */ 632 HardErrorParameters[0] = (ULONG_PTR)FullName; 633 634 /* Raise the error */ 635 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT, 636 1, 637 1, 638 HardErrorParameters, 639 OptionOk, 640 &Response); 641 642 /* Increment the error count */ 643 if (LdrpInLdrInit) LdrpFatalHardErrorCount++; 644 645 goto Exit; 646 } 647 648 /* Check for Safer restrictions */ 649 if (!DllCharacteristics || 650 !(*DllCharacteristics & IMAGE_FILE_SYSTEM)) 651 { 652 /* Make sure it's executable */ 653 Status = ZwQuerySection(*SectionHandle, 654 SectionImageInformation, 655 &SectionImageInfo, 656 sizeof(SECTION_IMAGE_INFORMATION), 657 NULL); 658 if (NT_SUCCESS(Status)) 659 { 660 /* Bypass the check for .NET images */ 661 if (!(SectionImageInfo.LoaderFlags & IMAGE_LOADER_FLAGS_COMPLUS)) 662 { 663 /* Check with Safer */ 664 Status = LdrpCodeAuthzCheckDllAllowed(FullName, DllHandle); 665 if (!NT_SUCCESS(Status) && (Status != STATUS_NOT_FOUND)) 666 { 667 /* Show debug message */ 668 if (ShowSnaps) 669 { 670 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n", 671 &FullName); 672 } 673 674 /* Failure case, close section handle */ 675 NtClose(*SectionHandle); 676 *SectionHandle = NULL; 677 } 678 } 679 } 680 else 681 { 682 /* Failure case, close section handle */ 683 NtClose(*SectionHandle); 684 *SectionHandle = NULL; 685 } 686 } 687 688 Exit: 689 /* Close the file handle, we don't need it */ 690 NtClose(FileHandle); 691 692 /* Return status */ 693 return Status; 694 } 695 696 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */ 697 BOOLEAN 698 NTAPI 699 LdrpResolveDllName(PWSTR DllPath, 700 PWSTR DllName, 701 PUNICODE_STRING FullDllName, 702 PUNICODE_STRING BaseDllName) 703 { 704 PWCHAR NameBuffer, p1, p2 = 0; 705 ULONG Length; 706 ULONG BufSize = 500; 707 708 /* Allocate space for full DLL name */ 709 FullDllName->Buffer = RtlAllocateHeap(LdrpHeap, 0, BufSize + sizeof(UNICODE_NULL)); 710 if (!FullDllName->Buffer) return FALSE; 711 712 Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer, 713 DllName, 714 NULL, 715 BufSize, 716 FullDllName->Buffer, 717 &BaseDllName->Buffer); 718 719 if (!Length || Length > BufSize) 720 { 721 if (ShowSnaps) 722 { 723 DPRINT1("LDR: LdrResolveDllName - Unable to find "); 724 DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer); 725 } 726 727 LdrpFreeUnicodeString(FullDllName); 728 return FALSE; 729 } 730 731 /* Construct full DLL name */ 732 FullDllName->Length = Length; 733 FullDllName->MaximumLength = FullDllName->Length + sizeof(UNICODE_NULL); 734 735 /* Allocate a new buffer */ 736 NameBuffer = RtlAllocateHeap(LdrpHeap, 0, FullDllName->MaximumLength); 737 if (!NameBuffer) 738 { 739 RtlFreeHeap(LdrpHeap, 0, FullDllName->Buffer); 740 return FALSE; 741 } 742 743 /* Copy over the contents from the previous one and free it */ 744 RtlCopyMemory(NameBuffer, FullDllName->Buffer, FullDllName->MaximumLength); 745 RtlFreeHeap(LdrpHeap, 0, FullDllName->Buffer); 746 FullDllName->Buffer = NameBuffer; 747 748 /* Find last backslash */ 749 p1 = FullDllName->Buffer; 750 while (*p1) 751 { 752 if (*p1++ == L'\\') 753 { 754 p2 = p1; 755 } 756 } 757 758 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */ 759 if (p2) 760 p1 = p2; 761 else 762 p1 = DllName; 763 764 p2 = p1; 765 766 /* Calculate remaining length */ 767 while (*p1) ++p1; 768 769 /* Construct base DLL name */ 770 BaseDllName->Length = (ULONG_PTR)p1 - (ULONG_PTR)p2; 771 BaseDllName->MaximumLength = BaseDllName->Length + sizeof(UNICODE_NULL); 772 BaseDllName->Buffer = RtlAllocateHeap(LdrpHeap, 0, BaseDllName->MaximumLength); 773 774 if (!BaseDllName->Buffer) 775 { 776 RtlFreeHeap(LdrpHeap, 0, NameBuffer); 777 return FALSE; 778 } 779 780 /* Copy base dll name to the new buffer */ 781 RtlMoveMemory(BaseDllName->Buffer, 782 p2, 783 BaseDllName->Length); 784 785 /* Null-terminate the string */ 786 BaseDllName->Buffer[BaseDllName->Length / sizeof(WCHAR)] = 0; 787 788 return TRUE; 789 } 790 791 PVOID 792 NTAPI 793 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase) 794 { 795 PIMAGE_NT_HEADERS NtHeaders; 796 ULONG_PTR EntryPoint = 0; 797 798 /* Get entry point offset from NT headers */ 799 NtHeaders = RtlImageNtHeader(ImageBase); 800 if (NtHeaders) 801 { 802 /* Add image base */ 803 EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint; 804 if (EntryPoint) EntryPoint += (ULONG_PTR)ImageBase; 805 } 806 807 /* Return calculated pointer (or zero in case of failure) */ 808 return (PVOID)EntryPoint; 809 } 810 811 /* NOTE: This function is partially missing SxS */ 812 NTSTATUS 813 NTAPI 814 LdrpCheckForKnownDll(PWSTR DllName, 815 PUNICODE_STRING FullDllName, 816 PUNICODE_STRING BaseDllName, 817 HANDLE *SectionHandle) 818 { 819 OBJECT_ATTRIBUTES ObjectAttributes; 820 HANDLE Section = NULL; 821 UNICODE_STRING DllNameUnic; 822 NTSTATUS Status; 823 PCHAR p1; 824 PWCHAR p2; 825 826 /* Zero initialize provided parameters */ 827 if (SectionHandle) *SectionHandle = 0; 828 829 if (FullDllName) 830 { 831 FullDllName->Length = 0; 832 FullDllName->MaximumLength = 0; 833 FullDllName->Buffer = NULL; 834 } 835 836 if (BaseDllName) 837 { 838 BaseDllName->Length = 0; 839 BaseDllName->MaximumLength = 0; 840 BaseDllName->Buffer = NULL; 841 } 842 843 /* If any of these three params are missing then fail */ 844 if (!SectionHandle || !FullDllName || !BaseDllName) 845 return STATUS_INVALID_PARAMETER; 846 847 /* Check the Loader Lock */ 848 LdrpEnsureLoaderLockIsHeld(); 849 850 /* Upgrade DllName to a unicode string */ 851 RtlInitUnicodeString(&DllNameUnic, DllName); 852 853 /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */ 854 855 /* Get the activation context */ 856 Status = RtlFindActivationContextSectionString(0, 857 NULL, 858 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, 859 &DllNameUnic, 860 NULL); 861 862 /* Check if it's a SxS or not */ 863 if (Status == STATUS_SXS_SECTION_NOT_FOUND || 864 Status == STATUS_SXS_KEY_NOT_FOUND) 865 { 866 /* NOTE: Here it's beneficial to allocate one big unicode string 867 using LdrpAllocateUnicodeString instead of fragmenting the heap 868 with two allocations as it's done now. */ 869 870 /* Set up BaseDllName */ 871 BaseDllName->Length = DllNameUnic.Length; 872 BaseDllName->MaximumLength = DllNameUnic.MaximumLength; 873 BaseDllName->Buffer = RtlAllocateHeap(LdrpHeap, 874 0, 875 DllNameUnic.MaximumLength); 876 if (!BaseDllName->Buffer) 877 { 878 Status = STATUS_NO_MEMORY; 879 goto Failure; 880 } 881 882 /* Copy the contents there */ 883 RtlMoveMemory(BaseDllName->Buffer, DllNameUnic.Buffer, DllNameUnic.MaximumLength); 884 885 /* Set up FullDllName */ 886 FullDllName->Length = LdrpKnownDllPath.Length + BaseDllName->Length + sizeof(WCHAR); 887 FullDllName->MaximumLength = FullDllName->Length + sizeof(UNICODE_NULL); 888 FullDllName->Buffer = RtlAllocateHeap(LdrpHeap, 0, FullDllName->MaximumLength); 889 if (!FullDllName->Buffer) 890 { 891 Status = STATUS_NO_MEMORY; 892 goto Failure; 893 } 894 895 RtlMoveMemory(FullDllName->Buffer, LdrpKnownDllPath.Buffer, LdrpKnownDllPath.Length); 896 897 /* Put a slash there */ 898 p1 = (PCHAR)FullDllName->Buffer + LdrpKnownDllPath.Length; 899 p2 = (PWCHAR)p1; 900 *p2++ = (WCHAR)'\\'; 901 p1 = (PCHAR)p2; 902 903 /* Set up DllNameUnic for a relative path */ 904 DllNameUnic.Buffer = (PWSTR)p1; 905 DllNameUnic.Length = BaseDllName->Length; 906 DllNameUnic.MaximumLength = DllNameUnic.Length + sizeof(UNICODE_NULL); 907 908 /* Copy the contents */ 909 RtlMoveMemory(p1, BaseDllName->Buffer, BaseDllName->MaximumLength); 910 911 /* There are all names, init attributes and open the section */ 912 InitializeObjectAttributes(&ObjectAttributes, 913 &DllNameUnic, 914 OBJ_CASE_INSENSITIVE, 915 LdrpKnownDllObjectDirectory, 916 NULL); 917 918 Status = NtOpenSection(&Section, 919 SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, 920 &ObjectAttributes); 921 if (!NT_SUCCESS(Status)) 922 { 923 /* Clear status in case it was just not found */ 924 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) Status = STATUS_SUCCESS; 925 goto Failure; 926 } 927 928 /* Pass section handle to the caller and return success */ 929 *SectionHandle = Section; 930 return STATUS_SUCCESS; 931 } 932 933 Failure: 934 /* Close section object if it was opened */ 935 if (Section) NtClose(Section); 936 937 /* Free string resources */ 938 if (BaseDllName->Buffer) RtlFreeHeap(LdrpHeap, 0, BaseDllName->Buffer); 939 if (FullDllName->Buffer) RtlFreeHeap(LdrpHeap, 0, FullDllName->Buffer); 940 941 /* Return status */ 942 return Status; 943 } 944 945 NTSTATUS 946 NTAPI 947 LdrpSetProtection(PVOID ViewBase, 948 BOOLEAN Restore) 949 { 950 PIMAGE_NT_HEADERS NtHeaders; 951 PIMAGE_SECTION_HEADER Section; 952 NTSTATUS Status; 953 PVOID SectionBase; 954 SIZE_T SectionSize; 955 ULONG NewProtection, OldProtection, i; 956 957 /* Get the NT headers */ 958 NtHeaders = RtlImageNtHeader(ViewBase); 959 if (!NtHeaders) return STATUS_INVALID_IMAGE_FORMAT; 960 961 /* Compute address of the first section header */ 962 Section = IMAGE_FIRST_SECTION(NtHeaders); 963 964 /* Go through all sections */ 965 for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++) 966 { 967 /* Check for read-only non-zero section */ 968 if ((Section->SizeOfRawData) && 969 !(Section->Characteristics & IMAGE_SCN_MEM_WRITE)) 970 { 971 /* Check if we are setting or restoring protection */ 972 if (Restore) 973 { 974 /* Set it to either EXECUTE or READONLY */ 975 if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) 976 { 977 NewProtection = PAGE_EXECUTE; 978 } 979 else 980 { 981 NewProtection = PAGE_READONLY; 982 } 983 984 /* Add PAGE_NOCACHE if needed */ 985 if (Section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) 986 { 987 NewProtection |= PAGE_NOCACHE; 988 } 989 } 990 else 991 { 992 /* Enable write access */ 993 NewProtection = PAGE_READWRITE; 994 } 995 996 /* Get the section VA */ 997 SectionBase = (PVOID)((ULONG_PTR)ViewBase + Section->VirtualAddress); 998 SectionSize = Section->SizeOfRawData; 999 if (SectionSize) 1000 { 1001 /* Set protection */ 1002 Status = ZwProtectVirtualMemory(NtCurrentProcess(), 1003 &SectionBase, 1004 &SectionSize, 1005 NewProtection, 1006 &OldProtection); 1007 if (!NT_SUCCESS(Status)) return Status; 1008 } 1009 } 1010 1011 /* Move to the next section */ 1012 Section++; 1013 } 1014 1015 /* Flush instruction cache if necessary */ 1016 if (Restore) ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); 1017 return STATUS_SUCCESS; 1018 } 1019 1020 /* NOTE: Not yet reviewed */ 1021 NTSTATUS 1022 NTAPI 1023 LdrpMapDll(IN PWSTR SearchPath OPTIONAL, 1024 IN PWSTR DllPath2, 1025 IN PWSTR DllName OPTIONAL, 1026 IN PULONG DllCharacteristics, 1027 IN BOOLEAN Static, 1028 IN BOOLEAN Redirect, 1029 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry) 1030 { 1031 PTEB Teb = NtCurrentTeb(); 1032 PPEB Peb = NtCurrentPeb(); 1033 PWCHAR p1 = DllName; 1034 WCHAR TempChar; 1035 BOOLEAN KnownDll = FALSE; 1036 UNICODE_STRING FullDllName, BaseDllName; 1037 HANDLE SectionHandle = NULL, DllHandle = 0; 1038 UNICODE_STRING NtPathDllName; 1039 ULONG_PTR HardErrorParameters[2]; 1040 UNICODE_STRING HardErrorDllName, HardErrorDllPath; 1041 ULONG Response; 1042 SIZE_T ViewSize = 0; 1043 PVOID ViewBase = NULL; 1044 PVOID ArbitraryUserPointer; 1045 PIMAGE_NT_HEADERS NtHeaders; 1046 NTSTATUS HardErrorStatus, Status; 1047 BOOLEAN OverlapDllFound = FALSE; 1048 ULONG_PTR ImageBase, ImageEnd; 1049 PLIST_ENTRY ListHead, NextEntry; 1050 PLDR_DATA_TABLE_ENTRY CandidateEntry, LdrEntry; 1051 ULONG_PTR CandidateBase, CandidateEnd; 1052 UNICODE_STRING OverlapDll; 1053 BOOLEAN RelocatableDll = TRUE; 1054 UNICODE_STRING IllegalDll; 1055 PVOID RelocData; 1056 ULONG RelocDataSize = 0; 1057 1058 // FIXME: AppCompat stuff is missing 1059 1060 if (ShowSnaps) 1061 { 1062 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n", 1063 DllName, 1064 SearchPath ? SearchPath : L""); 1065 } 1066 1067 /* Check if we have a known dll directory */ 1068 if (LdrpKnownDllObjectDirectory && Redirect == FALSE) 1069 { 1070 /* Check if the path is full */ 1071 while (*p1) 1072 { 1073 TempChar = *p1++; 1074 if (TempChar == '\\' || TempChar == '/' ) 1075 { 1076 /* Complete path, don't do Known Dll lookup */ 1077 goto SkipCheck; 1078 } 1079 } 1080 1081 /* Try to find a Known DLL */ 1082 Status = LdrpCheckForKnownDll(DllName, 1083 &FullDllName, 1084 &BaseDllName, 1085 &SectionHandle); 1086 1087 if (!NT_SUCCESS(Status) && (Status != STATUS_DLL_NOT_FOUND)) 1088 { 1089 /* Failure */ 1090 DbgPrintEx(DPFLTR_LDR_ID, 1091 DPFLTR_ERROR_LEVEL, 1092 "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n", 1093 __FUNCTION__, 1094 DllName, 1095 Status); 1096 1097 return Status; 1098 } 1099 } 1100 1101 SkipCheck: 1102 1103 /* Check if the Known DLL Check returned something */ 1104 if (!SectionHandle) 1105 { 1106 /* It didn't, so try to resolve the name now */ 1107 if (LdrpResolveDllName(SearchPath, 1108 DllName, 1109 &FullDllName, 1110 &BaseDllName)) 1111 { 1112 /* Got a name, display a message */ 1113 if (ShowSnaps) 1114 { 1115 DPRINT1("LDR: Loading (%s) %wZ\n", 1116 Static ? "STATIC" : "DYNAMIC", 1117 &FullDllName); 1118 } 1119 1120 /* Convert to NT Name */ 1121 if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer, 1122 &NtPathDllName, 1123 NULL, 1124 NULL)) 1125 { 1126 /* Path was invalid */ 1127 return STATUS_OBJECT_PATH_SYNTAX_BAD; 1128 } 1129 1130 /* Create a section for this dLL */ 1131 Status = LdrpCreateDllSection(&NtPathDllName, 1132 DllHandle, 1133 DllCharacteristics, 1134 &SectionHandle); 1135 1136 /* Free the NT Name */ 1137 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName.Buffer); 1138 1139 /* If we failed */ 1140 if (!NT_SUCCESS(Status)) 1141 { 1142 /* Free the name strings and return */ 1143 LdrpFreeUnicodeString(&FullDllName); 1144 LdrpFreeUnicodeString(&BaseDllName); 1145 return Status; 1146 } 1147 } 1148 else 1149 { 1150 /* We couldn't resolve the name, is this a static load? */ 1151 if (Static) 1152 { 1153 /* 1154 * This is BAD! Static loads are CRITICAL. Bugcheck! 1155 * Initialize the strings for the error 1156 */ 1157 RtlInitUnicodeString(&HardErrorDllName, DllName); 1158 RtlInitUnicodeString(&HardErrorDllPath, 1159 DllPath2 ? DllPath2 : LdrpDefaultPath.Buffer); 1160 1161 /* Set them as error parameters */ 1162 HardErrorParameters[0] = (ULONG_PTR)&HardErrorDllName; 1163 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllPath; 1164 1165 /* Raise the hard error */ 1166 NtRaiseHardError(STATUS_DLL_NOT_FOUND, 1167 2, 1168 0x00000003, 1169 HardErrorParameters, 1170 OptionOk, 1171 &Response); 1172 1173 /* We're back, where we initializing? */ 1174 if (LdrpInLdrInit) LdrpFatalHardErrorCount++; 1175 } 1176 1177 /* Return failure */ 1178 return STATUS_DLL_NOT_FOUND; 1179 } 1180 } 1181 else 1182 { 1183 /* We have a section handle, so this is a known dll */ 1184 KnownDll = TRUE; 1185 } 1186 1187 /* Stuff the image name in the TIB, for the debugger */ 1188 ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; 1189 Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; 1190 1191 /* Map the DLL */ 1192 ViewBase = NULL; 1193 ViewSize = 0; 1194 Status = NtMapViewOfSection(SectionHandle, 1195 NtCurrentProcess(), 1196 &ViewBase, 1197 0, 1198 0, 1199 NULL, 1200 &ViewSize, 1201 ViewShare, 1202 0, 1203 PAGE_READWRITE); 1204 1205 /* Restore */ 1206 Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; 1207 1208 /* Fail if we couldn't map it */ 1209 if (!NT_SUCCESS(Status)) 1210 { 1211 /* Close and return */ 1212 NtClose(SectionHandle); 1213 return Status; 1214 } 1215 1216 /* Get the NT Header */ 1217 if (!(NtHeaders = RtlImageNtHeader(ViewBase))) 1218 { 1219 /* Invalid image, unmap, close handle and fail */ 1220 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 1221 NtClose(SectionHandle); 1222 return STATUS_INVALID_IMAGE_FORMAT; 1223 } 1224 1225 // FIXME: .NET support is missing 1226 1227 /* Allocate an entry */ 1228 if (!(LdrEntry = LdrpAllocateDataTableEntry(ViewBase))) 1229 { 1230 /* Invalid image, unmap, close handle and fail */ 1231 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 1232 NtClose(SectionHandle); 1233 return STATUS_NO_MEMORY; 1234 } 1235 1236 /* Setup the entry */ 1237 LdrEntry->Flags = Static ? LDRP_STATIC_LINK : 0; 1238 if (Redirect) LdrEntry->Flags |= LDRP_REDIRECTED; 1239 LdrEntry->LoadCount = 0; 1240 LdrEntry->FullDllName = FullDllName; 1241 LdrEntry->BaseDllName = BaseDllName; 1242 LdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrEntry->DllBase); 1243 1244 /* Show debug message */ 1245 if (ShowSnaps) 1246 { 1247 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n", 1248 &FullDllName, 1249 &BaseDllName); 1250 } 1251 1252 /* Insert this entry */ 1253 LdrpInsertMemoryTableEntry(LdrEntry); 1254 1255 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE) 1256 1257 /* Check for invalid CPU Image */ 1258 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 1259 { 1260 /* Load our header */ 1261 PIMAGE_NT_HEADERS ImageNtHeader = RtlImageNtHeader(Peb->ImageBaseAddress); 1262 1263 /* Assume defaults if we don't have to run the Hard Error path */ 1264 HardErrorStatus = STATUS_SUCCESS; 1265 Response = ResponseCancel; 1266 1267 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */ 1268 if (ImageNtHeader->OptionalHeader.MajorSubsystemVersion <= 3) 1269 { 1270 /* Reset the entrypoint, save our Dll Name */ 1271 LdrEntry->EntryPoint = 0; 1272 HardErrorParameters[0] = (ULONG_PTR)&FullDllName; 1273 1274 /* Raise the error */ 1275 HardErrorStatus = ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH, 1276 1, 1277 1, 1278 HardErrorParameters, 1279 OptionOkCancel, 1280 &Response); 1281 } 1282 1283 /* Check if the user pressed cancel */ 1284 if (NT_SUCCESS(HardErrorStatus) && Response == ResponseCancel) 1285 { 1286 /* Remove the DLL from the lists */ 1287 RemoveEntryList(&LdrEntry->InLoadOrderLinks); 1288 RemoveEntryList(&LdrEntry->InMemoryOrderLinks); 1289 RemoveEntryList(&LdrEntry->HashLinks); 1290 1291 /* Remove the LDR Entry */ 1292 RtlFreeHeap(LdrpHeap, 0, LdrEntry ); 1293 1294 /* Unmap and close section */ 1295 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 1296 NtClose(SectionHandle); 1297 1298 /* Did we do a hard error? */ 1299 if (ImageNtHeader->OptionalHeader.MajorSubsystemVersion <= 3) 1300 { 1301 /* Yup, so increase fatal error count if we are initializing */ 1302 if (LdrpInLdrInit) LdrpFatalHardErrorCount++; 1303 } 1304 1305 /* Return failure */ 1306 return STATUS_INVALID_IMAGE_FORMAT; 1307 } 1308 } 1309 else 1310 { 1311 /* The image was valid. Is it a DLL? */ 1312 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) 1313 { 1314 /* Set the DLL Flag */ 1315 LdrEntry->Flags |= LDRP_IMAGE_DLL; 1316 } 1317 1318 /* If we're not a DLL, clear the entrypoint */ 1319 if (!(LdrEntry->Flags & LDRP_IMAGE_DLL)) 1320 { 1321 LdrEntry->EntryPoint = 0; 1322 } 1323 } 1324 1325 /* Return it for the caller */ 1326 *DataTableEntry = LdrEntry; 1327 1328 /* Check if we loaded somewhere else */ 1329 if (Status == STATUS_IMAGE_NOT_AT_BASE) 1330 { 1331 /* Write the flag */ 1332 LdrEntry->Flags |= LDRP_IMAGE_NOT_AT_BASE; 1333 1334 /* Find our region */ 1335 ImageBase = (ULONG_PTR)NtHeaders->OptionalHeader.ImageBase; 1336 ImageEnd = ImageBase + ViewSize; 1337 1338 DPRINT("LDR: LdrpMapDll Relocating Image Name %ws (%p-%p -> %p)\n", DllName, (PVOID)ImageBase, (PVOID)ImageEnd, ViewBase); 1339 1340 /* Scan all the modules */ 1341 ListHead = &Peb->Ldr->InLoadOrderModuleList; 1342 NextEntry = ListHead->Flink; 1343 while (NextEntry != ListHead) 1344 { 1345 /* Get the entry */ 1346 CandidateEntry = CONTAINING_RECORD(NextEntry, 1347 LDR_DATA_TABLE_ENTRY, 1348 InLoadOrderLinks); 1349 NextEntry = NextEntry->Flink; 1350 1351 /* Get the entry's bounds */ 1352 CandidateBase = (ULONG_PTR)CandidateEntry->DllBase; 1353 CandidateEnd = CandidateBase + CandidateEntry->SizeOfImage; 1354 1355 /* Make sure this entry isn't unloading */ 1356 if (!CandidateEntry->InMemoryOrderLinks.Flink) continue; 1357 1358 /* Check if our regions are colliding */ 1359 if ((ImageBase >= CandidateBase && ImageBase <= CandidateEnd) || 1360 (ImageEnd >= CandidateBase && ImageEnd <= CandidateEnd) || 1361 (CandidateBase >= ImageBase && CandidateBase <= ImageEnd)) 1362 { 1363 /* Found who is overlapping */ 1364 OverlapDllFound = TRUE; 1365 OverlapDll = CandidateEntry->FullDllName; 1366 break; 1367 } 1368 } 1369 1370 /* Check if we found the DLL overlapping with us */ 1371 if (!OverlapDllFound) 1372 { 1373 /* It's not another DLL, it's memory already here */ 1374 RtlInitUnicodeString(&OverlapDll, L"Dynamically Allocated Memory"); 1375 } 1376 1377 DPRINT("Overlapping DLL: %wZ\n", &OverlapDll); 1378 1379 /* Are we dealing with a DLL? */ 1380 if (LdrEntry->Flags & LDRP_IMAGE_DLL) 1381 { 1382 /* Check if relocs were stripped */ 1383 if (!(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)) 1384 { 1385 /* Get the relocation data */ 1386 RelocData = RtlImageDirectoryEntryToData(ViewBase, 1387 TRUE, 1388 IMAGE_DIRECTORY_ENTRY_BASERELOC, 1389 &RelocDataSize); 1390 1391 /* Does the DLL not have any? */ 1392 if (!RelocData && !RelocDataSize) 1393 { 1394 /* We'll allow this and simply continue */ 1395 goto NoRelocNeeded; 1396 } 1397 } 1398 1399 /* See if this is an Illegal DLL - IE: user32 and kernel32 */ 1400 RtlInitUnicodeString(&IllegalDll,L"user32.dll"); 1401 if (RtlEqualUnicodeString(&BaseDllName, &IllegalDll, TRUE)) 1402 { 1403 /* Can't relocate user32 */ 1404 RelocatableDll = FALSE; 1405 } 1406 else 1407 { 1408 RtlInitUnicodeString(&IllegalDll, L"kernel32.dll"); 1409 if (RtlEqualUnicodeString(&BaseDllName, &IllegalDll, TRUE)) 1410 { 1411 /* Can't relocate kernel32 */ 1412 RelocatableDll = FALSE; 1413 } 1414 } 1415 1416 /* Known DLLs are not allowed to be relocated */ 1417 if (KnownDll && !RelocatableDll) 1418 { 1419 /* Setup for hard error */ 1420 HardErrorParameters[0] = (ULONG_PTR)&IllegalDll; 1421 HardErrorParameters[1] = (ULONG_PTR)&OverlapDll; 1422 1423 DPRINT1("Illegal DLL relocation! %wZ overlaps %wZ\n", &OverlapDll, &IllegalDll); 1424 1425 /* Raise the error */ 1426 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION, 1427 2, 1428 3, 1429 HardErrorParameters, 1430 OptionOk, 1431 &Response); 1432 1433 /* If initializing, increase the error count */ 1434 if (LdrpInLdrInit) LdrpFatalHardErrorCount++; 1435 1436 /* Don't do relocation */ 1437 Status = STATUS_CONFLICTING_ADDRESSES; 1438 goto FailRelocate; 1439 } 1440 1441 /* Change the protection to prepare for relocation */ 1442 Status = LdrpSetProtection(ViewBase, FALSE); 1443 1444 /* Make sure we changed the protection */ 1445 if (NT_SUCCESS(Status)) 1446 { 1447 /* Do the relocation */ 1448 Status = LdrRelocateImageWithBias(ViewBase, 0LL, NULL, STATUS_SUCCESS, 1449 STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT); 1450 1451 if (NT_SUCCESS(Status)) 1452 { 1453 /* Stuff the image name in the TIB, for the debugger */ 1454 ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; 1455 Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; 1456 #if 0 1457 /* Map the DLL */ 1458 Status = NtMapViewOfSection(SectionHandle, 1459 NtCurrentProcess(), 1460 &ViewBase, 1461 0, 1462 0, 1463 NULL, 1464 &ViewSize, 1465 ViewShare, 1466 0, 1467 PAGE_READWRITE); 1468 #endif 1469 /* Restore */ 1470 Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; 1471 1472 /* Return the protection */ 1473 Status = LdrpSetProtection(ViewBase, TRUE); 1474 } 1475 } 1476 FailRelocate: 1477 /* Handle any kind of failure */ 1478 if (!NT_SUCCESS(Status)) 1479 { 1480 /* Remove it from the lists */ 1481 RemoveEntryList(&LdrEntry->InLoadOrderLinks); 1482 RemoveEntryList(&LdrEntry->InMemoryOrderLinks); 1483 RemoveEntryList(&LdrEntry->HashLinks); 1484 1485 /* Unmap it, clear the entry */ 1486 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 1487 LdrEntry = NULL; 1488 } 1489 1490 /* Show debug message */ 1491 if (ShowSnaps) 1492 { 1493 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n", 1494 NT_SUCCESS(Status) ? "s" : "uns", ViewBase); 1495 } 1496 } 1497 else 1498 { 1499 NoRelocNeeded: 1500 /* Not a DLL, or no relocation needed */ 1501 Status = STATUS_SUCCESS; 1502 1503 /* Stuff the image name in the TIB, for the debugger */ 1504 ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; 1505 Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; 1506 #if 0 1507 /* Map the DLL */ 1508 Status = NtMapViewOfSection(SectionHandle, 1509 NtCurrentProcess(), 1510 &ViewBase, 1511 0, 1512 0, 1513 NULL, 1514 &ViewSize, 1515 ViewShare, 1516 0, 1517 PAGE_READWRITE); 1518 #endif 1519 /* Restore */ 1520 Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; 1521 1522 /* Show debug message */ 1523 if (ShowSnaps) 1524 { 1525 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase); 1526 } 1527 } 1528 } 1529 1530 // FIXME: LdrpCheckCorImage() is missing 1531 1532 /* Check if this is an SMP Machine and a DLL */ 1533 if ((LdrpNumberOfProcessors > 1) && 1534 (LdrEntry && (LdrEntry->Flags & LDRP_IMAGE_DLL))) 1535 { 1536 /* Validate the image for MP */ 1537 LdrpValidateImageForMp(LdrEntry); 1538 } 1539 1540 // FIXME: LdrpCorUnloadImage() is missing 1541 1542 /* Close section and return status */ 1543 NtClose(SectionHandle); 1544 return Status; 1545 } 1546 1547 PLDR_DATA_TABLE_ENTRY 1548 NTAPI 1549 LdrpAllocateDataTableEntry(IN PVOID BaseAddress) 1550 { 1551 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL; 1552 PIMAGE_NT_HEADERS NtHeader; 1553 1554 /* Make sure the header is valid */ 1555 NtHeader = RtlImageNtHeader(BaseAddress); 1556 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress, NtHeader); 1557 1558 if (NtHeader) 1559 { 1560 /* Allocate an entry */ 1561 LdrEntry = RtlAllocateHeap(LdrpHeap, 1562 HEAP_ZERO_MEMORY, 1563 sizeof(LDR_DATA_TABLE_ENTRY)); 1564 1565 /* Make sure we got one */ 1566 if (LdrEntry) 1567 { 1568 /* Set it up */ 1569 LdrEntry->DllBase = BaseAddress; 1570 LdrEntry->SizeOfImage = NtHeader->OptionalHeader.SizeOfImage; 1571 LdrEntry->TimeDateStamp = NtHeader->FileHeader.TimeDateStamp; 1572 LdrEntry->PatchInformation = NULL; 1573 } 1574 } 1575 1576 /* Return the entry */ 1577 return LdrEntry; 1578 } 1579 1580 VOID 1581 NTAPI 1582 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 1583 { 1584 PPEB_LDR_DATA PebData = NtCurrentPeb()->Ldr; 1585 ULONG i; 1586 1587 /* Insert into hash table */ 1588 i = LDR_GET_HASH_ENTRY(LdrEntry->BaseDllName.Buffer[0]); 1589 InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks); 1590 1591 /* Insert into other lists */ 1592 InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks); 1593 InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks); 1594 } 1595 1596 VOID 1597 NTAPI 1598 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry) 1599 { 1600 /* Sanity check */ 1601 ASSERT(Entry != NULL); 1602 1603 /* Release the activation context if it exists and wasn't already released */ 1604 if ((Entry->EntryPointActivationContext) && 1605 (Entry->EntryPointActivationContext != INVALID_HANDLE_VALUE)) 1606 { 1607 /* Mark it as invalid */ 1608 RtlReleaseActivationContext(Entry->EntryPointActivationContext); 1609 Entry->EntryPointActivationContext = INVALID_HANDLE_VALUE; 1610 } 1611 1612 /* Release the full dll name string */ 1613 if (Entry->FullDllName.Buffer) LdrpFreeUnicodeString(&Entry->FullDllName); 1614 1615 /* Finally free the entry's memory */ 1616 RtlFreeHeap(LdrpHeap, 0, Entry); 1617 } 1618 1619 BOOLEAN 1620 NTAPI 1621 LdrpCheckForLoadedDllHandle(IN PVOID Base, 1622 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) 1623 { 1624 PLDR_DATA_TABLE_ENTRY Current; 1625 PLIST_ENTRY ListHead, Next; 1626 1627 /* Check the cache first */ 1628 if ((LdrpLoadedDllHandleCache) && 1629 (LdrpLoadedDllHandleCache->DllBase == Base)) 1630 { 1631 /* We got lucky, return the cached entry */ 1632 *LdrEntry = LdrpLoadedDllHandleCache; 1633 return TRUE; 1634 } 1635 1636 /* Time for a lookup */ 1637 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 1638 Next = ListHead->Flink; 1639 while (Next != ListHead) 1640 { 1641 /* Get the current entry */ 1642 Current = CONTAINING_RECORD(Next, 1643 LDR_DATA_TABLE_ENTRY, 1644 InLoadOrderLinks); 1645 1646 /* Make sure it's not unloading and check for a match */ 1647 if ((Current->InMemoryOrderLinks.Flink) && (Base == Current->DllBase)) 1648 { 1649 /* Save in cache */ 1650 LdrpLoadedDllHandleCache = Current; 1651 1652 /* Return it */ 1653 *LdrEntry = Current; 1654 return TRUE; 1655 } 1656 1657 /* Move to the next one */ 1658 Next = Next->Flink; 1659 } 1660 1661 /* Nothing found */ 1662 return FALSE; 1663 } 1664 1665 NTSTATUS 1666 NTAPI 1667 LdrpResolveFullName(IN PUNICODE_STRING OriginalName, 1668 IN PUNICODE_STRING PathName, 1669 IN PUNICODE_STRING FullPathName, 1670 IN PUNICODE_STRING *ExpandedName) 1671 { 1672 NTSTATUS Status = STATUS_SUCCESS; 1673 // RTL_PATH_TYPE PathType; 1674 // BOOLEAN InvalidName; 1675 ULONG Length; 1676 1677 /* Display debug output if snaps are on */ 1678 if (ShowSnaps) 1679 { 1680 DbgPrintEx(DPFLTR_LDR_ID, 1681 DPFLTR_ERROR_LEVEL, 1682 "LDR: %s - Expanding full name of %wZ\n", 1683 __FUNCTION__, 1684 OriginalName); 1685 } 1686 1687 /* FIXME: Lock the PEB */ 1688 //RtlEnterCriticalSection(&FastPebLock); 1689 #if 0 1690 /* Get the path name */ 1691 Length = RtlGetFullPathName_Ustr(OriginalName, 1692 PathName->Length, 1693 PathName->Buffer, 1694 NULL, 1695 &InvalidName, 1696 &PathType); 1697 #else 1698 Length = 0; 1699 #endif 1700 if (!(Length) || (Length > UNICODE_STRING_MAX_BYTES)) 1701 { 1702 /* Fail */ 1703 Status = STATUS_NAME_TOO_LONG; 1704 goto Quickie; 1705 } 1706 1707 /* Check if the length hasn't changed */ 1708 if (Length <= PathName->Length) 1709 { 1710 /* Return the same thing */ 1711 *ExpandedName = PathName; 1712 PathName->Length = (USHORT)Length; 1713 goto Quickie; 1714 } 1715 1716 /* Sanity check */ 1717 ASSERT(Length >= sizeof(WCHAR)); 1718 1719 /* Allocate a string */ 1720 Status = LdrpAllocateUnicodeString(FullPathName, Length - sizeof(WCHAR)); 1721 if (!NT_SUCCESS(Status)) goto Quickie; 1722 1723 /* Now get the full path again */ 1724 #if 0 1725 Length = RtlGetFullPathName_Ustr(OriginalName, 1726 FullPathName->Length, 1727 FullPathName->Buffer, 1728 NULL, 1729 &InvalidName, 1730 &PathType); 1731 #else 1732 Length = 0; 1733 #endif 1734 if (!(Length) || (Length > FullPathName->Length)) 1735 { 1736 /* Fail */ 1737 LdrpFreeUnicodeString(FullPathName); 1738 Status = STATUS_NAME_TOO_LONG; 1739 } 1740 else 1741 { 1742 /* Return the expanded name */ 1743 *ExpandedName = FullPathName; 1744 FullPathName->Length = (USHORT)Length; 1745 } 1746 1747 Quickie: 1748 /* FIXME: Unlock the PEB */ 1749 //RtlLeaveCriticalSection(&FastPebLock); 1750 1751 /* Display debug output if snaps are on */ 1752 if (ShowSnaps) 1753 { 1754 /* Check which output to use -- failure or success */ 1755 if (NT_SUCCESS(Status)) 1756 { 1757 DbgPrintEx(DPFLTR_LDR_ID, 1758 DPFLTR_ERROR_LEVEL, 1759 "LDR: %s - Expanded to %wZ\n", 1760 __FUNCTION__, 1761 *ExpandedName); 1762 } 1763 else 1764 { 1765 DbgPrintEx(DPFLTR_LDR_ID, 1766 DPFLTR_ERROR_LEVEL, 1767 "LDR: %s - Failed to expand %wZ; 0x%08x\n", 1768 __FUNCTION__, 1769 OriginalName, 1770 Status); 1771 } 1772 } 1773 1774 /* If we failed, return NULL */ 1775 if (!NT_SUCCESS(Status)) *ExpandedName = NULL; 1776 1777 /* Return status */ 1778 return Status; 1779 } 1780 1781 NTSTATUS 1782 NTAPI 1783 LdrpSearchPath(IN PWCHAR *SearchPath, 1784 IN PWCHAR DllName, 1785 IN PUNICODE_STRING PathName, 1786 IN PUNICODE_STRING FullPathName, 1787 IN PUNICODE_STRING *ExpandedName) 1788 { 1789 BOOLEAN TryAgain = FALSE; 1790 PWCHAR ActualSearchPath = *SearchPath; 1791 UNICODE_STRING TestName; 1792 NTSTATUS Status; 1793 PWCHAR Buffer, BufEnd = NULL; 1794 ULONG Length = 0; 1795 WCHAR p; 1796 //PWCHAR pp; 1797 1798 /* Check if we don't have a search path */ 1799 if (!ActualSearchPath) *SearchPath = LdrpDefaultPath.Buffer; 1800 1801 /* Display debug output if snaps are on */ 1802 if (ShowSnaps) 1803 { 1804 DbgPrintEx(DPFLTR_LDR_ID, 1805 DPFLTR_ERROR_LEVEL, 1806 "LDR: %s - Looking for %ws in %ws\n", 1807 __FUNCTION__, 1808 DllName, 1809 *SearchPath); 1810 } 1811 1812 /* Check if we're dealing with a relative path */ 1813 if (RtlDetermineDosPathNameType_U(DllName) != RtlPathTypeRelative) 1814 { 1815 /* Good, we're not. Create the name string */ 1816 Status = RtlInitUnicodeStringEx(&TestName, DllName); 1817 if (!NT_SUCCESS(Status)) goto Quickie; 1818 1819 /* Make sure it exists */ 1820 #if 0 1821 if (!RtlDoesFileExists_UstrEx(&TestName, TRUE)) 1822 { 1823 /* It doesn't, fail */ 1824 Status = STATUS_DLL_NOT_FOUND; 1825 goto Quickie; 1826 } 1827 #endif 1828 1829 /* Resolve the full name */ 1830 Status = LdrpResolveFullName(&TestName, 1831 PathName, 1832 FullPathName, 1833 ExpandedName); 1834 goto Quickie; 1835 } 1836 1837 /* FIXME: Handle relative case semicolon-lookup here */ 1838 1839 /* Calculate length */ 1840 Length += (ULONG)wcslen(DllName) + 1; 1841 if (Length > UNICODE_STRING_MAX_CHARS) 1842 { 1843 /* Too long, fail */ 1844 Status = STATUS_NAME_TOO_LONG; 1845 goto Quickie; 1846 } 1847 1848 /* Allocate buffer */ 1849 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR)); 1850 if (!Buffer) 1851 { 1852 /* Fail */ 1853 Status = STATUS_NO_MEMORY; 1854 goto Quickie; 1855 } 1856 1857 /* FIXME: Setup TestName here */ 1858 Status = STATUS_NOT_FOUND; 1859 BufEnd = Buffer; 1860 1861 /* Start loop */ 1862 do 1863 { 1864 /* Get character */ 1865 p = *ActualSearchPath; 1866 if (!(p) || (p == ';')) 1867 { 1868 /* FIXME: We don't have a character, or is a semicolon.*/ 1869 1870 /* Display debug output if snaps are on */ 1871 if (ShowSnaps) 1872 { 1873 DbgPrintEx(DPFLTR_LDR_ID, 1874 DPFLTR_ERROR_LEVEL, 1875 "LDR: %s - Looking for %ws\n", 1876 __FUNCTION__, 1877 Buffer); 1878 } 1879 1880 /* Sanity check */ 1881 TestName.Length = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR); 1882 #if 0 1883 ASSERT(TestName.Length < TestName.MaximumLength); 1884 #endif 1885 1886 /* Check if the file exists */ 1887 #if 0 1888 if (RtlDoesFileExists_UstrEx(&TestName, FALSE)) 1889 #endif 1890 { 1891 /* It does. Reallocate the buffer */ 1892 TestName.MaximumLength = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR) + sizeof(WCHAR); 1893 TestName.Buffer = RtlReAllocateHeap(RtlGetProcessHeap(), 1894 0, 1895 Buffer, 1896 TestName.MaximumLength); 1897 if (!TestName.Buffer) 1898 { 1899 /* Keep the old one */ 1900 TestName.Buffer = Buffer; 1901 } 1902 else 1903 { 1904 /* Update buffer */ 1905 Buffer = TestName.Buffer; 1906 } 1907 1908 /* Make sure we have a buffer at least */ 1909 ASSERT(TestName.Buffer); 1910 1911 /* Resolve the name */ 1912 *SearchPath = ActualSearchPath++; 1913 Status = LdrpResolveFullName(&TestName, 1914 PathName, 1915 FullPathName, 1916 ExpandedName); 1917 break; 1918 } 1919 1920 /* Update buffer end */ 1921 BufEnd = Buffer; 1922 1923 /* Update string position */ 1924 //pp = ActualSearchPath++; 1925 } 1926 else 1927 { 1928 /* Otherwise, write the character */ 1929 *BufEnd = p; 1930 BufEnd++; 1931 } 1932 1933 /* Check if the string is empty, meaning we're done */ 1934 if (!(*ActualSearchPath)) TryAgain = TRUE; 1935 1936 /* Advance in the string */ 1937 ActualSearchPath++; 1938 } while (!TryAgain); 1939 1940 /* Check if we had a buffer and free it */ 1941 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 1942 1943 Quickie: 1944 /* Check if we got here through failure */ 1945 if (!NT_SUCCESS(Status)) *ExpandedName = NULL; 1946 1947 /* Display debug output if snaps are on */ 1948 if (ShowSnaps) 1949 { 1950 /* Check which output to use -- failure or success */ 1951 if (NT_SUCCESS(Status)) 1952 { 1953 DbgPrintEx(DPFLTR_LDR_ID, 1954 DPFLTR_ERROR_LEVEL, 1955 "LDR: %s - Returning %wZ\n", 1956 __FUNCTION__, 1957 *ExpandedName); 1958 } 1959 else 1960 { 1961 DbgPrintEx(DPFLTR_LDR_ID, 1962 DPFLTR_ERROR_LEVEL, 1963 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n", 1964 __FUNCTION__, 1965 DllName, 1966 ActualSearchPath, 1967 Status); 1968 } 1969 } 1970 1971 /* Return status */ 1972 return Status; 1973 } 1974 1975 1976 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */ 1977 BOOLEAN 1978 NTAPI 1979 LdrpCheckForLoadedDll(IN PWSTR DllPath, 1980 IN PUNICODE_STRING DllName, 1981 IN BOOLEAN Flag, 1982 IN BOOLEAN RedirectedDll, 1983 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) 1984 { 1985 ULONG HashIndex; 1986 PLIST_ENTRY ListHead, ListEntry; 1987 PLDR_DATA_TABLE_ENTRY CurEntry; 1988 BOOLEAN FullPath = FALSE; 1989 PWCHAR wc; 1990 WCHAR NameBuf[266]; 1991 UNICODE_STRING FullDllName, NtPathName; 1992 ULONG Length; 1993 OBJECT_ATTRIBUTES ObjectAttributes; 1994 NTSTATUS Status; 1995 HANDLE FileHandle, SectionHandle; 1996 IO_STATUS_BLOCK Iosb; 1997 PVOID ViewBase = NULL; 1998 SIZE_T ViewSize = 0; 1999 PIMAGE_NT_HEADERS NtHeader, NtHeader2; 2000 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry); 2001 2002 /* Check if a dll name was provided */ 2003 if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE; 2004 2005 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */ 2006 /* FIXME: Warning, code does not support redirection at all */ 2007 2008 /* Look in the hash table if flag was set */ 2009 lookinhash: 2010 if (Flag /* the second check is a hack */ && !RedirectedDll) 2011 { 2012 /* FIXME: if we get redirected dll it means that we also get a full path so we need to find its filename for the hash lookup */ 2013 2014 /* Get hash index */ 2015 HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]); 2016 2017 /* Traverse that list */ 2018 ListHead = &LdrpHashTable[HashIndex]; 2019 ListEntry = ListHead->Flink; 2020 while (ListEntry != ListHead) 2021 { 2022 /* Get the current entry */ 2023 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 2024 2025 /* Check base name of that module */ 2026 if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE)) 2027 { 2028 /* It matches, return it */ 2029 *LdrEntry = CurEntry; 2030 return TRUE; 2031 } 2032 2033 /* Advance to the next entry */ 2034 ListEntry = ListEntry->Flink; 2035 } 2036 2037 /* Module was not found, return failure */ 2038 return FALSE; 2039 } 2040 2041 /* Check if this is a redirected DLL */ 2042 if (RedirectedDll) 2043 { 2044 /* Redirected dlls already have a full path */ 2045 FullPath = TRUE; 2046 FullDllName = *DllName; 2047 } 2048 else 2049 { 2050 /* Check if there is a full path in this DLL */ 2051 wc = DllName->Buffer; 2052 while (*wc) 2053 { 2054 /* Check for a slash in the current position*/ 2055 if ((*wc == L'\\') || (*wc == L'/')) 2056 { 2057 /* Found the slash, so dll name contains path */ 2058 FullPath = TRUE; 2059 2060 /* Setup full dll name string */ 2061 FullDllName.Buffer = NameBuf; 2062 2063 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */ 2064 Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer, 2065 DllName->Buffer, 2066 NULL, 2067 sizeof(NameBuf) - sizeof(UNICODE_NULL), 2068 FullDllName.Buffer, 2069 NULL); 2070 2071 /* Check if that was successful */ 2072 if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL)))) 2073 { 2074 if (ShowSnaps) 2075 { 2076 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n", 2077 &DllName, Length); 2078 } 2079 } 2080 2081 /* Full dll name is found */ 2082 FullDllName.Length = Length; 2083 FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL); 2084 break; 2085 } 2086 2087 wc++; 2088 } 2089 } 2090 2091 /* Go check the hash table */ 2092 if (!FullPath) 2093 { 2094 Flag = TRUE; 2095 goto lookinhash; 2096 } 2097 2098 /* FIXME: Warning, activation context missing */ 2099 DPRINT("Warning, activation context missing\n"); 2100 2101 /* NOTE: From here on down, everything looks good */ 2102 2103 /* Loop the module list */ 2104 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2105 ListEntry = ListHead->Flink; 2106 while (ListEntry != ListHead) 2107 { 2108 /* Get the current entry and advance to the next one */ 2109 CurEntry = CONTAINING_RECORD(ListEntry, 2110 LDR_DATA_TABLE_ENTRY, 2111 InLoadOrderLinks); 2112 ListEntry = ListEntry->Flink; 2113 2114 /* Check if it's being unloaded */ 2115 if (!CurEntry->InMemoryOrderLinks.Flink) continue; 2116 2117 /* Check if name matches */ 2118 if (RtlEqualUnicodeString(&FullDllName, 2119 &CurEntry->FullDllName, 2120 TRUE)) 2121 { 2122 /* Found it */ 2123 *LdrEntry = CurEntry; 2124 return TRUE; 2125 } 2126 } 2127 2128 /* Convert given path to NT path */ 2129 if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer, 2130 &NtPathName, 2131 NULL, 2132 NULL)) 2133 { 2134 /* Fail if conversion failed */ 2135 return FALSE; 2136 } 2137 2138 /* Initialize object attributes and open it */ 2139 InitializeObjectAttributes(&ObjectAttributes, 2140 &NtPathName, 2141 OBJ_CASE_INSENSITIVE, 2142 NULL, 2143 NULL); 2144 Status = NtOpenFile(&FileHandle, 2145 SYNCHRONIZE | FILE_EXECUTE, 2146 &ObjectAttributes, 2147 &Iosb, 2148 FILE_SHARE_READ | FILE_SHARE_DELETE, 2149 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 2150 2151 /* Free NT path name */ 2152 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer); 2153 2154 /* If opening the file failed - return failure */ 2155 if (!NT_SUCCESS(Status)) return FALSE; 2156 2157 /* Create a section for this file */ 2158 Status = NtCreateSection(&SectionHandle, 2159 SECTION_MAP_READ | 2160 SECTION_MAP_EXECUTE | 2161 SECTION_MAP_WRITE, 2162 NULL, 2163 NULL, 2164 PAGE_EXECUTE, 2165 SEC_COMMIT, 2166 FileHandle); 2167 2168 /* Close file handle */ 2169 NtClose(FileHandle); 2170 2171 /* If creating section failed - return failure */ 2172 if (!NT_SUCCESS(Status)) return FALSE; 2173 2174 /* Map view of this section */ 2175 Status = ZwMapViewOfSection(SectionHandle, 2176 NtCurrentProcess(), 2177 &ViewBase, 2178 0, 2179 0, 2180 NULL, 2181 &ViewSize, 2182 ViewShare, 2183 0, 2184 PAGE_EXECUTE); 2185 2186 /* Close section handle */ 2187 NtClose(SectionHandle); 2188 2189 /* If section mapping failed - return failure */ 2190 if (!NT_SUCCESS(Status)) return FALSE; 2191 2192 /* Get pointer to the NT header of this section */ 2193 Status = RtlImageNtHeaderEx(0, ViewBase, ViewSize, &NtHeader); 2194 if (!(NT_SUCCESS(Status)) || !(NtHeader)) 2195 { 2196 /* Unmap the section and fail */ 2197 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2198 return FALSE; 2199 } 2200 2201 /* Go through the list of modules again */ 2202 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2203 ListEntry = ListHead->Flink; 2204 while (ListEntry != ListHead) 2205 { 2206 /* Get the current entry and advance to the next one */ 2207 CurEntry = CONTAINING_RECORD(ListEntry, 2208 LDR_DATA_TABLE_ENTRY, 2209 InLoadOrderLinks); 2210 ListEntry = ListEntry->Flink; 2211 2212 /* Check if it's in the process of being unloaded */ 2213 if (!CurEntry->InMemoryOrderLinks.Flink) continue; 2214 2215 /* The header is untrusted, use SEH */ 2216 _SEH2_TRY 2217 { 2218 /* Check if timedate stamp and sizes match */ 2219 if ((CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp) && 2220 (CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage)) 2221 { 2222 /* Time, date and size match. Let's compare their headers */ 2223 NtHeader2 = RtlImageNtHeader(CurEntry->DllBase); 2224 if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS))) 2225 { 2226 /* Headers match too! Finally ask the kernel to compare mapped files */ 2227 Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase); 2228 if (NT_SUCCESS(Status)) 2229 { 2230 /* This is our entry!, unmap and return success */ 2231 *LdrEntry = CurEntry; 2232 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2233 _SEH2_YIELD(return TRUE;) 2234 } 2235 } 2236 } 2237 } 2238 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) 2239 { 2240 _SEH2_YIELD(break;) 2241 } 2242 _SEH2_END; 2243 } 2244 2245 /* Unmap the section and fail */ 2246 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2247 return FALSE; 2248 } 2249 2250 NTSTATUS 2251 NTAPI 2252 LdrpGetProcedureAddress( 2253 _In_ PVOID BaseAddress, 2254 _In_opt_ _When_(Ordinal == 0, _Notnull_) PANSI_STRING Name, 2255 _In_opt_ _When_(Name == NULL, _In_range_(>, 0)) ULONG Ordinal, 2256 _Out_ PVOID *ProcedureAddress, 2257 _In_ BOOLEAN ExecuteInit) 2258 { 2259 NTSTATUS Status = STATUS_SUCCESS; 2260 UCHAR ImportBuffer[64]; // 128 since NT6.2 2261 PLDR_DATA_TABLE_ENTRY LdrEntry; 2262 IMAGE_THUNK_DATA Thunk; 2263 PVOID ImageBase; 2264 PIMAGE_IMPORT_BY_NAME ImportName = NULL; 2265 PIMAGE_EXPORT_DIRECTORY ExportDir; 2266 ULONG ExportDirSize, Length; 2267 PLIST_ENTRY Entry; 2268 2269 /* Show debug message */ 2270 if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by "); 2271 2272 /* Check if we got a name */ 2273 if (Name) 2274 { 2275 /* Show debug message */ 2276 if (ShowSnaps) DbgPrint("NAME - %s\n", Name->Buffer); 2277 2278 /* Make sure it's not too long */ 2279 Length = Name->Length + 2280 sizeof(CHAR) + 2281 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name); 2282 if (Length > UNICODE_STRING_MAX_BYTES) 2283 { 2284 /* Won't have enough space to add the hint */ 2285 return STATUS_NAME_TOO_LONG; 2286 } 2287 2288 /* Check if our buffer is large enough */ 2289 if (Length > sizeof(ImportBuffer)) 2290 { 2291 /* Allocate from heap, plus 2 bytes for the Hint */ 2292 ImportName = RtlAllocateHeap(RtlGetProcessHeap(), 2293 0, 2294 Length); 2295 if (!ImportName) 2296 { 2297 /* Return STATUS_INSUFFICIENT_RESOURCES since NT6.2 */ 2298 return STATUS_INVALID_PARAMETER; 2299 } 2300 } 2301 else 2302 { 2303 /* Use our internal buffer */ 2304 ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer; 2305 } 2306 2307 /* Clear the hint */ 2308 ImportName->Hint = 0; 2309 2310 /* Copy the name and null-terminate it */ 2311 RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length); 2312 ImportName->Name[Name->Length] = ANSI_NULL; 2313 2314 /* Clear the high bit */ 2315 ImageBase = ImportName; 2316 Thunk.u1.AddressOfData = 0; 2317 } 2318 else 2319 { 2320 /* Do it by ordinal */ 2321 ImageBase = NULL; 2322 2323 /* Show debug message */ 2324 if (ShowSnaps) DbgPrint("ORDINAL - %lx\n", Ordinal); 2325 2326 /* Make sure an ordinal was given */ 2327 if (!Ordinal) 2328 { 2329 /* No ordinal */ 2330 DPRINT1("No ordinal and no name\n"); 2331 return STATUS_INVALID_PARAMETER; 2332 } 2333 2334 /* Set the original flag in the thunk */ 2335 Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG; 2336 } 2337 2338 /* Acquire lock unless we are initting */ 2339 if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock); 2340 2341 _SEH2_TRY 2342 { 2343 /* Try to find the loaded DLL */ 2344 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 2345 { 2346 /* Invalid base */ 2347 DPRINT1("Invalid base address %p\n", BaseAddress); 2348 Status = STATUS_DLL_NOT_FOUND; 2349 _SEH2_YIELD(goto Quickie;) 2350 } 2351 2352 /* Get the pointer to the export directory */ 2353 ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 2354 TRUE, 2355 IMAGE_DIRECTORY_ENTRY_EXPORT, 2356 &ExportDirSize); 2357 2358 if (!ExportDir) 2359 { 2360 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n", 2361 &LdrEntry->BaseDllName, Name, BaseAddress, LdrEntry->DllBase); 2362 Status = STATUS_PROCEDURE_NOT_FOUND; 2363 _SEH2_YIELD(goto Quickie;) 2364 } 2365 2366 /* Now get the thunk */ 2367 Status = LdrpSnapThunk(LdrEntry->DllBase, 2368 ImageBase, 2369 &Thunk, 2370 &Thunk, 2371 ExportDir, 2372 ExportDirSize, 2373 FALSE, 2374 NULL); 2375 2376 /* Finally, see if we're supposed to run the init routines */ 2377 if ((NT_SUCCESS(Status)) && (ExecuteInit)) 2378 { 2379 /* 2380 * It's possible a forwarded entry had us load the DLL. In that case, 2381 * then we will call its DllMain. Use the last loaded DLL for this. 2382 */ 2383 Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink; 2384 LdrEntry = CONTAINING_RECORD(Entry, 2385 LDR_DATA_TABLE_ENTRY, 2386 InInitializationOrderLinks); 2387 2388 /* Make sure we didn't process it yet*/ 2389 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) 2390 { 2391 /* Call the init routine */ 2392 _SEH2_TRY 2393 { 2394 Status = LdrpRunInitializeRoutines(NULL); 2395 } 2396 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2397 { 2398 /* Get the exception code */ 2399 Status = _SEH2_GetExceptionCode(); 2400 } 2401 _SEH2_END; 2402 } 2403 } 2404 2405 /* Make sure we're OK till here */ 2406 if (NT_SUCCESS(Status)) 2407 { 2408 /* Return the address */ 2409 *ProcedureAddress = (PVOID)Thunk.u1.Function; 2410 } 2411 } 2412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2413 { 2414 /* Just ignore exceptions */ 2415 } 2416 _SEH2_END; 2417 2418 Quickie: 2419 /* Cleanup */ 2420 if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer)) 2421 { 2422 /* We allocated from heap, free it */ 2423 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName); 2424 } 2425 2426 /* Release the CS if we entered it */ 2427 if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock); 2428 2429 /* We're done */ 2430 return Status; 2431 } 2432 2433 NTSTATUS 2434 NTAPI 2435 LdrpLoadDll(IN BOOLEAN Redirected, 2436 IN PWSTR DllPath OPTIONAL, 2437 IN PULONG DllCharacteristics OPTIONAL, 2438 IN PUNICODE_STRING DllName, 2439 OUT PVOID *BaseAddress, 2440 IN BOOLEAN CallInit) 2441 { 2442 PPEB Peb = NtCurrentPeb(); 2443 NTSTATUS Status = STATUS_SUCCESS; 2444 const WCHAR *p; 2445 BOOLEAN GotExtension; 2446 WCHAR c; 2447 WCHAR NameBuffer[MAX_PATH + 6]; 2448 UNICODE_STRING RawDllName; 2449 PLDR_DATA_TABLE_ENTRY LdrEntry; 2450 BOOLEAN InInit = LdrpInLdrInit; 2451 2452 /* Save the Raw DLL Name */ 2453 if (DllName->Length >= sizeof(NameBuffer)) return STATUS_NAME_TOO_LONG; 2454 RtlInitEmptyUnicodeString(&RawDllName, NameBuffer, sizeof(NameBuffer)); 2455 RtlCopyUnicodeString(&RawDllName, DllName); 2456 2457 /* Find the extension, if present */ 2458 /* NOTE: Access violation is expected here in some cases (Buffer[-1]) */ 2459 p = DllName->Buffer + DllName->Length / sizeof(WCHAR) - 1; 2460 GotExtension = FALSE; 2461 while (p >= DllName->Buffer) 2462 { 2463 c = *p--; 2464 if (c == L'.') 2465 { 2466 GotExtension = TRUE; 2467 break; 2468 } 2469 else if (c == L'\\') 2470 { 2471 break; 2472 } 2473 } 2474 2475 /* If no extension was found, add the default extension */ 2476 if (!GotExtension) 2477 { 2478 /* Check that we have space to add one */ 2479 if ((DllName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >= 2480 sizeof(NameBuffer)) 2481 { 2482 /* No space to add the extension */ 2483 DbgPrintEx(DPFLTR_LDR_ID, 2484 DPFLTR_ERROR_LEVEL, 2485 "LDR: %s - Dll name missing extension; with extension " 2486 "added the name is too long\n" 2487 " DllName: (@ %p) \"%wZ\"\n" 2488 " DllName->Length: %u\n", 2489 __FUNCTION__, 2490 DllName, 2491 DllName, 2492 DllName->Length); 2493 return STATUS_NAME_TOO_LONG; 2494 } 2495 2496 /* Add it. Needs to be null terminated, thus the length check above */ 2497 (VOID)RtlAppendUnicodeStringToString(&RawDllName, 2498 &LdrApiDefaultExtension); 2499 } 2500 2501 /* Check for init flag and acquire lock */ 2502 if (!InInit) RtlEnterCriticalSection(&LdrpLoaderLock); 2503 2504 _SEH2_TRY 2505 { 2506 /* Show debug message */ 2507 if (ShowSnaps) 2508 { 2509 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n", 2510 &RawDllName, 2511 DllPath ? DllPath : L""); 2512 } 2513 2514 /* Check if the DLL is already loaded */ 2515 if (!LdrpCheckForLoadedDll(DllPath, 2516 &RawDllName, 2517 FALSE, 2518 Redirected, 2519 &LdrEntry)) 2520 { 2521 /* Map it */ 2522 Status = LdrpMapDll(DllPath, 2523 DllPath, 2524 NameBuffer, 2525 DllCharacteristics, 2526 FALSE, 2527 Redirected, 2528 &LdrEntry); 2529 if (!NT_SUCCESS(Status)) 2530 _SEH2_LEAVE; 2531 2532 /* FIXME: Need to mark the DLL range for the stack DB */ 2533 //RtlpStkMarkDllRange(LdrEntry); 2534 2535 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */ 2536 if ((DllCharacteristics) && 2537 (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) 2538 { 2539 /* This is not a DLL, so remove such data */ 2540 LdrEntry->EntryPoint = NULL; 2541 LdrEntry->Flags &= ~LDRP_IMAGE_DLL; 2542 } 2543 2544 /* Make sure it's a DLL */ 2545 if (LdrEntry->Flags & LDRP_IMAGE_DLL) 2546 { 2547 /* Check if this is a .NET Image */ 2548 if (!(LdrEntry->Flags & LDRP_COR_IMAGE)) 2549 { 2550 /* Walk the Import Descriptor */ 2551 Status = LdrpWalkImportDescriptor(DllPath, LdrEntry); 2552 } 2553 2554 /* Update load count, unless it's locked */ 2555 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++; 2556 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 2557 2558 /* Check if we failed */ 2559 if (!NT_SUCCESS(Status)) 2560 { 2561 /* Clear entrypoint, and insert into list */ 2562 LdrEntry->EntryPoint = NULL; 2563 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 2564 &LdrEntry->InInitializationOrderLinks); 2565 2566 /* Cancel the load */ 2567 LdrpClearLoadInProgress(); 2568 2569 /* Unload the DLL */ 2570 if (ShowSnaps) 2571 { 2572 DbgPrint("LDR: Unloading %wZ due to error %x walking " 2573 "import descriptors\n", 2574 DllName, 2575 Status); 2576 } 2577 LdrUnloadDll(LdrEntry->DllBase); 2578 2579 /* Return the error */ 2580 _SEH2_LEAVE; 2581 } 2582 } 2583 else if (LdrEntry->LoadCount != 0xFFFF) 2584 { 2585 /* Increase load count */ 2586 LdrEntry->LoadCount++; 2587 } 2588 2589 /* Insert it into the list */ 2590 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 2591 &LdrEntry->InInitializationOrderLinks); 2592 2593 /* If we have to run the entrypoint, make sure the DB is ready */ 2594 if (CallInit && LdrpLdrDatabaseIsSetup) 2595 { 2596 /* Notify Shim Engine */ 2597 if (g_ShimsEnabled) 2598 { 2599 VOID (NTAPI* SE_DllLoaded)(PLDR_DATA_TABLE_ENTRY) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded); 2600 SE_DllLoaded(LdrEntry); 2601 } 2602 2603 /* Run the init routine */ 2604 Status = LdrpRunInitializeRoutines(NULL); 2605 if (!NT_SUCCESS(Status)) 2606 { 2607 /* Failed, unload the DLL */ 2608 if (ShowSnaps) 2609 { 2610 DbgPrint("LDR: Unloading %wZ because either its init " 2611 "routine or one of its static imports failed; " 2612 "status = 0x%08lx\n", 2613 DllName, 2614 Status); 2615 } 2616 LdrUnloadDll(LdrEntry->DllBase); 2617 } 2618 } 2619 else 2620 { 2621 /* The DB isn't ready, which means we were loaded because of a forwarder */ 2622 Status = STATUS_SUCCESS; 2623 } 2624 } 2625 else 2626 { 2627 /* We were already loaded. Are we a DLL? */ 2628 if ((LdrEntry->Flags & LDRP_IMAGE_DLL) && (LdrEntry->LoadCount != 0xFFFF)) 2629 { 2630 /* Increase load count */ 2631 LdrEntry->LoadCount++; 2632 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 2633 2634 /* Clear the load in progress */ 2635 LdrpClearLoadInProgress(); 2636 } 2637 else 2638 { 2639 /* Not a DLL, just increase the load count */ 2640 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++; 2641 } 2642 } 2643 2644 } 2645 _SEH2_FINALLY 2646 { 2647 /* Release the lock */ 2648 if (!InInit) RtlLeaveCriticalSection(&LdrpLoaderLock); 2649 } 2650 _SEH2_END; 2651 2652 /* Check for success */ 2653 if (NT_SUCCESS(Status)) 2654 { 2655 /* Return the base address */ 2656 *BaseAddress = LdrEntry->DllBase; 2657 } 2658 else 2659 { 2660 /* Nothing found */ 2661 *BaseAddress = NULL; 2662 } 2663 2664 /* Return status */ 2665 return Status; 2666 } 2667 2668 ULONG 2669 NTAPI 2670 LdrpClearLoadInProgress(VOID) 2671 { 2672 PLIST_ENTRY ListHead, Entry; 2673 PLDR_DATA_TABLE_ENTRY LdrEntry; 2674 ULONG ModulesCount = 0; 2675 2676 /* Traverse the init list */ 2677 ListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; 2678 Entry = ListHead->Flink; 2679 while (Entry != ListHead) 2680 { 2681 /* Get the loader entry */ 2682 LdrEntry = CONTAINING_RECORD(Entry, 2683 LDR_DATA_TABLE_ENTRY, 2684 InInitializationOrderLinks); 2685 2686 /* Clear load in progress flag */ 2687 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS; 2688 2689 /* Check for modules with entry point count but not processed yet */ 2690 if ((LdrEntry->EntryPoint) && 2691 !(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) 2692 { 2693 /* Increase counter */ 2694 ModulesCount++; 2695 } 2696 2697 /* Advance to the next entry */ 2698 Entry = Entry->Flink; 2699 } 2700 2701 /* Return final count */ 2702 return ModulesCount; 2703 } 2704 2705 PVOID LdrpGetShimEngineFunction(PCSZ FunctionName) 2706 { 2707 ANSI_STRING Function; 2708 NTSTATUS Status; 2709 PVOID Address; 2710 RtlInitAnsiString(&Function, FunctionName); 2711 /* Skip Dll init */ 2712 Status = LdrpGetProcedureAddress(g_pShimEngineModule, &Function, 0, &Address, FALSE); 2713 return NT_SUCCESS(Status) ? Address : NULL; 2714 } 2715 2716 VOID 2717 NTAPI 2718 LdrpGetShimEngineInterface() 2719 { 2720 PVOID SE_DllLoaded = LdrpGetShimEngineFunction("SE_DllLoaded"); 2721 PVOID SE_DllUnloaded = LdrpGetShimEngineFunction("SE_DllUnloaded"); 2722 PVOID SE_InstallBeforeInit = LdrpGetShimEngineFunction("SE_InstallBeforeInit"); 2723 PVOID SE_InstallAfterInit = LdrpGetShimEngineFunction("SE_InstallAfterInit"); 2724 PVOID SE_ProcessDying = LdrpGetShimEngineFunction("SE_ProcessDying"); 2725 2726 if (SE_DllLoaded && SE_DllUnloaded && SE_InstallBeforeInit && SE_InstallAfterInit && SE_ProcessDying) 2727 { 2728 g_pfnSE_DllLoaded = RtlEncodeSystemPointer(SE_DllLoaded); 2729 g_pfnSE_DllUnloaded = RtlEncodeSystemPointer(SE_DllUnloaded); 2730 g_pfnSE_InstallBeforeInit = RtlEncodeSystemPointer(SE_InstallBeforeInit); 2731 g_pfnSE_InstallAfterInit = RtlEncodeSystemPointer(SE_InstallAfterInit); 2732 g_pfnSE_ProcessDying = RtlEncodeSystemPointer(SE_ProcessDying); 2733 g_ShimsEnabled = TRUE; 2734 } 2735 else 2736 { 2737 LdrpUnloadShimEngine(); 2738 } 2739 } 2740 2741 VOID 2742 NTAPI 2743 LdrpRunShimEngineInitRoutine(IN ULONG Reason) 2744 { 2745 PLIST_ENTRY ListHead, Next; 2746 PLDR_DATA_TABLE_ENTRY LdrEntry; 2747 2748 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2749 Next = ListHead->Flink; 2750 while (Next != ListHead) 2751 { 2752 LdrEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 2753 2754 if (g_pShimEngineModule == LdrEntry->DllBase) 2755 { 2756 if (LdrEntry->EntryPoint) 2757 { 2758 _SEH2_TRY 2759 { 2760 LdrpCallInitRoutine(LdrEntry->EntryPoint, LdrEntry->DllBase, Reason, NULL); 2761 } 2762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2763 { 2764 DPRINT1("WARNING: Exception 0x%x during LdrpRunShimEngineInitRoutine(%u)\n", 2765 _SEH2_GetExceptionCode(), Reason); 2766 } 2767 _SEH2_END; 2768 } 2769 return; 2770 } 2771 2772 Next = Next->Flink; 2773 } 2774 } 2775 2776 VOID 2777 NTAPI 2778 LdrpLoadShimEngine(IN PWSTR ImageName, IN PUNICODE_STRING ProcessImage, IN PVOID pShimData) 2779 { 2780 UNICODE_STRING ShimLibraryName; 2781 PVOID ShimLibrary; 2782 NTSTATUS Status; 2783 RtlInitUnicodeString(&ShimLibraryName, ImageName); 2784 /* We should NOT pass CallInit = TRUE! 2785 If we do this, other init routines will be called before we get a chance to shim stuff.. */ 2786 Status = LdrpLoadDll(FALSE, NULL, NULL, &ShimLibraryName, &ShimLibrary, FALSE); 2787 if (NT_SUCCESS(Status)) 2788 { 2789 g_pShimEngineModule = ShimLibrary; 2790 LdrpRunShimEngineInitRoutine(DLL_PROCESS_ATTACH); 2791 LdrpGetShimEngineInterface(); 2792 if (g_ShimsEnabled) 2793 { 2794 VOID(NTAPI *SE_InstallBeforeInit)(PUNICODE_STRING, PVOID); 2795 SE_InstallBeforeInit = RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit); 2796 SE_InstallBeforeInit(ProcessImage, pShimData); 2797 } 2798 } 2799 } 2800 2801 VOID 2802 NTAPI 2803 LdrpUnloadShimEngine() 2804 { 2805 /* Make sure we do not call into the shim engine anymore */ 2806 g_ShimsEnabled = FALSE; 2807 LdrpRunShimEngineInitRoutine(DLL_PROCESS_DETACH); 2808 LdrUnloadDll(g_pShimEngineModule); 2809 g_pShimEngineModule = NULL; 2810 } 2811 2812 /* EOF */ 2813