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 *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache
, LdrpGetModuleHandleCache
;
21 BOOLEAN g_ShimsEnabled
;
22 PVOID g_pShimEngineModule
;
23 PVOID g_pfnSE_DllLoaded
;
24 PVOID g_pfnSE_DllUnloaded
;
25 PVOID g_pfnSE_InstallBeforeInit
;
26 PVOID g_pfnSE_InstallAfterInit
;
27 PVOID g_pfnSE_ProcessDying
;
29 /* FUNCTIONS *****************************************************************/
33 LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut
,
38 ASSERT(Length
<= UNICODE_STRING_MAX_BYTES
);
41 StringOut
->Length
= 0;
43 /* Make sure it's not mis-aligned */
47 StringOut
->Buffer
= NULL
;
48 StringOut
->MaximumLength
= 0;
49 return STATUS_INVALID_PARAMETER
;
52 /* Allocate the string*/
53 StringOut
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
55 StringOut
->Length
+ sizeof(WCHAR
));
56 if (!StringOut
->Buffer
)
59 StringOut
->MaximumLength
= 0;
60 return STATUS_NO_MEMORY
;
63 /* Null-terminate it */
64 StringOut
->Buffer
[StringOut
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
66 /* Check if this is a maximum-sized string */
67 if (StringOut
->Length
!= UNICODE_STRING_MAX_BYTES
)
69 /* It's not, so set the maximum length to be one char more */
70 StringOut
->MaximumLength
= StringOut
->Length
+ sizeof(UNICODE_NULL
);
74 /* The length is already the maximum possible */
75 StringOut
->MaximumLength
= UNICODE_STRING_MAX_BYTES
;
79 return STATUS_SUCCESS
;
84 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn
)
86 ASSERT(StringIn
!= NULL
);
88 /* If Buffer is not NULL - free it */
91 RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn
->Buffer
);
95 RtlInitEmptyUnicodeString(StringIn
, NULL
, 0);
100 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint
,
101 IN PVOID BaseAddress
,
106 return EntryPoint(BaseAddress
, Reason
, Context
);
109 /* NOTE: This function is broken */
112 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
114 OUT PUNICODE_STRING UpdateString
)
116 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder
;
117 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
;
118 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
119 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
120 PIMAGE_THUNK_DATA FirstThunk
;
121 PLDR_DATA_TABLE_ENTRY Entry
;
122 PUNICODE_STRING ImportNameUnic
, RedirectedImportName
;
123 ANSI_STRING ImportNameAnsi
;
128 BOOLEAN RedirectedDll
;
129 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
131 /* Set up the Act Ctx */
132 ActCtx
.Size
= sizeof(ActCtx
);
133 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
134 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
136 /* Activate the ActCtx */
137 RtlActivateActivationContextUnsafeFast(&ActCtx
,
138 LdrEntry
->EntryPointActivationContext
);
140 /* Check the action we need to perform */
141 if ((Flags
== LDRP_UPDATE_REFCOUNT
) || (Flags
== LDRP_UPDATE_PIN
))
143 /* Make sure entry is not being loaded already */
144 if (LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
)
147 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
149 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
151 /* Make sure the entry is not being unloaded already */
152 if (LdrEntry
->Flags
& LDRP_UNLOAD_IN_PROGRESS
)
155 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
158 /* Go through all bound DLLs and dereference them */
159 ImportNameUnic
= &NtCurrentTeb()->StaticUnicodeString
;
161 /* Try to get the new import entry */
162 FirstEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
164 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
169 /* Set entry flags if refing/derefing */
170 if (Flags
== LDRP_UPDATE_REFCOUNT
)
171 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
172 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
173 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
175 BoundEntry
= FirstEntry
;
176 while (BoundEntry
->OffsetModuleName
)
178 /* Get pointer to the current import name */
179 ImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
181 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
182 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
184 if (NT_SUCCESS(Status
))
186 RedirectedDll
= FALSE
;
187 RedirectedImportName
= ImportNameUnic
;
189 /* Check if the SxS Assemblies specify another file */
190 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
192 &LdrApiDefaultExtension
,
195 &RedirectedImportName
,
201 if (NT_SUCCESS(Status
))
206 DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi
, RedirectedImportName
);
209 RedirectedDll
= TRUE
;
212 if (RedirectedDll
|| Status
== STATUS_SXS_KEY_NOT_FOUND
)
214 if (LdrpCheckForLoadedDll(NULL
,
215 RedirectedImportName
,
220 if (Entry
->LoadCount
!= 0xFFFF)
222 /* Perform the required action */
225 case LDRP_UPDATE_REFCOUNT
:
228 case LDRP_UPDATE_DEREFCOUNT
:
231 case LDRP_UPDATE_PIN
:
232 Entry
->LoadCount
= 0xFFFF;
239 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, RedirectedImportName
, Entry
->LoadCount
);
243 /* Recurse into this entry */
244 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
246 else if (RedirectedDll
)
248 DPRINT1("LDR: LdrpCheckForLoadedDll failed for redirected dll %wZ\n", RedirectedImportName
);
253 /* Unrecoverable SxS failure */
254 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status
, ImportNameUnic
);
259 /* Go through forwarders */
260 NewImportForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
261 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
263 ImportName
= (LPSTR
)FirstEntry
+ NewImportForwarder
->OffsetModuleName
;
265 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
266 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
267 if (NT_SUCCESS(Status
))
269 RedirectedDll
= FALSE
;
270 RedirectedImportName
= ImportNameUnic
;
272 /* Check if the SxS Assemblies specify another file */
273 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
275 &LdrApiDefaultExtension
,
278 &RedirectedImportName
,
283 if (NT_SUCCESS(Status
))
287 DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi
, RedirectedImportName
);
290 RedirectedDll
= TRUE
;
293 if (RedirectedDll
|| Status
== STATUS_SXS_KEY_NOT_FOUND
)
295 if (LdrpCheckForLoadedDll(NULL
,
296 RedirectedImportName
,
301 if (Entry
->LoadCount
!= 0xFFFF)
303 /* Perform the required action */
306 case LDRP_UPDATE_REFCOUNT
:
309 case LDRP_UPDATE_DEREFCOUNT
:
312 case LDRP_UPDATE_PIN
:
313 Entry
->LoadCount
= 0xFFFF;
320 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, RedirectedImportName
, Entry
->LoadCount
);
324 /* Recurse into this entry */
325 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
327 else if (RedirectedDll
)
329 DPRINT1("LDR: LdrpCheckForLoadedDll failed with status %x for redirected dll %wZ\n", Status
, RedirectedImportName
);
334 /* Unrecoverable SxS failure */
335 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status
, ImportNameUnic
);
340 NewImportForwarder
++;
343 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)NewImportForwarder
;
350 /* Check oldstyle import descriptor */
351 ImportEntry
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
353 IMAGE_DIRECTORY_ENTRY_IMPORT
,
357 /* There is old one, so go through its entries */
358 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
360 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->FirstThunk
);
362 /* Skip this entry if needed */
363 if (!FirstThunk
->u1
.Function
)
369 ImportName
= (PSZ
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
371 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
372 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
373 if (NT_SUCCESS(Status
))
375 RedirectedDll
= FALSE
;
376 RedirectedImportName
= ImportNameUnic
;
378 /* Check if the SxS Assemblies specify another file */
379 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
381 &LdrApiDefaultExtension
,
384 &RedirectedImportName
,
389 if (NT_SUCCESS(Status
))
393 DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi
, RedirectedImportName
);
397 RedirectedDll
= TRUE
;
400 if (RedirectedDll
|| Status
== STATUS_SXS_KEY_NOT_FOUND
)
402 if (LdrpCheckForLoadedDll(NULL
,
403 RedirectedImportName
,
408 if (Entry
->LoadCount
!= 0xFFFF)
410 /* Perform the required action */
413 case LDRP_UPDATE_REFCOUNT
:
416 case LDRP_UPDATE_DEREFCOUNT
:
419 case LDRP_UPDATE_PIN
:
420 Entry
->LoadCount
= 0xFFFF;
427 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, RedirectedImportName
, Entry
->LoadCount
);
432 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
434 else if (RedirectedDll
)
436 DPRINT1("LDR: LdrpCheckForLoadedDll failed for redirected dll %wZ\n", RedirectedImportName
);
442 /* Unrecoverable SxS failure */
443 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed for dll %wZ\n", ImportNameUnic
);
448 /* Go to the next entry */
454 /* Release the context */
455 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
460 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
463 WCHAR Buffer
[MAX_PATH
];
464 UNICODE_STRING UpdateString
;
466 /* Setup the string and call the extended API */
467 RtlInitEmptyUnicodeString(&UpdateString
, Buffer
, sizeof(Buffer
));
468 LdrpUpdateLoadCount3(LdrEntry
, Flags
, &UpdateString
);
473 LdrpCallTlsInitializers(IN PVOID BaseAddress
,
476 PIMAGE_TLS_DIRECTORY TlsDirectory
;
477 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
480 /* Get the TLS Directory */
481 TlsDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
483 IMAGE_DIRECTORY_ENTRY_TLS
,
486 /* Protect against invalid pointers */
489 /* Make sure it's valid */
493 Array
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
;
499 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
500 BaseAddress
, TlsDirectory
, Array
);
506 /* Get the TLS Entrypoint */
512 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
513 BaseAddress
, Callback
);
517 LdrpCallInitRoutine((PDLL_INIT_ROUTINE
)Callback
,
525 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
534 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName
,
537 /* Not implemented */
538 return STATUS_SUCCESS
;
543 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
545 IN PULONG DllCharacteristics OPTIONAL
,
546 OUT PHANDLE SectionHandle
)
550 OBJECT_ATTRIBUTES ObjectAttributes
;
551 IO_STATUS_BLOCK IoStatusBlock
;
552 ULONG_PTR HardErrorParameters
[1];
554 SECTION_IMAGE_INFORMATION SectionImageInfo
;
556 /* Check if we don't already have a handle */
559 /* Create the object attributes */
560 InitializeObjectAttributes(&ObjectAttributes
,
562 OBJ_CASE_INSENSITIVE
,
567 Status
= NtOpenFile(&FileHandle
,
568 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
571 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
572 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
574 /* Check if we failed */
575 if (!NT_SUCCESS(Status
))
577 /* Attempt to open for execute only */
578 Status
= NtOpenFile(&FileHandle
,
579 SYNCHRONIZE
| FILE_EXECUTE
,
582 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
583 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
585 /* Check if this failed too */
586 if (!NT_SUCCESS(Status
))
588 /* Show debug message */
591 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
595 /* Make sure to return an expected status code */
596 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
598 /* Callers expect this instead */
599 Status
= STATUS_DLL_NOT_FOUND
;
602 /* Return an empty section handle */
603 *SectionHandle
= NULL
;
610 /* Use the handle we already have */
611 FileHandle
= DllHandle
;
614 /* Create a section for the DLL */
615 Status
= NtCreateSection(SectionHandle
,
616 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
617 SECTION_MAP_WRITE
| SECTION_QUERY
,
624 /* If mapping failed, raise a hard error */
625 if (!NT_SUCCESS(Status
))
627 /* Forget the handle */
628 *SectionHandle
= NULL
;
630 /* Give the DLL name */
631 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
633 /* Raise the error */
634 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
641 /* Increment the error count */
642 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
645 /* Check for Safer restrictions */
646 if (DllCharacteristics
&&
647 !(*DllCharacteristics
& IMAGE_FILE_SYSTEM
))
649 /* Make sure it's executable */
650 Status
= ZwQuerySection(*SectionHandle
,
651 SectionImageInformation
,
653 sizeof(SECTION_IMAGE_INFORMATION
),
655 if (NT_SUCCESS(Status
))
657 /* Bypass the check for .NET images */
658 if (!(SectionImageInfo
.LoaderFlags
& IMAGE_LOADER_FLAGS_COMPLUS
))
660 /* Check with Safer */
661 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
662 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
664 /* Show debug message */
667 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
671 /* Failure case, close section handle */
672 NtClose(*SectionHandle
);
673 *SectionHandle
= NULL
;
679 /* Failure case, close section handle */
680 NtClose(*SectionHandle
);
681 *SectionHandle
= NULL
;
685 /* Close the file handle, we don't need it */
692 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
695 LdrpResolveDllName(PWSTR DllPath
,
697 PUNICODE_STRING FullDllName
,
698 PUNICODE_STRING BaseDllName
)
700 PWCHAR NameBuffer
, p1
, p2
= 0;
704 /* Allocate space for full DLL name */
705 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize
+ sizeof(UNICODE_NULL
));
706 if (!FullDllName
->Buffer
) return FALSE
;
708 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
713 &BaseDllName
->Buffer
);
715 if (!Length
|| Length
> BufSize
)
719 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
720 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
723 RtlFreeUnicodeString(FullDllName
);
727 /* Construct full DLL name */
728 FullDllName
->Length
= Length
;
729 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
731 /* Allocate a new buffer */
732 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
735 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
739 /* Copy over the contents from the previous one and free it */
740 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
741 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
742 FullDllName
->Buffer
= NameBuffer
;
744 /* Find last backslash */
745 p1
= FullDllName
->Buffer
;
754 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
762 /* Calculate remaining length */
765 /* Construct base DLL name */
766 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
767 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
768 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName
->MaximumLength
);
770 if (!BaseDllName
->Buffer
)
772 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
776 /* Copy base dll name to the new buffer */
777 RtlMoveMemory(BaseDllName
->Buffer
,
779 BaseDllName
->Length
);
781 /* Null-terminate the string */
782 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
789 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase
)
791 PIMAGE_NT_HEADERS NtHeaders
;
792 ULONG_PTR EntryPoint
= 0;
794 /* Get entry point offset from NT headers */
795 NtHeaders
= RtlImageNtHeader(ImageBase
);
799 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
800 if (EntryPoint
) EntryPoint
+= (ULONG_PTR
)ImageBase
;
803 /* Return calculated pointer (or zero in case of failure) */
804 return (PVOID
)EntryPoint
;
807 /* NOTE: This function is partially missing SxS */
810 LdrpCheckForKnownDll(PWSTR DllName
,
811 PUNICODE_STRING FullDllName
,
812 PUNICODE_STRING BaseDllName
,
813 HANDLE
*SectionHandle
)
815 OBJECT_ATTRIBUTES ObjectAttributes
;
816 HANDLE Section
= NULL
;
817 UNICODE_STRING DllNameUnic
;
822 /* Zero initialize provided parameters */
823 if (SectionHandle
) *SectionHandle
= 0;
827 FullDllName
->Length
= 0;
828 FullDllName
->MaximumLength
= 0;
829 FullDllName
->Buffer
= NULL
;
834 BaseDllName
->Length
= 0;
835 BaseDllName
->MaximumLength
= 0;
836 BaseDllName
->Buffer
= NULL
;
839 /* If any of these three params are missing then fail */
840 if (!SectionHandle
|| !FullDllName
|| !BaseDllName
)
841 return STATUS_INVALID_PARAMETER
;
843 /* Check the Loader Lock */
844 LdrpEnsureLoaderLockIsHeld();
846 /* Upgrade DllName to a unicode string */
847 RtlInitUnicodeString(&DllNameUnic
, DllName
);
849 /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
851 /* Get the activation context */
852 Status
= RtlFindActivationContextSectionString(0,
854 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
858 /* Check if it's a SxS or not */
859 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
860 Status
== STATUS_SXS_KEY_NOT_FOUND
)
862 /* NOTE: Here it's beneficial to allocate one big unicode string
863 using LdrpAllocateUnicodeString instead of fragmenting the heap
864 with two allocations as it's done now. */
866 /* Set up BaseDllName */
867 BaseDllName
->Length
= DllNameUnic
.Length
;
868 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
869 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
871 DllNameUnic
.MaximumLength
);
872 if (!BaseDllName
->Buffer
)
874 Status
= STATUS_NO_MEMORY
;
878 /* Copy the contents there */
879 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
881 /* Set up FullDllName */
882 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
883 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
884 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
885 if (!FullDllName
->Buffer
)
887 Status
= STATUS_NO_MEMORY
;
891 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
893 /* Put a slash there */
894 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
899 /* Set up DllNameUnic for a relative path */
900 DllNameUnic
.Buffer
= (PWSTR
)p1
;
901 DllNameUnic
.Length
= BaseDllName
->Length
;
902 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
904 /* Copy the contents */
905 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
907 /* There are all names, init attributes and open the section */
908 InitializeObjectAttributes(&ObjectAttributes
,
910 OBJ_CASE_INSENSITIVE
,
911 LdrpKnownDllObjectDirectory
,
914 Status
= NtOpenSection(&Section
,
915 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
917 if (!NT_SUCCESS(Status
))
919 /* Clear status in case it was just not found */
920 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) Status
= STATUS_SUCCESS
;
924 /* Pass section handle to the caller and return success */
925 *SectionHandle
= Section
;
926 return STATUS_SUCCESS
;
930 /* Close section object if it was opened */
931 if (Section
) NtClose(Section
);
933 /* Free string resources */
934 if (BaseDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
935 if (FullDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
943 LdrpSetProtection(PVOID ViewBase
,
946 PIMAGE_NT_HEADERS NtHeaders
;
947 PIMAGE_SECTION_HEADER Section
;
951 ULONG NewProtection
, OldProtection
, i
;
953 /* Get the NT headers */
954 NtHeaders
= RtlImageNtHeader(ViewBase
);
955 if (!NtHeaders
) return STATUS_INVALID_IMAGE_FORMAT
;
957 /* Compute address of the first section header */
958 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
960 /* Go through all sections */
961 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
963 /* Check for read-only non-zero section */
964 if ((Section
->SizeOfRawData
) &&
965 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
967 /* Check if we are setting or restoring protection */
970 /* Set it to either EXECUTE or READONLY */
971 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
973 NewProtection
= PAGE_EXECUTE
;
977 NewProtection
= PAGE_READONLY
;
980 /* Add PAGE_NOCACHE if needed */
981 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
983 NewProtection
|= PAGE_NOCACHE
;
988 /* Enable write access */
989 NewProtection
= PAGE_READWRITE
;
992 /* Get the section VA */
993 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
994 SectionSize
= Section
->SizeOfRawData
;
998 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
1003 if (!NT_SUCCESS(Status
)) return Status
;
1007 /* Move to the next section */
1011 /* Flush instruction cache if necessary */
1012 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
1013 return STATUS_SUCCESS
;
1016 /* NOTE: Not yet reviewed */
1019 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
1021 IN PWSTR DllName OPTIONAL
,
1022 IN PULONG DllCharacteristics
,
1024 IN BOOLEAN Redirect
,
1025 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
1027 PTEB Teb
= NtCurrentTeb();
1028 PPEB Peb
= NtCurrentPeb();
1029 PWCHAR p1
= DllName
;
1031 BOOLEAN KnownDll
= FALSE
;
1032 UNICODE_STRING FullDllName
, BaseDllName
;
1033 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
1034 UNICODE_STRING NtPathDllName
;
1035 ULONG_PTR HardErrorParameters
[2];
1036 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
1038 SIZE_T ViewSize
= 0;
1039 PVOID ViewBase
= NULL
;
1040 PVOID ArbitraryUserPointer
;
1041 PIMAGE_NT_HEADERS NtHeaders
;
1042 NTSTATUS HardErrorStatus
, Status
;
1043 BOOLEAN OverlapDllFound
= FALSE
;
1044 ULONG_PTR ImageBase
, ImageEnd
;
1045 PLIST_ENTRY ListHead
, NextEntry
;
1046 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
1047 ULONG_PTR CandidateBase
, CandidateEnd
;
1048 UNICODE_STRING OverlapDll
;
1049 BOOLEAN RelocatableDll
= TRUE
;
1050 UNICODE_STRING IllegalDll
;
1052 ULONG RelocDataSize
= 0;
1054 // FIXME: AppCompat stuff is missing
1058 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
1060 SearchPath
? SearchPath
: L
"");
1063 /* Check if we have a known dll directory */
1064 if (LdrpKnownDllObjectDirectory
&& Redirect
== FALSE
)
1066 /* Check if the path is full */
1070 if (TempChar
== '\\' || TempChar
== '/' )
1072 /* Complete path, don't do Known Dll lookup */
1077 /* Try to find a Known DLL */
1078 Status
= LdrpCheckForKnownDll(DllName
,
1083 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_DLL_NOT_FOUND
))
1086 DbgPrintEx(DPFLTR_LDR_ID
,
1088 "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
1099 /* Check if the Known DLL Check returned something */
1102 /* It didn't, so try to resolve the name now */
1103 if (LdrpResolveDllName(SearchPath
,
1108 /* Got a name, display a message */
1111 DPRINT1("LDR: Loading (%s) %wZ\n",
1112 Static
? "STATIC" : "DYNAMIC",
1116 /* Convert to NT Name */
1117 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1122 /* Path was invalid */
1123 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1126 /* Create a section for this dLL */
1127 Status
= LdrpCreateDllSection(&NtPathDllName
,
1132 /* Free the NT Name */
1133 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
1136 if (!NT_SUCCESS(Status
))
1138 /* Free the name strings and return */
1139 RtlFreeUnicodeString(&FullDllName
);
1140 RtlFreeUnicodeString(&BaseDllName
);
1146 /* We couldn't resolve the name, is this a static load? */
1150 * This is BAD! Static loads are CRITICAL. Bugcheck!
1151 * Initialize the strings for the error
1153 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
1154 RtlInitUnicodeString(&HardErrorDllPath
,
1155 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
1157 /* Set them as error parameters */
1158 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
1159 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
1161 /* Raise the hard error */
1162 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
1165 HardErrorParameters
,
1169 /* We're back, where we initializing? */
1170 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1173 /* Return failure */
1174 return STATUS_DLL_NOT_FOUND
;
1179 /* We have a section handle, so this is a known dll */
1183 /* Stuff the image name in the TIB, for the debugger */
1184 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1185 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1190 Status
= NtMapViewOfSection(SectionHandle
,
1202 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1204 /* Fail if we couldn't map it */
1205 if (!NT_SUCCESS(Status
))
1207 /* Close and return */
1208 NtClose(SectionHandle
);
1212 /* Get the NT Header */
1213 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
1215 /* Invalid image, unmap, close handle and fail */
1216 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1217 NtClose(SectionHandle
);
1218 return STATUS_INVALID_IMAGE_FORMAT
;
1221 // FIXME: .NET support is missing
1223 /* Allocate an entry */
1224 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
1226 /* Invalid image, unmap, close handle and fail */
1227 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1228 NtClose(SectionHandle
);
1229 return STATUS_NO_MEMORY
;
1232 /* Setup the entry */
1233 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
1234 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
1235 LdrEntry
->LoadCount
= 0;
1236 LdrEntry
->FullDllName
= FullDllName
;
1237 LdrEntry
->BaseDllName
= BaseDllName
;
1238 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
1240 /* Show debug message */
1243 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
1248 /* Insert this entry */
1249 LdrpInsertMemoryTableEntry(LdrEntry
);
1251 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
1253 /* Check for invalid CPU Image */
1254 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1256 /* Load our header */
1257 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1259 /* Assume defaults if we don't have to run the Hard Error path */
1260 HardErrorStatus
= STATUS_SUCCESS
;
1261 Response
= ResponseCancel
;
1263 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1264 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1266 /* Reset the entrypoint, save our Dll Name */
1267 LdrEntry
->EntryPoint
= 0;
1268 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1270 /* Raise the error */
1271 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1274 HardErrorParameters
,
1279 /* Check if the user pressed cancel */
1280 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1282 /* Remove the DLL from the lists */
1283 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1284 RemoveEntryList(&LdrEntry
->InMemoryOrderLinks
);
1285 RemoveEntryList(&LdrEntry
->HashLinks
);
1287 /* Remove the LDR Entry */
1288 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry
);
1290 /* Unmap and close section */
1291 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1292 NtClose(SectionHandle
);
1294 /* Did we do a hard error? */
1295 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1297 /* Yup, so increase fatal error count if we are initializing */
1298 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1301 /* Return failure */
1302 return STATUS_INVALID_IMAGE_FORMAT
;
1307 /* The image was valid. Is it a DLL? */
1308 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1310 /* Set the DLL Flag */
1311 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1314 /* If we're not a DLL, clear the entrypoint */
1315 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1317 LdrEntry
->EntryPoint
= 0;
1321 /* Return it for the caller */
1322 *DataTableEntry
= LdrEntry
;
1324 /* Check if we loaded somewhere else */
1325 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1327 /* Write the flag */
1328 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1330 /* Find our region */
1331 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1332 ImageEnd
= ImageBase
+ ViewSize
;
1334 DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p-%p -> %p)\n", DllName
, (PVOID
)ImageBase
, (PVOID
)ImageEnd
, ViewBase
);
1336 /* Scan all the modules */
1337 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1338 NextEntry
= ListHead
->Flink
;
1339 while (NextEntry
!= ListHead
)
1342 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1343 LDR_DATA_TABLE_ENTRY
,
1345 NextEntry
= NextEntry
->Flink
;
1347 /* Get the entry's bounds */
1348 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1349 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1351 /* Make sure this entry isn't unloading */
1352 if (!CandidateEntry
->InMemoryOrderLinks
.Flink
) continue;
1354 /* Check if our regions are colliding */
1355 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1356 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1357 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1359 /* Found who is overlapping */
1360 OverlapDllFound
= TRUE
;
1361 OverlapDll
= CandidateEntry
->FullDllName
;
1366 /* Check if we found the DLL overlapping with us */
1367 if (!OverlapDllFound
)
1369 /* It's not another DLL, it's memory already here */
1370 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1373 DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll
);
1375 /* Are we dealing with a DLL? */
1376 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1378 /* Check if relocs were stripped */
1379 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1381 /* Get the relocation data */
1382 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1384 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1387 /* Does the DLL not have any? */
1388 if (!RelocData
&& !RelocDataSize
)
1390 /* We'll allow this and simply continue */
1395 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1396 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1397 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1399 /* Can't relocate user32 */
1400 RelocatableDll
= FALSE
;
1404 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1405 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1407 /* Can't relocate kernel32 */
1408 RelocatableDll
= FALSE
;
1412 /* Known DLLs are not allowed to be relocated */
1413 if (KnownDll
&& !RelocatableDll
)
1415 /* Setup for hard error */
1416 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1417 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1419 /* Raise the error */
1420 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1423 HardErrorParameters
,
1427 /* If initializing, increase the error count */
1428 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1430 /* Don't do relocation */
1431 Status
= STATUS_CONFLICTING_ADDRESSES
;
1435 /* Change the protection to prepare for relocation */
1436 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1438 /* Make sure we changed the protection */
1439 if (NT_SUCCESS(Status
))
1441 /* Do the relocation */
1442 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1443 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1445 if (NT_SUCCESS(Status
))
1447 /* Stuff the image name in the TIB, for the debugger */
1448 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1449 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1452 Status
= NtMapViewOfSection(SectionHandle
,
1464 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1466 /* Return the protection */
1467 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1471 /* Handle any kind of failure */
1472 if (!NT_SUCCESS(Status
))
1474 /* Remove it from the lists */
1475 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1476 RemoveEntryList(&LdrEntry
->InMemoryOrderLinks
);
1477 RemoveEntryList(&LdrEntry
->HashLinks
);
1479 /* Unmap it, clear the entry */
1480 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1484 /* Show debug message */
1487 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1488 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1494 /* Not a DLL, or no relocation needed */
1495 Status
= STATUS_SUCCESS
;
1497 /* Stuff the image name in the TIB, for the debugger */
1498 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1499 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1502 Status
= NtMapViewOfSection(SectionHandle
,
1514 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1516 /* Show debug message */
1519 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1524 // FIXME: LdrpCheckCorImage() is missing
1526 /* Check if this is an SMP Machine and a DLL */
1527 if ((LdrpNumberOfProcessors
> 1) &&
1528 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1530 /* Validate the image for MP */
1531 LdrpValidateImageForMp(LdrEntry
);
1534 // FIXME: LdrpCorUnloadImage() is missing
1536 /* Close section and return status */
1537 NtClose(SectionHandle
);
1541 PLDR_DATA_TABLE_ENTRY
1543 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1545 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1546 PIMAGE_NT_HEADERS NtHeader
;
1548 /* Make sure the header is valid */
1549 NtHeader
= RtlImageNtHeader(BaseAddress
);
1550 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1554 /* Allocate an entry */
1555 LdrEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
1557 sizeof(LDR_DATA_TABLE_ENTRY
));
1559 /* Make sure we got one */
1563 LdrEntry
->DllBase
= BaseAddress
;
1564 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1565 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1566 LdrEntry
->PatchInformation
= NULL
;
1570 /* Return the entry */
1576 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1578 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1581 /* Insert into hash table */
1582 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1583 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1585 /* Insert into other lists */
1586 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1587 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderLinks
);
1592 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry
)
1595 ASSERT(Entry
!= NULL
);
1597 /* Release the activation context if it exists and wasn't already released */
1598 if ((Entry
->EntryPointActivationContext
) &&
1599 (Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
))
1601 /* Mark it as invalid */
1602 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1603 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1606 /* Release the full dll name string */
1607 if (Entry
->FullDllName
.Buffer
) LdrpFreeUnicodeString(&Entry
->FullDllName
);
1609 /* Finally free the entry's memory */
1610 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry
);
1615 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1616 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1618 PLDR_DATA_TABLE_ENTRY Current
;
1619 PLIST_ENTRY ListHead
, Next
;
1621 /* Check the cache first */
1622 if ((LdrpLoadedDllHandleCache
) &&
1623 (LdrpLoadedDllHandleCache
->DllBase
== Base
))
1625 /* We got lucky, return the cached entry */
1626 *LdrEntry
= LdrpLoadedDllHandleCache
;
1630 /* Time for a lookup */
1631 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1632 Next
= ListHead
->Flink
;
1633 while (Next
!= ListHead
)
1635 /* Get the current entry */
1636 Current
= CONTAINING_RECORD(Next
,
1637 LDR_DATA_TABLE_ENTRY
,
1640 /* Make sure it's not unloading and check for a match */
1641 if ((Current
->InMemoryOrderLinks
.Flink
) && (Base
== Current
->DllBase
))
1644 LdrpLoadedDllHandleCache
= Current
;
1647 *LdrEntry
= Current
;
1651 /* Move to the next one */
1661 LdrpResolveFullName(IN PUNICODE_STRING OriginalName
,
1662 IN PUNICODE_STRING PathName
,
1663 IN PUNICODE_STRING FullPathName
,
1664 IN PUNICODE_STRING
*ExpandedName
)
1666 NTSTATUS Status
= STATUS_SUCCESS
;
1667 // RTL_PATH_TYPE PathType;
1668 // BOOLEAN InvalidName;
1671 /* Display debug output if snaps are on */
1674 DbgPrintEx(DPFLTR_LDR_ID
,
1676 "LDR: %s - Expanding full name of %wZ\n",
1681 /* FIXME: Lock the PEB */
1682 //RtlEnterCriticalSection(&FastPebLock);
1684 /* Get the path name */
1685 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1694 if (!(Length
) || (Length
> UNICODE_STRING_MAX_BYTES
))
1697 Status
= STATUS_NAME_TOO_LONG
;
1701 /* Check if the length hasn't changed */
1702 if (Length
<= PathName
->Length
)
1704 /* Return the same thing */
1705 *ExpandedName
= PathName
;
1706 PathName
->Length
= (USHORT
)Length
;
1711 ASSERT(Length
>= sizeof(WCHAR
));
1713 /* Allocate a string */
1714 Status
= LdrpAllocateUnicodeString(FullPathName
, Length
- sizeof(WCHAR
));
1715 if (!NT_SUCCESS(Status
)) goto Quickie
;
1717 /* Now get the full path again */
1719 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1720 FullPathName
->Length
,
1721 FullPathName
->Buffer
,
1728 if (!(Length
) || (Length
> FullPathName
->Length
))
1731 LdrpFreeUnicodeString(FullPathName
);
1732 Status
= STATUS_NAME_TOO_LONG
;
1736 /* Return the expanded name */
1737 *ExpandedName
= FullPathName
;
1738 FullPathName
->Length
= (USHORT
)Length
;
1742 /* FIXME: Unlock the PEB */
1743 //RtlLeaveCriticalSection(&FastPebLock);
1745 /* Display debug output if snaps are on */
1748 /* Check which output to use -- failure or success */
1749 if (NT_SUCCESS(Status
))
1751 DbgPrintEx(DPFLTR_LDR_ID
,
1753 "LDR: %s - Expanded to %wZ\n",
1759 DbgPrintEx(DPFLTR_LDR_ID
,
1761 "LDR: %s - Failed to expand %wZ; 0x%08x\n",
1768 /* If we failed, return NULL */
1769 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1777 LdrpSearchPath(IN PWCHAR
*SearchPath
,
1779 IN PUNICODE_STRING PathName
,
1780 IN PUNICODE_STRING FullPathName
,
1781 IN PUNICODE_STRING
*ExpandedName
)
1783 BOOLEAN TryAgain
= FALSE
;
1784 PWCHAR ActualSearchPath
= *SearchPath
;
1785 UNICODE_STRING TestName
;
1787 PWCHAR Buffer
, BufEnd
= NULL
;
1792 /* Check if we don't have a search path */
1793 if (!ActualSearchPath
) *SearchPath
= LdrpDefaultPath
.Buffer
;
1795 /* Display debug output if snaps are on */
1798 DbgPrintEx(DPFLTR_LDR_ID
,
1800 "LDR: %s - Looking for %ws in %ws\n",
1806 /* Check if we're dealing with a relative path */
1807 if (RtlDetermineDosPathNameType_U(DllName
) != RtlPathTypeRelative
)
1809 /* Good, we're not. Create the name string */
1810 Status
= RtlInitUnicodeStringEx(&TestName
, DllName
);
1811 if (!NT_SUCCESS(Status
)) goto Quickie
;
1813 /* Make sure it exists */
1815 if (!RtlDoesFileExists_UstrEx(&TestName
, TRUE
))
1817 /* It doesn't, fail */
1818 Status
= STATUS_DLL_NOT_FOUND
;
1823 /* Resolve the full name */
1824 Status
= LdrpResolveFullName(&TestName
,
1831 /* FIXME: Handle relative case semicolon-lookup here */
1833 /* Calculate length */
1834 Length
+= (ULONG
)wcslen(DllName
) + 1;
1835 if (Length
> UNICODE_STRING_MAX_CHARS
)
1837 /* Too long, fail */
1838 Status
= STATUS_NAME_TOO_LONG
;
1842 /* Allocate buffer */
1843 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
1847 Status
= STATUS_NO_MEMORY
;
1851 /* FIXME: Setup TestName here */
1852 Status
= STATUS_NOT_FOUND
;
1858 p
= *ActualSearchPath
;
1859 if (!(p
) || (p
== ';'))
1861 /* FIXME: We don't have a character, or is a semicolon.*/
1863 /* Display debug output if snaps are on */
1866 DbgPrintEx(DPFLTR_LDR_ID
,
1868 "LDR: %s - Looking for %ws\n",
1874 TestName
.Length
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
);
1876 ASSERT(TestName
.Length
< TestName
.MaximumLength
);
1879 /* Check if the file exists */
1881 if (RtlDoesFileExists_UstrEx(&TestName
, FALSE
))
1884 /* It does. Reallocate the buffer */
1885 TestName
.MaximumLength
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
) + sizeof(WCHAR
);
1886 TestName
.Buffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
1889 TestName
.MaximumLength
);
1890 if (!TestName
.Buffer
)
1892 /* Keep the old one */
1893 TestName
.Buffer
= Buffer
;
1898 Buffer
= TestName
.Buffer
;
1901 /* Make sure we have a buffer at least */
1902 ASSERT(TestName
.Buffer
);
1904 /* Resolve the name */
1905 *SearchPath
= ActualSearchPath
++;
1906 Status
= LdrpResolveFullName(&TestName
,
1913 /* Update buffer end */
1916 /* Update string position */
1917 //pp = ActualSearchPath++;
1921 /* Otherwise, write the character */
1926 /* Check if the string is empty, meaning we're done */
1927 if (!(*ActualSearchPath
)) TryAgain
= TRUE
;
1929 /* Advance in the string */
1931 } while (!TryAgain
);
1933 /* Check if we had a buffer and free it */
1934 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1937 /* Check if we got here through failure */
1938 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1940 /* Display debug output if snaps are on */
1943 /* Check which output to use -- failure or success */
1944 if (NT_SUCCESS(Status
))
1946 DbgPrintEx(DPFLTR_LDR_ID
,
1948 "LDR: %s - Returning %wZ\n",
1954 DbgPrintEx(DPFLTR_LDR_ID
,
1956 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1969 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1972 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1973 IN PUNICODE_STRING DllName
,
1975 IN BOOLEAN RedirectedDll
,
1976 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1979 PLIST_ENTRY ListHead
, ListEntry
;
1980 PLDR_DATA_TABLE_ENTRY CurEntry
;
1981 BOOLEAN FullPath
= FALSE
;
1984 UNICODE_STRING FullDllName
, NtPathName
;
1986 OBJECT_ATTRIBUTES ObjectAttributes
;
1988 HANDLE FileHandle
, SectionHandle
;
1989 IO_STATUS_BLOCK Iosb
;
1990 PVOID ViewBase
= NULL
;
1991 SIZE_T ViewSize
= 0;
1992 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1993 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"", DllName
, Flag
, RedirectedDll
, LdrEntry
);
1995 /* Check if a dll name was provided */
1996 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
1998 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1999 /* FIXME: Warning, code does not support redirection at all */
2001 /* Look in the hash table if flag was set */
2003 if (Flag
/* the second check is a hack */ && !RedirectedDll
)
2005 /* FIXME: if we get redirected dll it means that we also get a full path so we need to find its filename for the hash lookup */
2007 /* Get hash index */
2008 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
2010 /* Traverse that list */
2011 ListHead
= &LdrpHashTable
[HashIndex
];
2012 ListEntry
= ListHead
->Flink
;
2013 while (ListEntry
!= ListHead
)
2015 /* Get the current entry */
2016 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2018 /* Check base name of that module */
2019 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
2021 /* It matches, return it */
2022 *LdrEntry
= CurEntry
;
2026 /* Advance to the next entry */
2027 ListEntry
= ListEntry
->Flink
;
2030 /* Module was not found, return failure */
2034 /* Check if this is a redirected DLL */
2037 /* Redirected dlls already have a full path */
2039 FullDllName
= *DllName
;
2043 /* Check if there is a full path in this DLL */
2044 wc
= DllName
->Buffer
;
2047 /* Check for a slash in the current position*/
2048 if ((*wc
== L
'\\') || (*wc
== L
'/'))
2050 /* Found the slash, so dll name contains path */
2053 /* Setup full dll name string */
2054 FullDllName
.Buffer
= NameBuf
;
2056 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2057 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
2060 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
2064 /* Check if that was successful */
2065 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
2069 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n",
2074 /* Full dll name is found */
2075 FullDllName
.Length
= Length
;
2076 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
2084 /* Go check the hash table */
2091 /* FIXME: Warning, activation context missing */
2092 DPRINT("Warning, activation context missing\n");
2094 /* NOTE: From here on down, everything looks good */
2096 /* Loop the module list */
2097 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2098 ListEntry
= ListHead
->Flink
;
2099 while (ListEntry
!= ListHead
)
2101 /* Get the current entry and advance to the next one */
2102 CurEntry
= CONTAINING_RECORD(ListEntry
,
2103 LDR_DATA_TABLE_ENTRY
,
2105 ListEntry
= ListEntry
->Flink
;
2107 /* Check if it's being unloaded */
2108 if (!CurEntry
->InMemoryOrderLinks
.Flink
) continue;
2110 /* Check if name matches */
2111 if (RtlEqualUnicodeString(&FullDllName
,
2112 &CurEntry
->FullDllName
,
2116 *LdrEntry
= CurEntry
;
2121 /* Convert given path to NT path */
2122 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
2127 /* Fail if conversion failed */
2131 /* Initialize object attributes and open it */
2132 InitializeObjectAttributes(&ObjectAttributes
,
2134 OBJ_CASE_INSENSITIVE
,
2137 Status
= NtOpenFile(&FileHandle
,
2138 SYNCHRONIZE
| FILE_EXECUTE
,
2141 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2142 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
2144 /* Free NT path name */
2145 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
2147 /* If opening the file failed - return failure */
2148 if (!NT_SUCCESS(Status
)) return FALSE
;
2150 /* Create a section for this file */
2151 Status
= NtCreateSection(&SectionHandle
,
2153 SECTION_MAP_EXECUTE
|
2161 /* Close file handle */
2162 NtClose(FileHandle
);
2164 /* If creating section failed - return failure */
2165 if (!NT_SUCCESS(Status
)) return FALSE
;
2167 /* Map view of this section */
2168 Status
= ZwMapViewOfSection(SectionHandle
,
2179 /* Close section handle */
2180 NtClose(SectionHandle
);
2182 /* If section mapping failed - return failure */
2183 if (!NT_SUCCESS(Status
)) return FALSE
;
2185 /* Get pointer to the NT header of this section */
2186 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
2187 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
2189 /* Unmap the section and fail */
2190 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2194 /* Go through the list of modules again */
2195 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2196 ListEntry
= ListHead
->Flink
;
2197 while (ListEntry
!= ListHead
)
2199 /* Get the current entry and advance to the next one */
2200 CurEntry
= CONTAINING_RECORD(ListEntry
,
2201 LDR_DATA_TABLE_ENTRY
,
2203 ListEntry
= ListEntry
->Flink
;
2205 /* Check if it's in the process of being unloaded */
2206 if (!CurEntry
->InMemoryOrderLinks
.Flink
) continue;
2208 /* The header is untrusted, use SEH */
2211 /* Check if timedate stamp and sizes match */
2212 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
2213 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
2215 /* Time, date and size match. Let's compare their headers */
2216 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
2217 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
2219 /* Headers match too! Finally ask the kernel to compare mapped files */
2220 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
2221 if (NT_SUCCESS(Status
))
2223 /* This is our entry!, unmap and return success */
2224 *LdrEntry
= CurEntry
;
2225 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2226 _SEH2_YIELD(return TRUE
;)
2231 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
2238 /* Unmap the section and fail */
2239 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2245 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
2246 IN PANSI_STRING Name
,
2248 OUT PVOID
*ProcedureAddress
,
2249 IN BOOLEAN ExecuteInit
)
2251 NTSTATUS Status
= STATUS_SUCCESS
;
2252 UCHAR ImportBuffer
[64];
2253 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2254 IMAGE_THUNK_DATA Thunk
;
2256 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
2257 PIMAGE_EXPORT_DIRECTORY ExportDir
;
2258 ULONG ExportDirSize
, Length
;
2261 /* Show debug message */
2262 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
2264 /* Check if we got a name */
2267 /* Show debug message */
2268 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
2270 /* Make sure it's not too long */
2271 Length
= Name
->Length
+
2273 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
2274 if (Length
> UNICODE_STRING_MAX_BYTES
)
2276 /* Won't have enough space to add the hint */
2277 return STATUS_NAME_TOO_LONG
;
2280 /* Check if our buffer is large enough */
2281 if (Length
> sizeof(ImportBuffer
))
2283 /* Allocate from heap, plus 2 bytes for the Hint */
2284 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
2290 /* Use our internal buffer */
2291 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
2294 /* Clear the hint */
2295 ImportName
->Hint
= 0;
2297 /* Copy the name and null-terminate it */
2298 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
2299 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
2301 /* Clear the high bit */
2302 ImageBase
= ImportName
;
2303 Thunk
.u1
.AddressOfData
= 0;
2307 /* Do it by ordinal */
2310 /* Show debug message */
2311 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
2313 /* Make sure an ordinal was given */
2317 DPRINT1("No ordinal and no name\n");
2318 return STATUS_INVALID_PARAMETER
;
2321 /* Set the original flag in the thunk */
2322 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
2325 /* Acquire lock unless we are initting */
2326 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2330 /* Try to find the loaded DLL */
2331 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2334 DPRINT1("Invalid base address %p\n", BaseAddress
);
2335 Status
= STATUS_DLL_NOT_FOUND
;
2336 _SEH2_YIELD(goto Quickie
;)
2339 /* Get the pointer to the export directory */
2340 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2342 IMAGE_DIRECTORY_ENTRY_EXPORT
,
2347 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n",
2348 &LdrEntry
->BaseDllName
, Name
, BaseAddress
, LdrEntry
->DllBase
);
2349 Status
= STATUS_PROCEDURE_NOT_FOUND
;
2350 _SEH2_YIELD(goto Quickie
;)
2353 /* Now get the thunk */
2354 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
2363 /* Finally, see if we're supposed to run the init routines */
2364 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
2367 * It's possible a forwarded entry had us load the DLL. In that case,
2368 * then we will call its DllMain. Use the last loaded DLL for this.
2370 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
2371 LdrEntry
= CONTAINING_RECORD(Entry
,
2372 LDR_DATA_TABLE_ENTRY
,
2373 InInitializationOrderLinks
);
2375 /* Make sure we didn't process it yet*/
2376 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2378 /* Call the init routine */
2381 Status
= LdrpRunInitializeRoutines(NULL
);
2383 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2385 /* Get the exception code */
2386 Status
= _SEH2_GetExceptionCode();
2392 /* Make sure we're OK till here */
2393 if (NT_SUCCESS(Status
))
2395 /* Return the address */
2396 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
2399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2401 /* Just ignore exceptions */
2407 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
2409 /* We allocated from heap, free it */
2410 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
2413 /* Release the CS if we entered it */
2414 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2422 LdrpLoadDll(IN BOOLEAN Redirected
,
2423 IN PWSTR DllPath OPTIONAL
,
2424 IN PULONG DllCharacteristics OPTIONAL
,
2425 IN PUNICODE_STRING DllName
,
2426 OUT PVOID
*BaseAddress
,
2427 IN BOOLEAN CallInit
)
2429 PPEB Peb
= NtCurrentPeb();
2430 NTSTATUS Status
= STATUS_SUCCESS
;
2432 BOOLEAN GotExtension
;
2434 WCHAR NameBuffer
[MAX_PATH
+ 6];
2435 UNICODE_STRING RawDllName
;
2436 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2437 BOOLEAN InInit
= LdrpInLdrInit
;
2439 /* Save the Raw DLL Name */
2440 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
2441 RtlInitEmptyUnicodeString(&RawDllName
, NameBuffer
, sizeof(NameBuffer
));
2442 RtlCopyUnicodeString(&RawDllName
, DllName
);
2444 /* Find the extension, if present */
2445 p
= DllName
->Buffer
+ DllName
->Length
/ sizeof(WCHAR
) - 1;
2446 GotExtension
= FALSE
;
2447 while (p
>= DllName
->Buffer
)
2452 GotExtension
= TRUE
;
2455 else if (c
== L
'\\')
2461 /* If no extension was found, add the default extension */
2464 /* Check that we have space to add one */
2465 if ((DllName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
2468 /* No space to add the extension */
2469 DbgPrintEx(DPFLTR_LDR_ID
,
2471 "LDR: %s - Dll name missing extension; with extension "
2472 "added the name is too long\n"
2473 " DllName: (@ %p) \"%wZ\"\n"
2474 " DllName->Length: %u\n",
2479 return STATUS_NAME_TOO_LONG
;
2482 /* Add it. Needs to be null terminated, thus the length check above */
2483 (VOID
)RtlAppendUnicodeStringToString(&RawDllName
,
2484 &LdrApiDefaultExtension
);
2487 /* Check for init flag and acquire lock */
2488 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2490 /* Show debug message */
2493 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
2495 DllPath
? DllPath
: L
"");
2498 /* Check if the DLL is already loaded */
2499 if (!LdrpCheckForLoadedDll(DllPath
,
2506 Status
= LdrpMapDll(DllPath
,
2513 if (!NT_SUCCESS(Status
)) goto Quickie
;
2515 /* FIXME: Need to mark the DLL range for the stack DB */
2516 //RtlpStkMarkDllRange(LdrEntry);
2518 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2519 if ((DllCharacteristics
) &&
2520 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
2522 /* This is not a DLL, so remove such data */
2523 LdrEntry
->EntryPoint
= NULL
;
2524 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
2527 /* Make sure it's a DLL */
2528 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2530 /* Check if this is a .NET Image */
2531 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
2533 /* Walk the Import Descriptor */
2534 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
2537 /* Update load count, unless it's locked */
2538 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2539 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2541 /* Check if we failed */
2542 if (!NT_SUCCESS(Status
))
2544 /* Clear entrypoint, and insert into list */
2545 LdrEntry
->EntryPoint
= NULL
;
2546 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2547 &LdrEntry
->InInitializationOrderLinks
);
2549 /* Cancel the load */
2550 LdrpClearLoadInProgress();
2552 /* Unload the DLL */
2555 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2556 "import descriptors\n",
2560 LdrUnloadDll(LdrEntry
->DllBase
);
2562 /* Return the error */
2566 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2568 /* Increase load count */
2569 LdrEntry
->LoadCount
++;
2572 /* Insert it into the list */
2573 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2574 &LdrEntry
->InInitializationOrderLinks
);
2576 /* If we have to run the entrypoint, make sure the DB is ready */
2577 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2579 /* Notify Shim Engine */
2582 VOID (NTAPI
* SE_DllLoaded
)(PLDR_DATA_TABLE_ENTRY
) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded
);
2583 SE_DllLoaded(LdrEntry
);
2586 /* Run the init routine */
2587 Status
= LdrpRunInitializeRoutines(NULL
);
2588 if (!NT_SUCCESS(Status
))
2590 /* Failed, unload the DLL */
2593 DbgPrint("LDR: Unloading %wZ because either its init "
2594 "routine or one of its static imports failed; "
2595 "status = 0x%08lx\n",
2599 LdrUnloadDll(LdrEntry
->DllBase
);
2604 /* The DB isn't ready, which means we were loaded because of a forwarder */
2605 Status
= STATUS_SUCCESS
;
2610 /* We were already loaded. Are we a DLL? */
2611 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2613 /* Increase load count */
2614 LdrEntry
->LoadCount
++;
2615 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2617 /* Clear the load in progress */
2618 LdrpClearLoadInProgress();
2622 /* Not a DLL, just increase the load count */
2623 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2628 /* Release the lock */
2629 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2631 /* Check for success */
2632 if (NT_SUCCESS(Status
))
2634 /* Return the base address */
2635 *BaseAddress
= LdrEntry
->DllBase
;
2640 *BaseAddress
= NULL
;
2649 LdrpClearLoadInProgress(VOID
)
2651 PLIST_ENTRY ListHead
, Entry
;
2652 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2653 ULONG ModulesCount
= 0;
2655 /* Traverse the init list */
2656 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2657 Entry
= ListHead
->Flink
;
2658 while (Entry
!= ListHead
)
2660 /* Get the loader entry */
2661 LdrEntry
= CONTAINING_RECORD(Entry
,
2662 LDR_DATA_TABLE_ENTRY
,
2663 InInitializationOrderLinks
);
2665 /* Clear load in progress flag */
2666 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2668 /* Check for modules with entry point count but not processed yet */
2669 if ((LdrEntry
->EntryPoint
) &&
2670 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2672 /* Increase counter */
2676 /* Advance to the next entry */
2677 Entry
= Entry
->Flink
;
2680 /* Return final count */
2681 return ModulesCount
;
2684 PVOID
LdrpGetShimEngineFunction(PCSZ FunctionName
)
2686 ANSI_STRING Function
;
2689 RtlInitAnsiString(&Function
, FunctionName
);
2690 Status
= LdrGetProcedureAddress(g_pShimEngineModule
, &Function
, 0, &Address
);
2691 return NT_SUCCESS(Status
) ? Address
: NULL
;
2696 LdrpGetShimEngineInterface()
2698 PVOID SE_DllLoaded
= LdrpGetShimEngineFunction("SE_DllLoaded");
2699 PVOID SE_DllUnloaded
= LdrpGetShimEngineFunction("SE_DllUnloaded");
2700 PVOID SE_InstallBeforeInit
= LdrpGetShimEngineFunction("SE_InstallBeforeInit");
2701 PVOID SE_InstallAfterInit
= LdrpGetShimEngineFunction("SE_InstallAfterInit");
2702 PVOID SE_ProcessDying
= LdrpGetShimEngineFunction("SE_ProcessDying");
2704 if (SE_DllLoaded
&& SE_DllUnloaded
&& SE_InstallBeforeInit
&& SE_InstallAfterInit
&& SE_ProcessDying
)
2706 g_pfnSE_DllLoaded
= RtlEncodeSystemPointer(SE_DllLoaded
);
2707 g_pfnSE_DllUnloaded
= RtlEncodeSystemPointer(SE_DllUnloaded
);
2708 g_pfnSE_InstallBeforeInit
= RtlEncodeSystemPointer(SE_InstallBeforeInit
);
2709 g_pfnSE_InstallAfterInit
= RtlEncodeSystemPointer(SE_InstallAfterInit
);
2710 g_pfnSE_ProcessDying
= RtlEncodeSystemPointer(SE_ProcessDying
);
2711 g_ShimsEnabled
= TRUE
;
2715 LdrpUnloadShimEngine();
2722 LdrpLoadShimEngine(IN PWSTR ImageName
, IN PUNICODE_STRING ProcessImage
, IN PVOID pShimData
)
2724 UNICODE_STRING ShimLibraryName
;
2727 RtlInitUnicodeString(&ShimLibraryName
, ImageName
);
2728 Status
= LdrpLoadDll(FALSE
, NULL
, NULL
, &ShimLibraryName
, &ShimLibrary
, TRUE
);
2729 if (NT_SUCCESS(Status
))
2731 g_pShimEngineModule
= ShimLibrary
;
2732 LdrpGetShimEngineInterface();
2735 VOID(NTAPI
*SE_InstallBeforeInit
)(PUNICODE_STRING
, PVOID
);
2736 SE_InstallBeforeInit
= RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit
);
2737 SE_InstallBeforeInit(ProcessImage
, pShimData
);
2744 LdrpUnloadShimEngine()
2746 /* Make sure we do not call into the shim engine anymore */
2747 g_ShimsEnabled
= FALSE
;
2748 LdrUnloadDll(g_pShimEngineModule
);
2749 g_pShimEngineModule
= NULL
;