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(LdrpHeap
,
55 Length
+ sizeof(WCHAR
));
56 if (!StringOut
->Buffer
)
59 StringOut
->MaximumLength
= 0;
60 return STATUS_NO_MEMORY
;
63 /* Null-terminate it */
64 StringOut
->Buffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
66 /* Check if this is a maximum-sized string */
67 if (Length
!= UNICODE_STRING_MAX_BYTES
)
69 /* It's not, so set the maximum length to be one char more */
70 StringOut
->MaximumLength
= 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(LdrpHeap
, 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 PLDR_DATA_TABLE_ENTRY LdrEntry
,
476 PIMAGE_TLS_DIRECTORY TlsDirectory
;
477 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
480 /* Get the TLS Directory */
481 TlsDirectory
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
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 LdrEntry
->DllBase
, TlsDirectory
, Array
);
506 /* Get the TLS Entrypoint */
512 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
513 LdrEntry
->DllBase
, Callback
);
517 LdrpCallInitRoutine((PDLL_INIT_ROUTINE
)Callback
,
525 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
527 DPRINT1("LDR: Exception 0x%x during Tls Callback(%u) for %wZ\n",
528 _SEH2_GetExceptionCode(), Reason
, &LdrEntry
->BaseDllName
);
535 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName
,
538 /* Not implemented */
539 return STATUS_SUCCESS
;
544 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
546 IN PULONG DllCharacteristics OPTIONAL
,
547 OUT PHANDLE SectionHandle
)
551 OBJECT_ATTRIBUTES ObjectAttributes
;
552 IO_STATUS_BLOCK IoStatusBlock
;
553 ULONG_PTR HardErrorParameters
[1];
555 SECTION_IMAGE_INFORMATION SectionImageInfo
;
557 /* Check if we don't already have a handle */
560 /* Create the object attributes */
561 InitializeObjectAttributes(&ObjectAttributes
,
563 OBJ_CASE_INSENSITIVE
,
568 Status
= NtOpenFile(&FileHandle
,
569 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
572 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
573 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
575 /* Check if we failed */
576 if (!NT_SUCCESS(Status
))
578 /* Attempt to open for execute only */
579 Status
= NtOpenFile(&FileHandle
,
580 SYNCHRONIZE
| FILE_EXECUTE
,
583 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
584 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
586 /* Check if this failed too */
587 if (!NT_SUCCESS(Status
))
589 /* Show debug message */
592 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
596 /* Make sure to return an expected status code */
597 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
599 /* Callers expect this instead */
600 Status
= STATUS_DLL_NOT_FOUND
;
603 /* Return an empty section handle */
604 *SectionHandle
= NULL
;
611 /* Use the handle we already have */
612 FileHandle
= DllHandle
;
615 /* Create a section for the DLL */
616 Status
= NtCreateSection(SectionHandle
,
617 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
618 SECTION_MAP_WRITE
| SECTION_QUERY
,
625 /* If mapping failed, raise a hard error */
626 if (!NT_SUCCESS(Status
))
628 /* Forget the handle */
629 *SectionHandle
= NULL
;
631 /* Give the DLL name */
632 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
634 /* Raise the error */
635 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
642 /* Increment the error count */
643 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
646 /* Check for Safer restrictions */
647 if (DllCharacteristics
&&
648 !(*DllCharacteristics
& IMAGE_FILE_SYSTEM
))
650 /* Make sure it's executable */
651 Status
= ZwQuerySection(*SectionHandle
,
652 SectionImageInformation
,
654 sizeof(SECTION_IMAGE_INFORMATION
),
656 if (NT_SUCCESS(Status
))
658 /* Bypass the check for .NET images */
659 if (!(SectionImageInfo
.LoaderFlags
& IMAGE_LOADER_FLAGS_COMPLUS
))
661 /* Check with Safer */
662 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
663 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
665 /* Show debug message */
668 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
672 /* Failure case, close section handle */
673 NtClose(*SectionHandle
);
674 *SectionHandle
= NULL
;
680 /* Failure case, close section handle */
681 NtClose(*SectionHandle
);
682 *SectionHandle
= NULL
;
686 /* Close the file handle, we don't need it */
693 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
696 LdrpResolveDllName(PWSTR DllPath
,
698 PUNICODE_STRING FullDllName
,
699 PUNICODE_STRING BaseDllName
)
701 PWCHAR NameBuffer
, p1
, p2
= 0;
705 /* Allocate space for full DLL name */
706 FullDllName
->Buffer
= RtlAllocateHeap(LdrpHeap
, 0, BufSize
+ sizeof(UNICODE_NULL
));
707 if (!FullDllName
->Buffer
) return FALSE
;
709 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
714 &BaseDllName
->Buffer
);
716 if (!Length
|| Length
> BufSize
)
720 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
721 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
724 LdrpFreeUnicodeString(FullDllName
);
728 /* Construct full DLL name */
729 FullDllName
->Length
= Length
;
730 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
732 /* Allocate a new buffer */
733 NameBuffer
= RtlAllocateHeap(LdrpHeap
, 0, FullDllName
->MaximumLength
);
736 RtlFreeHeap(LdrpHeap
, 0, FullDllName
->Buffer
);
740 /* Copy over the contents from the previous one and free it */
741 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
742 RtlFreeHeap(LdrpHeap
, 0, FullDllName
->Buffer
);
743 FullDllName
->Buffer
= NameBuffer
;
745 /* Find last backslash */
746 p1
= FullDllName
->Buffer
;
755 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
763 /* Calculate remaining length */
766 /* Construct base DLL name */
767 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
768 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
769 BaseDllName
->Buffer
= RtlAllocateHeap(LdrpHeap
, 0, BaseDllName
->MaximumLength
);
771 if (!BaseDllName
->Buffer
)
773 RtlFreeHeap(LdrpHeap
, 0, NameBuffer
);
777 /* Copy base dll name to the new buffer */
778 RtlMoveMemory(BaseDllName
->Buffer
,
780 BaseDllName
->Length
);
782 /* Null-terminate the string */
783 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
790 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase
)
792 PIMAGE_NT_HEADERS NtHeaders
;
793 ULONG_PTR EntryPoint
= 0;
795 /* Get entry point offset from NT headers */
796 NtHeaders
= RtlImageNtHeader(ImageBase
);
800 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
801 if (EntryPoint
) EntryPoint
+= (ULONG_PTR
)ImageBase
;
804 /* Return calculated pointer (or zero in case of failure) */
805 return (PVOID
)EntryPoint
;
808 /* NOTE: This function is partially missing SxS */
811 LdrpCheckForKnownDll(PWSTR DllName
,
812 PUNICODE_STRING FullDllName
,
813 PUNICODE_STRING BaseDllName
,
814 HANDLE
*SectionHandle
)
816 OBJECT_ATTRIBUTES ObjectAttributes
;
817 HANDLE Section
= NULL
;
818 UNICODE_STRING DllNameUnic
;
823 /* Zero initialize provided parameters */
824 if (SectionHandle
) *SectionHandle
= 0;
828 FullDllName
->Length
= 0;
829 FullDllName
->MaximumLength
= 0;
830 FullDllName
->Buffer
= NULL
;
835 BaseDllName
->Length
= 0;
836 BaseDllName
->MaximumLength
= 0;
837 BaseDllName
->Buffer
= NULL
;
840 /* If any of these three params are missing then fail */
841 if (!SectionHandle
|| !FullDllName
|| !BaseDllName
)
842 return STATUS_INVALID_PARAMETER
;
844 /* Check the Loader Lock */
845 LdrpEnsureLoaderLockIsHeld();
847 /* Upgrade DllName to a unicode string */
848 RtlInitUnicodeString(&DllNameUnic
, DllName
);
850 /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
852 /* Get the activation context */
853 Status
= RtlFindActivationContextSectionString(0,
855 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
859 /* Check if it's a SxS or not */
860 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
861 Status
== STATUS_SXS_KEY_NOT_FOUND
)
863 /* NOTE: Here it's beneficial to allocate one big unicode string
864 using LdrpAllocateUnicodeString instead of fragmenting the heap
865 with two allocations as it's done now. */
867 /* Set up BaseDllName */
868 BaseDllName
->Length
= DllNameUnic
.Length
;
869 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
870 BaseDllName
->Buffer
= RtlAllocateHeap(LdrpHeap
,
872 DllNameUnic
.MaximumLength
);
873 if (!BaseDllName
->Buffer
)
875 Status
= STATUS_NO_MEMORY
;
879 /* Copy the contents there */
880 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
882 /* Set up FullDllName */
883 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
884 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
885 FullDllName
->Buffer
= RtlAllocateHeap(LdrpHeap
, 0, FullDllName
->MaximumLength
);
886 if (!FullDllName
->Buffer
)
888 Status
= STATUS_NO_MEMORY
;
892 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
894 /* Put a slash there */
895 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
900 /* Set up DllNameUnic for a relative path */
901 DllNameUnic
.Buffer
= (PWSTR
)p1
;
902 DllNameUnic
.Length
= BaseDllName
->Length
;
903 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
905 /* Copy the contents */
906 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
908 /* There are all names, init attributes and open the section */
909 InitializeObjectAttributes(&ObjectAttributes
,
911 OBJ_CASE_INSENSITIVE
,
912 LdrpKnownDllObjectDirectory
,
915 Status
= NtOpenSection(&Section
,
916 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
918 if (!NT_SUCCESS(Status
))
920 /* Clear status in case it was just not found */
921 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) Status
= STATUS_SUCCESS
;
925 /* Pass section handle to the caller and return success */
926 *SectionHandle
= Section
;
927 return STATUS_SUCCESS
;
931 /* Close section object if it was opened */
932 if (Section
) NtClose(Section
);
934 /* Free string resources */
935 if (BaseDllName
->Buffer
) RtlFreeHeap(LdrpHeap
, 0, BaseDllName
->Buffer
);
936 if (FullDllName
->Buffer
) RtlFreeHeap(LdrpHeap
, 0, FullDllName
->Buffer
);
944 LdrpSetProtection(PVOID ViewBase
,
947 PIMAGE_NT_HEADERS NtHeaders
;
948 PIMAGE_SECTION_HEADER Section
;
952 ULONG NewProtection
, OldProtection
, i
;
954 /* Get the NT headers */
955 NtHeaders
= RtlImageNtHeader(ViewBase
);
956 if (!NtHeaders
) return STATUS_INVALID_IMAGE_FORMAT
;
958 /* Compute address of the first section header */
959 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
961 /* Go through all sections */
962 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
964 /* Check for read-only non-zero section */
965 if ((Section
->SizeOfRawData
) &&
966 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
968 /* Check if we are setting or restoring protection */
971 /* Set it to either EXECUTE or READONLY */
972 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
974 NewProtection
= PAGE_EXECUTE
;
978 NewProtection
= PAGE_READONLY
;
981 /* Add PAGE_NOCACHE if needed */
982 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
984 NewProtection
|= PAGE_NOCACHE
;
989 /* Enable write access */
990 NewProtection
= PAGE_READWRITE
;
993 /* Get the section VA */
994 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
995 SectionSize
= Section
->SizeOfRawData
;
999 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
1004 if (!NT_SUCCESS(Status
)) return Status
;
1008 /* Move to the next section */
1012 /* Flush instruction cache if necessary */
1013 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
1014 return STATUS_SUCCESS
;
1017 /* NOTE: Not yet reviewed */
1020 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
1022 IN PWSTR DllName OPTIONAL
,
1023 IN PULONG DllCharacteristics
,
1025 IN BOOLEAN Redirect
,
1026 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
1028 PTEB Teb
= NtCurrentTeb();
1029 PPEB Peb
= NtCurrentPeb();
1030 PWCHAR p1
= DllName
;
1032 BOOLEAN KnownDll
= FALSE
;
1033 UNICODE_STRING FullDllName
, BaseDllName
;
1034 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
1035 UNICODE_STRING NtPathDllName
;
1036 ULONG_PTR HardErrorParameters
[2];
1037 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
1039 SIZE_T ViewSize
= 0;
1040 PVOID ViewBase
= NULL
;
1041 PVOID ArbitraryUserPointer
;
1042 PIMAGE_NT_HEADERS NtHeaders
;
1043 NTSTATUS HardErrorStatus
, Status
;
1044 BOOLEAN OverlapDllFound
= FALSE
;
1045 ULONG_PTR ImageBase
, ImageEnd
;
1046 PLIST_ENTRY ListHead
, NextEntry
;
1047 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
1048 ULONG_PTR CandidateBase
, CandidateEnd
;
1049 UNICODE_STRING OverlapDll
;
1050 BOOLEAN RelocatableDll
= TRUE
;
1051 UNICODE_STRING IllegalDll
;
1053 ULONG RelocDataSize
= 0;
1055 // FIXME: AppCompat stuff is missing
1059 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
1061 SearchPath
? SearchPath
: L
"");
1064 /* Check if we have a known dll directory */
1065 if (LdrpKnownDllObjectDirectory
&& Redirect
== FALSE
)
1067 /* Check if the path is full */
1071 if (TempChar
== '\\' || TempChar
== '/' )
1073 /* Complete path, don't do Known Dll lookup */
1078 /* Try to find a Known DLL */
1079 Status
= LdrpCheckForKnownDll(DllName
,
1084 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_DLL_NOT_FOUND
))
1087 DbgPrintEx(DPFLTR_LDR_ID
,
1089 "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
1100 /* Check if the Known DLL Check returned something */
1103 /* It didn't, so try to resolve the name now */
1104 if (LdrpResolveDllName(SearchPath
,
1109 /* Got a name, display a message */
1112 DPRINT1("LDR: Loading (%s) %wZ\n",
1113 Static
? "STATIC" : "DYNAMIC",
1117 /* Convert to NT Name */
1118 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1123 /* Path was invalid */
1124 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1127 /* Create a section for this dLL */
1128 Status
= LdrpCreateDllSection(&NtPathDllName
,
1133 /* Free the NT Name */
1134 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
1137 if (!NT_SUCCESS(Status
))
1139 /* Free the name strings and return */
1140 LdrpFreeUnicodeString(&FullDllName
);
1141 LdrpFreeUnicodeString(&BaseDllName
);
1147 /* We couldn't resolve the name, is this a static load? */
1151 * This is BAD! Static loads are CRITICAL. Bugcheck!
1152 * Initialize the strings for the error
1154 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
1155 RtlInitUnicodeString(&HardErrorDllPath
,
1156 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
1158 /* Set them as error parameters */
1159 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
1160 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
1162 /* Raise the hard error */
1163 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
1166 HardErrorParameters
,
1170 /* We're back, where we initializing? */
1171 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1174 /* Return failure */
1175 return STATUS_DLL_NOT_FOUND
;
1180 /* We have a section handle, so this is a known dll */
1184 /* Stuff the image name in the TIB, for the debugger */
1185 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1186 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1191 Status
= NtMapViewOfSection(SectionHandle
,
1203 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1205 /* Fail if we couldn't map it */
1206 if (!NT_SUCCESS(Status
))
1208 /* Close and return */
1209 NtClose(SectionHandle
);
1213 /* Get the NT Header */
1214 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
1216 /* Invalid image, unmap, close handle and fail */
1217 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1218 NtClose(SectionHandle
);
1219 return STATUS_INVALID_IMAGE_FORMAT
;
1222 // FIXME: .NET support is missing
1224 /* Allocate an entry */
1225 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
1227 /* Invalid image, unmap, close handle and fail */
1228 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1229 NtClose(SectionHandle
);
1230 return STATUS_NO_MEMORY
;
1233 /* Setup the entry */
1234 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
1235 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
1236 LdrEntry
->LoadCount
= 0;
1237 LdrEntry
->FullDllName
= FullDllName
;
1238 LdrEntry
->BaseDllName
= BaseDllName
;
1239 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
1241 /* Show debug message */
1244 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
1249 /* Insert this entry */
1250 LdrpInsertMemoryTableEntry(LdrEntry
);
1252 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
1254 /* Check for invalid CPU Image */
1255 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1257 /* Load our header */
1258 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1260 /* Assume defaults if we don't have to run the Hard Error path */
1261 HardErrorStatus
= STATUS_SUCCESS
;
1262 Response
= ResponseCancel
;
1264 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1265 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1267 /* Reset the entrypoint, save our Dll Name */
1268 LdrEntry
->EntryPoint
= 0;
1269 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1271 /* Raise the error */
1272 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1275 HardErrorParameters
,
1280 /* Check if the user pressed cancel */
1281 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1283 /* Remove the DLL from the lists */
1284 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1285 RemoveEntryList(&LdrEntry
->InMemoryOrderLinks
);
1286 RemoveEntryList(&LdrEntry
->HashLinks
);
1288 /* Remove the LDR Entry */
1289 RtlFreeHeap(LdrpHeap
, 0, LdrEntry
);
1291 /* Unmap and close section */
1292 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1293 NtClose(SectionHandle
);
1295 /* Did we do a hard error? */
1296 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1298 /* Yup, so increase fatal error count if we are initializing */
1299 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1302 /* Return failure */
1303 return STATUS_INVALID_IMAGE_FORMAT
;
1308 /* The image was valid. Is it a DLL? */
1309 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1311 /* Set the DLL Flag */
1312 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1315 /* If we're not a DLL, clear the entrypoint */
1316 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1318 LdrEntry
->EntryPoint
= 0;
1322 /* Return it for the caller */
1323 *DataTableEntry
= LdrEntry
;
1325 /* Check if we loaded somewhere else */
1326 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1328 /* Write the flag */
1329 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1331 /* Find our region */
1332 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1333 ImageEnd
= ImageBase
+ ViewSize
;
1335 DPRINT("LDR: LdrpMapDll Relocating Image Name %ws (%p-%p -> %p)\n", DllName
, (PVOID
)ImageBase
, (PVOID
)ImageEnd
, ViewBase
);
1337 /* Scan all the modules */
1338 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1339 NextEntry
= ListHead
->Flink
;
1340 while (NextEntry
!= ListHead
)
1343 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1344 LDR_DATA_TABLE_ENTRY
,
1346 NextEntry
= NextEntry
->Flink
;
1348 /* Get the entry's bounds */
1349 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1350 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1352 /* Make sure this entry isn't unloading */
1353 if (!CandidateEntry
->InMemoryOrderLinks
.Flink
) continue;
1355 /* Check if our regions are colliding */
1356 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1357 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1358 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1360 /* Found who is overlapping */
1361 OverlapDllFound
= TRUE
;
1362 OverlapDll
= CandidateEntry
->FullDllName
;
1367 /* Check if we found the DLL overlapping with us */
1368 if (!OverlapDllFound
)
1370 /* It's not another DLL, it's memory already here */
1371 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1374 DPRINT("Overlapping DLL: %wZ\n", &OverlapDll
);
1376 /* Are we dealing with a DLL? */
1377 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1379 /* Check if relocs were stripped */
1380 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1382 /* Get the relocation data */
1383 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1385 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1388 /* Does the DLL not have any? */
1389 if (!RelocData
&& !RelocDataSize
)
1391 /* We'll allow this and simply continue */
1396 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1397 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1398 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1400 /* Can't relocate user32 */
1401 RelocatableDll
= FALSE
;
1405 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1406 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1408 /* Can't relocate kernel32 */
1409 RelocatableDll
= FALSE
;
1413 /* Known DLLs are not allowed to be relocated */
1414 if (KnownDll
&& !RelocatableDll
)
1416 /* Setup for hard error */
1417 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1418 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1420 /* Raise the error */
1421 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1424 HardErrorParameters
,
1428 /* If initializing, increase the error count */
1429 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1431 /* Don't do relocation */
1432 Status
= STATUS_CONFLICTING_ADDRESSES
;
1436 /* Change the protection to prepare for relocation */
1437 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1439 /* Make sure we changed the protection */
1440 if (NT_SUCCESS(Status
))
1442 /* Do the relocation */
1443 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1444 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1446 if (NT_SUCCESS(Status
))
1448 /* Stuff the image name in the TIB, for the debugger */
1449 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1450 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1453 Status
= NtMapViewOfSection(SectionHandle
,
1465 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1467 /* Return the protection */
1468 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1472 /* Handle any kind of failure */
1473 if (!NT_SUCCESS(Status
))
1475 /* Remove it from the lists */
1476 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1477 RemoveEntryList(&LdrEntry
->InMemoryOrderLinks
);
1478 RemoveEntryList(&LdrEntry
->HashLinks
);
1480 /* Unmap it, clear the entry */
1481 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1485 /* Show debug message */
1488 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1489 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1495 /* Not a DLL, or no relocation needed */
1496 Status
= STATUS_SUCCESS
;
1498 /* Stuff the image name in the TIB, for the debugger */
1499 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1500 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1503 Status
= NtMapViewOfSection(SectionHandle
,
1515 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1517 /* Show debug message */
1520 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1525 // FIXME: LdrpCheckCorImage() is missing
1527 /* Check if this is an SMP Machine and a DLL */
1528 if ((LdrpNumberOfProcessors
> 1) &&
1529 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1531 /* Validate the image for MP */
1532 LdrpValidateImageForMp(LdrEntry
);
1535 // FIXME: LdrpCorUnloadImage() is missing
1537 /* Close section and return status */
1538 NtClose(SectionHandle
);
1542 PLDR_DATA_TABLE_ENTRY
1544 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1546 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1547 PIMAGE_NT_HEADERS NtHeader
;
1549 /* Make sure the header is valid */
1550 NtHeader
= RtlImageNtHeader(BaseAddress
);
1551 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1555 /* Allocate an entry */
1556 LdrEntry
= RtlAllocateHeap(LdrpHeap
,
1558 sizeof(LDR_DATA_TABLE_ENTRY
));
1560 /* Make sure we got one */
1564 LdrEntry
->DllBase
= BaseAddress
;
1565 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1566 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1567 LdrEntry
->PatchInformation
= NULL
;
1571 /* Return the entry */
1577 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1579 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1582 /* Insert into hash table */
1583 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1584 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1586 /* Insert into other lists */
1587 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1588 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderLinks
);
1593 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry
)
1596 ASSERT(Entry
!= NULL
);
1598 /* Release the activation context if it exists and wasn't already released */
1599 if ((Entry
->EntryPointActivationContext
) &&
1600 (Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
))
1602 /* Mark it as invalid */
1603 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1604 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1607 /* Release the full dll name string */
1608 if (Entry
->FullDllName
.Buffer
) LdrpFreeUnicodeString(&Entry
->FullDllName
);
1610 /* Finally free the entry's memory */
1611 RtlFreeHeap(LdrpHeap
, 0, Entry
);
1616 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1617 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1619 PLDR_DATA_TABLE_ENTRY Current
;
1620 PLIST_ENTRY ListHead
, Next
;
1622 /* Check the cache first */
1623 if ((LdrpLoadedDllHandleCache
) &&
1624 (LdrpLoadedDllHandleCache
->DllBase
== Base
))
1626 /* We got lucky, return the cached entry */
1627 *LdrEntry
= LdrpLoadedDllHandleCache
;
1631 /* Time for a lookup */
1632 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1633 Next
= ListHead
->Flink
;
1634 while (Next
!= ListHead
)
1636 /* Get the current entry */
1637 Current
= CONTAINING_RECORD(Next
,
1638 LDR_DATA_TABLE_ENTRY
,
1641 /* Make sure it's not unloading and check for a match */
1642 if ((Current
->InMemoryOrderLinks
.Flink
) && (Base
== Current
->DllBase
))
1645 LdrpLoadedDllHandleCache
= Current
;
1648 *LdrEntry
= Current
;
1652 /* Move to the next one */
1662 LdrpResolveFullName(IN PUNICODE_STRING OriginalName
,
1663 IN PUNICODE_STRING PathName
,
1664 IN PUNICODE_STRING FullPathName
,
1665 IN PUNICODE_STRING
*ExpandedName
)
1667 NTSTATUS Status
= STATUS_SUCCESS
;
1668 // RTL_PATH_TYPE PathType;
1669 // BOOLEAN InvalidName;
1672 /* Display debug output if snaps are on */
1675 DbgPrintEx(DPFLTR_LDR_ID
,
1677 "LDR: %s - Expanding full name of %wZ\n",
1682 /* FIXME: Lock the PEB */
1683 //RtlEnterCriticalSection(&FastPebLock);
1685 /* Get the path name */
1686 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1695 if (!(Length
) || (Length
> UNICODE_STRING_MAX_BYTES
))
1698 Status
= STATUS_NAME_TOO_LONG
;
1702 /* Check if the length hasn't changed */
1703 if (Length
<= PathName
->Length
)
1705 /* Return the same thing */
1706 *ExpandedName
= PathName
;
1707 PathName
->Length
= (USHORT
)Length
;
1712 ASSERT(Length
>= sizeof(WCHAR
));
1714 /* Allocate a string */
1715 Status
= LdrpAllocateUnicodeString(FullPathName
, Length
- sizeof(WCHAR
));
1716 if (!NT_SUCCESS(Status
)) goto Quickie
;
1718 /* Now get the full path again */
1720 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1721 FullPathName
->Length
,
1722 FullPathName
->Buffer
,
1729 if (!(Length
) || (Length
> FullPathName
->Length
))
1732 LdrpFreeUnicodeString(FullPathName
);
1733 Status
= STATUS_NAME_TOO_LONG
;
1737 /* Return the expanded name */
1738 *ExpandedName
= FullPathName
;
1739 FullPathName
->Length
= (USHORT
)Length
;
1743 /* FIXME: Unlock the PEB */
1744 //RtlLeaveCriticalSection(&FastPebLock);
1746 /* Display debug output if snaps are on */
1749 /* Check which output to use -- failure or success */
1750 if (NT_SUCCESS(Status
))
1752 DbgPrintEx(DPFLTR_LDR_ID
,
1754 "LDR: %s - Expanded to %wZ\n",
1760 DbgPrintEx(DPFLTR_LDR_ID
,
1762 "LDR: %s - Failed to expand %wZ; 0x%08x\n",
1769 /* If we failed, return NULL */
1770 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1778 LdrpSearchPath(IN PWCHAR
*SearchPath
,
1780 IN PUNICODE_STRING PathName
,
1781 IN PUNICODE_STRING FullPathName
,
1782 IN PUNICODE_STRING
*ExpandedName
)
1784 BOOLEAN TryAgain
= FALSE
;
1785 PWCHAR ActualSearchPath
= *SearchPath
;
1786 UNICODE_STRING TestName
;
1788 PWCHAR Buffer
, BufEnd
= NULL
;
1793 /* Check if we don't have a search path */
1794 if (!ActualSearchPath
) *SearchPath
= LdrpDefaultPath
.Buffer
;
1796 /* Display debug output if snaps are on */
1799 DbgPrintEx(DPFLTR_LDR_ID
,
1801 "LDR: %s - Looking for %ws in %ws\n",
1807 /* Check if we're dealing with a relative path */
1808 if (RtlDetermineDosPathNameType_U(DllName
) != RtlPathTypeRelative
)
1810 /* Good, we're not. Create the name string */
1811 Status
= RtlInitUnicodeStringEx(&TestName
, DllName
);
1812 if (!NT_SUCCESS(Status
)) goto Quickie
;
1814 /* Make sure it exists */
1816 if (!RtlDoesFileExists_UstrEx(&TestName
, TRUE
))
1818 /* It doesn't, fail */
1819 Status
= STATUS_DLL_NOT_FOUND
;
1824 /* Resolve the full name */
1825 Status
= LdrpResolveFullName(&TestName
,
1832 /* FIXME: Handle relative case semicolon-lookup here */
1834 /* Calculate length */
1835 Length
+= (ULONG
)wcslen(DllName
) + 1;
1836 if (Length
> UNICODE_STRING_MAX_CHARS
)
1838 /* Too long, fail */
1839 Status
= STATUS_NAME_TOO_LONG
;
1843 /* Allocate buffer */
1844 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
1848 Status
= STATUS_NO_MEMORY
;
1852 /* FIXME: Setup TestName here */
1853 Status
= STATUS_NOT_FOUND
;
1860 p
= *ActualSearchPath
;
1861 if (!(p
) || (p
== ';'))
1863 /* FIXME: We don't have a character, or is a semicolon.*/
1865 /* Display debug output if snaps are on */
1868 DbgPrintEx(DPFLTR_LDR_ID
,
1870 "LDR: %s - Looking for %ws\n",
1876 TestName
.Length
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
);
1878 ASSERT(TestName
.Length
< TestName
.MaximumLength
);
1881 /* Check if the file exists */
1883 if (RtlDoesFileExists_UstrEx(&TestName
, FALSE
))
1886 /* It does. Reallocate the buffer */
1887 TestName
.MaximumLength
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
) + sizeof(WCHAR
);
1888 TestName
.Buffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
1891 TestName
.MaximumLength
);
1892 if (!TestName
.Buffer
)
1894 /* Keep the old one */
1895 TestName
.Buffer
= Buffer
;
1900 Buffer
= TestName
.Buffer
;
1903 /* Make sure we have a buffer at least */
1904 ASSERT(TestName
.Buffer
);
1906 /* Resolve the name */
1907 *SearchPath
= ActualSearchPath
++;
1908 Status
= LdrpResolveFullName(&TestName
,
1915 /* Update buffer end */
1918 /* Update string position */
1919 //pp = ActualSearchPath++;
1923 /* Otherwise, write the character */
1928 /* Check if the string is empty, meaning we're done */
1929 if (!(*ActualSearchPath
)) TryAgain
= TRUE
;
1931 /* Advance in the string */
1933 } while (!TryAgain
);
1935 /* Check if we had a buffer and free it */
1936 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1939 /* Check if we got here through failure */
1940 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1942 /* Display debug output if snaps are on */
1945 /* Check which output to use -- failure or success */
1946 if (NT_SUCCESS(Status
))
1948 DbgPrintEx(DPFLTR_LDR_ID
,
1950 "LDR: %s - Returning %wZ\n",
1956 DbgPrintEx(DPFLTR_LDR_ID
,
1958 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1971 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1974 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1975 IN PUNICODE_STRING DllName
,
1977 IN BOOLEAN RedirectedDll
,
1978 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1981 PLIST_ENTRY ListHead
, ListEntry
;
1982 PLDR_DATA_TABLE_ENTRY CurEntry
;
1983 BOOLEAN FullPath
= FALSE
;
1986 UNICODE_STRING FullDllName
, NtPathName
;
1988 OBJECT_ATTRIBUTES ObjectAttributes
;
1990 HANDLE FileHandle
, SectionHandle
;
1991 IO_STATUS_BLOCK Iosb
;
1992 PVOID ViewBase
= NULL
;
1993 SIZE_T ViewSize
= 0;
1994 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1995 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"", DllName
, Flag
, RedirectedDll
, LdrEntry
);
1997 /* Check if a dll name was provided */
1998 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
2000 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
2001 /* FIXME: Warning, code does not support redirection at all */
2003 /* Look in the hash table if flag was set */
2005 if (Flag
/* the second check is a hack */ && !RedirectedDll
)
2007 /* FIXME: if we get redirected dll it means that we also get a full path so we need to find its filename for the hash lookup */
2009 /* Get hash index */
2010 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
2012 /* Traverse that list */
2013 ListHead
= &LdrpHashTable
[HashIndex
];
2014 ListEntry
= ListHead
->Flink
;
2015 while (ListEntry
!= ListHead
)
2017 /* Get the current entry */
2018 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2020 /* Check base name of that module */
2021 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
2023 /* It matches, return it */
2024 *LdrEntry
= CurEntry
;
2028 /* Advance to the next entry */
2029 ListEntry
= ListEntry
->Flink
;
2032 /* Module was not found, return failure */
2036 /* Check if this is a redirected DLL */
2039 /* Redirected dlls already have a full path */
2041 FullDllName
= *DllName
;
2045 /* Check if there is a full path in this DLL */
2046 wc
= DllName
->Buffer
;
2049 /* Check for a slash in the current position*/
2050 if ((*wc
== L
'\\') || (*wc
== L
'/'))
2052 /* Found the slash, so dll name contains path */
2055 /* Setup full dll name string */
2056 FullDllName
.Buffer
= NameBuf
;
2058 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2059 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
2062 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
2066 /* Check if that was successful */
2067 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
2071 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n",
2076 /* Full dll name is found */
2077 FullDllName
.Length
= Length
;
2078 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
2086 /* Go check the hash table */
2093 /* FIXME: Warning, activation context missing */
2094 DPRINT("Warning, activation context missing\n");
2096 /* NOTE: From here on down, everything looks good */
2098 /* Loop the module list */
2099 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2100 ListEntry
= ListHead
->Flink
;
2101 while (ListEntry
!= ListHead
)
2103 /* Get the current entry and advance to the next one */
2104 CurEntry
= CONTAINING_RECORD(ListEntry
,
2105 LDR_DATA_TABLE_ENTRY
,
2107 ListEntry
= ListEntry
->Flink
;
2109 /* Check if it's being unloaded */
2110 if (!CurEntry
->InMemoryOrderLinks
.Flink
) continue;
2112 /* Check if name matches */
2113 if (RtlEqualUnicodeString(&FullDllName
,
2114 &CurEntry
->FullDllName
,
2118 *LdrEntry
= CurEntry
;
2123 /* Convert given path to NT path */
2124 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
2129 /* Fail if conversion failed */
2133 /* Initialize object attributes and open it */
2134 InitializeObjectAttributes(&ObjectAttributes
,
2136 OBJ_CASE_INSENSITIVE
,
2139 Status
= NtOpenFile(&FileHandle
,
2140 SYNCHRONIZE
| FILE_EXECUTE
,
2143 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2144 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
2146 /* Free NT path name */
2147 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
2149 /* If opening the file failed - return failure */
2150 if (!NT_SUCCESS(Status
)) return FALSE
;
2152 /* Create a section for this file */
2153 Status
= NtCreateSection(&SectionHandle
,
2155 SECTION_MAP_EXECUTE
|
2163 /* Close file handle */
2164 NtClose(FileHandle
);
2166 /* If creating section failed - return failure */
2167 if (!NT_SUCCESS(Status
)) return FALSE
;
2169 /* Map view of this section */
2170 Status
= ZwMapViewOfSection(SectionHandle
,
2181 /* Close section handle */
2182 NtClose(SectionHandle
);
2184 /* If section mapping failed - return failure */
2185 if (!NT_SUCCESS(Status
)) return FALSE
;
2187 /* Get pointer to the NT header of this section */
2188 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
2189 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
2191 /* Unmap the section and fail */
2192 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2196 /* Go through the list of modules again */
2197 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2198 ListEntry
= ListHead
->Flink
;
2199 while (ListEntry
!= ListHead
)
2201 /* Get the current entry and advance to the next one */
2202 CurEntry
= CONTAINING_RECORD(ListEntry
,
2203 LDR_DATA_TABLE_ENTRY
,
2205 ListEntry
= ListEntry
->Flink
;
2207 /* Check if it's in the process of being unloaded */
2208 if (!CurEntry
->InMemoryOrderLinks
.Flink
) continue;
2210 /* The header is untrusted, use SEH */
2213 /* Check if timedate stamp and sizes match */
2214 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
2215 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
2217 /* Time, date and size match. Let's compare their headers */
2218 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
2219 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
2221 /* Headers match too! Finally ask the kernel to compare mapped files */
2222 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
2223 if (NT_SUCCESS(Status
))
2225 /* This is our entry!, unmap and return success */
2226 *LdrEntry
= CurEntry
;
2227 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2228 _SEH2_YIELD(return TRUE
;)
2233 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
2240 /* Unmap the section and fail */
2241 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2247 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
2248 IN PANSI_STRING Name
,
2250 OUT PVOID
*ProcedureAddress
,
2251 IN BOOLEAN ExecuteInit
)
2253 NTSTATUS Status
= STATUS_SUCCESS
;
2254 UCHAR ImportBuffer
[64];
2255 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2256 IMAGE_THUNK_DATA Thunk
;
2258 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
2259 PIMAGE_EXPORT_DIRECTORY ExportDir
;
2260 ULONG ExportDirSize
, Length
;
2263 /* Show debug message */
2264 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
2266 /* Check if we got a name */
2269 /* Show debug message */
2270 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
2272 /* Make sure it's not too long */
2273 Length
= Name
->Length
+
2275 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
2276 if (Length
> UNICODE_STRING_MAX_BYTES
)
2278 /* Won't have enough space to add the hint */
2279 return STATUS_NAME_TOO_LONG
;
2282 /* Check if our buffer is large enough */
2283 if (Length
> sizeof(ImportBuffer
))
2285 /* Allocate from heap, plus 2 bytes for the Hint */
2286 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
2292 /* Use our internal buffer */
2293 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
2296 /* Clear the hint */
2297 ImportName
->Hint
= 0;
2299 /* Copy the name and null-terminate it */
2300 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
2301 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
2303 /* Clear the high bit */
2304 ImageBase
= ImportName
;
2305 Thunk
.u1
.AddressOfData
= 0;
2309 /* Do it by ordinal */
2312 /* Show debug message */
2313 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
2315 /* Make sure an ordinal was given */
2319 DPRINT1("No ordinal and no name\n");
2320 return STATUS_INVALID_PARAMETER
;
2323 /* Set the original flag in the thunk */
2324 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
2327 /* Acquire lock unless we are initting */
2328 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2332 /* Try to find the loaded DLL */
2333 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2336 DPRINT1("Invalid base address %p\n", BaseAddress
);
2337 Status
= STATUS_DLL_NOT_FOUND
;
2338 _SEH2_YIELD(goto Quickie
;)
2341 /* Get the pointer to the export directory */
2342 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2344 IMAGE_DIRECTORY_ENTRY_EXPORT
,
2349 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n",
2350 &LdrEntry
->BaseDllName
, Name
, BaseAddress
, LdrEntry
->DllBase
);
2351 Status
= STATUS_PROCEDURE_NOT_FOUND
;
2352 _SEH2_YIELD(goto Quickie
;)
2355 /* Now get the thunk */
2356 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
2365 /* Finally, see if we're supposed to run the init routines */
2366 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
2369 * It's possible a forwarded entry had us load the DLL. In that case,
2370 * then we will call its DllMain. Use the last loaded DLL for this.
2372 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
2373 LdrEntry
= CONTAINING_RECORD(Entry
,
2374 LDR_DATA_TABLE_ENTRY
,
2375 InInitializationOrderLinks
);
2377 /* Make sure we didn't process it yet*/
2378 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2380 /* Call the init routine */
2383 Status
= LdrpRunInitializeRoutines(NULL
);
2385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2387 /* Get the exception code */
2388 Status
= _SEH2_GetExceptionCode();
2394 /* Make sure we're OK till here */
2395 if (NT_SUCCESS(Status
))
2397 /* Return the address */
2398 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
2401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2403 /* Just ignore exceptions */
2409 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
2411 /* We allocated from heap, free it */
2412 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
2415 /* Release the CS if we entered it */
2416 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2424 LdrpLoadDll(IN BOOLEAN Redirected
,
2425 IN PWSTR DllPath OPTIONAL
,
2426 IN PULONG DllCharacteristics OPTIONAL
,
2427 IN PUNICODE_STRING DllName
,
2428 OUT PVOID
*BaseAddress
,
2429 IN BOOLEAN CallInit
)
2431 PPEB Peb
= NtCurrentPeb();
2432 NTSTATUS Status
= STATUS_SUCCESS
;
2434 BOOLEAN GotExtension
;
2436 WCHAR NameBuffer
[MAX_PATH
+ 6];
2437 UNICODE_STRING RawDllName
;
2438 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2439 BOOLEAN InInit
= LdrpInLdrInit
;
2441 /* Save the Raw DLL Name */
2442 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
2443 RtlInitEmptyUnicodeString(&RawDllName
, NameBuffer
, sizeof(NameBuffer
));
2444 RtlCopyUnicodeString(&RawDllName
, DllName
);
2446 /* Find the extension, if present */
2447 p
= DllName
->Buffer
+ DllName
->Length
/ sizeof(WCHAR
) - 1;
2448 GotExtension
= FALSE
;
2449 while (p
>= DllName
->Buffer
)
2454 GotExtension
= TRUE
;
2457 else if (c
== L
'\\')
2463 /* If no extension was found, add the default extension */
2466 /* Check that we have space to add one */
2467 if ((DllName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
2470 /* No space to add the extension */
2471 DbgPrintEx(DPFLTR_LDR_ID
,
2473 "LDR: %s - Dll name missing extension; with extension "
2474 "added the name is too long\n"
2475 " DllName: (@ %p) \"%wZ\"\n"
2476 " DllName->Length: %u\n",
2481 return STATUS_NAME_TOO_LONG
;
2484 /* Add it. Needs to be null terminated, thus the length check above */
2485 (VOID
)RtlAppendUnicodeStringToString(&RawDllName
,
2486 &LdrApiDefaultExtension
);
2489 /* Check for init flag and acquire lock */
2490 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2494 /* Show debug message */
2497 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
2499 DllPath
? DllPath
: L
"");
2502 /* Check if the DLL is already loaded */
2503 if (!LdrpCheckForLoadedDll(DllPath
,
2510 Status
= LdrpMapDll(DllPath
,
2517 if (!NT_SUCCESS(Status
))
2520 /* FIXME: Need to mark the DLL range for the stack DB */
2521 //RtlpStkMarkDllRange(LdrEntry);
2523 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2524 if ((DllCharacteristics
) &&
2525 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
2527 /* This is not a DLL, so remove such data */
2528 LdrEntry
->EntryPoint
= NULL
;
2529 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
2532 /* Make sure it's a DLL */
2533 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2535 /* Check if this is a .NET Image */
2536 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
2538 /* Walk the Import Descriptor */
2539 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
2542 /* Update load count, unless it's locked */
2543 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2544 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2546 /* Check if we failed */
2547 if (!NT_SUCCESS(Status
))
2549 /* Clear entrypoint, and insert into list */
2550 LdrEntry
->EntryPoint
= NULL
;
2551 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2552 &LdrEntry
->InInitializationOrderLinks
);
2554 /* Cancel the load */
2555 LdrpClearLoadInProgress();
2557 /* Unload the DLL */
2560 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2561 "import descriptors\n",
2565 LdrUnloadDll(LdrEntry
->DllBase
);
2567 /* Return the error */
2571 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2573 /* Increase load count */
2574 LdrEntry
->LoadCount
++;
2577 /* Insert it into the list */
2578 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2579 &LdrEntry
->InInitializationOrderLinks
);
2581 /* If we have to run the entrypoint, make sure the DB is ready */
2582 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2584 /* Notify Shim Engine */
2587 VOID (NTAPI
* SE_DllLoaded
)(PLDR_DATA_TABLE_ENTRY
) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded
);
2588 SE_DllLoaded(LdrEntry
);
2591 /* Run the init routine */
2592 Status
= LdrpRunInitializeRoutines(NULL
);
2593 if (!NT_SUCCESS(Status
))
2595 /* Failed, unload the DLL */
2598 DbgPrint("LDR: Unloading %wZ because either its init "
2599 "routine or one of its static imports failed; "
2600 "status = 0x%08lx\n",
2604 LdrUnloadDll(LdrEntry
->DllBase
);
2609 /* The DB isn't ready, which means we were loaded because of a forwarder */
2610 Status
= STATUS_SUCCESS
;
2615 /* We were already loaded. Are we a DLL? */
2616 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2618 /* Increase load count */
2619 LdrEntry
->LoadCount
++;
2620 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2622 /* Clear the load in progress */
2623 LdrpClearLoadInProgress();
2627 /* Not a DLL, just increase the load count */
2628 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2635 /* Release the lock */
2636 if (!InInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2640 /* Check for success */
2641 if (NT_SUCCESS(Status
))
2643 /* Return the base address */
2644 *BaseAddress
= LdrEntry
->DllBase
;
2649 *BaseAddress
= NULL
;
2658 LdrpClearLoadInProgress(VOID
)
2660 PLIST_ENTRY ListHead
, Entry
;
2661 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2662 ULONG ModulesCount
= 0;
2664 /* Traverse the init list */
2665 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2666 Entry
= ListHead
->Flink
;
2667 while (Entry
!= ListHead
)
2669 /* Get the loader entry */
2670 LdrEntry
= CONTAINING_RECORD(Entry
,
2671 LDR_DATA_TABLE_ENTRY
,
2672 InInitializationOrderLinks
);
2674 /* Clear load in progress flag */
2675 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2677 /* Check for modules with entry point count but not processed yet */
2678 if ((LdrEntry
->EntryPoint
) &&
2679 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2681 /* Increase counter */
2685 /* Advance to the next entry */
2686 Entry
= Entry
->Flink
;
2689 /* Return final count */
2690 return ModulesCount
;
2693 PVOID
LdrpGetShimEngineFunction(PCSZ FunctionName
)
2695 ANSI_STRING Function
;
2698 RtlInitAnsiString(&Function
, FunctionName
);
2700 Status
= LdrpGetProcedureAddress(g_pShimEngineModule
, &Function
, 0, &Address
, FALSE
);
2701 return NT_SUCCESS(Status
) ? Address
: NULL
;
2706 LdrpGetShimEngineInterface()
2708 PVOID SE_DllLoaded
= LdrpGetShimEngineFunction("SE_DllLoaded");
2709 PVOID SE_DllUnloaded
= LdrpGetShimEngineFunction("SE_DllUnloaded");
2710 PVOID SE_InstallBeforeInit
= LdrpGetShimEngineFunction("SE_InstallBeforeInit");
2711 PVOID SE_InstallAfterInit
= LdrpGetShimEngineFunction("SE_InstallAfterInit");
2712 PVOID SE_ProcessDying
= LdrpGetShimEngineFunction("SE_ProcessDying");
2714 if (SE_DllLoaded
&& SE_DllUnloaded
&& SE_InstallBeforeInit
&& SE_InstallAfterInit
&& SE_ProcessDying
)
2716 g_pfnSE_DllLoaded
= RtlEncodeSystemPointer(SE_DllLoaded
);
2717 g_pfnSE_DllUnloaded
= RtlEncodeSystemPointer(SE_DllUnloaded
);
2718 g_pfnSE_InstallBeforeInit
= RtlEncodeSystemPointer(SE_InstallBeforeInit
);
2719 g_pfnSE_InstallAfterInit
= RtlEncodeSystemPointer(SE_InstallAfterInit
);
2720 g_pfnSE_ProcessDying
= RtlEncodeSystemPointer(SE_ProcessDying
);
2721 g_ShimsEnabled
= TRUE
;
2725 LdrpUnloadShimEngine();
2731 LdrpRunShimEngineInitRoutine(IN ULONG Reason
)
2733 PLIST_ENTRY ListHead
, Next
;
2734 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2736 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2737 Next
= ListHead
->Flink
;
2738 while (Next
!= ListHead
)
2740 LdrEntry
= CONTAINING_RECORD(Next
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2742 if (g_pShimEngineModule
== LdrEntry
->DllBase
)
2744 if (LdrEntry
->EntryPoint
)
2748 LdrpCallInitRoutine(LdrEntry
->EntryPoint
, LdrEntry
->DllBase
, Reason
, NULL
);
2750 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2752 DPRINT1("WARNING: Exception 0x%x during LdrpRunShimEngineInitRoutine(%u)\n",
2753 _SEH2_GetExceptionCode(), Reason
);
2766 LdrpLoadShimEngine(IN PWSTR ImageName
, IN PUNICODE_STRING ProcessImage
, IN PVOID pShimData
)
2768 UNICODE_STRING ShimLibraryName
;
2771 RtlInitUnicodeString(&ShimLibraryName
, ImageName
);
2772 /* We should NOT pass CallInit = TRUE!
2773 If we do this, other init routines will be called before we get a chance to shim stuff.. */
2774 Status
= LdrpLoadDll(FALSE
, NULL
, NULL
, &ShimLibraryName
, &ShimLibrary
, FALSE
);
2775 if (NT_SUCCESS(Status
))
2777 g_pShimEngineModule
= ShimLibrary
;
2778 LdrpRunShimEngineInitRoutine(DLL_PROCESS_ATTACH
);
2779 LdrpGetShimEngineInterface();
2782 VOID(NTAPI
*SE_InstallBeforeInit
)(PUNICODE_STRING
, PVOID
);
2783 SE_InstallBeforeInit
= RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit
);
2784 SE_InstallBeforeInit(ProcessImage
, pShimData
);
2791 LdrpUnloadShimEngine()
2793 /* Make sure we do not call into the shim engine anymore */
2794 g_ShimsEnabled
= FALSE
;
2795 LdrpRunShimEngineInitRoutine(DLL_PROCESS_DETACH
);
2796 LdrUnloadDll(g_pShimEngineModule
);
2797 g_pShimEngineModule
= NULL
;