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)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache
, LdrpGetModuleHandleCache
;
19 BOOLEAN g_ShimsEnabled
;
21 /* FUNCTIONS *****************************************************************/
25 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint
,
31 return EntryPoint(BaseAddress
, Reason
, Context
);
34 /* NOTE: This function is broken */
37 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
39 OUT PUNICODE_STRING UpdateString
)
41 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder
;
42 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
43 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
44 PIMAGE_THUNK_DATA FirstThunk
;
45 PLDR_DATA_TABLE_ENTRY Entry
;
46 PUNICODE_STRING ImportNameUnic
;
47 ANSI_STRING ImportNameAnsi
;
53 /* Check the action we need to perform */
54 if (Flags
== LDRP_UPDATE_REFCOUNT
)
56 /* Make sure entry is not being loaded already */
57 if (LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
)
60 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
62 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
64 /* Make sure the entry is not being unloaded already */
65 if (LdrEntry
->Flags
& LDRP_UNLOAD_IN_PROGRESS
)
68 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
71 /* Go through all bound DLLs and dereference them */
72 ImportNameUnic
= &NtCurrentTeb()->StaticUnicodeString
;
74 /* Try to get the new import entry */
75 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
77 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
82 /* Set entry flags if refing/derefing */
83 if (Flags
== LDRP_UPDATE_REFCOUNT
)
84 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
85 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
86 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
88 while (BoundEntry
->OffsetModuleName
)
90 /* Get pointer to the current import name */
91 ImportName
= (PCHAR
)BoundEntry
+ BoundEntry
->OffsetModuleName
;
93 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
94 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
96 if (NT_SUCCESS(Status
))
98 if (LdrpCheckForLoadedDll(NULL
,
104 if (Entry
->LoadCount
!= 0xFFFF)
106 /* Perform the required action */
109 case LDRP_UPDATE_REFCOUNT
:
112 case LDRP_UPDATE_DEREFCOUNT
:
115 case LDRP_UPDATE_PIN
:
116 Entry
->LoadCount
= 0xFFFF;
123 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
127 /* Recurse into this entry */
128 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
132 /* Go through forwarders */
133 NewImportForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
134 for (i
=0; i
<BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
136 ImportName
= (PCHAR
)BoundEntry
+ NewImportForwarder
->OffsetModuleName
;
138 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
139 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
140 if (NT_SUCCESS(Status
))
142 if (LdrpCheckForLoadedDll(NULL
,
148 if (Entry
->LoadCount
!= 0xFFFF)
150 /* Perform the required action */
153 case LDRP_UPDATE_REFCOUNT
:
156 case LDRP_UPDATE_DEREFCOUNT
:
159 case LDRP_UPDATE_PIN
:
160 Entry
->LoadCount
= 0xFFFF;
167 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
171 /* Recurse into this entry */
172 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
176 NewImportForwarder
++;
179 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)NewImportForwarder
;
186 /* Check oldstyle import descriptor */
187 ImportEntry
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
189 IMAGE_DIRECTORY_ENTRY_IMPORT
,
193 /* There is old one, so go through its entries */
194 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
196 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->FirstThunk
);
198 /* Skip this entry if needed */
199 if (!FirstThunk
->u1
.Function
)
205 ImportName
= (PSZ
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
207 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
208 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
209 if (NT_SUCCESS(Status
))
211 if (LdrpCheckForLoadedDll(NULL
,
217 if (Entry
->LoadCount
!= 0xFFFF)
219 /* Perform the required action */
222 case LDRP_UPDATE_REFCOUNT
:
225 case LDRP_UPDATE_DEREFCOUNT
:
228 case LDRP_UPDATE_PIN
:
229 Entry
->LoadCount
= 0xFFFF;
236 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
241 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
245 /* Go to the next entry */
253 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
256 WCHAR Buffer
[MAX_PATH
];
257 UNICODE_STRING UpdateString
;
259 /* Setup the string and call the extended API */
260 RtlInitEmptyUnicodeString(&UpdateString
, Buffer
, sizeof(Buffer
));
261 LdrpUpdateLoadCount3(LdrEntry
, Flags
, &UpdateString
);
266 LdrpCallTlsInitializers(IN PVOID BaseAddress
,
269 PIMAGE_TLS_DIRECTORY TlsDirectory
;
270 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
273 /* Get the TLS Directory */
274 TlsDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
276 IMAGE_DIRECTORY_ENTRY_TLS
,
279 /* Protect against invalid pointers */
282 /* Make sure it's valid */
286 Array
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
;
292 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
293 BaseAddress
, TlsDirectory
, Array
);
299 /* Get the TLS Entrypoint */
305 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
306 BaseAddress
, Callback
);
310 LdrpCallInitRoutine((PDLL_INIT_ROUTINE
)Callback
,
318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
327 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName
,
330 /* Not implemented */
331 return STATUS_SUCCESS
;
336 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
338 IN PULONG DllCharacteristics OPTIONAL
,
339 OUT PHANDLE SectionHandle
)
343 OBJECT_ATTRIBUTES ObjectAttributes
;
344 IO_STATUS_BLOCK IoStatusBlock
;
345 ULONG_PTR HardErrorParameters
[1];
347 SECTION_IMAGE_INFORMATION SectionImageInfo
;
349 /* Check if we don't already have a handle */
352 /* Create the object attributes */
353 InitializeObjectAttributes(&ObjectAttributes
,
355 OBJ_CASE_INSENSITIVE
,
360 Status
= NtOpenFile(&FileHandle
,
361 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
364 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
365 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
367 /* Check if we failed */
368 if (!NT_SUCCESS(Status
))
370 /* Attempt to open for execute only */
371 Status
= NtOpenFile(&FileHandle
,
372 SYNCHRONIZE
| FILE_EXECUTE
,
375 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
376 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
378 /* Check if this failed too */
379 if (!NT_SUCCESS(Status
))
381 /* Show debug message */
384 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
388 /* Make sure to return an expected status code */
389 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
391 /* Callers expect this instead */
392 Status
= STATUS_DLL_NOT_FOUND
;
395 /* Return an empty section handle */
396 *SectionHandle
= NULL
;
403 /* Use the handle we already have */
404 FileHandle
= DllHandle
;
407 /* Create a section for the DLL */
408 Status
= NtCreateSection(SectionHandle
,
409 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
410 SECTION_MAP_WRITE
| SECTION_QUERY
,
417 /* If mapping failed, raise a hard error */
418 if (!NT_SUCCESS(Status
))
420 /* Forget the handle */
421 *SectionHandle
= NULL
;
423 /* Give the DLL name */
424 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
426 /* Raise the error */
427 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
434 /* Increment the error count */
435 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
438 /* Check for Safer restrictions */
439 if (DllCharacteristics
&&
440 !(*DllCharacteristics
& IMAGE_FILE_SYSTEM
))
442 /* Make sure it's executable */
443 Status
= ZwQuerySection(*SectionHandle
,
444 SectionImageInformation
,
446 sizeof(SECTION_IMAGE_INFORMATION
),
448 if (NT_SUCCESS(Status
))
450 /* Bypass the check for .NET images */
451 if (!(SectionImageInfo
.LoaderFlags
& IMAGE_LOADER_FLAGS_COMPLUS
))
453 /* Check with Safer */
454 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
455 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
457 /* Show debug message */
460 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
464 /* Failure case, close section handle */
465 NtClose(*SectionHandle
);
466 *SectionHandle
= NULL
;
472 /* Failure case, close section handle */
473 NtClose(*SectionHandle
);
474 *SectionHandle
= NULL
;
478 /* Close the file handle, we don't need it */
485 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
488 LdrpResolveDllName(PWSTR DllPath
,
490 PUNICODE_STRING FullDllName
,
491 PUNICODE_STRING BaseDllName
)
493 PWCHAR NameBuffer
, p1
, p2
= 0;
497 /* Allocate space for full DLL name */
498 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize
+ sizeof(UNICODE_NULL
));
499 if (!FullDllName
->Buffer
) return FALSE
;
501 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
506 &BaseDllName
->Buffer
);
508 if (!Length
|| Length
> BufSize
)
512 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
513 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
516 RtlFreeUnicodeString(FullDllName
);
520 /* Construct full DLL name */
521 FullDllName
->Length
= Length
;
522 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
524 /* Allocate a new buffer */
525 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
528 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
532 /* Copy over the contents from the previous one and free it */
533 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
534 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
535 FullDllName
->Buffer
= NameBuffer
;
537 /* Find last backslash */
538 p1
= FullDllName
->Buffer
;
547 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
555 /* Calculate remaining length */
558 /* Construct base DLL name */
559 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
560 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
561 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName
->MaximumLength
);
563 if (!BaseDllName
->Buffer
)
565 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
569 /* Copy base dll name to the new buffer */
570 RtlMoveMemory(BaseDllName
->Buffer
,
572 BaseDllName
->Length
);
574 /* Null-terminate the string */
575 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
582 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase
)
584 PIMAGE_NT_HEADERS NtHeaders
;
585 ULONG_PTR EntryPoint
= 0;
587 /* Get entry point offset from NT headers */
588 NtHeaders
= RtlImageNtHeader(ImageBase
);
592 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
593 if (EntryPoint
) EntryPoint
+= (ULONG_PTR
)ImageBase
;
596 /* Return calculated pointer (or zero in case of failure) */
597 return (PVOID
)EntryPoint
;
600 /* NOTE: This function is broken, wrong number of parameters, no SxS, etc */
603 LdrpCheckForKnownDll(PWSTR DllName
,
604 PUNICODE_STRING FullDllName
,
605 PUNICODE_STRING BaseDllName
)
607 OBJECT_ATTRIBUTES ObjectAttributes
;
608 HANDLE Section
= NULL
;
609 UNICODE_STRING DllNameUnic
;
614 /* Upgrade DllName to a unicode string */
615 RtlInitUnicodeString(&DllNameUnic
, DllName
);
617 /* Get the activation context */
618 Status
= RtlFindActivationContextSectionString(0,
620 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
624 /* Check if it's a SxS or not */
625 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
626 Status
== STATUS_SXS_KEY_NOT_FOUND
)
628 /* Set up BaseDllName */
629 BaseDllName
->Length
= DllNameUnic
.Length
;
630 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
631 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
633 DllNameUnic
.MaximumLength
);
634 if (!BaseDllName
->Buffer
) return NULL
;
636 /* Copy the contents there */
637 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
639 /* Set up FullDllName */
640 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
641 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
642 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
643 if (!FullDllName
->Buffer
)
645 /* Free base name and fail */
646 RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
650 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
652 /* Put a slash there */
653 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
658 /* Set up DllNameUnic for a relative path */
659 DllNameUnic
.Buffer
= (PWSTR
)p1
;
660 DllNameUnic
.Length
= BaseDllName
->Length
;
661 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
663 /* Copy the contents */
664 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
666 /* There are all names, init attributes and open the section */
667 InitializeObjectAttributes(&ObjectAttributes
,
669 OBJ_CASE_INSENSITIVE
,
670 LdrpKnownDllObjectDirectory
,
673 Status
= NtOpenSection(&Section
,
674 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
676 if (!NT_SUCCESS(Status
))
678 /* Opening failed, free resources */
680 RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
681 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
686 if (!NT_SUCCESS(Status
)) Section
= NULL
;
689 /* Return section handle */
695 LdrpSetProtection(PVOID ViewBase
,
698 PIMAGE_NT_HEADERS NtHeaders
;
699 PIMAGE_SECTION_HEADER Section
;
703 ULONG NewProtection
, OldProtection
, i
;
705 /* Get the NT headers */
706 NtHeaders
= RtlImageNtHeader(ViewBase
);
707 if (!NtHeaders
) return STATUS_INVALID_IMAGE_FORMAT
;
709 /* Compute address of the first section header */
710 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
712 /* Go through all sections */
713 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
715 /* Check for read-only non-zero section */
716 if ((Section
->SizeOfRawData
) &&
717 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
719 /* Check if we are setting or restoring protection */
722 /* Set it to either EXECUTE or READONLY */
723 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
725 NewProtection
= PAGE_EXECUTE
;
729 NewProtection
= PAGE_READONLY
;
732 /* Add PAGE_NOCACHE if needed */
733 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
735 NewProtection
|= PAGE_NOCACHE
;
740 /* Enable write access */
741 NewProtection
= PAGE_READWRITE
;
744 /* Get the section VA */
745 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
746 SectionSize
= Section
->SizeOfRawData
;
750 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
755 if (!NT_SUCCESS(Status
)) return Status
;
759 /* Move to the next section */
763 /* Flush instruction cache if necessary */
764 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
765 return STATUS_SUCCESS
;
768 /* NOTE: Not yet reviewed */
771 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
773 IN PWSTR DllName OPTIONAL
,
774 IN PULONG DllCharacteristics
,
777 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
779 PTEB Teb
= NtCurrentTeb();
780 PPEB Peb
= NtCurrentPeb();
783 BOOLEAN KnownDll
= FALSE
;
784 UNICODE_STRING FullDllName
, BaseDllName
;
785 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
786 UNICODE_STRING NtPathDllName
;
787 ULONG_PTR HardErrorParameters
[2];
788 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
791 PVOID ViewBase
= NULL
;
792 PVOID ArbitraryUserPointer
;
793 PIMAGE_NT_HEADERS NtHeaders
;
794 NTSTATUS HardErrorStatus
, Status
;
795 BOOLEAN OverlapDllFound
= FALSE
;
796 ULONG_PTR ImageBase
, ImageEnd
;
797 PLIST_ENTRY ListHead
, NextEntry
;
798 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
799 ULONG_PTR CandidateBase
, CandidateEnd
;
800 UNICODE_STRING OverlapDll
;
801 BOOLEAN RelocatableDll
= TRUE
;
802 UNICODE_STRING IllegalDll
;
804 ULONG RelocDataSize
= 0;
806 // FIXME: AppCompat stuff is missing
810 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
812 SearchPath
? SearchPath
: L
"");
815 /* Check if we have a known dll directory */
816 if (LdrpKnownDllObjectDirectory
)
818 /* Check if the path is full */
822 if (TempChar
== '\\' || TempChar
== '/' )
824 /* Complete path, don't do Known Dll lookup */
829 /* Try to find a Known DLL */
830 SectionHandle
= LdrpCheckForKnownDll(DllName
,
837 /* Check if the Known DLL Check returned something */
840 /* It didn't, so try to resolve the name now */
841 if (LdrpResolveDllName(SearchPath
,
846 /* Got a name, display a message */
849 DPRINT1("LDR: Loading (%s) %wZ\n",
850 Static
? "STATIC" : "DYNAMIC",
854 /* Convert to NT Name */
855 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
860 /* Path was invalid */
861 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
864 /* Create a section for this dLL */
865 Status
= LdrpCreateDllSection(&NtPathDllName
,
870 /* Free the NT Name */
871 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
874 if (!NT_SUCCESS(Status
))
876 /* Free the name strings and return */
877 RtlFreeUnicodeString(&FullDllName
);
878 RtlFreeUnicodeString(&BaseDllName
);
884 /* We couldn't resolve the name, is this a static load? */
888 * This is BAD! Static loads are CRITICAL. Bugcheck!
889 * Initialize the strings for the error
891 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
892 RtlInitUnicodeString(&HardErrorDllPath
,
893 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
895 /* Set them as error parameters */
896 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
897 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
899 /* Raise the hard error */
900 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
907 /* We're back, where we initializing? */
908 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
912 return STATUS_DLL_NOT_FOUND
;
917 /* We have a section handle, so this is a known dll */
921 /* Stuff the image name in the TIB, for the debugger */
922 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
923 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
928 Status
= NtMapViewOfSection(SectionHandle
,
940 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
942 /* Fail if we couldn't map it */
943 if (!NT_SUCCESS(Status
))
945 /* Close and return */
946 NtClose(SectionHandle
);
950 /* Get the NT Header */
951 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
953 /* Invalid image, unmap, close handle and fail */
954 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
955 NtClose(SectionHandle
);
956 return STATUS_INVALID_IMAGE_FORMAT
;
959 // FIXME: .NET support is missing
961 /* Allocate an entry */
962 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
964 /* Invalid image, unmap, close handle and fail */
965 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
966 NtClose(SectionHandle
);
967 return STATUS_NO_MEMORY
;
970 /* Setup the entry */
971 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
972 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
973 LdrEntry
->LoadCount
= 0;
974 LdrEntry
->FullDllName
= FullDllName
;
975 LdrEntry
->BaseDllName
= BaseDllName
;
976 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
978 /* Show debug message */
981 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
986 /* Insert this entry */
987 LdrpInsertMemoryTableEntry(LdrEntry
);
989 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
991 /* Check for invalid CPU Image */
992 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
994 /* Load our header */
995 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
997 /* Assume defaults if we don't have to run the Hard Error path */
998 HardErrorStatus
= STATUS_SUCCESS
;
999 Response
= ResponseCancel
;
1001 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1002 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1004 /* Reset the entrypoint, save our Dll Name */
1005 LdrEntry
->EntryPoint
= 0;
1006 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1008 /* Raise the error */
1009 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1012 HardErrorParameters
,
1017 /* Check if the user pressed cancel */
1018 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1020 /* Remove the DLL from the lists */
1021 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1022 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1023 RemoveEntryList(&LdrEntry
->HashLinks
);
1025 /* Remove the LDR Entry */
1026 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry
);
1028 /* Unmap and close section */
1029 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1030 NtClose(SectionHandle
);
1032 /* Did we do a hard error? */
1033 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1035 /* Yup, so increase fatal error count if we are initializing */
1036 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1039 /* Return failure */
1040 return STATUS_INVALID_IMAGE_FORMAT
;
1045 /* The image was valid. Is it a DLL? */
1046 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1048 /* Set the DLL Flag */
1049 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1052 /* If we're not a DLL, clear the entrypoint */
1053 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1055 LdrEntry
->EntryPoint
= 0;
1059 /* Return it for the caller */
1060 *DataTableEntry
= LdrEntry
;
1062 /* Check if we loaded somewhere else */
1063 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1065 /* Write the flag */
1066 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1068 /* Find our region */
1069 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1070 ImageEnd
= ImageBase
+ ViewSize
;
1072 DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p -> %p)\n", DllName
, ImageBase
, ViewBase
);
1074 /* Scan all the modules */
1075 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1076 NextEntry
= ListHead
->Flink
;
1077 while (NextEntry
!= ListHead
)
1080 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1081 LDR_DATA_TABLE_ENTRY
,
1083 NextEntry
= NextEntry
->Flink
;
1085 /* Get the entry's bounds */
1086 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1087 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1089 /* Make sure this entry isn't unloading */
1090 if (!CandidateEntry
->InMemoryOrderModuleList
.Flink
) continue;
1092 /* Check if our regions are colliding */
1093 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1094 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1095 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1097 /* Found who is overlapping */
1098 OverlapDllFound
= TRUE
;
1099 OverlapDll
= CandidateEntry
->FullDllName
;
1104 /* Check if we found the DLL overlapping with us */
1105 if (!OverlapDllFound
)
1107 /* It's not another DLL, it's memory already here */
1108 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1111 DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll
);
1113 /* Are we dealing with a DLL? */
1114 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1116 /* Check if relocs were stripped */
1117 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1119 /* Get the relocation data */
1120 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1122 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1125 /* Does the DLL not have any? */
1126 if (!RelocData
&& !RelocDataSize
)
1128 /* We'll allow this and simply continue */
1133 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1134 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1135 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1137 /* Can't relocate user32 */
1138 RelocatableDll
= FALSE
;
1142 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1143 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1145 /* Can't relocate kernel32 */
1146 RelocatableDll
= FALSE
;
1150 /* Check if this was a non-relocatable DLL or a known dll */
1151 if (!RelocatableDll
&& KnownDll
)
1153 /* Setup for hard error */
1154 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1155 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1157 /* Raise the error */
1158 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1161 HardErrorParameters
,
1165 /* If initializing, increase the error count */
1166 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1168 /* Don't do relocation */
1169 Status
= STATUS_CONFLICTING_ADDRESSES
;
1173 /* Change the protection to prepare for relocation */
1174 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1176 /* Make sure we changed the protection */
1177 if (NT_SUCCESS(Status
))
1179 /* Do the relocation */
1180 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1181 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1183 if (NT_SUCCESS(Status
))
1185 /* Stuff the image name in the TIB, for the debugger */
1186 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1187 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1190 Status
= NtMapViewOfSection(SectionHandle
,
1202 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1204 /* Return the protection */
1205 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1209 /* Handle any kind of failure */
1210 if (!NT_SUCCESS(Status
))
1212 /* Remove it from the lists */
1213 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1214 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1215 RemoveEntryList(&LdrEntry
->HashLinks
);
1217 /* Unmap it, clear the entry */
1218 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1222 /* Show debug message */
1225 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1226 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1232 /* Not a DLL, or no relocation needed */
1233 Status
= STATUS_SUCCESS
;
1235 /* Stuff the image name in the TIB, for the debugger */
1236 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1237 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1240 Status
= NtMapViewOfSection(SectionHandle
,
1252 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1254 /* Show debug message */
1257 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1262 // FIXME: LdrpCheckCorImage() is missing
1264 /* Check if this is an SMP Machine and a DLL */
1265 if ((LdrpNumberOfProcessors
> 1) &&
1266 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1268 /* Validate the image for MP */
1269 LdrpValidateImageForMp(LdrEntry
);
1272 // FIXME: LdrpCorUnloadImage() is missing
1274 /* Close section and return status */
1275 NtClose(SectionHandle
);
1279 PLDR_DATA_TABLE_ENTRY
1281 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1283 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1284 PIMAGE_NT_HEADERS NtHeader
;
1286 /* Make sure the header is valid */
1287 NtHeader
= RtlImageNtHeader(BaseAddress
);
1288 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1292 /* Allocate an entry */
1293 LdrEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
1295 sizeof(LDR_DATA_TABLE_ENTRY
));
1297 /* Make sure we got one */
1301 LdrEntry
->DllBase
= BaseAddress
;
1302 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1303 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1304 LdrEntry
->PatchInformation
= NULL
;
1308 /* Return the entry */
1314 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1316 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1319 /* Insert into hash table */
1320 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1321 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1323 /* Insert into other lists */
1324 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1325 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderModuleList
);
1330 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry
)
1333 ASSERT(Entry
!= NULL
);
1335 /* Release the activation context if it exists and wasn't already released */
1336 if ((Entry
->EntryPointActivationContext
) &&
1337 (Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
))
1339 /* Mark it as invalid */
1340 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1341 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1344 /* Release the full dll name string */
1345 if (Entry
->FullDllName
.Buffer
) LdrpFreeUnicodeString(&Entry
->FullDllName
);
1347 /* Finally free the entry's memory */
1348 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry
);
1353 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1354 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1356 PLDR_DATA_TABLE_ENTRY Current
;
1357 PLIST_ENTRY ListHead
, Next
;
1359 /* Check the cache first */
1360 if ((LdrpLoadedDllHandleCache
) &&
1361 (LdrpLoadedDllHandleCache
->DllBase
== Base
))
1363 /* We got lucky, return the cached entry */
1364 *LdrEntry
= LdrpLoadedDllHandleCache
;
1368 /* Time for a lookup */
1369 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1370 Next
= ListHead
->Flink
;
1371 while (Next
!= ListHead
)
1373 /* Get the current entry */
1374 Current
= CONTAINING_RECORD(Next
,
1375 LDR_DATA_TABLE_ENTRY
,
1378 /* Make sure it's not unloading and check for a match */
1379 if ((Current
->InMemoryOrderModuleList
.Flink
) && (Base
== Current
->DllBase
))
1382 LdrpLoadedDllHandleCache
= Current
;
1385 *LdrEntry
= Current
;
1389 /* Move to the next one */
1397 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1400 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1401 IN PUNICODE_STRING DllName
,
1403 IN BOOLEAN RedirectedDll
,
1404 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1407 PLIST_ENTRY ListHead
, ListEntry
;
1408 PLDR_DATA_TABLE_ENTRY CurEntry
;
1409 BOOLEAN FullPath
= FALSE
;
1412 UNICODE_STRING FullDllName
, NtPathName
;
1414 OBJECT_ATTRIBUTES ObjectAttributes
;
1416 HANDLE FileHandle
, SectionHandle
;
1417 IO_STATUS_BLOCK Iosb
;
1418 PVOID ViewBase
= NULL
;
1419 SIZE_T ViewSize
= 0;
1420 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1421 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath
, DllName
, Flag
, RedirectedDll
, LdrEntry
);
1423 /* Check if a dll name was provided */
1424 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
1426 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1427 /* FIXME: Warning, code does not support redirection at all */
1429 /* Look in the hash table if flag was set */
1433 /* Get hash index */
1434 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
1436 /* Traverse that list */
1437 ListHead
= &LdrpHashTable
[HashIndex
];
1438 ListEntry
= ListHead
->Flink
;
1439 while (ListEntry
!= ListHead
)
1441 /* Get the current entry */
1442 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1444 /* Check base name of that module */
1445 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
1447 /* It matches, return it */
1448 *LdrEntry
= CurEntry
;
1452 /* Advance to the next entry */
1453 ListEntry
= ListEntry
->Flink
;
1456 /* Module was not found, return failure */
1460 /* Check if there is a full path in this DLL */
1461 wc
= DllName
->Buffer
;
1464 /* Check for a slash in the current position*/
1465 if ((*wc
== L
'\\') || (*wc
== L
'/'))
1467 /* Found the slash, so dll name contains path */
1470 /* Setup full dll name string */
1471 FullDllName
.Buffer
= NameBuf
;
1473 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
1474 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
1477 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
1481 /* Check if that was successful */
1482 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
1486 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
1487 DllName
->Buffer
, Length
);
1490 /* Return failure */
1494 /* Full dll name is found */
1495 FullDllName
.Length
= Length
;
1496 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
1503 /* Go check the hash table */
1510 /* FIXME: Warning, activation context missing */
1511 /* NOTE: From here on down, everything looks good */
1513 /* Loop the module list */
1514 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1515 ListEntry
= ListHead
->Flink
;
1516 while (ListEntry
!= ListHead
)
1518 /* Get the current entry and advance to the next one */
1519 CurEntry
= CONTAINING_RECORD(ListEntry
,
1520 LDR_DATA_TABLE_ENTRY
,
1522 ListEntry
= ListEntry
->Flink
;
1524 /* Check if it's being unloaded */
1525 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
1527 /* Check if name matches */
1528 if (RtlEqualUnicodeString(&FullDllName
,
1529 &CurEntry
->FullDllName
,
1533 *LdrEntry
= CurEntry
;
1538 /* Convert given path to NT path */
1539 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1544 /* Fail if conversion failed */
1548 /* Initialize object attributes and open it */
1549 InitializeObjectAttributes(&ObjectAttributes
,
1551 OBJ_CASE_INSENSITIVE
,
1554 Status
= NtOpenFile(&FileHandle
,
1555 SYNCHRONIZE
| FILE_EXECUTE
,
1558 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1559 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1561 /* Free NT path name */
1562 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
1564 /* If opening the file failed - return failure */
1565 if (!NT_SUCCESS(Status
)) return FALSE
;
1567 /* Create a section for this file */
1568 Status
= NtCreateSection(&SectionHandle
,
1570 SECTION_MAP_EXECUTE
|
1578 /* Close file handle */
1579 NtClose(FileHandle
);
1581 /* If creating section failed - return failure */
1582 if (!NT_SUCCESS(Status
)) return FALSE
;
1584 /* Map view of this section */
1585 Status
= ZwMapViewOfSection(SectionHandle
,
1596 /* Close section handle */
1597 NtClose(SectionHandle
);
1599 /* If section mapping failed - return failure */
1600 if (!NT_SUCCESS(Status
)) return FALSE
;
1602 /* Get pointer to the NT header of this section */
1603 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
1604 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
1606 /* Unmap the section and fail */
1607 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1611 /* Go through the list of modules again */
1612 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1613 ListEntry
= ListHead
->Flink
;
1614 while (ListEntry
!= ListHead
)
1616 /* Get the current entry and advance to the next one */
1617 CurEntry
= CONTAINING_RECORD(ListEntry
,
1618 LDR_DATA_TABLE_ENTRY
,
1620 ListEntry
= ListEntry
->Flink
;
1622 /* Check if it's in the process of being unloaded */
1623 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
1625 /* The header is untrusted, use SEH */
1628 /* Check if timedate stamp and sizes match */
1629 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
1630 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
1632 /* Time, date and size match. Let's compare their headers */
1633 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
1634 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
1636 /* Headers match too! Finally ask the kernel to compare mapped files */
1637 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
1638 if (!NT_SUCCESS(Status
))
1640 /* Almost identical, but not quite, keep trying */
1641 _SEH2_YIELD(continue;)
1645 /* This is our entry!, unmap and return success */
1646 *LdrEntry
= CurEntry
;
1647 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1648 _SEH2_YIELD(return TRUE
;)
1653 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
1660 /* Unmap the section and fail */
1661 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1667 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
1668 IN PANSI_STRING Name
,
1670 OUT PVOID
*ProcedureAddress
,
1671 IN BOOLEAN ExecuteInit
)
1673 NTSTATUS Status
= STATUS_SUCCESS
;
1674 UCHAR ImportBuffer
[64];
1675 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1676 IMAGE_THUNK_DATA Thunk
;
1678 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
1679 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1680 ULONG ExportDirSize
, Length
;
1683 /* Show debug message */
1684 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
1686 /* Check if we got a name */
1689 /* Show debug message */
1690 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
1692 /* Make sure it's not too long */
1693 Length
= Name
->Length
+
1695 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
1696 if (Length
> UNICODE_STRING_MAX_BYTES
)
1698 /* Won't have enough space to add the hint */
1699 return STATUS_NAME_TOO_LONG
;
1702 /* Check if our buffer is large enough */
1703 if (Name
->Length
> sizeof(ImportBuffer
))
1705 /* Allocate from heap, plus 2 bytes for the Hint */
1706 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
1712 /* Use our internal buffer */
1713 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
1716 /* Clear the hint */
1717 ImportName
->Hint
= 0;
1719 /* Copy the name and null-terminate it */
1720 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
1721 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
1723 /* Clear the high bit */
1724 ImageBase
= ImportName
;
1725 Thunk
.u1
.AddressOfData
= 0;
1729 /* Do it by ordinal */
1732 /* Show debug message */
1733 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
1735 /* Make sure an ordinal was given */
1739 DPRINT1("No ordinal and no name\n");
1740 return STATUS_INVALID_PARAMETER
;
1743 /* Set the orginal flag in the thunk */
1744 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
1747 /* Acquire lock unless we are initting */
1748 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
1752 /* Try to find the loaded DLL */
1753 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1756 DPRINT1("Invalid base address %p\n", BaseAddress
);
1757 Status
= STATUS_DLL_NOT_FOUND
;
1758 _SEH2_YIELD(goto Quickie
;)
1761 /* Get the pointer to the export directory */
1762 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1764 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1769 DPRINT1("Image %wZ has no exports, but were trying to get procedure %s. BaseAddress asked %p, got entry BA %p\n", &LdrEntry
->BaseDllName
, Name
? Name
->Buffer
: NULL
, BaseAddress
, LdrEntry
->DllBase
);
1770 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1771 _SEH2_YIELD(goto Quickie
;)
1774 /* Now get the thunk */
1775 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
1784 /* Finally, see if we're supposed to run the init routines */
1785 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
1788 * It's possible a forwarded entry had us load the DLL. In that case,
1789 * then we will call its DllMain. Use the last loaded DLL for this.
1791 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
1792 LdrEntry
= CONTAINING_RECORD(Entry
,
1793 LDR_DATA_TABLE_ENTRY
,
1794 InInitializationOrderModuleList
);
1796 /* Make sure we didn't process it yet*/
1797 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
1799 /* Call the init routine */
1802 Status
= LdrpRunInitializeRoutines(NULL
);
1804 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1806 /* Get the exception code */
1807 Status
= _SEH2_GetExceptionCode();
1813 /* Make sure we're OK till here */
1814 if (NT_SUCCESS(Status
))
1816 /* Return the address */
1817 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
1820 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1822 /* Just ignore exceptions */
1828 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
1830 /* We allocated from heap, free it */
1831 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
1834 /* Release the CS if we entered it */
1835 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
1843 LdrpLoadDll(IN BOOLEAN Redirected
,
1844 IN PWSTR DllPath OPTIONAL
,
1845 IN PULONG DllCharacteristics OPTIONAL
,
1846 IN PUNICODE_STRING DllName
,
1847 OUT PVOID
*BaseAddress
,
1848 IN BOOLEAN CallInit
)
1850 PPEB Peb
= NtCurrentPeb();
1851 NTSTATUS Status
= STATUS_SUCCESS
;
1854 WCHAR NameBuffer
[266];
1856 UNICODE_STRING RawDllNameString
;
1857 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1858 BOOLEAN InInit
= LdrpInLdrInit
;
1860 /* Find the name without the extension */
1861 p1
= DllName
->Buffer
;
1870 else if (c
== L
'\\')
1876 /* Save the Raw DLL Name */
1877 RawDllName
= NameBuffer
;
1878 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
1879 RtlMoveMemory(RawDllName
, DllName
->Buffer
, DllName
->Length
);
1881 /* Check if no extension was found or if we got a slash */
1882 if (!(p2
) || (*p2
== '\\'))
1884 /* Check that we have space to add one */
1885 if ((DllName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
1888 /* No space to add the extension */
1889 DbgPrintEx(81, //DPFLTR_LDR_ID,
1891 "LDR: %s - Dll name missing extension; with extension "
1892 "added the name is too long\n"
1893 " DllName: (@ %p) \"%wZ\"\n"
1894 " DllName->Length: %u\n",
1899 return STATUS_NAME_TOO_LONG
;
1902 /* FIXME: CLEAN THIS UP WITH Rtl String Functions */
1904 RtlMoveMemory((PVOID
)((ULONG_PTR
)RawDllName
+ DllName
->Length
),
1905 LdrApiDefaultExtension
.Buffer
,
1906 LdrApiDefaultExtension
.Length
);
1908 /* Save the length to a unicode string */
1909 RawDllNameString
.Length
= DllName
->Length
+ LdrApiDefaultExtension
.Length
;
1911 /* Null terminate it */
1912 RawDllName
[RawDllNameString
.Length
/ sizeof(WCHAR
)] = 0;
1916 /* Null terminate it */
1917 RawDllName
[DllName
->Length
/ sizeof(WCHAR
)] = 0;
1919 /* Save the length to a unicode string */
1920 RawDllNameString
.Length
= DllName
->Length
;
1923 /* Now create a unicode string for the DLL's name */
1924 RawDllNameString
.MaximumLength
= sizeof(NameBuffer
);
1925 RawDllNameString
.Buffer
= NameBuffer
;
1927 /* Check for init flag and acquire lock */
1928 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
1930 /* Show debug message */
1933 DPRINT1("LDR: LdrLoadDll, loading %ws from %ws\n",
1935 DllPath
? DllPath
: L
"");
1938 /* Check if the DLL is already loaded */
1939 if (!LdrpCheckForLoadedDll(DllPath
,
1946 Status
= LdrpMapDll(DllPath
,
1953 if (!NT_SUCCESS(Status
)) goto Quickie
;
1955 /* FIXME: Need to mark the DLL range for the stack DB */
1956 //RtlpStkMarkDllRange(LdrEntry);
1958 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
1959 if ((DllCharacteristics
) &&
1960 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
1962 /* This is not a DLL, so remove such data */
1963 LdrEntry
->EntryPoint
= NULL
;
1964 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
1967 /* Make sure it's a DLL */
1968 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1970 /* Check if this is a .NET Image */
1971 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
1973 /* Walk the Import Descriptor */
1974 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
1977 /* Update load count, unless it's locked */
1978 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
1979 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1981 /* Check if we failed */
1982 if (!NT_SUCCESS(Status
))
1984 /* Clear entrypoint, and insert into list */
1985 LdrEntry
->EntryPoint
= NULL
;
1986 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1987 &LdrEntry
->InInitializationOrderModuleList
);
1989 /* Cancel the load */
1990 LdrpClearLoadInProgress();
1992 /* Unload the DLL */
1995 DbgPrint("LDR: Unloading %wZ due to error %x walking "
1996 "import descriptors",
2000 LdrUnloadDll(LdrEntry
->DllBase
);
2002 /* Return the error */
2006 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2008 /* Increase load count */
2009 LdrEntry
->LoadCount
++;
2012 /* Insert it into the list */
2013 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2014 &LdrEntry
->InInitializationOrderModuleList
);
2016 /* If we have to run the entrypoint, make sure the DB is ready */
2017 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2019 /* FIXME: Notify Shim Engine */
2023 //ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
2024 //ShimLoadCallback(LdrEntry);
2027 /* Run the init routine */
2028 Status
= LdrpRunInitializeRoutines(NULL
);
2029 if (!NT_SUCCESS(Status
))
2031 /* Failed, unload the DLL */
2034 DbgPrint("LDR: Unloading %wZ because either its init "
2035 "routine or one of its static imports failed; "
2036 "status = 0x%08lx\n",
2040 LdrUnloadDll(LdrEntry
->DllBase
);
2045 /* The DB isn't ready, which means we were loaded because of a forwarder */
2046 Status
= STATUS_SUCCESS
;
2051 /* We were already loaded. Are we a DLL? */
2052 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2054 /* Increase load count */
2055 LdrEntry
->LoadCount
++;
2056 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2058 /* Clear the load in progress */
2059 LdrpClearLoadInProgress();
2063 /* Not a DLL, just increase the load count */
2064 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2069 /* Release the lock */
2070 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2072 /* Check for success */
2073 if (NT_SUCCESS(Status
))
2075 /* Return the base address */
2076 *BaseAddress
= LdrEntry
->DllBase
;
2081 *BaseAddress
= NULL
;
2090 LdrpClearLoadInProgress(VOID
)
2092 PLIST_ENTRY ListHead
, Entry
;
2093 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2094 ULONG ModulesCount
= 0;
2096 /* Traverse the init list */
2097 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2098 Entry
= ListHead
->Flink
;
2099 while (Entry
!= ListHead
)
2101 /* Get the loader entry */
2102 LdrEntry
= CONTAINING_RECORD(Entry
,
2103 LDR_DATA_TABLE_ENTRY
,
2104 InInitializationOrderModuleList
);
2106 /* Clear load in progress flag */
2107 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2109 /* Check for modules with entry point count but not processed yet */
2110 if ((LdrEntry
->EntryPoint
) &&
2111 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2113 /* Increase counter */
2117 /* Advance to the next entry */
2118 Entry
= Entry
->Flink
;
2121 /* Return final count */
2122 return ModulesCount
;
2127 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn
)
2129 ASSERT(StringIn
!= NULL
);
2131 /* If Buffer is not NULL - free it */
2132 if (StringIn
->Buffer
)
2134 RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn
->Buffer
);
2138 RtlInitEmptyUnicodeString(StringIn
, NULL
, 0);