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