2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User Mode Library
4 * FILE: dll/ntdll/ldr/ldrapi.c
5 * PURPOSE: PE Loader Public APIs
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 LIST_ENTRY LdrpUnloadHead
;
20 LONG LdrpLoaderLockAcquisitionCount
;
21 BOOLEAN LdrpShowRecursiveLoads
, LdrpBreakOnRecursiveDllLoads
;
22 UNICODE_STRING LdrApiDefaultExtension
= RTL_CONSTANT_STRING(L
".DLL");
23 ULONG AlternateResourceModuleCount
;
24 extern PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine
;
26 /* FUNCTIONS *****************************************************************/
30 LdrFindCreateProcessManifest(IN ULONG Flags
,
33 IN ULONG IdPathLength
,
34 IN PVOID OutDataEntry
)
37 return STATUS_NOT_IMPLEMENTED
;
42 LdrDestroyOutOfProcessImage(IN PVOID Image
)
45 return STATUS_NOT_IMPLEMENTED
;
50 LdrCreateOutOfProcessImage(IN ULONG Flags
,
51 IN HANDLE ProcessHandle
,
56 return STATUS_NOT_IMPLEMENTED
;
61 LdrAccessOutOfProcessResource(IN PVOID Unknown
,
68 return STATUS_NOT_IMPLEMENTED
;
73 LdrSetDllManifestProber(
74 _In_ PLDR_MANIFEST_PROBER_ROUTINE Routine
)
76 LdrpManifestProberRoutine
= Routine
;
81 LdrAlternateResourcesEnabled(VOID
)
83 /* ReactOS does not support this */
91 /* Generate a cookie */
92 return (((ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) |
93 (_InterlockedIncrement(&LdrpLoaderLockAcquisitionCount
) & 0xFFFF);
101 LdrUnlockLoaderLock(IN ULONG Flags
,
102 IN ULONG Cookie OPTIONAL
)
104 NTSTATUS Status
= STATUS_SUCCESS
;
106 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
108 /* Check for valid flags */
109 if (Flags
& ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
111 /* Flags are invalid, check how to fail */
112 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
114 /* The caller wants us to raise status */
115 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
118 /* A normal failure */
119 return STATUS_INVALID_PARAMETER_1
;
122 /* If we don't have a cookie, just return */
123 if (!Cookie
) return STATUS_SUCCESS
;
125 /* Validate the cookie */
126 if ((Cookie
& 0xF0000000) ||
127 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
129 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
131 /* Invalid cookie, check how to fail */
132 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
134 /* The caller wants us to raise status */
135 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
138 /* A normal failure */
139 return STATUS_INVALID_PARAMETER_2
;
142 /* Ready to release the lock */
143 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
145 /* Do a direct leave */
146 RtlLeaveCriticalSection(&LdrpLoaderLock
);
150 /* Wrap this in SEH, since we're not supposed to raise */
154 RtlLeaveCriticalSection(&LdrpLoaderLock
);
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
158 /* We should use the LDR Filter instead */
159 Status
= _SEH2_GetExceptionCode();
173 LdrLockLoaderLock(IN ULONG Flags
,
174 OUT PULONG Disposition OPTIONAL
,
175 OUT PULONG_PTR Cookie OPTIONAL
)
177 NTSTATUS Status
= STATUS_SUCCESS
;
178 BOOLEAN InInit
= LdrpInLdrInit
;
180 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Disposition
, Cookie
);
182 /* Zero out the outputs */
183 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID
;
184 if (Cookie
) *Cookie
= 0;
186 /* Validate the flags */
187 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
188 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
190 /* Flags are invalid, check how to fail */
191 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
193 /* The caller wants us to raise status */
194 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
197 /* A normal failure */
198 return STATUS_INVALID_PARAMETER_1
;
201 /* Make sure we got a cookie */
204 /* No cookie check how to fail */
205 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
207 /* The caller wants us to raise status */
208 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
211 /* A normal failure */
212 return STATUS_INVALID_PARAMETER_3
;
215 /* If the flag is set, make sure we have a valid pointer to use */
216 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Disposition
))
218 /* No pointer to return the data to */
219 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
221 /* The caller wants us to raise status */
222 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
226 return STATUS_INVALID_PARAMETER_2
;
229 /* Return now if we are in the init phase */
230 if (InInit
) return STATUS_SUCCESS
;
232 /* Check what locking semantic to use */
233 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
235 /* Check if we should enter or simply try */
236 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
239 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
242 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
247 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
248 *Cookie
= LdrpMakeCookie();
254 RtlEnterCriticalSection(&LdrpLoaderLock
);
256 /* See if result was requested */
257 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
258 *Cookie
= LdrpMakeCookie();
263 /* Wrap this in SEH, since we're not supposed to raise */
266 /* Check if we should enter or simply try */
267 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
270 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
273 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
278 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
279 *Cookie
= LdrpMakeCookie();
285 RtlEnterCriticalSection(&LdrpLoaderLock
);
287 /* See if result was requested */
288 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
289 *Cookie
= LdrpMakeCookie();
292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
294 /* We should use the LDR Filter instead */
295 Status
= _SEH2_GetExceptionCode();
310 LdrLoadDll(IN PWSTR SearchPath OPTIONAL
,
311 IN PULONG DllCharacteristics OPTIONAL
,
312 IN PUNICODE_STRING DllName
,
313 OUT PVOID
*BaseAddress
)
315 WCHAR StringBuffer
[MAX_PATH
];
316 UNICODE_STRING DllString1
, DllString2
;
317 BOOLEAN RedirectedDll
= FALSE
;
320 PUNICODE_STRING OldTldDll
;
321 PTEB Teb
= NtCurrentTeb();
323 /* Initialize the strings */
324 RtlInitEmptyUnicodeString(&DllString1
, StringBuffer
, sizeof(StringBuffer
));
325 RtlInitEmptyUnicodeString(&DllString2
, NULL
, 0);
327 /* Check if the SxS Assemblies specify another file */
328 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
330 &LdrApiDefaultExtension
,
339 if (NT_SUCCESS(Status
))
342 RedirectedDll
= TRUE
;
344 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
346 /* Unrecoverable SxS failure; did we get a string? */
347 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
351 /* Lock the loader lock */
352 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
354 /* Check if there's a TLD DLL being loaded */
355 OldTldDll
= LdrpTopLevelDllBeingLoaded
;
358 /* This is a recursive load, do something about it? */
359 if ((ShowSnaps
) || (LdrpShowRecursiveLoads
) || (LdrpBreakOnRecursiveDllLoads
))
361 /* Print out debug messages */
362 DPRINT1("[%p, %p] LDR: Recursive DLL Load\n",
363 Teb
->RealClientId
.UniqueProcess
,
364 Teb
->RealClientId
.UniqueThread
);
365 DPRINT1("[%p, %p] Previous DLL being loaded \"%wZ\"\n",
366 Teb
->RealClientId
.UniqueProcess
,
367 Teb
->RealClientId
.UniqueThread
,
369 DPRINT1("[%p, %p] DLL being requested \"%wZ\"\n",
370 Teb
->RealClientId
.UniqueProcess
,
371 Teb
->RealClientId
.UniqueThread
,
374 /* Was it initializing too? */
375 if (!LdrpCurrentDllInitializer
)
377 DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n",
378 Teb
->RealClientId
.UniqueProcess
,
379 Teb
->RealClientId
.UniqueThread
);
383 DPRINT1("[%p, %p] DLL whose initializer was currently running \"%wZ\"\n",
384 Teb
->ClientId
.UniqueProcess
,
385 Teb
->ClientId
.UniqueThread
,
386 &LdrpCurrentDllInitializer
->BaseDllName
);
391 /* Set this one as the TLD DLL being loaded*/
392 LdrpTopLevelDllBeingLoaded
= DllName
;
395 Status
= LdrpLoadDll(RedirectedDll
,
401 if (NT_SUCCESS(Status
))
403 Status
= STATUS_SUCCESS
;
405 else if ((Status
!= STATUS_NO_SUCH_FILE
) &&
406 (Status
!= STATUS_DLL_NOT_FOUND
) &&
407 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) &&
408 (Status
!= STATUS_DLL_INIT_FAILED
))
410 DbgPrintEx(DPFLTR_LDR_ID
,
411 DPFLTR_WARNING_LEVEL
,
412 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
418 /* Restore the old TLD DLL */
419 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
421 /* Release the lock */
422 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
424 /* Do we have a redirect string? */
425 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
436 LdrFindEntryForAddress(PVOID Address
,
437 PLDR_DATA_TABLE_ENTRY
*Module
)
439 PLIST_ENTRY ListHead
, NextEntry
;
440 PLDR_DATA_TABLE_ENTRY LdrEntry
;
441 PIMAGE_NT_HEADERS NtHeader
;
442 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
443 ULONG_PTR DllBase
, DllEnd
;
445 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
448 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
450 /* Get the current entry */
451 LdrEntry
= Ldr
->EntryInProgress
;
454 /* Get the NT Headers */
455 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
458 /* Get the Image Base */
459 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
460 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
462 /* Check if they match */
463 if (((ULONG_PTR
)Address
>= DllBase
) &&
464 ((ULONG_PTR
)Address
< DllEnd
))
468 return STATUS_SUCCESS
;
473 /* Loop the module list */
474 ListHead
= &Ldr
->InMemoryOrderModuleList
;
475 NextEntry
= ListHead
->Flink
;
476 while (NextEntry
!= ListHead
)
478 /* Get the entry and NT Headers */
479 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderLinks
);
480 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
483 /* Get the Image Base */
484 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
485 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
487 /* Check if they match */
488 if (((ULONG_PTR
)Address
>= DllBase
) &&
489 ((ULONG_PTR
)Address
< DllEnd
))
493 return STATUS_SUCCESS
;
497 NextEntry
= NextEntry
->Flink
;
502 DbgPrintEx(DPFLTR_LDR_ID
,
503 DPFLTR_WARNING_LEVEL
,
504 "LDR: %s() exiting 0x%08lx\n",
506 STATUS_NO_MORE_ENTRIES
);
507 return STATUS_NO_MORE_ENTRIES
;
515 LdrGetDllHandleEx(IN ULONG Flags
,
516 IN PWSTR DllPath OPTIONAL
,
517 IN PULONG DllCharacteristics OPTIONAL
,
518 IN PUNICODE_STRING DllName
,
519 OUT PVOID
*DllHandle OPTIONAL
)
522 PLDR_DATA_TABLE_ENTRY LdrEntry
;
523 UNICODE_STRING RedirectName
, DllString1
, RawDllName
;
524 PUNICODE_STRING pRedirectName
, CompareName
;
526 BOOLEAN Locked
, RedirectedDll
;
528 ULONG LoadFlag
, Length
;
530 /* Initialize the strings */
531 RtlInitEmptyUnicodeString(&DllString1
, NULL
, 0);
532 RtlInitEmptyUnicodeString(&RawDllName
, NULL
, 0);
533 RedirectName
= *DllName
;
534 pRedirectName
= &RedirectName
;
536 /* Initialize state */
537 RedirectedDll
= Locked
= FALSE
;
541 /* Clear the handle */
542 if (DllHandle
) *DllHandle
= NULL
;
544 /* Check for a valid flag combination */
545 if ((Flags
& ~(LDR_GET_DLL_HANDLE_EX_PIN
| LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
)) ||
546 (!DllHandle
&& !(Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)))
548 DPRINT1("Flags are invalid or no DllHandle given\n");
549 Status
= STATUS_INVALID_PARAMETER
;
553 /* If not initializing */
556 /* Acquire the lock */
557 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
558 if (!NT_SUCCESS(Status
)) goto Quickie
;
560 /* Remember we own it */
564 /* Check if the SxS Assemblies specify another file */
565 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
567 &LdrApiDefaultExtension
,
576 if (NT_SUCCESS(Status
))
579 RedirectedDll
= TRUE
;
581 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
583 /* Unrecoverable SxS failure */
588 ASSERT(pRedirectName
== &RedirectName
);
591 /* Set default failure code */
592 Status
= STATUS_DLL_NOT_FOUND
;
594 /* Use the cache if we can */
595 if (LdrpGetModuleHandleCache
)
597 /* Check if we were redirected */
601 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
606 /* Use the right name */
607 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
612 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
617 /* Use the right name */
618 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
621 /* Check if the name matches */
622 if (RtlEqualUnicodeString(pRedirectName
,
627 LdrEntry
= LdrpGetModuleHandleCache
;
630 Status
= STATUS_SUCCESS
;
636 /* Find the name without the extension */
637 p1
= pRedirectName
->Buffer
;
639 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
646 else if (*p1
== L
'\\')
652 /* Check if no extension was found or if we got a slash */
653 if (!(p2
) || (*p2
== L
'\\') || (*p2
== L
'/'))
655 /* Check that we have space to add one */
656 Length
= pRedirectName
->Length
+
657 LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
658 if (Length
>= UNICODE_STRING_MAX_BYTES
)
660 /* No space to add the extension */
661 Status
= STATUS_NAME_TOO_LONG
;
665 /* Setup the string */
666 RawDllName
.MaximumLength
= Length
;
667 ASSERT(Length
>= sizeof(UNICODE_NULL
));
668 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
670 RawDllName
.MaximumLength
);
671 if (!RawDllName
.Buffer
)
673 Status
= STATUS_NO_MEMORY
;
677 /* Copy the string and add extension */
678 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
679 RtlAppendUnicodeStringToString(&RawDllName
, &LdrApiDefaultExtension
);
683 /* Check if there's something in the name */
684 Length
= pRedirectName
->Length
;
687 /* Check and remove trailing period */
688 if (pRedirectName
->Buffer
[Length
/ sizeof(WCHAR
) - sizeof(ANSI_NULL
)] == '.')
690 /* Decrease the size */
691 pRedirectName
->Length
-= sizeof(WCHAR
);
695 /* Setup the string */
696 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
697 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
699 RawDllName
.MaximumLength
);
700 if (!RawDllName
.Buffer
)
702 Status
= STATUS_NO_MEMORY
;
706 /* Copy the string */
707 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
710 /* Display debug string */
713 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
715 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
719 if (LdrpCheckForLoadedDll(DllPath
,
721 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
725 /* Update cached entry */
726 LdrpGetModuleHandleCache
= LdrEntry
;
729 Status
= STATUS_SUCCESS
;
733 /* Make sure to NULL this */
737 /* The success path must have a valid loader entry */
738 ASSERT((LdrEntry
!= NULL
) == NT_SUCCESS(Status
));
740 /* Check if we got an entry and success */
741 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
742 if ((LdrEntry
) && (NT_SUCCESS(Status
)))
744 /* Check if the DLL is locked */
745 if ((LdrEntry
->LoadCount
!= 0xFFFF) &&
746 !(Flags
& LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
))
748 /* Check what to do with the load count */
749 if (Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)
752 LdrEntry
->LoadCount
= 0xFFFF;
753 LoadFlag
= LDRP_UPDATE_PIN
;
757 /* Increase the load count */
758 LdrEntry
->LoadCount
++;
759 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
762 /* Update the load count now */
763 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
764 LdrpClearLoadInProgress();
767 /* Check if the caller is requesting the handle */
768 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
771 /* Free string if needed */
772 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
774 /* Free the raw DLL Name if needed */
775 if (RawDllName
.Buffer
)
777 /* Free the heap-allocated buffer */
778 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
779 RawDllName
.Buffer
= NULL
;
785 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
,
798 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
799 IN PULONG DllCharacteristics OPTIONAL
,
800 IN PUNICODE_STRING DllName
,
801 OUT PVOID
*DllHandle
)
803 /* Call the newer API */
804 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
,
816 LdrGetProcedureAddress(IN PVOID BaseAddress
,
817 IN PANSI_STRING Name
,
819 OUT PVOID
*ProcedureAddress
)
821 /* Call the internal routine and tell it to execute DllInit */
822 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
830 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
831 IN PLDR_CALLBACK Callback
,
832 IN PVOID CallbackContext
,
833 OUT PUSHORT ImageCharacteristics
)
835 FILE_STANDARD_INFORMATION FileStandardInfo
;
836 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
837 PIMAGE_SECTION_HEADER LastSection
= NULL
;
838 IO_STATUS_BLOCK IoStatusBlock
;
839 PIMAGE_NT_HEADERS NtHeader
;
840 HANDLE SectionHandle
;
843 BOOLEAN Result
, NoActualCheck
;
847 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
849 /* If the handle has the magic KnownDll flag, skip actual checksums */
850 NoActualCheck
= ((ULONG_PTR
)FileHandle
& 1);
852 /* Create the section */
853 Status
= NtCreateSection(&SectionHandle
,
860 if (!NT_SUCCESS(Status
))
862 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
866 /* Map the section */
869 Status
= NtMapViewOfSection(SectionHandle
,
879 if (!NT_SUCCESS(Status
))
881 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
882 NtClose(SectionHandle
);
886 /* Get the file information */
887 Status
= NtQueryInformationFile(FileHandle
,
890 sizeof(FILE_STANDARD_INFORMATION
),
891 FileStandardInformation
);
892 if (!NT_SUCCESS(Status
))
894 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
895 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
896 NtClose(SectionHandle
);
900 /* Protect with SEH */
903 /* Check if this is the KnownDll hack */
906 /* Don't actually do it */
911 /* Verify the checksum */
912 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
913 FileStandardInfo
.EndOfFile
.LowPart
,
914 FileStandardInfo
.EndOfFile
.LowPart
);
917 /* Check if a callback was supplied */
918 if ((Result
) && (Callback
))
920 /* Get the NT Header */
921 NtHeader
= RtlImageNtHeader(ViewBase
);
923 /* Check if caller requested this back */
924 if (ImageCharacteristics
)
926 /* Return to caller */
927 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
930 /* Get the Import Directory Data */
931 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
933 IMAGE_DIRECTORY_ENTRY_IMPORT
,
936 /* Make sure there is one */
939 /* Loop the imports */
940 while (ImportData
->Name
)
943 ImportName
= RtlImageRvaToVa(NtHeader
,
948 /* Notify the callback */
949 Callback(CallbackContext
, ImportName
);
955 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
957 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
962 /* Unmap file and close handle */
963 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
964 NtClose(SectionHandle
);
967 return Result
? Status
: STATUS_IMAGE_CHECKSUM_MISMATCH
;
972 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
974 OUT PRTL_PROCESS_MODULES ModuleInformation
,
976 OUT PULONG ReturnedSize OPTIONAL
)
978 PLIST_ENTRY ModuleListHead
, InitListHead
;
979 PLIST_ENTRY Entry
, InitEntry
;
980 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
981 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
982 NTSTATUS Status
= STATUS_SUCCESS
;
983 ULONG UsedSize
= sizeof(ULONG
);
984 ANSI_STRING AnsiString
;
987 DPRINT("LdrQueryProcessModuleInformation() called\n");
989 /* Acquire loader lock */
990 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
994 /* Check if we were given enough space */
997 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1001 ModuleInformation
->NumberOfModules
= 0;
1002 ModulePtr
= &ModuleInformation
->Modules
[0];
1003 Status
= STATUS_SUCCESS
;
1006 /* Traverse the list of modules */
1007 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1008 Entry
= ModuleListHead
->Flink
;
1010 while (Entry
!= ModuleListHead
)
1012 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1014 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
1016 /* Increase the used size */
1017 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
1019 if (UsedSize
> Size
)
1021 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1025 ModulePtr
->ImageBase
= Module
->DllBase
;
1026 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
1027 ModulePtr
->Flags
= Module
->Flags
;
1028 ModulePtr
->LoadCount
= Module
->LoadCount
;
1029 ModulePtr
->MappedBase
= NULL
;
1030 ModulePtr
->InitOrderIndex
= 0;
1031 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
1033 /* Now get init order index by traversing init list */
1034 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1035 InitEntry
= InitListHead
->Flink
;
1037 while (InitEntry
!= InitListHead
)
1039 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
1041 /* Increase the index */
1042 ModulePtr
->InitOrderIndex
++;
1044 /* Quit the loop if our module is found */
1045 if (InitModule
== Module
) break;
1047 /* Advance to the next entry */
1048 InitEntry
= InitEntry
->Flink
;
1051 /* Prepare ANSI string with the module's name */
1052 AnsiString
.Length
= 0;
1053 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
1054 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
1055 RtlUnicodeStringToAnsiString(&AnsiString
,
1056 &Module
->FullDllName
,
1059 /* Calculate OffsetToFileName field */
1060 p
= strrchr(ModulePtr
->FullPathName
, '\\');
1062 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
1064 ModulePtr
->OffsetToFileName
= 0;
1066 /* Advance to the next module in the output list */
1069 /* Increase number of modules */
1070 if (ModuleInformation
)
1071 ModuleInformation
->NumberOfModules
++;
1074 /* Go to the next entry in the modules list */
1075 Entry
= Entry
->Flink
;
1078 /* Set returned size if it was provided */
1080 *ReturnedSize
= UsedSize
;
1082 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1084 /* Ignoring the exception */
1087 /* Release the lock */
1088 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1090 DPRINT("LdrQueryProcessModuleInformation() done\n");
1100 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
1102 OUT PULONG ReturnedSize OPTIONAL
)
1104 /* Call Ex version of the API */
1105 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
1113 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag
,
1114 IN PLDR_ENUM_CALLBACK EnumProc
,
1117 PLIST_ENTRY ListHead
, ListEntry
;
1118 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1121 BOOLEAN Stop
= FALSE
;
1123 /* Check parameters */
1124 if ((ReservedFlag
) || !(EnumProc
)) return STATUS_INVALID_PARAMETER
;
1126 /* Acquire the loader lock */
1127 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1128 if (!NT_SUCCESS(Status
)) return Status
;
1130 /* Loop all the modules and call enum proc */
1131 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1132 ListEntry
= ListHead
->Flink
;
1133 while (ListHead
!= ListEntry
)
1136 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1138 /* Call the enumeration proc inside SEH */
1141 EnumProc(LdrEntry
, Context
, &Stop
);
1143 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1145 /* Ignoring the exception */
1148 /* Break if we were asked to stop enumeration */
1151 /* Release loader lock */
1152 Status
= LdrUnlockLoaderLock(0, Cookie
);
1154 /* Reset any successful status to STATUS_SUCCESS, but leave
1155 failure to the caller */
1156 if (NT_SUCCESS(Status
))
1157 Status
= STATUS_SUCCESS
;
1159 /* Return any possible failure status */
1163 /* Advance to the next module */
1164 ListEntry
= ListEntry
->Flink
;
1167 /* Release loader lock, it must succeed this time */
1168 Status
= LdrUnlockLoaderLock(0, Cookie
);
1169 ASSERT(NT_SUCCESS(Status
));
1171 /* Return success */
1172 return STATUS_SUCCESS
;
1180 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1182 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1186 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
1188 /* Don't do it during shutdown */
1189 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
1191 /* Check if we should grab the lock */
1196 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1197 if (!NT_SUCCESS(Status
)) return Status
;
1201 /* Make sure the DLL is valid and get its entry */
1202 Status
= STATUS_DLL_NOT_FOUND
;
1203 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1205 /* Get if it has a TLS slot */
1206 if (!LdrEntry
->TlsIndex
)
1208 /* It doesn't, so you're allowed to call this */
1209 LdrEntry
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
1210 Status
= STATUS_SUCCESS
;
1214 /* Check if the lock was held */
1218 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1221 /* Return the status */
1230 LdrAddRefDll(IN ULONG Flags
,
1231 IN PVOID BaseAddress
)
1233 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1234 NTSTATUS Status
= STATUS_SUCCESS
;
1236 BOOLEAN Locked
= FALSE
;
1238 /* Check for invalid flags */
1239 if (Flags
& ~(LDR_ADDREF_DLL_PIN
))
1241 /* Fail with invalid parameter status if so */
1242 Status
= STATUS_INVALID_PARAMETER
;
1246 /* Acquire the loader lock if not in init phase */
1249 /* Acquire the lock */
1250 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1251 if (!NT_SUCCESS(Status
)) goto quickie
;
1255 /* Get this module's data table entry */
1256 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1260 /* Shouldn't happen */
1261 Status
= STATUS_INTERNAL_ERROR
;
1265 /* If this is not a pinned module */
1266 if (LdrEntry
->LoadCount
!= 0xFFFF)
1268 /* Update its load count */
1269 if (Flags
& LDR_ADDREF_DLL_PIN
)
1271 /* Pin it by setting load count to -1 */
1272 LdrEntry
->LoadCount
= 0xFFFF;
1273 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
1277 /* Increase its load count by one */
1278 LdrEntry
->LoadCount
++;
1279 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1282 /* Clear load in progress */
1283 LdrpClearLoadInProgress();
1288 /* There was an error getting this module's handle, return invalid param status */
1289 Status
= STATUS_INVALID_PARAMETER
;
1293 /* Check for error case */
1294 if (!NT_SUCCESS(Status
))
1296 /* Print debug information */
1297 if ((ShowSnaps
) || ((Status
!= STATUS_NO_SUCH_FILE
) &&
1298 (Status
!= STATUS_DLL_NOT_FOUND
) &&
1299 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)))
1301 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
, Status
);
1305 /* Release the lock if needed */
1306 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1315 LdrUnloadDll(IN PVOID BaseAddress
)
1317 NTSTATUS Status
= STATUS_SUCCESS
;
1318 PPEB Peb
= NtCurrentPeb();
1319 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
1321 PLIST_ENTRY NextEntry
;
1322 LIST_ENTRY UnloadList
;
1323 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1325 ULONG ComSectionSize
;
1327 /* Get the LDR Lock */
1328 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
1330 /* Increase the unload count */
1331 LdrpActiveUnloadCount
++;
1334 if (LdrpShutdownInProgress
) goto Quickie
;
1336 /* Make sure the DLL is valid and get its entry */
1337 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1339 Status
= STATUS_DLL_NOT_FOUND
;
1343 /* Check the current Load Count */
1344 if (LdrEntry
->LoadCount
!= 0xFFFF)
1347 LdrEntry
->LoadCount
--;
1350 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1352 /* Set up the Act Ctx */
1353 ActCtx
.Size
= sizeof(ActCtx
);
1354 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1355 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1357 /* Activate the ActCtx */
1358 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1359 LdrEntry
->EntryPointActivationContext
);
1361 /* Update the load count */
1362 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
1364 /* Release the context */
1365 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1370 /* The DLL is locked */
1374 /* Show debug message */
1375 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
1377 /* Check if this is our only unload and initialize the list if so */
1378 if (LdrpActiveUnloadCount
== 1) InitializeListHead(&LdrpUnloadHead
);
1380 /* Loop the modules to build the list */
1381 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
1382 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
1385 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1386 LDR_DATA_TABLE_ENTRY
,
1387 InInitializationOrderLinks
);
1388 NextEntry
= NextEntry
->Blink
;
1391 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
1393 /* If the load count is now 0 */
1394 if (!LdrEntry
->LoadCount
)
1399 DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n",
1400 LdrpActiveUnloadCount
,
1401 LdrEntry
->BaseDllName
.Buffer
,
1402 LdrEntry
->FullDllName
.Buffer
,
1403 (ULONG
)LdrEntry
->LoadCount
,
1404 LdrEntry
->EntryPoint
);
1407 /* Call Shim Engine and notify */
1410 VOID (NTAPI
* SE_DllUnloaded
)(PVOID
) = RtlDecodeSystemPointer(g_pfnSE_DllUnloaded
);
1411 SE_DllUnloaded(LdrEntry
);
1415 CurrentEntry
= LdrEntry
;
1416 RemoveEntryList(&CurrentEntry
->InInitializationOrderLinks
);
1417 RemoveEntryList(&CurrentEntry
->InMemoryOrderLinks
);
1418 RemoveEntryList(&CurrentEntry
->HashLinks
);
1420 /* If there's more then one active unload */
1421 if (LdrpActiveUnloadCount
> 1)
1423 /* Flush the cached DLL handle and clear the list */
1424 LdrpLoadedDllHandleCache
= NULL
;
1425 CurrentEntry
->InMemoryOrderLinks
.Flink
= NULL
;
1428 /* Add the entry on the unload list */
1429 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
1433 /* Only call the entrypoints once */
1434 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
1436 /* Now loop the unload list and create our own */
1437 InitializeListHead(&UnloadList
);
1438 CurrentEntry
= NULL
;
1439 NextEntry
= LdrpUnloadHead
.Flink
;
1440 while (NextEntry
!= &LdrpUnloadHead
)
1442 /* Get the current entry */
1443 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1445 /* FIXME: Log the Unload Event */
1446 //LdrpRecordUnloadEvent(LdrEntry);
1448 /* Set the entry and clear it from the list */
1449 CurrentEntry
= LdrEntry
;
1450 LdrpLoadedDllHandleCache
= NULL
;
1451 CurrentEntry
->InMemoryOrderLinks
.Flink
= NULL
;
1453 /* Move it from the global to the local list */
1454 RemoveEntryList(&CurrentEntry
->HashLinks
);
1455 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
1457 /* Get the entrypoint */
1458 EntryPoint
= LdrEntry
->EntryPoint
;
1460 /* Check if we should call it */
1461 if ((EntryPoint
) && (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
1466 DPRINT1("LDR: Calling deinit %p\n", EntryPoint
);
1469 /* Set up the Act Ctx */
1470 ActCtx
.Size
= sizeof(ActCtx
);
1471 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1472 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1474 /* Activate the ActCtx */
1475 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1476 LdrEntry
->EntryPointActivationContext
);
1478 /* Call the entrypoint */
1479 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
1484 /* Release the context */
1485 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1488 /* Remove it from the list */
1489 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1490 CurrentEntry
= NULL
;
1491 NextEntry
= LdrpUnloadHead
.Flink
;
1494 /* Now loop our local list */
1495 NextEntry
= UnloadList
.Flink
;
1496 while (NextEntry
!= &UnloadList
)
1499 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1500 NextEntry
= NextEntry
->Flink
;
1501 CurrentEntry
= LdrEntry
;
1503 /* Notify Application Verifier */
1504 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
1506 DPRINT1("We don't support Application Verifier yet\n");
1512 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
1515 /* Check if this is a .NET executable */
1516 CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1518 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1523 DPRINT1(".NET Images are not supported yet\n");
1526 /* Check if we should unmap*/
1527 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
1530 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
1531 CurrentEntry
->DllBase
);
1532 ASSERT(NT_SUCCESS(Status
));
1535 /* Unload the alternate resource module, if any */
1536 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
1538 /* FIXME: Send shutdown notification */
1539 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1541 /* Check if a Hotpatch is active */
1542 if (LdrEntry
->PatchInformation
)
1545 DPRINT1("We don't support Hotpatching yet\n");
1548 /* Deallocate the Entry */
1549 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
1551 /* If this is the cached entry, invalidate it */
1552 if (LdrpGetModuleHandleCache
== CurrentEntry
)
1554 LdrpGetModuleHandleCache
= NULL
;
1559 /* Decrease unload count */
1560 LdrpActiveUnloadCount
--;
1561 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
1563 /* Return to caller */
1572 RtlDllShutdownInProgress(VOID
)
1574 /* Return the internal global */
1575 return LdrpShutdownInProgress
;
1581 PIMAGE_BASE_RELOCATION
1583 LdrProcessRelocationBlock(IN ULONG_PTR Address
,
1585 IN PUSHORT TypeOffset
,
1588 return LdrProcessRelocationBlockLongLong(Address
, Count
, TypeOffset
, Delta
);
1591 /* FIXME: Add to ntstatus.mc */
1592 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L)
1599 LdrLoadAlternateResourceModule(IN PVOID Module
,
1602 /* Is MUI Support enabled? */
1603 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS
;
1606 return STATUS_MUI_FILE_NOT_FOUND
;
1614 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress
)
1618 /* Acquire the loader lock */
1619 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
1621 /* Check if there's any alternate resources loaded */
1622 if (AlternateResourceModuleCount
)
1627 /* Release the loader lock */
1628 LdrUnlockLoaderLock(1, Cookie
);
1639 LdrFlushAlternateResourceModules(VOID
)