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(RtlGetProcessHeap(), 54 0, 55 StringOut->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[StringOut->Length / sizeof(WCHAR)] = UNICODE_NULL; 65 66 /* Check if this is a maximum-sized string */ 67 if (StringOut->Length != UNICODE_STRING_MAX_BYTES) 68 { 69 /* It's not, so set the maximum length to be one char more */ 70 StringOut->MaximumLength = StringOut->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(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 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 RtlFreeUnicodeString(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(RtlGetProcessHeap(), 0, FullDllName->MaximumLength); 734 if (!NameBuffer) 735 { 736 RtlFreeHeap(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 0, BaseDllName->MaximumLength); 770 771 if (!BaseDllName->Buffer) 772 { 773 RtlFreeHeap(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 0, BaseDllName->Buffer); 936 if (FullDllName->Buffer) RtlFreeHeap(RtlGetProcessHeap(), 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 RtlFreeUnicodeString(&FullDllName); 1141 RtlFreeUnicodeString(&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(RtlGetProcessHeap(), 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 DPRINT1("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 DPRINT1("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 /* Raise the error */ 1421 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION, 1422 2, 1423 3, 1424 HardErrorParameters, 1425 OptionOk, 1426 &Response); 1427 1428 /* If initializing, increase the error count */ 1429 if (LdrpInLdrInit) LdrpFatalHardErrorCount++; 1430 1431 /* Don't do relocation */ 1432 Status = STATUS_CONFLICTING_ADDRESSES; 1433 goto FailRelocate; 1434 } 1435 1436 /* Change the protection to prepare for relocation */ 1437 Status = LdrpSetProtection(ViewBase, FALSE); 1438 1439 /* Make sure we changed the protection */ 1440 if (NT_SUCCESS(Status)) 1441 { 1442 /* Do the relocation */ 1443 Status = LdrRelocateImageWithBias(ViewBase, 0LL, NULL, STATUS_SUCCESS, 1444 STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT); 1445 1446 if (NT_SUCCESS(Status)) 1447 { 1448 /* Stuff the image name in the TIB, for the debugger */ 1449 ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; 1450 Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; 1451 #if 0 1452 /* Map the DLL */ 1453 Status = NtMapViewOfSection(SectionHandle, 1454 NtCurrentProcess(), 1455 &ViewBase, 1456 0, 1457 0, 1458 NULL, 1459 &ViewSize, 1460 ViewShare, 1461 0, 1462 PAGE_READWRITE); 1463 #endif 1464 /* Restore */ 1465 Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; 1466 1467 /* Return the protection */ 1468 Status = LdrpSetProtection(ViewBase, TRUE); 1469 } 1470 } 1471 FailRelocate: 1472 /* Handle any kind of failure */ 1473 if (!NT_SUCCESS(Status)) 1474 { 1475 /* Remove it from the lists */ 1476 RemoveEntryList(&LdrEntry->InLoadOrderLinks); 1477 RemoveEntryList(&LdrEntry->InMemoryOrderLinks); 1478 RemoveEntryList(&LdrEntry->HashLinks); 1479 1480 /* Unmap it, clear the entry */ 1481 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 1482 LdrEntry = NULL; 1483 } 1484 1485 /* Show debug message */ 1486 if (ShowSnaps) 1487 { 1488 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n", 1489 NT_SUCCESS(Status) ? "s" : "uns", ViewBase); 1490 } 1491 } 1492 else 1493 { 1494 NoRelocNeeded: 1495 /* Not a DLL, or no relocation needed */ 1496 Status = STATUS_SUCCESS; 1497 1498 /* Stuff the image name in the TIB, for the debugger */ 1499 ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; 1500 Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; 1501 #if 0 1502 /* Map the DLL */ 1503 Status = NtMapViewOfSection(SectionHandle, 1504 NtCurrentProcess(), 1505 &ViewBase, 1506 0, 1507 0, 1508 NULL, 1509 &ViewSize, 1510 ViewShare, 1511 0, 1512 PAGE_READWRITE); 1513 #endif 1514 /* Restore */ 1515 Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; 1516 1517 /* Show debug message */ 1518 if (ShowSnaps) 1519 { 1520 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase); 1521 } 1522 } 1523 } 1524 1525 // FIXME: LdrpCheckCorImage() is missing 1526 1527 /* Check if this is an SMP Machine and a DLL */ 1528 if ((LdrpNumberOfProcessors > 1) && 1529 (LdrEntry && (LdrEntry->Flags & LDRP_IMAGE_DLL))) 1530 { 1531 /* Validate the image for MP */ 1532 LdrpValidateImageForMp(LdrEntry); 1533 } 1534 1535 // FIXME: LdrpCorUnloadImage() is missing 1536 1537 /* Close section and return status */ 1538 NtClose(SectionHandle); 1539 return Status; 1540 } 1541 1542 PLDR_DATA_TABLE_ENTRY 1543 NTAPI 1544 LdrpAllocateDataTableEntry(IN PVOID BaseAddress) 1545 { 1546 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL; 1547 PIMAGE_NT_HEADERS NtHeader; 1548 1549 /* Make sure the header is valid */ 1550 NtHeader = RtlImageNtHeader(BaseAddress); 1551 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress, NtHeader); 1552 1553 if (NtHeader) 1554 { 1555 /* Allocate an entry */ 1556 LdrEntry = RtlAllocateHeap(RtlGetProcessHeap(), 1557 HEAP_ZERO_MEMORY, 1558 sizeof(LDR_DATA_TABLE_ENTRY)); 1559 1560 /* Make sure we got one */ 1561 if (LdrEntry) 1562 { 1563 /* Set it up */ 1564 LdrEntry->DllBase = BaseAddress; 1565 LdrEntry->SizeOfImage = NtHeader->OptionalHeader.SizeOfImage; 1566 LdrEntry->TimeDateStamp = NtHeader->FileHeader.TimeDateStamp; 1567 LdrEntry->PatchInformation = NULL; 1568 } 1569 } 1570 1571 /* Return the entry */ 1572 return LdrEntry; 1573 } 1574 1575 VOID 1576 NTAPI 1577 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 1578 { 1579 PPEB_LDR_DATA PebData = NtCurrentPeb()->Ldr; 1580 ULONG i; 1581 1582 /* Insert into hash table */ 1583 i = LDR_GET_HASH_ENTRY(LdrEntry->BaseDllName.Buffer[0]); 1584 InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks); 1585 1586 /* Insert into other lists */ 1587 InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks); 1588 InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks); 1589 } 1590 1591 VOID 1592 NTAPI 1593 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry) 1594 { 1595 /* Sanity check */ 1596 ASSERT(Entry != NULL); 1597 1598 /* Release the activation context if it exists and wasn't already released */ 1599 if ((Entry->EntryPointActivationContext) && 1600 (Entry->EntryPointActivationContext != INVALID_HANDLE_VALUE)) 1601 { 1602 /* Mark it as invalid */ 1603 RtlReleaseActivationContext(Entry->EntryPointActivationContext); 1604 Entry->EntryPointActivationContext = INVALID_HANDLE_VALUE; 1605 } 1606 1607 /* Release the full dll name string */ 1608 if (Entry->FullDllName.Buffer) LdrpFreeUnicodeString(&Entry->FullDllName); 1609 1610 /* Finally free the entry's memory */ 1611 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry); 1612 } 1613 1614 BOOLEAN 1615 NTAPI 1616 LdrpCheckForLoadedDllHandle(IN PVOID Base, 1617 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) 1618 { 1619 PLDR_DATA_TABLE_ENTRY Current; 1620 PLIST_ENTRY ListHead, Next; 1621 1622 /* Check the cache first */ 1623 if ((LdrpLoadedDllHandleCache) && 1624 (LdrpLoadedDllHandleCache->DllBase == Base)) 1625 { 1626 /* We got lucky, return the cached entry */ 1627 *LdrEntry = LdrpLoadedDllHandleCache; 1628 return TRUE; 1629 } 1630 1631 /* Time for a lookup */ 1632 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 1633 Next = ListHead->Flink; 1634 while (Next != ListHead) 1635 { 1636 /* Get the current entry */ 1637 Current = CONTAINING_RECORD(Next, 1638 LDR_DATA_TABLE_ENTRY, 1639 InLoadOrderLinks); 1640 1641 /* Make sure it's not unloading and check for a match */ 1642 if ((Current->InMemoryOrderLinks.Flink) && (Base == Current->DllBase)) 1643 { 1644 /* Save in cache */ 1645 LdrpLoadedDllHandleCache = Current; 1646 1647 /* Return it */ 1648 *LdrEntry = Current; 1649 return TRUE; 1650 } 1651 1652 /* Move to the next one */ 1653 Next = Next->Flink; 1654 } 1655 1656 /* Nothing found */ 1657 return FALSE; 1658 } 1659 1660 NTSTATUS 1661 NTAPI 1662 LdrpResolveFullName(IN PUNICODE_STRING OriginalName, 1663 IN PUNICODE_STRING PathName, 1664 IN PUNICODE_STRING FullPathName, 1665 IN PUNICODE_STRING *ExpandedName) 1666 { 1667 NTSTATUS Status = STATUS_SUCCESS; 1668 // RTL_PATH_TYPE PathType; 1669 // BOOLEAN InvalidName; 1670 ULONG Length; 1671 1672 /* Display debug output if snaps are on */ 1673 if (ShowSnaps) 1674 { 1675 DbgPrintEx(DPFLTR_LDR_ID, 1676 DPFLTR_ERROR_LEVEL, 1677 "LDR: %s - Expanding full name of %wZ\n", 1678 __FUNCTION__, 1679 OriginalName); 1680 } 1681 1682 /* FIXME: Lock the PEB */ 1683 //RtlEnterCriticalSection(&FastPebLock); 1684 #if 0 1685 /* Get the path name */ 1686 Length = RtlGetFullPathName_Ustr(OriginalName, 1687 PathName->Length, 1688 PathName->Buffer, 1689 NULL, 1690 &InvalidName, 1691 &PathType); 1692 #else 1693 Length = 0; 1694 #endif 1695 if (!(Length) || (Length > UNICODE_STRING_MAX_BYTES)) 1696 { 1697 /* Fail */ 1698 Status = STATUS_NAME_TOO_LONG; 1699 goto Quickie; 1700 } 1701 1702 /* Check if the length hasn't changed */ 1703 if (Length <= PathName->Length) 1704 { 1705 /* Return the same thing */ 1706 *ExpandedName = PathName; 1707 PathName->Length = (USHORT)Length; 1708 goto Quickie; 1709 } 1710 1711 /* Sanity check */ 1712 ASSERT(Length >= sizeof(WCHAR)); 1713 1714 /* Allocate a string */ 1715 Status = LdrpAllocateUnicodeString(FullPathName, Length - sizeof(WCHAR)); 1716 if (!NT_SUCCESS(Status)) goto Quickie; 1717 1718 /* Now get the full path again */ 1719 #if 0 1720 Length = RtlGetFullPathName_Ustr(OriginalName, 1721 FullPathName->Length, 1722 FullPathName->Buffer, 1723 NULL, 1724 &InvalidName, 1725 &PathType); 1726 #else 1727 Length = 0; 1728 #endif 1729 if (!(Length) || (Length > FullPathName->Length)) 1730 { 1731 /* Fail */ 1732 LdrpFreeUnicodeString(FullPathName); 1733 Status = STATUS_NAME_TOO_LONG; 1734 } 1735 else 1736 { 1737 /* Return the expanded name */ 1738 *ExpandedName = FullPathName; 1739 FullPathName->Length = (USHORT)Length; 1740 } 1741 1742 Quickie: 1743 /* FIXME: Unlock the PEB */ 1744 //RtlLeaveCriticalSection(&FastPebLock); 1745 1746 /* Display debug output if snaps are on */ 1747 if (ShowSnaps) 1748 { 1749 /* Check which output to use -- failure or success */ 1750 if (NT_SUCCESS(Status)) 1751 { 1752 DbgPrintEx(DPFLTR_LDR_ID, 1753 DPFLTR_ERROR_LEVEL, 1754 "LDR: %s - Expanded to %wZ\n", 1755 __FUNCTION__, 1756 *ExpandedName); 1757 } 1758 else 1759 { 1760 DbgPrintEx(DPFLTR_LDR_ID, 1761 DPFLTR_ERROR_LEVEL, 1762 "LDR: %s - Failed to expand %wZ; 0x%08x\n", 1763 __FUNCTION__, 1764 OriginalName, 1765 Status); 1766 } 1767 } 1768 1769 /* If we failed, return NULL */ 1770 if (!NT_SUCCESS(Status)) *ExpandedName = NULL; 1771 1772 /* Return status */ 1773 return Status; 1774 } 1775 1776 NTSTATUS 1777 NTAPI 1778 LdrpSearchPath(IN PWCHAR *SearchPath, 1779 IN PWCHAR DllName, 1780 IN PUNICODE_STRING PathName, 1781 IN PUNICODE_STRING FullPathName, 1782 IN PUNICODE_STRING *ExpandedName) 1783 { 1784 BOOLEAN TryAgain = FALSE; 1785 PWCHAR ActualSearchPath = *SearchPath; 1786 UNICODE_STRING TestName; 1787 NTSTATUS Status; 1788 PWCHAR Buffer, BufEnd = NULL; 1789 ULONG Length = 0; 1790 WCHAR p; 1791 //PWCHAR pp; 1792 1793 /* Check if we don't have a search path */ 1794 if (!ActualSearchPath) *SearchPath = LdrpDefaultPath.Buffer; 1795 1796 /* Display debug output if snaps are on */ 1797 if (ShowSnaps) 1798 { 1799 DbgPrintEx(DPFLTR_LDR_ID, 1800 DPFLTR_ERROR_LEVEL, 1801 "LDR: %s - Looking for %ws in %ws\n", 1802 __FUNCTION__, 1803 DllName, 1804 *SearchPath); 1805 } 1806 1807 /* Check if we're dealing with a relative path */ 1808 if (RtlDetermineDosPathNameType_U(DllName) != RtlPathTypeRelative) 1809 { 1810 /* Good, we're not. Create the name string */ 1811 Status = RtlInitUnicodeStringEx(&TestName, DllName); 1812 if (!NT_SUCCESS(Status)) goto Quickie; 1813 1814 /* Make sure it exists */ 1815 #if 0 1816 if (!RtlDoesFileExists_UstrEx(&TestName, TRUE)) 1817 { 1818 /* It doesn't, fail */ 1819 Status = STATUS_DLL_NOT_FOUND; 1820 goto Quickie; 1821 } 1822 #endif 1823 1824 /* Resolve the full name */ 1825 Status = LdrpResolveFullName(&TestName, 1826 PathName, 1827 FullPathName, 1828 ExpandedName); 1829 goto Quickie; 1830 } 1831 1832 /* FIXME: Handle relative case semicolon-lookup here */ 1833 1834 /* Calculate length */ 1835 Length += (ULONG)wcslen(DllName) + 1; 1836 if (Length > UNICODE_STRING_MAX_CHARS) 1837 { 1838 /* Too long, fail */ 1839 Status = STATUS_NAME_TOO_LONG; 1840 goto Quickie; 1841 } 1842 1843 /* Allocate buffer */ 1844 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR)); 1845 if (!Buffer) 1846 { 1847 /* Fail */ 1848 Status = STATUS_NO_MEMORY; 1849 goto Quickie; 1850 } 1851 1852 /* FIXME: Setup TestName here */ 1853 Status = STATUS_NOT_FOUND; 1854 1855 /* Start loop */ 1856 do 1857 { 1858 /* Get character */ 1859 p = *ActualSearchPath; 1860 if (!(p) || (p == ';')) 1861 { 1862 /* FIXME: We don't have a character, or is a semicolon.*/ 1863 1864 /* Display debug output if snaps are on */ 1865 if (ShowSnaps) 1866 { 1867 DbgPrintEx(DPFLTR_LDR_ID, 1868 DPFLTR_ERROR_LEVEL, 1869 "LDR: %s - Looking for %ws\n", 1870 __FUNCTION__, 1871 Buffer); 1872 } 1873 1874 /* Sanity check */ 1875 TestName.Length = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR); 1876 #if 0 1877 ASSERT(TestName.Length < TestName.MaximumLength); 1878 #endif 1879 1880 /* Check if the file exists */ 1881 #if 0 1882 if (RtlDoesFileExists_UstrEx(&TestName, FALSE)) 1883 #endif 1884 { 1885 /* It does. Reallocate the buffer */ 1886 TestName.MaximumLength = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR) + sizeof(WCHAR); 1887 TestName.Buffer = RtlReAllocateHeap(RtlGetProcessHeap(), 1888 0, 1889 Buffer, 1890 TestName.MaximumLength); 1891 if (!TestName.Buffer) 1892 { 1893 /* Keep the old one */ 1894 TestName.Buffer = Buffer; 1895 } 1896 else 1897 { 1898 /* Update buffer */ 1899 Buffer = TestName.Buffer; 1900 } 1901 1902 /* Make sure we have a buffer at least */ 1903 ASSERT(TestName.Buffer); 1904 1905 /* Resolve the name */ 1906 *SearchPath = ActualSearchPath++; 1907 Status = LdrpResolveFullName(&TestName, 1908 PathName, 1909 FullPathName, 1910 ExpandedName); 1911 break; 1912 } 1913 1914 /* Update buffer end */ 1915 BufEnd = Buffer; 1916 1917 /* Update string position */ 1918 //pp = ActualSearchPath++; 1919 } 1920 else 1921 { 1922 /* Otherwise, write the character */ 1923 *BufEnd = p; 1924 BufEnd++; 1925 } 1926 1927 /* Check if the string is empty, meaning we're done */ 1928 if (!(*ActualSearchPath)) TryAgain = TRUE; 1929 1930 /* Advance in the string */ 1931 ActualSearchPath++; 1932 } while (!TryAgain); 1933 1934 /* Check if we had a buffer and free it */ 1935 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 1936 1937 Quickie: 1938 /* Check if we got here through failure */ 1939 if (!NT_SUCCESS(Status)) *ExpandedName = NULL; 1940 1941 /* Display debug output if snaps are on */ 1942 if (ShowSnaps) 1943 { 1944 /* Check which output to use -- failure or success */ 1945 if (NT_SUCCESS(Status)) 1946 { 1947 DbgPrintEx(DPFLTR_LDR_ID, 1948 DPFLTR_ERROR_LEVEL, 1949 "LDR: %s - Returning %wZ\n", 1950 __FUNCTION__, 1951 *ExpandedName); 1952 } 1953 else 1954 { 1955 DbgPrintEx(DPFLTR_LDR_ID, 1956 DPFLTR_ERROR_LEVEL, 1957 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n", 1958 __FUNCTION__, 1959 DllName, 1960 ActualSearchPath, 1961 Status); 1962 } 1963 } 1964 1965 /* Return status */ 1966 return Status; 1967 } 1968 1969 1970 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */ 1971 BOOLEAN 1972 NTAPI 1973 LdrpCheckForLoadedDll(IN PWSTR DllPath, 1974 IN PUNICODE_STRING DllName, 1975 IN BOOLEAN Flag, 1976 IN BOOLEAN RedirectedDll, 1977 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) 1978 { 1979 ULONG HashIndex; 1980 PLIST_ENTRY ListHead, ListEntry; 1981 PLDR_DATA_TABLE_ENTRY CurEntry; 1982 BOOLEAN FullPath = FALSE; 1983 PWCHAR wc; 1984 WCHAR NameBuf[266]; 1985 UNICODE_STRING FullDllName, NtPathName; 1986 ULONG Length; 1987 OBJECT_ATTRIBUTES ObjectAttributes; 1988 NTSTATUS Status; 1989 HANDLE FileHandle, SectionHandle; 1990 IO_STATUS_BLOCK Iosb; 1991 PVOID ViewBase = NULL; 1992 SIZE_T ViewSize = 0; 1993 PIMAGE_NT_HEADERS NtHeader, NtHeader2; 1994 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry); 1995 1996 /* Check if a dll name was provided */ 1997 if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE; 1998 1999 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */ 2000 /* FIXME: Warning, code does not support redirection at all */ 2001 2002 /* Look in the hash table if flag was set */ 2003 lookinhash: 2004 if (Flag /* the second check is a hack */ && !RedirectedDll) 2005 { 2006 /* 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 */ 2007 2008 /* Get hash index */ 2009 HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]); 2010 2011 /* Traverse that list */ 2012 ListHead = &LdrpHashTable[HashIndex]; 2013 ListEntry = ListHead->Flink; 2014 while (ListEntry != ListHead) 2015 { 2016 /* Get the current entry */ 2017 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 2018 2019 /* Check base name of that module */ 2020 if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE)) 2021 { 2022 /* It matches, return it */ 2023 *LdrEntry = CurEntry; 2024 return TRUE; 2025 } 2026 2027 /* Advance to the next entry */ 2028 ListEntry = ListEntry->Flink; 2029 } 2030 2031 /* Module was not found, return failure */ 2032 return FALSE; 2033 } 2034 2035 /* Check if this is a redirected DLL */ 2036 if (RedirectedDll) 2037 { 2038 /* Redirected dlls already have a full path */ 2039 FullPath = TRUE; 2040 FullDllName = *DllName; 2041 } 2042 else 2043 { 2044 /* Check if there is a full path in this DLL */ 2045 wc = DllName->Buffer; 2046 while (*wc) 2047 { 2048 /* Check for a slash in the current position*/ 2049 if ((*wc == L'\\') || (*wc == L'/')) 2050 { 2051 /* Found the slash, so dll name contains path */ 2052 FullPath = TRUE; 2053 2054 /* Setup full dll name string */ 2055 FullDllName.Buffer = NameBuf; 2056 2057 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */ 2058 Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer, 2059 DllName->Buffer, 2060 NULL, 2061 sizeof(NameBuf) - sizeof(UNICODE_NULL), 2062 FullDllName.Buffer, 2063 NULL); 2064 2065 /* Check if that was successful */ 2066 if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL)))) 2067 { 2068 if (ShowSnaps) 2069 { 2070 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n", 2071 &DllName, Length); 2072 } 2073 } 2074 2075 /* Full dll name is found */ 2076 FullDllName.Length = Length; 2077 FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL); 2078 break; 2079 } 2080 2081 wc++; 2082 } 2083 } 2084 2085 /* Go check the hash table */ 2086 if (!FullPath) 2087 { 2088 Flag = TRUE; 2089 goto lookinhash; 2090 } 2091 2092 /* FIXME: Warning, activation context missing */ 2093 DPRINT("Warning, activation context missing\n"); 2094 2095 /* NOTE: From here on down, everything looks good */ 2096 2097 /* Loop the module list */ 2098 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2099 ListEntry = ListHead->Flink; 2100 while (ListEntry != ListHead) 2101 { 2102 /* Get the current entry and advance to the next one */ 2103 CurEntry = CONTAINING_RECORD(ListEntry, 2104 LDR_DATA_TABLE_ENTRY, 2105 InLoadOrderLinks); 2106 ListEntry = ListEntry->Flink; 2107 2108 /* Check if it's being unloaded */ 2109 if (!CurEntry->InMemoryOrderLinks.Flink) continue; 2110 2111 /* Check if name matches */ 2112 if (RtlEqualUnicodeString(&FullDllName, 2113 &CurEntry->FullDllName, 2114 TRUE)) 2115 { 2116 /* Found it */ 2117 *LdrEntry = CurEntry; 2118 return TRUE; 2119 } 2120 } 2121 2122 /* Convert given path to NT path */ 2123 if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer, 2124 &NtPathName, 2125 NULL, 2126 NULL)) 2127 { 2128 /* Fail if conversion failed */ 2129 return FALSE; 2130 } 2131 2132 /* Initialize object attributes and open it */ 2133 InitializeObjectAttributes(&ObjectAttributes, 2134 &NtPathName, 2135 OBJ_CASE_INSENSITIVE, 2136 NULL, 2137 NULL); 2138 Status = NtOpenFile(&FileHandle, 2139 SYNCHRONIZE | FILE_EXECUTE, 2140 &ObjectAttributes, 2141 &Iosb, 2142 FILE_SHARE_READ | FILE_SHARE_DELETE, 2143 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 2144 2145 /* Free NT path name */ 2146 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer); 2147 2148 /* If opening the file failed - return failure */ 2149 if (!NT_SUCCESS(Status)) return FALSE; 2150 2151 /* Create a section for this file */ 2152 Status = NtCreateSection(&SectionHandle, 2153 SECTION_MAP_READ | 2154 SECTION_MAP_EXECUTE | 2155 SECTION_MAP_WRITE, 2156 NULL, 2157 NULL, 2158 PAGE_EXECUTE, 2159 SEC_COMMIT, 2160 FileHandle); 2161 2162 /* Close file handle */ 2163 NtClose(FileHandle); 2164 2165 /* If creating section failed - return failure */ 2166 if (!NT_SUCCESS(Status)) return FALSE; 2167 2168 /* Map view of this section */ 2169 Status = ZwMapViewOfSection(SectionHandle, 2170 NtCurrentProcess(), 2171 &ViewBase, 2172 0, 2173 0, 2174 NULL, 2175 &ViewSize, 2176 ViewShare, 2177 0, 2178 PAGE_EXECUTE); 2179 2180 /* Close section handle */ 2181 NtClose(SectionHandle); 2182 2183 /* If section mapping failed - return failure */ 2184 if (!NT_SUCCESS(Status)) return FALSE; 2185 2186 /* Get pointer to the NT header of this section */ 2187 Status = RtlImageNtHeaderEx(0, ViewBase, ViewSize, &NtHeader); 2188 if (!(NT_SUCCESS(Status)) || !(NtHeader)) 2189 { 2190 /* Unmap the section and fail */ 2191 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2192 return FALSE; 2193 } 2194 2195 /* Go through the list of modules again */ 2196 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2197 ListEntry = ListHead->Flink; 2198 while (ListEntry != ListHead) 2199 { 2200 /* Get the current entry and advance to the next one */ 2201 CurEntry = CONTAINING_RECORD(ListEntry, 2202 LDR_DATA_TABLE_ENTRY, 2203 InLoadOrderLinks); 2204 ListEntry = ListEntry->Flink; 2205 2206 /* Check if it's in the process of being unloaded */ 2207 if (!CurEntry->InMemoryOrderLinks.Flink) continue; 2208 2209 /* The header is untrusted, use SEH */ 2210 _SEH2_TRY 2211 { 2212 /* Check if timedate stamp and sizes match */ 2213 if ((CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp) && 2214 (CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage)) 2215 { 2216 /* Time, date and size match. Let's compare their headers */ 2217 NtHeader2 = RtlImageNtHeader(CurEntry->DllBase); 2218 if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS))) 2219 { 2220 /* Headers match too! Finally ask the kernel to compare mapped files */ 2221 Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase); 2222 if (NT_SUCCESS(Status)) 2223 { 2224 /* This is our entry!, unmap and return success */ 2225 *LdrEntry = CurEntry; 2226 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2227 _SEH2_YIELD(return TRUE;) 2228 } 2229 } 2230 } 2231 } 2232 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) 2233 { 2234 _SEH2_YIELD(break;) 2235 } 2236 _SEH2_END; 2237 } 2238 2239 /* Unmap the section and fail */ 2240 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2241 return FALSE; 2242 } 2243 2244 NTSTATUS 2245 NTAPI 2246 LdrpGetProcedureAddress(IN PVOID BaseAddress, 2247 IN PANSI_STRING Name, 2248 IN ULONG Ordinal, 2249 OUT PVOID *ProcedureAddress, 2250 IN BOOLEAN ExecuteInit) 2251 { 2252 NTSTATUS Status = STATUS_SUCCESS; 2253 UCHAR ImportBuffer[64]; 2254 PLDR_DATA_TABLE_ENTRY LdrEntry; 2255 IMAGE_THUNK_DATA Thunk; 2256 PVOID ImageBase; 2257 PIMAGE_IMPORT_BY_NAME ImportName = NULL; 2258 PIMAGE_EXPORT_DIRECTORY ExportDir; 2259 ULONG ExportDirSize, Length; 2260 PLIST_ENTRY Entry; 2261 2262 /* Show debug message */ 2263 if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by "); 2264 2265 /* Check if we got a name */ 2266 if (Name) 2267 { 2268 /* Show debug message */ 2269 if (ShowSnaps) DbgPrint("NAME - %s\n", Name->Buffer); 2270 2271 /* Make sure it's not too long */ 2272 Length = Name->Length + 2273 sizeof(CHAR) + 2274 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name); 2275 if (Length > UNICODE_STRING_MAX_BYTES) 2276 { 2277 /* Won't have enough space to add the hint */ 2278 return STATUS_NAME_TOO_LONG; 2279 } 2280 2281 /* Check if our buffer is large enough */ 2282 if (Length > sizeof(ImportBuffer)) 2283 { 2284 /* Allocate from heap, plus 2 bytes for the Hint */ 2285 ImportName = RtlAllocateHeap(RtlGetProcessHeap(), 2286 0, 2287 Length); 2288 } 2289 else 2290 { 2291 /* Use our internal buffer */ 2292 ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer; 2293 } 2294 2295 /* Clear the hint */ 2296 ImportName->Hint = 0; 2297 2298 /* Copy the name and null-terminate it */ 2299 RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length); 2300 ImportName->Name[Name->Length] = ANSI_NULL; 2301 2302 /* Clear the high bit */ 2303 ImageBase = ImportName; 2304 Thunk.u1.AddressOfData = 0; 2305 } 2306 else 2307 { 2308 /* Do it by ordinal */ 2309 ImageBase = NULL; 2310 2311 /* Show debug message */ 2312 if (ShowSnaps) DbgPrint("ORDINAL - %lx\n", Ordinal); 2313 2314 /* Make sure an ordinal was given */ 2315 if (!Ordinal) 2316 { 2317 /* No ordinal */ 2318 DPRINT1("No ordinal and no name\n"); 2319 return STATUS_INVALID_PARAMETER; 2320 } 2321 2322 /* Set the original flag in the thunk */ 2323 Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG; 2324 } 2325 2326 /* Acquire lock unless we are initting */ 2327 if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock); 2328 2329 _SEH2_TRY 2330 { 2331 /* Try to find the loaded DLL */ 2332 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 2333 { 2334 /* Invalid base */ 2335 DPRINT1("Invalid base address %p\n", BaseAddress); 2336 Status = STATUS_DLL_NOT_FOUND; 2337 _SEH2_YIELD(goto Quickie;) 2338 } 2339 2340 /* Get the pointer to the export directory */ 2341 ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 2342 TRUE, 2343 IMAGE_DIRECTORY_ENTRY_EXPORT, 2344 &ExportDirSize); 2345 2346 if (!ExportDir) 2347 { 2348 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n", 2349 &LdrEntry->BaseDllName, Name, BaseAddress, LdrEntry->DllBase); 2350 Status = STATUS_PROCEDURE_NOT_FOUND; 2351 _SEH2_YIELD(goto Quickie;) 2352 } 2353 2354 /* Now get the thunk */ 2355 Status = LdrpSnapThunk(LdrEntry->DllBase, 2356 ImageBase, 2357 &Thunk, 2358 &Thunk, 2359 ExportDir, 2360 ExportDirSize, 2361 FALSE, 2362 NULL); 2363 2364 /* Finally, see if we're supposed to run the init routines */ 2365 if ((NT_SUCCESS(Status)) && (ExecuteInit)) 2366 { 2367 /* 2368 * It's possible a forwarded entry had us load the DLL. In that case, 2369 * then we will call its DllMain. Use the last loaded DLL for this. 2370 */ 2371 Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink; 2372 LdrEntry = CONTAINING_RECORD(Entry, 2373 LDR_DATA_TABLE_ENTRY, 2374 InInitializationOrderLinks); 2375 2376 /* Make sure we didn't process it yet*/ 2377 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) 2378 { 2379 /* Call the init routine */ 2380 _SEH2_TRY 2381 { 2382 Status = LdrpRunInitializeRoutines(NULL); 2383 } 2384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2385 { 2386 /* Get the exception code */ 2387 Status = _SEH2_GetExceptionCode(); 2388 } 2389 _SEH2_END; 2390 } 2391 } 2392 2393 /* Make sure we're OK till here */ 2394 if (NT_SUCCESS(Status)) 2395 { 2396 /* Return the address */ 2397 *ProcedureAddress = (PVOID)Thunk.u1.Function; 2398 } 2399 } 2400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2401 { 2402 /* Just ignore exceptions */ 2403 } 2404 _SEH2_END; 2405 2406 Quickie: 2407 /* Cleanup */ 2408 if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer)) 2409 { 2410 /* We allocated from heap, free it */ 2411 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName); 2412 } 2413 2414 /* Release the CS if we entered it */ 2415 if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock); 2416 2417 /* We're done */ 2418 return Status; 2419 } 2420 2421 NTSTATUS 2422 NTAPI 2423 LdrpLoadDll(IN BOOLEAN Redirected, 2424 IN PWSTR DllPath OPTIONAL, 2425 IN PULONG DllCharacteristics OPTIONAL, 2426 IN PUNICODE_STRING DllName, 2427 OUT PVOID *BaseAddress, 2428 IN BOOLEAN CallInit) 2429 { 2430 PPEB Peb = NtCurrentPeb(); 2431 NTSTATUS Status = STATUS_SUCCESS; 2432 const WCHAR *p; 2433 BOOLEAN GotExtension; 2434 WCHAR c; 2435 WCHAR NameBuffer[MAX_PATH + 6]; 2436 UNICODE_STRING RawDllName; 2437 PLDR_DATA_TABLE_ENTRY LdrEntry; 2438 BOOLEAN InInit = LdrpInLdrInit; 2439 2440 /* Save the Raw DLL Name */ 2441 if (DllName->Length >= sizeof(NameBuffer)) return STATUS_NAME_TOO_LONG; 2442 RtlInitEmptyUnicodeString(&RawDllName, NameBuffer, sizeof(NameBuffer)); 2443 RtlCopyUnicodeString(&RawDllName, DllName); 2444 2445 /* Find the extension, if present */ 2446 p = DllName->Buffer + DllName->Length / sizeof(WCHAR) - 1; 2447 GotExtension = FALSE; 2448 while (p >= DllName->Buffer) 2449 { 2450 c = *p--; 2451 if (c == L'.') 2452 { 2453 GotExtension = TRUE; 2454 break; 2455 } 2456 else if (c == L'\\') 2457 { 2458 break; 2459 } 2460 } 2461 2462 /* If no extension was found, add the default extension */ 2463 if (!GotExtension) 2464 { 2465 /* Check that we have space to add one */ 2466 if ((DllName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >= 2467 sizeof(NameBuffer)) 2468 { 2469 /* No space to add the extension */ 2470 DbgPrintEx(DPFLTR_LDR_ID, 2471 DPFLTR_ERROR_LEVEL, 2472 "LDR: %s - Dll name missing extension; with extension " 2473 "added the name is too long\n" 2474 " DllName: (@ %p) \"%wZ\"\n" 2475 " DllName->Length: %u\n", 2476 __FUNCTION__, 2477 DllName, 2478 DllName, 2479 DllName->Length); 2480 return STATUS_NAME_TOO_LONG; 2481 } 2482 2483 /* Add it. Needs to be null terminated, thus the length check above */ 2484 (VOID)RtlAppendUnicodeStringToString(&RawDllName, 2485 &LdrApiDefaultExtension); 2486 } 2487 2488 /* Check for init flag and acquire lock */ 2489 if (!InInit) RtlEnterCriticalSection(&LdrpLoaderLock); 2490 2491 _SEH2_TRY 2492 { 2493 /* Show debug message */ 2494 if (ShowSnaps) 2495 { 2496 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n", 2497 &RawDllName, 2498 DllPath ? DllPath : L""); 2499 } 2500 2501 /* Check if the DLL is already loaded */ 2502 if (!LdrpCheckForLoadedDll(DllPath, 2503 &RawDllName, 2504 FALSE, 2505 Redirected, 2506 &LdrEntry)) 2507 { 2508 /* Map it */ 2509 Status = LdrpMapDll(DllPath, 2510 DllPath, 2511 NameBuffer, 2512 DllCharacteristics, 2513 FALSE, 2514 Redirected, 2515 &LdrEntry); 2516 if (!NT_SUCCESS(Status)) 2517 _SEH2_LEAVE; 2518 2519 /* FIXME: Need to mark the DLL range for the stack DB */ 2520 //RtlpStkMarkDllRange(LdrEntry); 2521 2522 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */ 2523 if ((DllCharacteristics) && 2524 (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) 2525 { 2526 /* This is not a DLL, so remove such data */ 2527 LdrEntry->EntryPoint = NULL; 2528 LdrEntry->Flags &= ~LDRP_IMAGE_DLL; 2529 } 2530 2531 /* Make sure it's a DLL */ 2532 if (LdrEntry->Flags & LDRP_IMAGE_DLL) 2533 { 2534 /* Check if this is a .NET Image */ 2535 if (!(LdrEntry->Flags & LDRP_COR_IMAGE)) 2536 { 2537 /* Walk the Import Descriptor */ 2538 Status = LdrpWalkImportDescriptor(DllPath, LdrEntry); 2539 } 2540 2541 /* Update load count, unless it's locked */ 2542 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++; 2543 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 2544 2545 /* Check if we failed */ 2546 if (!NT_SUCCESS(Status)) 2547 { 2548 /* Clear entrypoint, and insert into list */ 2549 LdrEntry->EntryPoint = NULL; 2550 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 2551 &LdrEntry->InInitializationOrderLinks); 2552 2553 /* Cancel the load */ 2554 LdrpClearLoadInProgress(); 2555 2556 /* Unload the DLL */ 2557 if (ShowSnaps) 2558 { 2559 DbgPrint("LDR: Unloading %wZ due to error %x walking " 2560 "import descriptors\n", 2561 DllName, 2562 Status); 2563 } 2564 LdrUnloadDll(LdrEntry->DllBase); 2565 2566 /* Return the error */ 2567 _SEH2_LEAVE; 2568 } 2569 } 2570 else if (LdrEntry->LoadCount != 0xFFFF) 2571 { 2572 /* Increase load count */ 2573 LdrEntry->LoadCount++; 2574 } 2575 2576 /* Insert it into the list */ 2577 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 2578 &LdrEntry->InInitializationOrderLinks); 2579 2580 /* If we have to run the entrypoint, make sure the DB is ready */ 2581 if (CallInit && LdrpLdrDatabaseIsSetup) 2582 { 2583 /* Notify Shim Engine */ 2584 if (g_ShimsEnabled) 2585 { 2586 VOID (NTAPI* SE_DllLoaded)(PLDR_DATA_TABLE_ENTRY) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded); 2587 SE_DllLoaded(LdrEntry); 2588 } 2589 2590 /* Run the init routine */ 2591 Status = LdrpRunInitializeRoutines(NULL); 2592 if (!NT_SUCCESS(Status)) 2593 { 2594 /* Failed, unload the DLL */ 2595 if (ShowSnaps) 2596 { 2597 DbgPrint("LDR: Unloading %wZ because either its init " 2598 "routine or one of its static imports failed; " 2599 "status = 0x%08lx\n", 2600 DllName, 2601 Status); 2602 } 2603 LdrUnloadDll(LdrEntry->DllBase); 2604 } 2605 } 2606 else 2607 { 2608 /* The DB isn't ready, which means we were loaded because of a forwarder */ 2609 Status = STATUS_SUCCESS; 2610 } 2611 } 2612 else 2613 { 2614 /* We were already loaded. Are we a DLL? */ 2615 if ((LdrEntry->Flags & LDRP_IMAGE_DLL) && (LdrEntry->LoadCount != 0xFFFF)) 2616 { 2617 /* Increase load count */ 2618 LdrEntry->LoadCount++; 2619 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 2620 2621 /* Clear the load in progress */ 2622 LdrpClearLoadInProgress(); 2623 } 2624 else 2625 { 2626 /* Not a DLL, just increase the load count */ 2627 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++; 2628 } 2629 } 2630 2631 } 2632 _SEH2_FINALLY 2633 { 2634 /* Release the lock */ 2635 if (!InInit) RtlLeaveCriticalSection(&LdrpLoaderLock); 2636 } 2637 _SEH2_END; 2638 2639 /* Check for success */ 2640 if (NT_SUCCESS(Status)) 2641 { 2642 /* Return the base address */ 2643 *BaseAddress = LdrEntry->DllBase; 2644 } 2645 else 2646 { 2647 /* Nothing found */ 2648 *BaseAddress = NULL; 2649 } 2650 2651 /* Return status */ 2652 return Status; 2653 } 2654 2655 ULONG 2656 NTAPI 2657 LdrpClearLoadInProgress(VOID) 2658 { 2659 PLIST_ENTRY ListHead, Entry; 2660 PLDR_DATA_TABLE_ENTRY LdrEntry; 2661 ULONG ModulesCount = 0; 2662 2663 /* Traverse the init list */ 2664 ListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; 2665 Entry = ListHead->Flink; 2666 while (Entry != ListHead) 2667 { 2668 /* Get the loader entry */ 2669 LdrEntry = CONTAINING_RECORD(Entry, 2670 LDR_DATA_TABLE_ENTRY, 2671 InInitializationOrderLinks); 2672 2673 /* Clear load in progress flag */ 2674 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS; 2675 2676 /* Check for modules with entry point count but not processed yet */ 2677 if ((LdrEntry->EntryPoint) && 2678 !(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) 2679 { 2680 /* Increase counter */ 2681 ModulesCount++; 2682 } 2683 2684 /* Advance to the next entry */ 2685 Entry = Entry->Flink; 2686 } 2687 2688 /* Return final count */ 2689 return ModulesCount; 2690 } 2691 2692 PVOID LdrpGetShimEngineFunction(PCSZ FunctionName) 2693 { 2694 ANSI_STRING Function; 2695 NTSTATUS Status; 2696 PVOID Address; 2697 RtlInitAnsiString(&Function, FunctionName); 2698 Status = LdrGetProcedureAddress(g_pShimEngineModule, &Function, 0, &Address); 2699 return NT_SUCCESS(Status) ? Address : NULL; 2700 } 2701 2702 VOID 2703 NTAPI 2704 LdrpGetShimEngineInterface() 2705 { 2706 PVOID SE_DllLoaded = LdrpGetShimEngineFunction("SE_DllLoaded"); 2707 PVOID SE_DllUnloaded = LdrpGetShimEngineFunction("SE_DllUnloaded"); 2708 PVOID SE_InstallBeforeInit = LdrpGetShimEngineFunction("SE_InstallBeforeInit"); 2709 PVOID SE_InstallAfterInit = LdrpGetShimEngineFunction("SE_InstallAfterInit"); 2710 PVOID SE_ProcessDying = LdrpGetShimEngineFunction("SE_ProcessDying"); 2711 2712 if (SE_DllLoaded && SE_DllUnloaded && SE_InstallBeforeInit && SE_InstallAfterInit && SE_ProcessDying) 2713 { 2714 g_pfnSE_DllLoaded = RtlEncodeSystemPointer(SE_DllLoaded); 2715 g_pfnSE_DllUnloaded = RtlEncodeSystemPointer(SE_DllUnloaded); 2716 g_pfnSE_InstallBeforeInit = RtlEncodeSystemPointer(SE_InstallBeforeInit); 2717 g_pfnSE_InstallAfterInit = RtlEncodeSystemPointer(SE_InstallAfterInit); 2718 g_pfnSE_ProcessDying = RtlEncodeSystemPointer(SE_ProcessDying); 2719 g_ShimsEnabled = TRUE; 2720 } 2721 else 2722 { 2723 LdrpUnloadShimEngine(); 2724 } 2725 } 2726 2727 2728 VOID 2729 NTAPI 2730 LdrpLoadShimEngine(IN PWSTR ImageName, IN PUNICODE_STRING ProcessImage, IN PVOID pShimData) 2731 { 2732 UNICODE_STRING ShimLibraryName; 2733 PVOID ShimLibrary; 2734 NTSTATUS Status; 2735 RtlInitUnicodeString(&ShimLibraryName, ImageName); 2736 Status = LdrpLoadDll(FALSE, NULL, NULL, &ShimLibraryName, &ShimLibrary, TRUE); 2737 if (NT_SUCCESS(Status)) 2738 { 2739 g_pShimEngineModule = ShimLibrary; 2740 LdrpGetShimEngineInterface(); 2741 if (g_ShimsEnabled) 2742 { 2743 VOID(NTAPI *SE_InstallBeforeInit)(PUNICODE_STRING, PVOID); 2744 SE_InstallBeforeInit = RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit); 2745 SE_InstallBeforeInit(ProcessImage, pShimData); 2746 } 2747 } 2748 } 2749 2750 VOID 2751 NTAPI 2752 LdrpUnloadShimEngine() 2753 { 2754 /* Make sure we do not call into the shim engine anymore */ 2755 g_ShimsEnabled = FALSE; 2756 LdrUnloadDll(g_pShimEngineModule); 2757 g_pShimEngineModule = NULL; 2758 } 2759 2760 /* EOF */ 2761