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