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 /* 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(LdrpHeap, 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(LdrpHeap, 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 BufEnd = Buffer; 1855 1856 /* Start loop */ 1857 do 1858 { 1859 /* Get character */ 1860 p = *ActualSearchPath; 1861 if (!(p) || (p == ';')) 1862 { 1863 /* FIXME: We don't have a character, or is a semicolon.*/ 1864 1865 /* Display debug output if snaps are on */ 1866 if (ShowSnaps) 1867 { 1868 DbgPrintEx(DPFLTR_LDR_ID, 1869 DPFLTR_ERROR_LEVEL, 1870 "LDR: %s - Looking for %ws\n", 1871 __FUNCTION__, 1872 Buffer); 1873 } 1874 1875 /* Sanity check */ 1876 TestName.Length = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR); 1877 #if 0 1878 ASSERT(TestName.Length < TestName.MaximumLength); 1879 #endif 1880 1881 /* Check if the file exists */ 1882 #if 0 1883 if (RtlDoesFileExists_UstrEx(&TestName, FALSE)) 1884 #endif 1885 { 1886 /* It does. Reallocate the buffer */ 1887 TestName.MaximumLength = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR) + sizeof(WCHAR); 1888 TestName.Buffer = RtlReAllocateHeap(RtlGetProcessHeap(), 1889 0, 1890 Buffer, 1891 TestName.MaximumLength); 1892 if (!TestName.Buffer) 1893 { 1894 /* Keep the old one */ 1895 TestName.Buffer = Buffer; 1896 } 1897 else 1898 { 1899 /* Update buffer */ 1900 Buffer = TestName.Buffer; 1901 } 1902 1903 /* Make sure we have a buffer at least */ 1904 ASSERT(TestName.Buffer); 1905 1906 /* Resolve the name */ 1907 *SearchPath = ActualSearchPath++; 1908 Status = LdrpResolveFullName(&TestName, 1909 PathName, 1910 FullPathName, 1911 ExpandedName); 1912 break; 1913 } 1914 1915 /* Update buffer end */ 1916 BufEnd = Buffer; 1917 1918 /* Update string position */ 1919 //pp = ActualSearchPath++; 1920 } 1921 else 1922 { 1923 /* Otherwise, write the character */ 1924 *BufEnd = p; 1925 BufEnd++; 1926 } 1927 1928 /* Check if the string is empty, meaning we're done */ 1929 if (!(*ActualSearchPath)) TryAgain = TRUE; 1930 1931 /* Advance in the string */ 1932 ActualSearchPath++; 1933 } while (!TryAgain); 1934 1935 /* Check if we had a buffer and free it */ 1936 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 1937 1938 Quickie: 1939 /* Check if we got here through failure */ 1940 if (!NT_SUCCESS(Status)) *ExpandedName = NULL; 1941 1942 /* Display debug output if snaps are on */ 1943 if (ShowSnaps) 1944 { 1945 /* Check which output to use -- failure or success */ 1946 if (NT_SUCCESS(Status)) 1947 { 1948 DbgPrintEx(DPFLTR_LDR_ID, 1949 DPFLTR_ERROR_LEVEL, 1950 "LDR: %s - Returning %wZ\n", 1951 __FUNCTION__, 1952 *ExpandedName); 1953 } 1954 else 1955 { 1956 DbgPrintEx(DPFLTR_LDR_ID, 1957 DPFLTR_ERROR_LEVEL, 1958 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n", 1959 __FUNCTION__, 1960 DllName, 1961 ActualSearchPath, 1962 Status); 1963 } 1964 } 1965 1966 /* Return status */ 1967 return Status; 1968 } 1969 1970 1971 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */ 1972 BOOLEAN 1973 NTAPI 1974 LdrpCheckForLoadedDll(IN PWSTR DllPath, 1975 IN PUNICODE_STRING DllName, 1976 IN BOOLEAN Flag, 1977 IN BOOLEAN RedirectedDll, 1978 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) 1979 { 1980 ULONG HashIndex; 1981 PLIST_ENTRY ListHead, ListEntry; 1982 PLDR_DATA_TABLE_ENTRY CurEntry; 1983 BOOLEAN FullPath = FALSE; 1984 PWCHAR wc; 1985 WCHAR NameBuf[266]; 1986 UNICODE_STRING FullDllName, NtPathName; 1987 ULONG Length; 1988 OBJECT_ATTRIBUTES ObjectAttributes; 1989 NTSTATUS Status; 1990 HANDLE FileHandle, SectionHandle; 1991 IO_STATUS_BLOCK Iosb; 1992 PVOID ViewBase = NULL; 1993 SIZE_T ViewSize = 0; 1994 PIMAGE_NT_HEADERS NtHeader, NtHeader2; 1995 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry); 1996 1997 /* Check if a dll name was provided */ 1998 if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE; 1999 2000 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */ 2001 /* FIXME: Warning, code does not support redirection at all */ 2002 2003 /* Look in the hash table if flag was set */ 2004 lookinhash: 2005 if (Flag /* the second check is a hack */ && !RedirectedDll) 2006 { 2007 /* 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 */ 2008 2009 /* Get hash index */ 2010 HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]); 2011 2012 /* Traverse that list */ 2013 ListHead = &LdrpHashTable[HashIndex]; 2014 ListEntry = ListHead->Flink; 2015 while (ListEntry != ListHead) 2016 { 2017 /* Get the current entry */ 2018 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 2019 2020 /* Check base name of that module */ 2021 if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE)) 2022 { 2023 /* It matches, return it */ 2024 *LdrEntry = CurEntry; 2025 return TRUE; 2026 } 2027 2028 /* Advance to the next entry */ 2029 ListEntry = ListEntry->Flink; 2030 } 2031 2032 /* Module was not found, return failure */ 2033 return FALSE; 2034 } 2035 2036 /* Check if this is a redirected DLL */ 2037 if (RedirectedDll) 2038 { 2039 /* Redirected dlls already have a full path */ 2040 FullPath = TRUE; 2041 FullDllName = *DllName; 2042 } 2043 else 2044 { 2045 /* Check if there is a full path in this DLL */ 2046 wc = DllName->Buffer; 2047 while (*wc) 2048 { 2049 /* Check for a slash in the current position*/ 2050 if ((*wc == L'\\') || (*wc == L'/')) 2051 { 2052 /* Found the slash, so dll name contains path */ 2053 FullPath = TRUE; 2054 2055 /* Setup full dll name string */ 2056 FullDllName.Buffer = NameBuf; 2057 2058 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */ 2059 Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer, 2060 DllName->Buffer, 2061 NULL, 2062 sizeof(NameBuf) - sizeof(UNICODE_NULL), 2063 FullDllName.Buffer, 2064 NULL); 2065 2066 /* Check if that was successful */ 2067 if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL)))) 2068 { 2069 if (ShowSnaps) 2070 { 2071 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n", 2072 &DllName, Length); 2073 } 2074 } 2075 2076 /* Full dll name is found */ 2077 FullDllName.Length = Length; 2078 FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL); 2079 break; 2080 } 2081 2082 wc++; 2083 } 2084 } 2085 2086 /* Go check the hash table */ 2087 if (!FullPath) 2088 { 2089 Flag = TRUE; 2090 goto lookinhash; 2091 } 2092 2093 /* FIXME: Warning, activation context missing */ 2094 DPRINT("Warning, activation context missing\n"); 2095 2096 /* NOTE: From here on down, everything looks good */ 2097 2098 /* Loop the module list */ 2099 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2100 ListEntry = ListHead->Flink; 2101 while (ListEntry != ListHead) 2102 { 2103 /* Get the current entry and advance to the next one */ 2104 CurEntry = CONTAINING_RECORD(ListEntry, 2105 LDR_DATA_TABLE_ENTRY, 2106 InLoadOrderLinks); 2107 ListEntry = ListEntry->Flink; 2108 2109 /* Check if it's being unloaded */ 2110 if (!CurEntry->InMemoryOrderLinks.Flink) continue; 2111 2112 /* Check if name matches */ 2113 if (RtlEqualUnicodeString(&FullDllName, 2114 &CurEntry->FullDllName, 2115 TRUE)) 2116 { 2117 /* Found it */ 2118 *LdrEntry = CurEntry; 2119 return TRUE; 2120 } 2121 } 2122 2123 /* Convert given path to NT path */ 2124 if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer, 2125 &NtPathName, 2126 NULL, 2127 NULL)) 2128 { 2129 /* Fail if conversion failed */ 2130 return FALSE; 2131 } 2132 2133 /* Initialize object attributes and open it */ 2134 InitializeObjectAttributes(&ObjectAttributes, 2135 &NtPathName, 2136 OBJ_CASE_INSENSITIVE, 2137 NULL, 2138 NULL); 2139 Status = NtOpenFile(&FileHandle, 2140 SYNCHRONIZE | FILE_EXECUTE, 2141 &ObjectAttributes, 2142 &Iosb, 2143 FILE_SHARE_READ | FILE_SHARE_DELETE, 2144 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 2145 2146 /* Free NT path name */ 2147 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer); 2148 2149 /* If opening the file failed - return failure */ 2150 if (!NT_SUCCESS(Status)) return FALSE; 2151 2152 /* Create a section for this file */ 2153 Status = NtCreateSection(&SectionHandle, 2154 SECTION_MAP_READ | 2155 SECTION_MAP_EXECUTE | 2156 SECTION_MAP_WRITE, 2157 NULL, 2158 NULL, 2159 PAGE_EXECUTE, 2160 SEC_COMMIT, 2161 FileHandle); 2162 2163 /* Close file handle */ 2164 NtClose(FileHandle); 2165 2166 /* If creating section failed - return failure */ 2167 if (!NT_SUCCESS(Status)) return FALSE; 2168 2169 /* Map view of this section */ 2170 Status = ZwMapViewOfSection(SectionHandle, 2171 NtCurrentProcess(), 2172 &ViewBase, 2173 0, 2174 0, 2175 NULL, 2176 &ViewSize, 2177 ViewShare, 2178 0, 2179 PAGE_EXECUTE); 2180 2181 /* Close section handle */ 2182 NtClose(SectionHandle); 2183 2184 /* If section mapping failed - return failure */ 2185 if (!NT_SUCCESS(Status)) return FALSE; 2186 2187 /* Get pointer to the NT header of this section */ 2188 Status = RtlImageNtHeaderEx(0, ViewBase, ViewSize, &NtHeader); 2189 if (!(NT_SUCCESS(Status)) || !(NtHeader)) 2190 { 2191 /* Unmap the section and fail */ 2192 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2193 return FALSE; 2194 } 2195 2196 /* Go through the list of modules again */ 2197 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2198 ListEntry = ListHead->Flink; 2199 while (ListEntry != ListHead) 2200 { 2201 /* Get the current entry and advance to the next one */ 2202 CurEntry = CONTAINING_RECORD(ListEntry, 2203 LDR_DATA_TABLE_ENTRY, 2204 InLoadOrderLinks); 2205 ListEntry = ListEntry->Flink; 2206 2207 /* Check if it's in the process of being unloaded */ 2208 if (!CurEntry->InMemoryOrderLinks.Flink) continue; 2209 2210 /* The header is untrusted, use SEH */ 2211 _SEH2_TRY 2212 { 2213 /* Check if timedate stamp and sizes match */ 2214 if ((CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp) && 2215 (CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage)) 2216 { 2217 /* Time, date and size match. Let's compare their headers */ 2218 NtHeader2 = RtlImageNtHeader(CurEntry->DllBase); 2219 if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS))) 2220 { 2221 /* Headers match too! Finally ask the kernel to compare mapped files */ 2222 Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase); 2223 if (NT_SUCCESS(Status)) 2224 { 2225 /* This is our entry!, unmap and return success */ 2226 *LdrEntry = CurEntry; 2227 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2228 _SEH2_YIELD(return TRUE;) 2229 } 2230 } 2231 } 2232 } 2233 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) 2234 { 2235 _SEH2_YIELD(break;) 2236 } 2237 _SEH2_END; 2238 } 2239 2240 /* Unmap the section and fail */ 2241 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2242 return FALSE; 2243 } 2244 2245 NTSTATUS 2246 NTAPI 2247 LdrpGetProcedureAddress(IN PVOID BaseAddress, 2248 IN PANSI_STRING Name, 2249 IN ULONG Ordinal, 2250 OUT PVOID *ProcedureAddress, 2251 IN BOOLEAN ExecuteInit) 2252 { 2253 NTSTATUS Status = STATUS_SUCCESS; 2254 UCHAR ImportBuffer[64]; 2255 PLDR_DATA_TABLE_ENTRY LdrEntry; 2256 IMAGE_THUNK_DATA Thunk; 2257 PVOID ImageBase; 2258 PIMAGE_IMPORT_BY_NAME ImportName = NULL; 2259 PIMAGE_EXPORT_DIRECTORY ExportDir; 2260 ULONG ExportDirSize, Length; 2261 PLIST_ENTRY Entry; 2262 2263 /* Show debug message */ 2264 if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by "); 2265 2266 /* Check if we got a name */ 2267 if (Name) 2268 { 2269 /* Show debug message */ 2270 if (ShowSnaps) DbgPrint("NAME - %s\n", Name->Buffer); 2271 2272 /* Make sure it's not too long */ 2273 Length = Name->Length + 2274 sizeof(CHAR) + 2275 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name); 2276 if (Length > UNICODE_STRING_MAX_BYTES) 2277 { 2278 /* Won't have enough space to add the hint */ 2279 return STATUS_NAME_TOO_LONG; 2280 } 2281 2282 /* Check if our buffer is large enough */ 2283 if (Length > sizeof(ImportBuffer)) 2284 { 2285 /* Allocate from heap, plus 2 bytes for the Hint */ 2286 ImportName = RtlAllocateHeap(RtlGetProcessHeap(), 2287 0, 2288 Length); 2289 } 2290 else 2291 { 2292 /* Use our internal buffer */ 2293 ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer; 2294 } 2295 2296 /* Clear the hint */ 2297 ImportName->Hint = 0; 2298 2299 /* Copy the name and null-terminate it */ 2300 RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length); 2301 ImportName->Name[Name->Length] = ANSI_NULL; 2302 2303 /* Clear the high bit */ 2304 ImageBase = ImportName; 2305 Thunk.u1.AddressOfData = 0; 2306 } 2307 else 2308 { 2309 /* Do it by ordinal */ 2310 ImageBase = NULL; 2311 2312 /* Show debug message */ 2313 if (ShowSnaps) DbgPrint("ORDINAL - %lx\n", Ordinal); 2314 2315 /* Make sure an ordinal was given */ 2316 if (!Ordinal) 2317 { 2318 /* No ordinal */ 2319 DPRINT1("No ordinal and no name\n"); 2320 return STATUS_INVALID_PARAMETER; 2321 } 2322 2323 /* Set the original flag in the thunk */ 2324 Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG; 2325 } 2326 2327 /* Acquire lock unless we are initting */ 2328 if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock); 2329 2330 _SEH2_TRY 2331 { 2332 /* Try to find the loaded DLL */ 2333 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 2334 { 2335 /* Invalid base */ 2336 DPRINT1("Invalid base address %p\n", BaseAddress); 2337 Status = STATUS_DLL_NOT_FOUND; 2338 _SEH2_YIELD(goto Quickie;) 2339 } 2340 2341 /* Get the pointer to the export directory */ 2342 ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 2343 TRUE, 2344 IMAGE_DIRECTORY_ENTRY_EXPORT, 2345 &ExportDirSize); 2346 2347 if (!ExportDir) 2348 { 2349 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n", 2350 &LdrEntry->BaseDllName, Name, BaseAddress, LdrEntry->DllBase); 2351 Status = STATUS_PROCEDURE_NOT_FOUND; 2352 _SEH2_YIELD(goto Quickie;) 2353 } 2354 2355 /* Now get the thunk */ 2356 Status = LdrpSnapThunk(LdrEntry->DllBase, 2357 ImageBase, 2358 &Thunk, 2359 &Thunk, 2360 ExportDir, 2361 ExportDirSize, 2362 FALSE, 2363 NULL); 2364 2365 /* Finally, see if we're supposed to run the init routines */ 2366 if ((NT_SUCCESS(Status)) && (ExecuteInit)) 2367 { 2368 /* 2369 * It's possible a forwarded entry had us load the DLL. In that case, 2370 * then we will call its DllMain. Use the last loaded DLL for this. 2371 */ 2372 Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink; 2373 LdrEntry = CONTAINING_RECORD(Entry, 2374 LDR_DATA_TABLE_ENTRY, 2375 InInitializationOrderLinks); 2376 2377 /* Make sure we didn't process it yet*/ 2378 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) 2379 { 2380 /* Call the init routine */ 2381 _SEH2_TRY 2382 { 2383 Status = LdrpRunInitializeRoutines(NULL); 2384 } 2385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2386 { 2387 /* Get the exception code */ 2388 Status = _SEH2_GetExceptionCode(); 2389 } 2390 _SEH2_END; 2391 } 2392 } 2393 2394 /* Make sure we're OK till here */ 2395 if (NT_SUCCESS(Status)) 2396 { 2397 /* Return the address */ 2398 *ProcedureAddress = (PVOID)Thunk.u1.Function; 2399 } 2400 } 2401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2402 { 2403 /* Just ignore exceptions */ 2404 } 2405 _SEH2_END; 2406 2407 Quickie: 2408 /* Cleanup */ 2409 if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer)) 2410 { 2411 /* We allocated from heap, free it */ 2412 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName); 2413 } 2414 2415 /* Release the CS if we entered it */ 2416 if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock); 2417 2418 /* We're done */ 2419 return Status; 2420 } 2421 2422 NTSTATUS 2423 NTAPI 2424 LdrpLoadDll(IN BOOLEAN Redirected, 2425 IN PWSTR DllPath OPTIONAL, 2426 IN PULONG DllCharacteristics OPTIONAL, 2427 IN PUNICODE_STRING DllName, 2428 OUT PVOID *BaseAddress, 2429 IN BOOLEAN CallInit) 2430 { 2431 PPEB Peb = NtCurrentPeb(); 2432 NTSTATUS Status = STATUS_SUCCESS; 2433 const WCHAR *p; 2434 BOOLEAN GotExtension; 2435 WCHAR c; 2436 WCHAR NameBuffer[MAX_PATH + 6]; 2437 UNICODE_STRING RawDllName; 2438 PLDR_DATA_TABLE_ENTRY LdrEntry; 2439 BOOLEAN InInit = LdrpInLdrInit; 2440 2441 /* Save the Raw DLL Name */ 2442 if (DllName->Length >= sizeof(NameBuffer)) return STATUS_NAME_TOO_LONG; 2443 RtlInitEmptyUnicodeString(&RawDllName, NameBuffer, sizeof(NameBuffer)); 2444 RtlCopyUnicodeString(&RawDllName, DllName); 2445 2446 /* Find the extension, if present */ 2447 p = DllName->Buffer + DllName->Length / sizeof(WCHAR) - 1; 2448 GotExtension = FALSE; 2449 while (p >= DllName->Buffer) 2450 { 2451 c = *p--; 2452 if (c == L'.') 2453 { 2454 GotExtension = TRUE; 2455 break; 2456 } 2457 else if (c == L'\\') 2458 { 2459 break; 2460 } 2461 } 2462 2463 /* If no extension was found, add the default extension */ 2464 if (!GotExtension) 2465 { 2466 /* Check that we have space to add one */ 2467 if ((DllName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >= 2468 sizeof(NameBuffer)) 2469 { 2470 /* No space to add the extension */ 2471 DbgPrintEx(DPFLTR_LDR_ID, 2472 DPFLTR_ERROR_LEVEL, 2473 "LDR: %s - Dll name missing extension; with extension " 2474 "added the name is too long\n" 2475 " DllName: (@ %p) \"%wZ\"\n" 2476 " DllName->Length: %u\n", 2477 __FUNCTION__, 2478 DllName, 2479 DllName, 2480 DllName->Length); 2481 return STATUS_NAME_TOO_LONG; 2482 } 2483 2484 /* Add it. Needs to be null terminated, thus the length check above */ 2485 (VOID)RtlAppendUnicodeStringToString(&RawDllName, 2486 &LdrApiDefaultExtension); 2487 } 2488 2489 /* Check for init flag and acquire lock */ 2490 if (!InInit) RtlEnterCriticalSection(&LdrpLoaderLock); 2491 2492 _SEH2_TRY 2493 { 2494 /* Show debug message */ 2495 if (ShowSnaps) 2496 { 2497 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n", 2498 &RawDllName, 2499 DllPath ? DllPath : L""); 2500 } 2501 2502 /* Check if the DLL is already loaded */ 2503 if (!LdrpCheckForLoadedDll(DllPath, 2504 &RawDllName, 2505 FALSE, 2506 Redirected, 2507 &LdrEntry)) 2508 { 2509 /* Map it */ 2510 Status = LdrpMapDll(DllPath, 2511 DllPath, 2512 NameBuffer, 2513 DllCharacteristics, 2514 FALSE, 2515 Redirected, 2516 &LdrEntry); 2517 if (!NT_SUCCESS(Status)) 2518 _SEH2_LEAVE; 2519 2520 /* FIXME: Need to mark the DLL range for the stack DB */ 2521 //RtlpStkMarkDllRange(LdrEntry); 2522 2523 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */ 2524 if ((DllCharacteristics) && 2525 (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) 2526 { 2527 /* This is not a DLL, so remove such data */ 2528 LdrEntry->EntryPoint = NULL; 2529 LdrEntry->Flags &= ~LDRP_IMAGE_DLL; 2530 } 2531 2532 /* Make sure it's a DLL */ 2533 if (LdrEntry->Flags & LDRP_IMAGE_DLL) 2534 { 2535 /* Check if this is a .NET Image */ 2536 if (!(LdrEntry->Flags & LDRP_COR_IMAGE)) 2537 { 2538 /* Walk the Import Descriptor */ 2539 Status = LdrpWalkImportDescriptor(DllPath, LdrEntry); 2540 } 2541 2542 /* Update load count, unless it's locked */ 2543 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++; 2544 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 2545 2546 /* Check if we failed */ 2547 if (!NT_SUCCESS(Status)) 2548 { 2549 /* Clear entrypoint, and insert into list */ 2550 LdrEntry->EntryPoint = NULL; 2551 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 2552 &LdrEntry->InInitializationOrderLinks); 2553 2554 /* Cancel the load */ 2555 LdrpClearLoadInProgress(); 2556 2557 /* Unload the DLL */ 2558 if (ShowSnaps) 2559 { 2560 DbgPrint("LDR: Unloading %wZ due to error %x walking " 2561 "import descriptors\n", 2562 DllName, 2563 Status); 2564 } 2565 LdrUnloadDll(LdrEntry->DllBase); 2566 2567 /* Return the error */ 2568 _SEH2_LEAVE; 2569 } 2570 } 2571 else if (LdrEntry->LoadCount != 0xFFFF) 2572 { 2573 /* Increase load count */ 2574 LdrEntry->LoadCount++; 2575 } 2576 2577 /* Insert it into the list */ 2578 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, 2579 &LdrEntry->InInitializationOrderLinks); 2580 2581 /* If we have to run the entrypoint, make sure the DB is ready */ 2582 if (CallInit && LdrpLdrDatabaseIsSetup) 2583 { 2584 /* Notify Shim Engine */ 2585 if (g_ShimsEnabled) 2586 { 2587 VOID (NTAPI* SE_DllLoaded)(PLDR_DATA_TABLE_ENTRY) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded); 2588 SE_DllLoaded(LdrEntry); 2589 } 2590 2591 /* Run the init routine */ 2592 Status = LdrpRunInitializeRoutines(NULL); 2593 if (!NT_SUCCESS(Status)) 2594 { 2595 /* Failed, unload the DLL */ 2596 if (ShowSnaps) 2597 { 2598 DbgPrint("LDR: Unloading %wZ because either its init " 2599 "routine or one of its static imports failed; " 2600 "status = 0x%08lx\n", 2601 DllName, 2602 Status); 2603 } 2604 LdrUnloadDll(LdrEntry->DllBase); 2605 } 2606 } 2607 else 2608 { 2609 /* The DB isn't ready, which means we were loaded because of a forwarder */ 2610 Status = STATUS_SUCCESS; 2611 } 2612 } 2613 else 2614 { 2615 /* We were already loaded. Are we a DLL? */ 2616 if ((LdrEntry->Flags & LDRP_IMAGE_DLL) && (LdrEntry->LoadCount != 0xFFFF)) 2617 { 2618 /* Increase load count */ 2619 LdrEntry->LoadCount++; 2620 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 2621 2622 /* Clear the load in progress */ 2623 LdrpClearLoadInProgress(); 2624 } 2625 else 2626 { 2627 /* Not a DLL, just increase the load count */ 2628 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++; 2629 } 2630 } 2631 2632 } 2633 _SEH2_FINALLY 2634 { 2635 /* Release the lock */ 2636 if (!InInit) RtlLeaveCriticalSection(&LdrpLoaderLock); 2637 } 2638 _SEH2_END; 2639 2640 /* Check for success */ 2641 if (NT_SUCCESS(Status)) 2642 { 2643 /* Return the base address */ 2644 *BaseAddress = LdrEntry->DllBase; 2645 } 2646 else 2647 { 2648 /* Nothing found */ 2649 *BaseAddress = NULL; 2650 } 2651 2652 /* Return status */ 2653 return Status; 2654 } 2655 2656 ULONG 2657 NTAPI 2658 LdrpClearLoadInProgress(VOID) 2659 { 2660 PLIST_ENTRY ListHead, Entry; 2661 PLDR_DATA_TABLE_ENTRY LdrEntry; 2662 ULONG ModulesCount = 0; 2663 2664 /* Traverse the init list */ 2665 ListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; 2666 Entry = ListHead->Flink; 2667 while (Entry != ListHead) 2668 { 2669 /* Get the loader entry */ 2670 LdrEntry = CONTAINING_RECORD(Entry, 2671 LDR_DATA_TABLE_ENTRY, 2672 InInitializationOrderLinks); 2673 2674 /* Clear load in progress flag */ 2675 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS; 2676 2677 /* Check for modules with entry point count but not processed yet */ 2678 if ((LdrEntry->EntryPoint) && 2679 !(LdrEntry->Flags & LDRP_ENTRY_PROCESSED)) 2680 { 2681 /* Increase counter */ 2682 ModulesCount++; 2683 } 2684 2685 /* Advance to the next entry */ 2686 Entry = Entry->Flink; 2687 } 2688 2689 /* Return final count */ 2690 return ModulesCount; 2691 } 2692 2693 PVOID LdrpGetShimEngineFunction(PCSZ FunctionName) 2694 { 2695 ANSI_STRING Function; 2696 NTSTATUS Status; 2697 PVOID Address; 2698 RtlInitAnsiString(&Function, FunctionName); 2699 /* Skip Dll init */ 2700 Status = LdrpGetProcedureAddress(g_pShimEngineModule, &Function, 0, &Address, FALSE); 2701 return NT_SUCCESS(Status) ? Address : NULL; 2702 } 2703 2704 VOID 2705 NTAPI 2706 LdrpGetShimEngineInterface() 2707 { 2708 PVOID SE_DllLoaded = LdrpGetShimEngineFunction("SE_DllLoaded"); 2709 PVOID SE_DllUnloaded = LdrpGetShimEngineFunction("SE_DllUnloaded"); 2710 PVOID SE_InstallBeforeInit = LdrpGetShimEngineFunction("SE_InstallBeforeInit"); 2711 PVOID SE_InstallAfterInit = LdrpGetShimEngineFunction("SE_InstallAfterInit"); 2712 PVOID SE_ProcessDying = LdrpGetShimEngineFunction("SE_ProcessDying"); 2713 2714 if (SE_DllLoaded && SE_DllUnloaded && SE_InstallBeforeInit && SE_InstallAfterInit && SE_ProcessDying) 2715 { 2716 g_pfnSE_DllLoaded = RtlEncodeSystemPointer(SE_DllLoaded); 2717 g_pfnSE_DllUnloaded = RtlEncodeSystemPointer(SE_DllUnloaded); 2718 g_pfnSE_InstallBeforeInit = RtlEncodeSystemPointer(SE_InstallBeforeInit); 2719 g_pfnSE_InstallAfterInit = RtlEncodeSystemPointer(SE_InstallAfterInit); 2720 g_pfnSE_ProcessDying = RtlEncodeSystemPointer(SE_ProcessDying); 2721 g_ShimsEnabled = TRUE; 2722 } 2723 else 2724 { 2725 LdrpUnloadShimEngine(); 2726 } 2727 } 2728 2729 VOID 2730 NTAPI 2731 LdrpRunShimEngineInitRoutine(IN ULONG Reason) 2732 { 2733 PLIST_ENTRY ListHead, Next; 2734 PLDR_DATA_TABLE_ENTRY LdrEntry; 2735 2736 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 2737 Next = ListHead->Flink; 2738 while (Next != ListHead) 2739 { 2740 LdrEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 2741 2742 if (g_pShimEngineModule == LdrEntry->DllBase) 2743 { 2744 if (LdrEntry->EntryPoint) 2745 { 2746 _SEH2_TRY 2747 { 2748 LdrpCallInitRoutine(LdrEntry->EntryPoint, LdrEntry->DllBase, Reason, NULL); 2749 } 2750 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2751 { 2752 DPRINT1("WARNING: Exception 0x%x during LdrpRunShimEngineInitRoutine(%u)\n", 2753 _SEH2_GetExceptionCode(), Reason); 2754 } 2755 _SEH2_END; 2756 } 2757 return; 2758 } 2759 2760 Next = Next->Flink; 2761 } 2762 } 2763 2764 VOID 2765 NTAPI 2766 LdrpLoadShimEngine(IN PWSTR ImageName, IN PUNICODE_STRING ProcessImage, IN PVOID pShimData) 2767 { 2768 UNICODE_STRING ShimLibraryName; 2769 PVOID ShimLibrary; 2770 NTSTATUS Status; 2771 RtlInitUnicodeString(&ShimLibraryName, ImageName); 2772 /* We should NOT pass CallInit = TRUE! 2773 If we do this, other init routines will be called before we get a chance to shim stuff.. */ 2774 Status = LdrpLoadDll(FALSE, NULL, NULL, &ShimLibraryName, &ShimLibrary, FALSE); 2775 if (NT_SUCCESS(Status)) 2776 { 2777 g_pShimEngineModule = ShimLibrary; 2778 LdrpRunShimEngineInitRoutine(DLL_PROCESS_ATTACH); 2779 LdrpGetShimEngineInterface(); 2780 if (g_ShimsEnabled) 2781 { 2782 VOID(NTAPI *SE_InstallBeforeInit)(PUNICODE_STRING, PVOID); 2783 SE_InstallBeforeInit = RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit); 2784 SE_InstallBeforeInit(ProcessImage, pShimData); 2785 } 2786 } 2787 } 2788 2789 VOID 2790 NTAPI 2791 LdrpUnloadShimEngine() 2792 { 2793 /* Make sure we do not call into the shim engine anymore */ 2794 g_ShimsEnabled = FALSE; 2795 LdrpRunShimEngineInitRoutine(DLL_PROCESS_DETACH); 2796 LdrUnloadDll(g_pShimEngineModule); 2797 g_pShimEngineModule = NULL; 2798 } 2799 2800 /* EOF */ 2801