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);
103 _In_opt_ ULONG_PTR Cookie
)
105 NTSTATUS Status
= STATUS_SUCCESS
;
107 DPRINT("LdrUnlockLoaderLock(%x %Ix)\n", Flags
, Cookie
);
109 /* Check for valid flags */
110 if (Flags
& ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
112 /* Flags are invalid, check how to fail */
113 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
115 /* The caller wants us to raise status */
116 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
119 /* A normal failure */
120 return STATUS_INVALID_PARAMETER_1
;
123 /* If we don't have a cookie, just return */
124 if (!Cookie
) return STATUS_SUCCESS
;
126 /* Validate the cookie */
127 if ((Cookie
& 0xF0000000) ||
128 ((Cookie
>> 16) ^ (HandleToUlong(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
130 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
132 /* Invalid cookie, check how to fail */
133 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
135 /* The caller wants us to raise status */
136 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
139 /* A normal failure */
140 return STATUS_INVALID_PARAMETER_2
;
143 /* Ready to release the lock */
144 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
146 /* Do a direct leave */
147 RtlLeaveCriticalSection(&LdrpLoaderLock
);
151 /* Wrap this in SEH, since we're not supposed to raise */
155 RtlLeaveCriticalSection(&LdrpLoaderLock
);
157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
159 /* We should use the LDR Filter instead */
160 Status
= _SEH2_GetExceptionCode();
176 _Out_opt_ PULONG Disposition
,
177 _Out_opt_ PULONG_PTR Cookie
)
179 NTSTATUS Status
= STATUS_SUCCESS
;
180 BOOLEAN InInit
= LdrpInLdrInit
;
182 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Disposition
, Cookie
);
184 /* Zero out the outputs */
185 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID
;
186 if (Cookie
) *Cookie
= 0;
188 /* Validate the flags */
189 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
190 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
192 /* Flags are invalid, check how to fail */
193 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
195 /* The caller wants us to raise status */
196 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
199 /* A normal failure */
200 return STATUS_INVALID_PARAMETER_1
;
203 /* Make sure we got a cookie */
206 /* No cookie check how to fail */
207 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
209 /* The caller wants us to raise status */
210 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
213 /* A normal failure */
214 return STATUS_INVALID_PARAMETER_3
;
217 /* If the flag is set, make sure we have a valid pointer to use */
218 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Disposition
))
220 /* No pointer to return the data to */
221 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
223 /* The caller wants us to raise status */
224 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
228 return STATUS_INVALID_PARAMETER_2
;
231 /* Return now if we are in the init phase */
232 if (InInit
) return STATUS_SUCCESS
;
234 /* Check what locking semantic to use */
235 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
237 /* Check if we should enter or simply try */
238 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
241 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
244 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
249 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
250 *Cookie
= LdrpMakeCookie();
256 RtlEnterCriticalSection(&LdrpLoaderLock
);
258 /* See if result was requested */
259 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
260 *Cookie
= LdrpMakeCookie();
265 /* Wrap this in SEH, since we're not supposed to raise */
268 /* Check if we should enter or simply try */
269 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
272 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
275 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
280 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
281 *Cookie
= LdrpMakeCookie();
287 RtlEnterCriticalSection(&LdrpLoaderLock
);
289 /* See if result was requested */
290 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
291 *Cookie
= LdrpMakeCookie();
294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
296 /* We should use the LDR Filter instead */
297 Status
= _SEH2_GetExceptionCode();
313 _In_opt_ PWSTR SearchPath
,
314 _In_opt_ PULONG DllCharacteristics
,
315 _In_ PUNICODE_STRING DllName
,
316 _Out_ PVOID
*BaseAddress
)
318 WCHAR StringBuffer
[MAX_PATH
];
319 UNICODE_STRING DllString1
, DllString2
;
320 BOOLEAN RedirectedDll
= FALSE
;
323 PUNICODE_STRING OldTldDll
;
324 PTEB Teb
= NtCurrentTeb();
326 /* Initialize the strings */
327 RtlInitEmptyUnicodeString(&DllString1
, StringBuffer
, sizeof(StringBuffer
));
328 RtlInitEmptyUnicodeString(&DllString2
, NULL
, 0);
330 /* Check if the SxS Assemblies specify another file */
331 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
333 &LdrApiDefaultExtension
,
342 if (NT_SUCCESS(Status
))
345 RedirectedDll
= TRUE
;
347 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
349 /* Unrecoverable SxS failure; did we get a string? */
350 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
354 /* Lock the loader lock */
355 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
357 /* Check if there's a TLD DLL being loaded */
358 OldTldDll
= LdrpTopLevelDllBeingLoaded
;
364 /* This is a recursive load, do something about it? */
365 if ((ShowSnaps
) || (LdrpShowRecursiveLoads
) || (LdrpBreakOnRecursiveDllLoads
))
367 /* Print out debug messages */
368 DPRINT1("[%p, %p] LDR: Recursive DLL Load\n",
369 Teb
->RealClientId
.UniqueProcess
,
370 Teb
->RealClientId
.UniqueThread
);
371 DPRINT1("[%p, %p] Previous DLL being loaded \"%wZ\"\n",
372 Teb
->RealClientId
.UniqueProcess
,
373 Teb
->RealClientId
.UniqueThread
,
375 DPRINT1("[%p, %p] DLL being requested \"%wZ\"\n",
376 Teb
->RealClientId
.UniqueProcess
,
377 Teb
->RealClientId
.UniqueThread
,
380 /* Was it initializing too? */
381 if (!LdrpCurrentDllInitializer
)
383 DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n",
384 Teb
->RealClientId
.UniqueProcess
,
385 Teb
->RealClientId
.UniqueThread
);
389 DPRINT1("[%p, %p] DLL whose initializer was currently running \"%wZ\"\n",
390 Teb
->ClientId
.UniqueProcess
,
391 Teb
->ClientId
.UniqueThread
,
392 &LdrpCurrentDllInitializer
->BaseDllName
);
397 /* Set this one as the TLD DLL being loaded*/
398 LdrpTopLevelDllBeingLoaded
= DllName
;
401 Status
= LdrpLoadDll(RedirectedDll
,
407 if (NT_SUCCESS(Status
))
409 Status
= STATUS_SUCCESS
;
411 else if ((Status
!= STATUS_NO_SUCH_FILE
) &&
412 (Status
!= STATUS_DLL_NOT_FOUND
) &&
413 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) &&
414 (Status
!= STATUS_DLL_INIT_FAILED
))
416 DbgPrintEx(DPFLTR_LDR_ID
,
417 DPFLTR_WARNING_LEVEL
,
418 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
426 /* Restore the old TLD DLL */
427 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
429 /* Release the lock */
430 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
434 /* Do we have a redirect string? */
435 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
446 LdrFindEntryForAddress(
448 _Out_ PLDR_DATA_TABLE_ENTRY
*Module
)
450 PLIST_ENTRY ListHead
, NextEntry
;
451 PLDR_DATA_TABLE_ENTRY LdrEntry
;
452 PIMAGE_NT_HEADERS NtHeader
;
453 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
454 ULONG_PTR DllBase
, DllEnd
;
456 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
459 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
461 /* Get the current entry */
462 LdrEntry
= Ldr
->EntryInProgress
;
465 /* Get the NT Headers */
466 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
469 /* Get the Image Base */
470 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
471 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
473 /* Check if they match */
474 if (((ULONG_PTR
)Address
>= DllBase
) &&
475 ((ULONG_PTR
)Address
< DllEnd
))
479 return STATUS_SUCCESS
;
484 /* Loop the module list */
485 ListHead
= &Ldr
->InMemoryOrderModuleList
;
486 NextEntry
= ListHead
->Flink
;
487 while (NextEntry
!= ListHead
)
489 /* Get the entry and NT Headers */
490 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderLinks
);
491 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
494 /* Get the Image Base */
495 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
496 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
498 /* Check if they match */
499 if (((ULONG_PTR
)Address
>= DllBase
) &&
500 ((ULONG_PTR
)Address
< DllEnd
))
504 return STATUS_SUCCESS
;
508 NextEntry
= NextEntry
->Flink
;
513 DbgPrintEx(DPFLTR_LDR_ID
,
514 DPFLTR_WARNING_LEVEL
,
515 "LDR: %s() exiting 0x%08lx\n",
517 STATUS_NO_MORE_ENTRIES
);
518 return STATUS_NO_MORE_ENTRIES
;
528 _In_opt_ PWSTR DllPath
,
529 _In_opt_ PULONG DllCharacteristics
,
530 _In_ PUNICODE_STRING DllName
,
531 _Out_opt_ PVOID
*DllHandle
)
534 PLDR_DATA_TABLE_ENTRY LdrEntry
;
535 UNICODE_STRING RedirectName
, DllString1
, RawDllName
;
536 PUNICODE_STRING pRedirectName
, CompareName
;
538 BOOLEAN Locked
, RedirectedDll
;
540 ULONG LoadFlag
, Length
;
542 /* Initialize the strings */
543 RtlInitEmptyUnicodeString(&DllString1
, NULL
, 0);
544 RtlInitEmptyUnicodeString(&RawDllName
, NULL
, 0);
545 RedirectName
= *DllName
;
546 pRedirectName
= &RedirectName
;
548 /* Initialize state */
549 RedirectedDll
= Locked
= FALSE
;
553 /* Clear the handle */
554 if (DllHandle
) *DllHandle
= NULL
;
556 /* Check for a valid flag combination */
557 if ((Flags
& ~(LDR_GET_DLL_HANDLE_EX_PIN
| LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
)) ||
558 (!DllHandle
&& !(Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)))
560 DPRINT1("Flags are invalid or no DllHandle given\n");
561 Status
= STATUS_INVALID_PARAMETER
;
565 /* If not initializing */
568 /* Acquire the lock */
569 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
570 if (!NT_SUCCESS(Status
)) goto Quickie
;
572 /* Remember we own it */
576 /* Check if the SxS Assemblies specify another file */
577 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
579 &LdrApiDefaultExtension
,
588 if (NT_SUCCESS(Status
))
591 RedirectedDll
= TRUE
;
593 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
595 /* Unrecoverable SxS failure */
600 ASSERT(pRedirectName
== &RedirectName
);
603 /* Set default failure code */
604 Status
= STATUS_DLL_NOT_FOUND
;
606 /* Use the cache if we can */
607 if (LdrpGetModuleHandleCache
)
609 /* Check if we were redirected */
613 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
618 /* Use the right name */
619 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
624 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
629 /* Use the right name */
630 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
633 /* Check if the name matches */
634 if (RtlEqualUnicodeString(pRedirectName
,
639 LdrEntry
= LdrpGetModuleHandleCache
;
642 Status
= STATUS_SUCCESS
;
648 /* Find the name without the extension */
649 p1
= pRedirectName
->Buffer
;
651 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
658 else if (*p1
== L
'\\')
664 /* Check if no extension was found or if we got a slash */
665 if (!(p2
) || (*p2
== L
'\\') || (*p2
== L
'/'))
667 /* Check that we have space to add one */
668 Length
= pRedirectName
->Length
+
669 LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
670 if (Length
>= UNICODE_STRING_MAX_BYTES
)
672 /* No space to add the extension */
673 Status
= STATUS_NAME_TOO_LONG
;
677 /* Setup the string */
678 RawDllName
.MaximumLength
= Length
;
679 ASSERT(Length
>= sizeof(UNICODE_NULL
));
680 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
682 RawDllName
.MaximumLength
);
683 if (!RawDllName
.Buffer
)
685 Status
= STATUS_NO_MEMORY
;
689 /* Copy the string and add extension */
690 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
691 RtlAppendUnicodeStringToString(&RawDllName
, &LdrApiDefaultExtension
);
695 /* Check if there's something in the name */
696 Length
= pRedirectName
->Length
;
699 /* Check and remove trailing period */
700 if (pRedirectName
->Buffer
[Length
/ sizeof(WCHAR
) - sizeof(ANSI_NULL
)] == '.')
702 /* Decrease the size */
703 pRedirectName
->Length
-= sizeof(WCHAR
);
707 /* Setup the string */
708 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
709 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
711 RawDllName
.MaximumLength
);
712 if (!RawDllName
.Buffer
)
714 Status
= STATUS_NO_MEMORY
;
718 /* Copy the string */
719 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
722 /* Display debug string */
725 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
727 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
731 if (LdrpCheckForLoadedDll(DllPath
,
733 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
737 /* Update cached entry */
738 LdrpGetModuleHandleCache
= LdrEntry
;
741 Status
= STATUS_SUCCESS
;
745 /* Make sure to NULL this */
749 /* The success path must have a valid loader entry */
750 ASSERT((LdrEntry
!= NULL
) == NT_SUCCESS(Status
));
752 /* Check if we got an entry and success */
753 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
754 if ((LdrEntry
) && (NT_SUCCESS(Status
)))
756 /* Check if the DLL is locked */
757 if ((LdrEntry
->LoadCount
!= 0xFFFF) &&
758 !(Flags
& LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
))
760 /* Check what to do with the load count */
761 if (Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)
764 LdrEntry
->LoadCount
= 0xFFFF;
765 LoadFlag
= LDRP_UPDATE_PIN
;
769 /* Increase the load count */
770 LdrEntry
->LoadCount
++;
771 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
774 /* Update the load count now */
775 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
776 LdrpClearLoadInProgress();
779 /* Check if the caller is requesting the handle */
780 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
783 /* Free string if needed */
784 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
786 /* Free the raw DLL Name if needed */
787 if (RawDllName
.Buffer
)
789 /* Free the heap-allocated buffer */
790 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
791 RawDllName
.Buffer
= NULL
;
797 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
,
811 _In_opt_ PWSTR DllPath
,
812 _In_opt_ PULONG DllCharacteristics
,
813 _In_ PUNICODE_STRING DllName
,
814 _Out_ PVOID
*DllHandle
)
816 /* Call the newer API */
817 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
,
829 LdrGetProcedureAddress(
830 _In_ PVOID BaseAddress
,
831 _In_opt_
_When_(Ordinal
== 0, _Notnull_
) PANSI_STRING Name
,
832 _In_opt_
_When_(Name
== NULL
, _In_range_(>, 0)) ULONG Ordinal
,
833 _Out_ PVOID
*ProcedureAddress
)
835 /* Call the internal routine and tell it to execute DllInit */
836 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
844 LdrVerifyImageMatchesChecksum(
845 _In_ HANDLE FileHandle
,
846 _In_ PLDR_CALLBACK Callback
,
847 _In_ PVOID CallbackContext
,
848 _Out_ PUSHORT ImageCharacteristics
)
850 FILE_STANDARD_INFORMATION FileStandardInfo
;
851 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
852 PIMAGE_SECTION_HEADER LastSection
= NULL
;
853 IO_STATUS_BLOCK IoStatusBlock
;
854 PIMAGE_NT_HEADERS NtHeader
;
855 HANDLE SectionHandle
;
858 BOOLEAN Result
, NoActualCheck
;
862 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
864 /* If the handle has the magic KnownDll flag, skip actual checksums */
865 NoActualCheck
= ((ULONG_PTR
)FileHandle
& 1);
867 /* Create the section */
868 Status
= NtCreateSection(&SectionHandle
,
875 if (!NT_SUCCESS(Status
))
877 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
881 /* Map the section */
884 Status
= NtMapViewOfSection(SectionHandle
,
894 if (!NT_SUCCESS(Status
))
896 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
897 NtClose(SectionHandle
);
901 /* Get the file information */
902 Status
= NtQueryInformationFile(FileHandle
,
905 sizeof(FILE_STANDARD_INFORMATION
),
906 FileStandardInformation
);
907 if (!NT_SUCCESS(Status
))
909 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
910 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
911 NtClose(SectionHandle
);
915 /* Protect with SEH */
918 /* Check if this is the KnownDll hack */
921 /* Don't actually do it */
926 /* Verify the checksum */
927 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
928 FileStandardInfo
.EndOfFile
.LowPart
,
929 FileStandardInfo
.EndOfFile
.LowPart
);
932 /* Check if a callback was supplied */
933 if ((Result
) && (Callback
))
935 /* Get the NT Header */
936 NtHeader
= RtlImageNtHeader(ViewBase
);
938 /* Check if caller requested this back */
939 if (ImageCharacteristics
)
941 /* Return to caller */
942 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
945 /* Get the Import Directory Data */
946 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
948 IMAGE_DIRECTORY_ENTRY_IMPORT
,
951 /* Make sure there is one */
954 /* Loop the imports */
955 while (ImportData
->Name
)
958 ImportName
= RtlImageRvaToVa(NtHeader
,
963 /* Notify the callback */
964 Callback(CallbackContext
, ImportName
);
970 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
972 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
977 /* Unmap file and close handle */
978 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
979 NtClose(SectionHandle
);
982 return Result
? Status
: STATUS_IMAGE_CHECKSUM_MISMATCH
;
987 LdrQueryProcessModuleInformationEx(
988 _In_opt_ ULONG ProcessId
,
989 _Reserved_ ULONG Reserved
,
990 _Out_writes_bytes_to_(Size
, *ReturnedSize
) PRTL_PROCESS_MODULES ModuleInformation
,
992 _Out_opt_ PULONG ReturnedSize
)
994 PLIST_ENTRY ModuleListHead
, InitListHead
;
995 PLIST_ENTRY Entry
, InitEntry
;
996 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
997 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
998 NTSTATUS Status
= STATUS_SUCCESS
;
999 ULONG UsedSize
= FIELD_OFFSET(RTL_PROCESS_MODULES
, Modules
);
1000 ANSI_STRING AnsiString
;
1003 DPRINT("LdrQueryProcessModuleInformation() called\n");
1005 /* Acquire loader lock */
1006 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
1010 /* Check if we were given enough space */
1011 if (Size
< UsedSize
)
1013 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1017 ModuleInformation
->NumberOfModules
= 0;
1018 ModulePtr
= &ModuleInformation
->Modules
[0];
1019 Status
= STATUS_SUCCESS
;
1022 /* Traverse the list of modules */
1023 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1024 Entry
= ModuleListHead
->Flink
;
1026 while (Entry
!= ModuleListHead
)
1028 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1030 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
1032 /* Increase the used size */
1033 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
1035 if (UsedSize
> Size
)
1037 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1041 ModulePtr
->ImageBase
= Module
->DllBase
;
1042 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
1043 ModulePtr
->Flags
= Module
->Flags
;
1044 ModulePtr
->LoadCount
= Module
->LoadCount
;
1045 ModulePtr
->MappedBase
= NULL
;
1046 ModulePtr
->InitOrderIndex
= 0;
1047 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
1049 /* Now get init order index by traversing init list */
1050 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1051 InitEntry
= InitListHead
->Flink
;
1053 while (InitEntry
!= InitListHead
)
1055 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
1057 /* Increase the index */
1058 ModulePtr
->InitOrderIndex
++;
1060 /* Quit the loop if our module is found */
1061 if (InitModule
== Module
) break;
1063 /* Advance to the next entry */
1064 InitEntry
= InitEntry
->Flink
;
1067 /* Prepare ANSI string with the module's name */
1068 AnsiString
.Length
= 0;
1069 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
1070 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
1071 RtlUnicodeStringToAnsiString(&AnsiString
,
1072 &Module
->FullDllName
,
1075 /* Calculate OffsetToFileName field */
1076 p
= strrchr(ModulePtr
->FullPathName
, '\\');
1078 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
1080 ModulePtr
->OffsetToFileName
= 0;
1082 /* Advance to the next module in the output list */
1085 /* Increase number of modules */
1086 if (ModuleInformation
)
1087 ModuleInformation
->NumberOfModules
++;
1090 /* Go to the next entry in the modules list */
1091 Entry
= Entry
->Flink
;
1094 /* Set returned size if it was provided */
1096 *ReturnedSize
= UsedSize
;
1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1100 /* Ignoring the exception */
1103 /* Release the lock */
1104 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1106 DPRINT("LdrQueryProcessModuleInformation() done\n");
1116 LdrQueryProcessModuleInformation(
1117 _Out_writes_bytes_to_(Size
, *ReturnedSize
) PRTL_PROCESS_MODULES ModuleInformation
,
1119 _Out_opt_ PULONG ReturnedSize
)
1121 /* Call Ex version of the API */
1122 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
1130 LdrEnumerateLoadedModules(
1131 _Reserved_ ULONG ReservedFlag
,
1132 _In_ PLDR_ENUM_CALLBACK EnumProc
,
1133 _In_opt_ PVOID Context
)
1135 PLIST_ENTRY ListHead
, ListEntry
;
1136 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1139 BOOLEAN Stop
= FALSE
;
1141 /* Check parameters */
1142 if ((ReservedFlag
) || !(EnumProc
)) return STATUS_INVALID_PARAMETER
;
1144 /* Acquire the loader lock */
1145 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1146 if (!NT_SUCCESS(Status
)) return Status
;
1148 /* Loop all the modules and call enum proc */
1149 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1150 ListEntry
= ListHead
->Flink
;
1151 while (ListHead
!= ListEntry
)
1154 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1156 /* Call the enumeration proc inside SEH */
1159 EnumProc(LdrEntry
, Context
, &Stop
);
1161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1163 /* Ignoring the exception */
1166 /* Break if we were asked to stop enumeration */
1172 /* Advance to the next module */
1173 ListEntry
= ListEntry
->Flink
;
1176 /* Release loader lock */
1177 Status
= LdrUnlockLoaderLock(0, Cookie
);
1178 ASSERT(NT_SUCCESS(Status
));
1180 /* Reset any successful status to STATUS_SUCCESS,
1181 * but leave failure to the caller */
1182 if (NT_SUCCESS(Status
))
1183 Status
= STATUS_SUCCESS
;
1185 /* Return any possible failure status */
1194 LdrDisableThreadCalloutsForDll(
1195 _In_ PVOID BaseAddress
)
1197 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1201 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
1203 /* Don't do it during shutdown */
1204 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
1206 /* Check if we should grab the lock */
1211 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1212 if (!NT_SUCCESS(Status
)) return Status
;
1216 /* Make sure the DLL is valid and get its entry */
1217 Status
= STATUS_DLL_NOT_FOUND
;
1218 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1220 /* Get if it has a TLS slot */
1221 if (!LdrEntry
->TlsIndex
)
1223 /* It doesn't, so you're allowed to call this */
1224 LdrEntry
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
1225 Status
= STATUS_SUCCESS
;
1229 /* Check if the lock was held */
1233 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1236 /* Return the status */
1247 _In_ PVOID BaseAddress
)
1249 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1250 NTSTATUS Status
= STATUS_SUCCESS
;
1252 BOOLEAN Locked
= FALSE
;
1254 /* Check for invalid flags */
1255 if (Flags
& ~(LDR_ADDREF_DLL_PIN
))
1257 /* Fail with invalid parameter status if so */
1258 Status
= STATUS_INVALID_PARAMETER
;
1262 /* Acquire the loader lock if not in init phase */
1265 /* Acquire the lock */
1266 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1267 if (!NT_SUCCESS(Status
)) goto quickie
;
1271 /* Get this module's data table entry */
1272 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1276 /* Shouldn't happen */
1277 Status
= STATUS_INTERNAL_ERROR
;
1281 /* If this is not a pinned module */
1282 if (LdrEntry
->LoadCount
!= 0xFFFF)
1284 /* Update its load count */
1285 if (Flags
& LDR_ADDREF_DLL_PIN
)
1287 /* Pin it by setting load count to -1 */
1288 LdrEntry
->LoadCount
= 0xFFFF;
1289 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
1293 /* Increase its load count by one */
1294 LdrEntry
->LoadCount
++;
1295 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1298 /* Clear load in progress */
1299 LdrpClearLoadInProgress();
1304 /* There was an error getting this module's handle, return invalid param status */
1305 Status
= STATUS_INVALID_PARAMETER
;
1309 /* Check for error case */
1310 if (!NT_SUCCESS(Status
))
1312 /* Print debug information */
1313 if ((ShowSnaps
) || ((Status
!= STATUS_NO_SUCH_FILE
) &&
1314 (Status
!= STATUS_DLL_NOT_FOUND
) &&
1315 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)))
1317 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
, Status
);
1321 /* Release the lock if needed */
1322 if (Locked
) LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1332 _In_ PVOID BaseAddress
)
1334 NTSTATUS Status
= STATUS_SUCCESS
;
1335 PPEB Peb
= NtCurrentPeb();
1336 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
1338 PLIST_ENTRY NextEntry
;
1339 LIST_ENTRY UnloadList
;
1340 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1342 ULONG ComSectionSize
;
1344 /* Get the LDR Lock */
1345 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
1347 /* Increase the unload count */
1348 LdrpActiveUnloadCount
++;
1351 if (LdrpShutdownInProgress
) goto Quickie
;
1353 /* Make sure the DLL is valid and get its entry */
1354 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1356 Status
= STATUS_DLL_NOT_FOUND
;
1360 /* Check the current Load Count */
1361 if (LdrEntry
->LoadCount
!= 0xFFFF)
1364 LdrEntry
->LoadCount
--;
1367 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1369 /* Set up the Act Ctx */
1370 ActCtx
.Size
= sizeof(ActCtx
);
1371 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1372 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1374 /* Activate the ActCtx */
1375 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1376 LdrEntry
->EntryPointActivationContext
);
1378 /* Update the load count */
1379 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
1381 /* Release the context */
1382 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1387 /* The DLL is locked */
1391 /* Show debug message */
1392 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
1394 /* Check if this is our only unload and initialize the list if so */
1395 if (LdrpActiveUnloadCount
== 1) InitializeListHead(&LdrpUnloadHead
);
1397 /* Loop the modules to build the list */
1398 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
1399 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
1402 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1403 LDR_DATA_TABLE_ENTRY
,
1404 InInitializationOrderLinks
);
1405 NextEntry
= NextEntry
->Blink
;
1408 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
1410 /* If the load count is now 0 */
1411 if (!LdrEntry
->LoadCount
)
1416 DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n",
1417 LdrpActiveUnloadCount
,
1418 LdrEntry
->BaseDllName
.Buffer
,
1419 LdrEntry
->FullDllName
.Buffer
,
1420 (ULONG
)LdrEntry
->LoadCount
,
1421 LdrEntry
->EntryPoint
);
1424 /* Call Shim Engine and notify */
1427 VOID (NTAPI
* SE_DllUnloaded
)(PVOID
) = RtlDecodeSystemPointer(g_pfnSE_DllUnloaded
);
1428 SE_DllUnloaded(LdrEntry
);
1432 CurrentEntry
= LdrEntry
;
1433 RemoveEntryList(&CurrentEntry
->InInitializationOrderLinks
);
1434 RemoveEntryList(&CurrentEntry
->InMemoryOrderLinks
);
1435 RemoveEntryList(&CurrentEntry
->HashLinks
);
1437 /* If there's more then one active unload */
1438 if (LdrpActiveUnloadCount
> 1)
1440 /* Flush the cached DLL handle and clear the list */
1441 LdrpLoadedDllHandleCache
= NULL
;
1442 CurrentEntry
->InMemoryOrderLinks
.Flink
= NULL
;
1445 /* Add the entry on the unload list */
1446 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
1450 /* Only call the entrypoints once */
1451 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
1453 /* Now loop the unload list and create our own */
1454 InitializeListHead(&UnloadList
);
1455 CurrentEntry
= NULL
;
1456 NextEntry
= LdrpUnloadHead
.Flink
;
1457 while (NextEntry
!= &LdrpUnloadHead
)
1459 /* Get the current entry */
1460 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1462 LdrpRecordUnloadEvent(LdrEntry
);
1464 /* Set the entry and clear it from the list */
1465 CurrentEntry
= LdrEntry
;
1466 LdrpLoadedDllHandleCache
= NULL
;
1467 CurrentEntry
->InMemoryOrderLinks
.Flink
= NULL
;
1469 /* Move it from the global to the local list */
1470 RemoveEntryList(&CurrentEntry
->HashLinks
);
1471 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
1473 /* Get the entrypoint */
1474 EntryPoint
= LdrEntry
->EntryPoint
;
1476 /* Check if we should call it */
1477 if ((EntryPoint
) && (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
1482 DPRINT1("LDR: Calling deinit %p\n", EntryPoint
);
1485 /* Set up the Act Ctx */
1486 ActCtx
.Size
= sizeof(ActCtx
);
1487 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1488 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1490 /* Activate the ActCtx */
1491 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1492 LdrEntry
->EntryPointActivationContext
);
1494 /* Call the entrypoint */
1497 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
1502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1504 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n",
1505 _SEH2_GetExceptionCode(), &LdrEntry
->BaseDllName
);
1509 /* Release the context */
1510 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1513 /* Remove it from the list */
1514 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1515 CurrentEntry
= NULL
;
1516 NextEntry
= LdrpUnloadHead
.Flink
;
1519 /* Now loop our local list */
1520 NextEntry
= UnloadList
.Flink
;
1521 while (NextEntry
!= &UnloadList
)
1524 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1525 NextEntry
= NextEntry
->Flink
;
1526 CurrentEntry
= LdrEntry
;
1528 /* Notify Application Verifier */
1529 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
1531 AVrfDllUnloadNotification(LdrEntry
);
1537 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
1540 /* Check if this is a .NET executable */
1541 CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1543 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1548 DPRINT1(".NET Images are not supported yet\n");
1551 /* Check if we should unmap*/
1552 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
1555 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
1556 CurrentEntry
->DllBase
);
1557 ASSERT(NT_SUCCESS(Status
));
1560 /* Unload the alternate resource module, if any */
1561 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
1563 /* FIXME: Send shutdown notification */
1564 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1566 /* Check if a Hotpatch is active */
1567 if (LdrEntry
->PatchInformation
)
1570 DPRINT1("We don't support Hotpatching yet\n");
1573 /* Deallocate the Entry */
1574 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
1576 /* If this is the cached entry, invalidate it */
1577 if (LdrpGetModuleHandleCache
== CurrentEntry
)
1579 LdrpGetModuleHandleCache
= NULL
;
1584 /* Decrease unload count */
1585 LdrpActiveUnloadCount
--;
1586 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
1588 /* Return to caller */
1597 RtlDllShutdownInProgress(VOID
)
1599 /* Return the internal global */
1600 return LdrpShutdownInProgress
;
1606 PIMAGE_BASE_RELOCATION
1608 LdrProcessRelocationBlock(
1609 _In_ ULONG_PTR Address
,
1611 _In_ PUSHORT TypeOffset
,
1612 _In_ LONG_PTR Delta
)
1614 return LdrProcessRelocationBlockLongLong(Address
, Count
, TypeOffset
, Delta
);
1617 /* FIXME: Add to ntstatus.mc */
1618 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L)
1625 LdrLoadAlternateResourceModule(
1629 /* Is MUI Support enabled? */
1630 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS
;
1633 return STATUS_MUI_FILE_NOT_FOUND
;
1641 LdrUnloadAlternateResourceModule(
1642 _In_ PVOID BaseAddress
)
1646 /* Acquire the loader lock */
1647 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
1649 /* Check if there's any alternate resources loaded */
1650 if (AlternateResourceModuleCount
)
1655 /* Release the loader lock */
1656 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1667 LdrFlushAlternateResourceModules(VOID
)
1675 * See https://www.kernelmode.info/forum/viewtopic.php?t=991
1679 LdrSetAppCompatDllRedirectionCallback(
1681 _In_ PLDR_APP_COMPAT_DLL_REDIRECTION_CALLBACK_FUNCTION CallbackFunction
,
1682 _In_opt_ PVOID CallbackData
)
1685 return STATUS_NOT_IMPLEMENTED
;
1690 LdrInitShimEngineDynamic(IN PVOID BaseAddress
)
1693 NTSTATUS Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1694 if (NT_SUCCESS(Status
))
1696 if (!g_pShimEngineModule
)
1698 g_pShimEngineModule
= BaseAddress
;
1699 LdrpGetShimEngineInterface();
1701 LdrUnlockLoaderLock(0, Cookie
);