2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrutils.c
5 * PURPOSE: Internal Loader Utility Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache
, LdrpGetModuleHandleCache
;
19 BOOLEAN g_ShimsEnabled
;
21 /* FUNCTIONS *****************************************************************/
23 /* NOTE: Remove those two once our actctx support becomes better */
24 NTSTATUS
create_module_activation_context( LDR_DATA_TABLE_ENTRY
*module
)
27 LDR_RESOURCE_INFO info
;
28 IMAGE_RESOURCE_DATA_ENTRY
*entry
;
30 info
.Type
= (ULONG
)RT_MANIFEST
;
31 info
.Name
= (ULONG
)ISOLATIONAWARE_MANIFEST_RESOURCE_ID
;
33 if (!(status
= LdrFindResource_U( module
->DllBase
, &info
, 3, &entry
)))
36 ctx
.cbSize
= sizeof(ctx
);
38 ctx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_HMODULE_VALID
;
39 ctx
.hModule
= module
->DllBase
;
40 ctx
.lpResourceName
= (LPCWSTR
)ISOLATIONAWARE_MANIFEST_RESOURCE_ID
;
41 status
= RtlCreateActivationContext( &module
->EntryPointActivationContext
, &ctx
);
46 NTSTATUS
find_actctx_dll( LPCWSTR libname
, WCHAR
*fullname
)
48 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\'};
49 static const WCHAR dotManifestW
[] = {'.','m','a','n','i','f','e','s','t',0};
51 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*info
;
52 ACTCTX_SECTION_KEYED_DATA data
;
55 SIZE_T needed
, size
= 1024;
58 RtlInitUnicodeString( &nameW
, libname
);
59 data
.cbSize
= sizeof(data
);
60 status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
61 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
63 if (status
!= STATUS_SUCCESS
) return status
;
67 if (!(info
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
69 status
= STATUS_NO_MEMORY
;
72 status
= RtlQueryInformationActivationContext( 0, data
.hActCtx
, &data
.ulAssemblyRosterIndex
,
73 AssemblyDetailedInformationInActivationContext
,
74 info
, size
, &needed
);
75 if (status
== STATUS_SUCCESS
) break;
76 if (status
!= STATUS_BUFFER_TOO_SMALL
) goto done
;
77 RtlFreeHeap( RtlGetProcessHeap(), 0, info
);
81 DPRINT("manifestpath === %S\n", info
->lpAssemblyManifestPath
);
82 DPRINT("DirectoryName === %S\n", info
->lpAssemblyDirectoryName
);
83 if (!info
->lpAssemblyManifestPath
|| !info
->lpAssemblyDirectoryName
)
85 status
= STATUS_SXS_KEY_NOT_FOUND
;
89 if ((p
= wcsrchr( info
->lpAssemblyManifestPath
, '\\' )))
91 DWORD dirlen
= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
94 if (_wcsnicmp( p
, info
->lpAssemblyDirectoryName
, dirlen
) || wcsicmp( p
+ dirlen
, dotManifestW
))
96 /* manifest name does not match directory name, so it's not a global
97 * windows/winsxs manifest; use the manifest directory name instead */
98 dirlen
= p
- info
->lpAssemblyManifestPath
;
99 needed
= (dirlen
+ 1) * sizeof(WCHAR
) + nameW
.Length
;
102 /*if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
104 status = STATUS_NO_MEMORY;
107 memcpy( p
, info
->lpAssemblyManifestPath
, dirlen
* sizeof(WCHAR
) );
109 wcscpy( p
, libname
);
114 needed
= (wcslen(SharedUserData
->NtSystemRoot
) * sizeof(WCHAR
) +
115 sizeof(winsxsW
) + info
->ulAssemblyDirectoryNameLength
+ nameW
.Length
+ 2*sizeof(WCHAR
));
118 //if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
120 //status = STATUS_NO_MEMORY;
123 wcscpy( p
, SharedUserData
->NtSystemRoot
);
125 memcpy( p
, winsxsW
, sizeof(winsxsW
) );
126 p
+= sizeof(winsxsW
) / sizeof(WCHAR
);
127 memcpy( p
, info
->lpAssemblyDirectoryName
, info
->ulAssemblyDirectoryNameLength
);
128 p
+= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
130 wcscpy( p
, libname
);
133 RtlFreeHeap( RtlGetProcessHeap(), 0, info
);
134 RtlReleaseActivationContext( data
.hActCtx
);
135 DPRINT("%S\n", fullname
);
142 LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut
,
147 ASSERT(Length
<= UNICODE_STRING_MAX_BYTES
);
150 StringOut
->Length
= 0;
152 /* Make sure it's not mis-aligned */
156 StringOut
->Buffer
= NULL
;
157 StringOut
->MaximumLength
= 0;
158 return STATUS_INVALID_PARAMETER
;
161 /* Allocate the string*/
162 StringOut
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
164 StringOut
->Length
+ sizeof(WCHAR
));
165 if (!StringOut
->Buffer
)
168 StringOut
->MaximumLength
= 0;
169 return STATUS_NO_MEMORY
;
172 /* Null-terminate it */
173 StringOut
->Buffer
[StringOut
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
175 /* Check if this is a maximum-sized string */
176 if (StringOut
->Length
!= UNICODE_STRING_MAX_BYTES
)
178 /* It's not, so set the maximum length to be one char more */
179 StringOut
->MaximumLength
= StringOut
->Length
+ sizeof(UNICODE_NULL
);
183 /* The length is already the maximum possible */
184 StringOut
->MaximumLength
= UNICODE_STRING_MAX_BYTES
;
188 return STATUS_SUCCESS
;
193 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn
)
195 ASSERT(StringIn
!= NULL
);
197 /* If Buffer is not NULL - free it */
198 if (StringIn
->Buffer
)
200 RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn
->Buffer
);
204 RtlInitEmptyUnicodeString(StringIn
, NULL
, 0);
208 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint
,
209 IN PVOID BaseAddress
,
214 return EntryPoint(BaseAddress
, Reason
, Context
);
217 /* NOTE: This function is broken */
220 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
222 OUT PUNICODE_STRING UpdateString
)
224 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder
;
225 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
226 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
227 PIMAGE_THUNK_DATA FirstThunk
;
228 PLDR_DATA_TABLE_ENTRY Entry
;
229 PUNICODE_STRING ImportNameUnic
;
230 ANSI_STRING ImportNameAnsi
;
236 /* Check the action we need to perform */
237 if (Flags
== LDRP_UPDATE_REFCOUNT
)
239 /* Make sure entry is not being loaded already */
240 if (LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
)
243 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
245 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
247 /* Make sure the entry is not being unloaded already */
248 if (LdrEntry
->Flags
& LDRP_UNLOAD_IN_PROGRESS
)
251 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
254 /* Go through all bound DLLs and dereference them */
255 ImportNameUnic
= &NtCurrentTeb()->StaticUnicodeString
;
257 /* Try to get the new import entry */
258 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
260 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
265 /* Set entry flags if refing/derefing */
266 if (Flags
== LDRP_UPDATE_REFCOUNT
)
267 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
268 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
269 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
271 while (BoundEntry
->OffsetModuleName
)
273 /* Get pointer to the current import name */
274 ImportName
= (PCHAR
)BoundEntry
+ BoundEntry
->OffsetModuleName
;
276 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
277 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
279 if (NT_SUCCESS(Status
))
281 if (LdrpCheckForLoadedDll(NULL
,
287 if (Entry
->LoadCount
!= 0xFFFF)
289 /* Perform the required action */
292 case LDRP_UPDATE_REFCOUNT
:
295 case LDRP_UPDATE_DEREFCOUNT
:
298 case LDRP_UPDATE_PIN
:
299 Entry
->LoadCount
= 0xFFFF;
306 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
310 /* Recurse into this entry */
311 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
315 /* Go through forwarders */
316 NewImportForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
317 for (i
=0; i
<BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
319 ImportName
= (PCHAR
)BoundEntry
+ NewImportForwarder
->OffsetModuleName
;
321 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
322 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
323 if (NT_SUCCESS(Status
))
325 if (LdrpCheckForLoadedDll(NULL
,
331 if (Entry
->LoadCount
!= 0xFFFF)
333 /* Perform the required action */
336 case LDRP_UPDATE_REFCOUNT
:
339 case LDRP_UPDATE_DEREFCOUNT
:
342 case LDRP_UPDATE_PIN
:
343 Entry
->LoadCount
= 0xFFFF;
350 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
354 /* Recurse into this entry */
355 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
359 NewImportForwarder
++;
362 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)NewImportForwarder
;
369 /* Check oldstyle import descriptor */
370 ImportEntry
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
372 IMAGE_DIRECTORY_ENTRY_IMPORT
,
376 /* There is old one, so go through its entries */
377 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
379 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->FirstThunk
);
381 /* Skip this entry if needed */
382 if (!FirstThunk
->u1
.Function
)
388 ImportName
= (PSZ
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
390 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
391 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
392 if (NT_SUCCESS(Status
))
394 if (LdrpCheckForLoadedDll(NULL
,
400 if (Entry
->LoadCount
!= 0xFFFF)
402 /* Perform the required action */
405 case LDRP_UPDATE_REFCOUNT
:
408 case LDRP_UPDATE_DEREFCOUNT
:
411 case LDRP_UPDATE_PIN
:
412 Entry
->LoadCount
= 0xFFFF;
419 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
424 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
428 /* Go to the next entry */
436 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
439 WCHAR Buffer
[MAX_PATH
];
440 UNICODE_STRING UpdateString
;
442 /* Setup the string and call the extended API */
443 RtlInitEmptyUnicodeString(&UpdateString
, Buffer
, sizeof(Buffer
));
444 LdrpUpdateLoadCount3(LdrEntry
, Flags
, &UpdateString
);
449 LdrpCallTlsInitializers(IN PVOID BaseAddress
,
452 PIMAGE_TLS_DIRECTORY TlsDirectory
;
453 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
456 /* Get the TLS Directory */
457 TlsDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
459 IMAGE_DIRECTORY_ENTRY_TLS
,
462 /* Protect against invalid pointers */
465 /* Make sure it's valid */
469 Array
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
;
475 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
476 BaseAddress
, TlsDirectory
, Array
);
482 /* Get the TLS Entrypoint */
488 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
489 BaseAddress
, Callback
);
493 LdrpCallInitRoutine((PDLL_INIT_ROUTINE
)Callback
,
501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
510 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName
,
513 /* Not implemented */
514 return STATUS_SUCCESS
;
519 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
521 IN PULONG DllCharacteristics OPTIONAL
,
522 OUT PHANDLE SectionHandle
)
526 OBJECT_ATTRIBUTES ObjectAttributes
;
527 IO_STATUS_BLOCK IoStatusBlock
;
528 ULONG_PTR HardErrorParameters
[1];
530 SECTION_IMAGE_INFORMATION SectionImageInfo
;
532 /* Check if we don't already have a handle */
535 /* Create the object attributes */
536 InitializeObjectAttributes(&ObjectAttributes
,
538 OBJ_CASE_INSENSITIVE
,
543 Status
= NtOpenFile(&FileHandle
,
544 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
547 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
548 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
550 /* Check if we failed */
551 if (!NT_SUCCESS(Status
))
553 /* Attempt to open for execute only */
554 Status
= NtOpenFile(&FileHandle
,
555 SYNCHRONIZE
| FILE_EXECUTE
,
558 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
559 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
561 /* Check if this failed too */
562 if (!NT_SUCCESS(Status
))
564 /* Show debug message */
567 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
571 /* Make sure to return an expected status code */
572 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
574 /* Callers expect this instead */
575 Status
= STATUS_DLL_NOT_FOUND
;
578 /* Return an empty section handle */
579 *SectionHandle
= NULL
;
586 /* Use the handle we already have */
587 FileHandle
= DllHandle
;
590 /* Create a section for the DLL */
591 Status
= NtCreateSection(SectionHandle
,
592 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
593 SECTION_MAP_WRITE
| SECTION_QUERY
,
600 /* If mapping failed, raise a hard error */
601 if (!NT_SUCCESS(Status
))
603 /* Forget the handle */
604 *SectionHandle
= NULL
;
606 /* Give the DLL name */
607 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
609 /* Raise the error */
610 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
617 /* Increment the error count */
618 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
621 /* Check for Safer restrictions */
622 if (DllCharacteristics
&&
623 !(*DllCharacteristics
& IMAGE_FILE_SYSTEM
))
625 /* Make sure it's executable */
626 Status
= ZwQuerySection(*SectionHandle
,
627 SectionImageInformation
,
629 sizeof(SECTION_IMAGE_INFORMATION
),
631 if (NT_SUCCESS(Status
))
633 /* Bypass the check for .NET images */
634 if (!(SectionImageInfo
.LoaderFlags
& IMAGE_LOADER_FLAGS_COMPLUS
))
636 /* Check with Safer */
637 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
638 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
640 /* Show debug message */
643 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
647 /* Failure case, close section handle */
648 NtClose(*SectionHandle
);
649 *SectionHandle
= NULL
;
655 /* Failure case, close section handle */
656 NtClose(*SectionHandle
);
657 *SectionHandle
= NULL
;
661 /* Close the file handle, we don't need it */
668 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
671 LdrpResolveDllName(PWSTR DllPath
,
673 PUNICODE_STRING FullDllName
,
674 PUNICODE_STRING BaseDllName
)
676 PWCHAR NameBuffer
, p1
, p2
= 0;
681 /* Allocate space for full DLL name */
682 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize
+ sizeof(UNICODE_NULL
));
683 if (!FullDllName
->Buffer
) return FALSE
;
685 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
690 &BaseDllName
->Buffer
);
692 if (!Length
|| Length
> BufSize
)
694 /* HACK: Try to find active context dll */
695 Status
= find_actctx_dll(DllName
, FullDllName
->Buffer
);
696 if(Status
== STATUS_SUCCESS
)
698 Length
= wcslen(FullDllName
->Buffer
) * sizeof(WCHAR
);
699 DPRINT1("found %S for %S\n", FullDllName
->Buffer
, DllName
);
703 /* NOTE: This code should remain after removing the hack */
706 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
707 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
710 RtlFreeUnicodeString(FullDllName
);
715 /* Construct full DLL name */
716 FullDllName
->Length
= Length
;
717 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
719 /* Allocate a new buffer */
720 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
723 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
727 /* Copy over the contents from the previous one and free it */
728 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
729 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
730 FullDllName
->Buffer
= NameBuffer
;
732 /* Find last backslash */
733 p1
= FullDllName
->Buffer
;
742 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
750 /* Calculate remaining length */
753 /* Construct base DLL name */
754 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
755 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
756 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName
->MaximumLength
);
758 if (!BaseDllName
->Buffer
)
760 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
764 /* Copy base dll name to the new buffer */
765 RtlMoveMemory(BaseDllName
->Buffer
,
767 BaseDllName
->Length
);
769 /* Null-terminate the string */
770 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
777 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase
)
779 PIMAGE_NT_HEADERS NtHeaders
;
780 ULONG_PTR EntryPoint
= 0;
782 /* Get entry point offset from NT headers */
783 NtHeaders
= RtlImageNtHeader(ImageBase
);
787 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
788 if (EntryPoint
) EntryPoint
+= (ULONG_PTR
)ImageBase
;
791 /* Return calculated pointer (or zero in case of failure) */
792 return (PVOID
)EntryPoint
;
795 /* NOTE: This function is partially missing SxS */
798 LdrpCheckForKnownDll(PWSTR DllName
,
799 PUNICODE_STRING FullDllName
,
800 PUNICODE_STRING BaseDllName
,
801 HANDLE
*SectionHandle
)
803 OBJECT_ATTRIBUTES ObjectAttributes
;
804 HANDLE Section
= NULL
;
805 UNICODE_STRING DllNameUnic
;
810 /* Zero initialize provided parameters */
811 if (SectionHandle
) *SectionHandle
= 0;
815 FullDllName
->Length
= 0;
816 FullDllName
->MaximumLength
= 0;
817 FullDllName
->Buffer
= NULL
;
822 BaseDllName
->Length
= 0;
823 BaseDllName
->MaximumLength
= 0;
824 BaseDllName
->Buffer
= NULL
;
827 /* If any of these three params are missing then fail */
828 if (!SectionHandle
|| !FullDllName
|| !BaseDllName
)
829 return STATUS_INVALID_PARAMETER
;
831 /* Check the Loader Lock */
832 LdrpEnsureLoaderLockIsHeld();
834 /* Upgrade DllName to a unicode string */
835 RtlInitUnicodeString(&DllNameUnic
, DllName
);
837 /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
839 /* Get the activation context */
840 Status
= RtlFindActivationContextSectionString(0,
842 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
846 /* Check if it's a SxS or not */
847 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
848 Status
== STATUS_SXS_KEY_NOT_FOUND
)
850 /* NOTE: Here it's beneficial to allocate one big unicode string
851 using LdrpAllocateUnicodeString instead of fragmenting the heap
852 with two allocations as it's done now. */
854 /* Set up BaseDllName */
855 BaseDllName
->Length
= DllNameUnic
.Length
;
856 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
857 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
859 DllNameUnic
.MaximumLength
);
860 if (!BaseDllName
->Buffer
)
862 Status
= STATUS_NO_MEMORY
;
866 /* Copy the contents there */
867 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
869 /* Set up FullDllName */
870 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
871 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
872 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
873 if (!FullDllName
->Buffer
)
875 Status
= STATUS_NO_MEMORY
;
879 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
881 /* Put a slash there */
882 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
887 /* Set up DllNameUnic for a relative path */
888 DllNameUnic
.Buffer
= (PWSTR
)p1
;
889 DllNameUnic
.Length
= BaseDllName
->Length
;
890 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
892 /* Copy the contents */
893 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
895 /* There are all names, init attributes and open the section */
896 InitializeObjectAttributes(&ObjectAttributes
,
898 OBJ_CASE_INSENSITIVE
,
899 LdrpKnownDllObjectDirectory
,
902 Status
= NtOpenSection(&Section
,
903 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
905 if (!NT_SUCCESS(Status
))
907 /* Clear status in case it was just not found */
908 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) Status
= STATUS_SUCCESS
;
912 /* Pass section handle to the caller and return success */
913 *SectionHandle
= Section
;
914 return STATUS_SUCCESS
;
918 /* Close section object if it was opened */
919 if (Section
) NtClose(Section
);
921 /* Free string resources */
922 if (BaseDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
923 if (FullDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
931 LdrpSetProtection(PVOID ViewBase
,
934 PIMAGE_NT_HEADERS NtHeaders
;
935 PIMAGE_SECTION_HEADER Section
;
939 ULONG NewProtection
, OldProtection
, i
;
941 /* Get the NT headers */
942 NtHeaders
= RtlImageNtHeader(ViewBase
);
943 if (!NtHeaders
) return STATUS_INVALID_IMAGE_FORMAT
;
945 /* Compute address of the first section header */
946 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
948 /* Go through all sections */
949 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
951 /* Check for read-only non-zero section */
952 if ((Section
->SizeOfRawData
) &&
953 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
955 /* Check if we are setting or restoring protection */
958 /* Set it to either EXECUTE or READONLY */
959 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
961 NewProtection
= PAGE_EXECUTE
;
965 NewProtection
= PAGE_READONLY
;
968 /* Add PAGE_NOCACHE if needed */
969 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
971 NewProtection
|= PAGE_NOCACHE
;
976 /* Enable write access */
977 NewProtection
= PAGE_READWRITE
;
980 /* Get the section VA */
981 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
982 SectionSize
= Section
->SizeOfRawData
;
986 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
991 if (!NT_SUCCESS(Status
)) return Status
;
995 /* Move to the next section */
999 /* Flush instruction cache if necessary */
1000 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
1001 return STATUS_SUCCESS
;
1004 /* NOTE: Not yet reviewed */
1007 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
1009 IN PWSTR DllName OPTIONAL
,
1010 IN PULONG DllCharacteristics
,
1012 IN BOOLEAN Redirect
,
1013 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
1015 PTEB Teb
= NtCurrentTeb();
1016 PPEB Peb
= NtCurrentPeb();
1017 PWCHAR p1
= DllName
;
1019 BOOLEAN KnownDll
= FALSE
;
1020 UNICODE_STRING FullDllName
, BaseDllName
;
1021 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
1022 UNICODE_STRING NtPathDllName
;
1023 ULONG_PTR HardErrorParameters
[2];
1024 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
1026 SIZE_T ViewSize
= 0;
1027 PVOID ViewBase
= NULL
;
1028 PVOID ArbitraryUserPointer
;
1029 PIMAGE_NT_HEADERS NtHeaders
;
1030 NTSTATUS HardErrorStatus
, Status
;
1031 BOOLEAN OverlapDllFound
= FALSE
;
1032 ULONG_PTR ImageBase
, ImageEnd
;
1033 PLIST_ENTRY ListHead
, NextEntry
;
1034 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
1035 ULONG_PTR CandidateBase
, CandidateEnd
;
1036 UNICODE_STRING OverlapDll
;
1037 BOOLEAN RelocatableDll
= TRUE
;
1038 UNICODE_STRING IllegalDll
;
1040 ULONG RelocDataSize
= 0;
1042 // FIXME: AppCompat stuff is missing
1046 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
1048 SearchPath
? SearchPath
: L
"");
1051 /* Check if we have a known dll directory */
1052 if (LdrpKnownDllObjectDirectory
)
1054 /* Check if the path is full */
1058 if (TempChar
== '\\' || TempChar
== '/' )
1060 /* Complete path, don't do Known Dll lookup */
1065 /* Try to find a Known DLL */
1066 Status
= LdrpCheckForKnownDll(DllName
,
1071 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_DLL_NOT_FOUND
))
1074 DbgPrintEx(81, //DPFLTR_LDR_ID,
1076 "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
1087 /* Check if the Known DLL Check returned something */
1090 /* It didn't, so try to resolve the name now */
1091 if (LdrpResolveDllName(SearchPath
,
1096 /* Got a name, display a message */
1099 DPRINT1("LDR: Loading (%s) %wZ\n",
1100 Static
? "STATIC" : "DYNAMIC",
1104 /* Convert to NT Name */
1105 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1110 /* Path was invalid */
1111 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1114 /* Create a section for this dLL */
1115 Status
= LdrpCreateDllSection(&NtPathDllName
,
1120 /* Free the NT Name */
1121 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
1124 if (!NT_SUCCESS(Status
))
1126 /* Free the name strings and return */
1127 RtlFreeUnicodeString(&FullDllName
);
1128 RtlFreeUnicodeString(&BaseDllName
);
1134 /* We couldn't resolve the name, is this a static load? */
1138 * This is BAD! Static loads are CRITICAL. Bugcheck!
1139 * Initialize the strings for the error
1141 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
1142 RtlInitUnicodeString(&HardErrorDllPath
,
1143 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
1145 /* Set them as error parameters */
1146 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
1147 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
1149 /* Raise the hard error */
1150 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
1153 HardErrorParameters
,
1157 /* We're back, where we initializing? */
1158 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1161 /* Return failure */
1162 return STATUS_DLL_NOT_FOUND
;
1167 /* We have a section handle, so this is a known dll */
1171 /* Stuff the image name in the TIB, for the debugger */
1172 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1173 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1178 Status
= NtMapViewOfSection(SectionHandle
,
1190 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1192 /* Fail if we couldn't map it */
1193 if (!NT_SUCCESS(Status
))
1195 /* Close and return */
1196 NtClose(SectionHandle
);
1200 /* Get the NT Header */
1201 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
1203 /* Invalid image, unmap, close handle and fail */
1204 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1205 NtClose(SectionHandle
);
1206 return STATUS_INVALID_IMAGE_FORMAT
;
1209 // FIXME: .NET support is missing
1211 /* Allocate an entry */
1212 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
1214 /* Invalid image, unmap, close handle and fail */
1215 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1216 NtClose(SectionHandle
);
1217 return STATUS_NO_MEMORY
;
1220 /* Setup the entry */
1221 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
1222 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
1223 LdrEntry
->LoadCount
= 0;
1224 LdrEntry
->FullDllName
= FullDllName
;
1225 LdrEntry
->BaseDllName
= BaseDllName
;
1226 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
1228 /* Show debug message */
1231 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
1236 /* Insert this entry */
1237 LdrpInsertMemoryTableEntry(LdrEntry
);
1239 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
1241 /* Check for invalid CPU Image */
1242 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1244 /* Load our header */
1245 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1247 /* Assume defaults if we don't have to run the Hard Error path */
1248 HardErrorStatus
= STATUS_SUCCESS
;
1249 Response
= ResponseCancel
;
1251 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1252 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1254 /* Reset the entrypoint, save our Dll Name */
1255 LdrEntry
->EntryPoint
= 0;
1256 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1258 /* Raise the error */
1259 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1262 HardErrorParameters
,
1267 /* Check if the user pressed cancel */
1268 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1270 /* Remove the DLL from the lists */
1271 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1272 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1273 RemoveEntryList(&LdrEntry
->HashLinks
);
1275 /* Remove the LDR Entry */
1276 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry
);
1278 /* Unmap and close section */
1279 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1280 NtClose(SectionHandle
);
1282 /* Did we do a hard error? */
1283 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1285 /* Yup, so increase fatal error count if we are initializing */
1286 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1289 /* Return failure */
1290 return STATUS_INVALID_IMAGE_FORMAT
;
1295 /* The image was valid. Is it a DLL? */
1296 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1298 /* Set the DLL Flag */
1299 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1302 /* If we're not a DLL, clear the entrypoint */
1303 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1305 LdrEntry
->EntryPoint
= 0;
1309 /* Return it for the caller */
1310 *DataTableEntry
= LdrEntry
;
1312 /* Check if we loaded somewhere else */
1313 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1315 /* Write the flag */
1316 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1318 /* Find our region */
1319 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1320 ImageEnd
= ImageBase
+ ViewSize
;
1322 DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p -> %p)\n", DllName
, ImageBase
, ViewBase
);
1324 /* Scan all the modules */
1325 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1326 NextEntry
= ListHead
->Flink
;
1327 while (NextEntry
!= ListHead
)
1330 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1331 LDR_DATA_TABLE_ENTRY
,
1333 NextEntry
= NextEntry
->Flink
;
1335 /* Get the entry's bounds */
1336 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1337 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1339 /* Make sure this entry isn't unloading */
1340 if (!CandidateEntry
->InMemoryOrderModuleList
.Flink
) continue;
1342 /* Check if our regions are colliding */
1343 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1344 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1345 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1347 /* Found who is overlapping */
1348 OverlapDllFound
= TRUE
;
1349 OverlapDll
= CandidateEntry
->FullDllName
;
1354 /* Check if we found the DLL overlapping with us */
1355 if (!OverlapDllFound
)
1357 /* It's not another DLL, it's memory already here */
1358 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1361 DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll
);
1363 /* Are we dealing with a DLL? */
1364 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1366 /* Check if relocs were stripped */
1367 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1369 /* Get the relocation data */
1370 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1372 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1375 /* Does the DLL not have any? */
1376 if (!RelocData
&& !RelocDataSize
)
1378 /* We'll allow this and simply continue */
1383 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1384 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1385 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1387 /* Can't relocate user32 */
1388 RelocatableDll
= FALSE
;
1392 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1393 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1395 /* Can't relocate kernel32 */
1396 RelocatableDll
= FALSE
;
1400 /* Known DLLs are not allowed to be relocated */
1401 if (KnownDll
&& !RelocatableDll
)
1403 /* Setup for hard error */
1404 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1405 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1407 /* Raise the error */
1408 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1411 HardErrorParameters
,
1415 /* If initializing, increase the error count */
1416 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1418 /* Don't do relocation */
1419 Status
= STATUS_CONFLICTING_ADDRESSES
;
1423 /* Change the protection to prepare for relocation */
1424 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1426 /* Make sure we changed the protection */
1427 if (NT_SUCCESS(Status
))
1429 /* Do the relocation */
1430 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1431 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1433 if (NT_SUCCESS(Status
))
1435 /* Stuff the image name in the TIB, for the debugger */
1436 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1437 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1440 Status
= NtMapViewOfSection(SectionHandle
,
1452 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1454 /* Return the protection */
1455 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1459 /* Handle any kind of failure */
1460 if (!NT_SUCCESS(Status
))
1462 /* Remove it from the lists */
1463 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1464 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1465 RemoveEntryList(&LdrEntry
->HashLinks
);
1467 /* Unmap it, clear the entry */
1468 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1472 /* Show debug message */
1475 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1476 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1482 /* Not a DLL, or no relocation needed */
1483 Status
= STATUS_SUCCESS
;
1485 /* Stuff the image name in the TIB, for the debugger */
1486 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1487 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1490 Status
= NtMapViewOfSection(SectionHandle
,
1502 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1504 /* Show debug message */
1507 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1512 // FIXME: LdrpCheckCorImage() is missing
1514 /* Check if this is an SMP Machine and a DLL */
1515 if ((LdrpNumberOfProcessors
> 1) &&
1516 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1518 /* Validate the image for MP */
1519 LdrpValidateImageForMp(LdrEntry
);
1522 // FIXME: LdrpCorUnloadImage() is missing
1524 /* Close section and return status */
1525 NtClose(SectionHandle
);
1529 PLDR_DATA_TABLE_ENTRY
1531 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1533 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1534 PIMAGE_NT_HEADERS NtHeader
;
1536 /* Make sure the header is valid */
1537 NtHeader
= RtlImageNtHeader(BaseAddress
);
1538 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1542 /* Allocate an entry */
1543 LdrEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
1545 sizeof(LDR_DATA_TABLE_ENTRY
));
1547 /* Make sure we got one */
1551 LdrEntry
->DllBase
= BaseAddress
;
1552 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1553 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1554 LdrEntry
->PatchInformation
= NULL
;
1558 /* Return the entry */
1564 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1566 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1569 /* Insert into hash table */
1570 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1571 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1573 /* Insert into other lists */
1574 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1575 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderModuleList
);
1580 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry
)
1583 ASSERT(Entry
!= NULL
);
1585 /* Release the activation context if it exists and wasn't already released */
1586 if ((Entry
->EntryPointActivationContext
) &&
1587 (Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
))
1589 /* Mark it as invalid */
1590 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1591 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1594 /* Release the full dll name string */
1595 if (Entry
->FullDllName
.Buffer
) LdrpFreeUnicodeString(&Entry
->FullDllName
);
1597 /* Finally free the entry's memory */
1598 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry
);
1603 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1604 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1606 PLDR_DATA_TABLE_ENTRY Current
;
1607 PLIST_ENTRY ListHead
, Next
;
1609 /* Check the cache first */
1610 if ((LdrpLoadedDllHandleCache
) &&
1611 (LdrpLoadedDllHandleCache
->DllBase
== Base
))
1613 /* We got lucky, return the cached entry */
1614 *LdrEntry
= LdrpLoadedDllHandleCache
;
1618 /* Time for a lookup */
1619 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1620 Next
= ListHead
->Flink
;
1621 while (Next
!= ListHead
)
1623 /* Get the current entry */
1624 Current
= CONTAINING_RECORD(Next
,
1625 LDR_DATA_TABLE_ENTRY
,
1628 /* Make sure it's not unloading and check for a match */
1629 if ((Current
->InMemoryOrderModuleList
.Flink
) && (Base
== Current
->DllBase
))
1632 LdrpLoadedDllHandleCache
= Current
;
1635 *LdrEntry
= Current
;
1639 /* Move to the next one */
1649 LdrpResolveFullName(IN PUNICODE_STRING OriginalName
,
1650 IN PUNICODE_STRING PathName
,
1651 IN PUNICODE_STRING FullPathName
,
1652 IN PUNICODE_STRING
*ExpandedName
)
1654 NTSTATUS Status
= STATUS_SUCCESS
;
1655 // RTL_PATH_TYPE PathType;
1656 // BOOLEAN InvalidName;
1659 /* Display debug output if snaps are on */
1662 DbgPrintEx(81, //DPFLTR_LDR_ID,
1664 "LDR: %s - Expanding full name of %wZ\n",
1669 /* FIXME: Lock the PEB */
1670 //RtlEnterCriticalSection(&FastPebLock);
1672 /* Get the path name */
1673 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1682 if (!(Length
) || (Length
> UNICODE_STRING_MAX_BYTES
))
1685 Status
= STATUS_NAME_TOO_LONG
;
1689 /* Check if the length hasn't changed */
1690 if (Length
<= PathName
->Length
)
1692 /* Return the same thing */
1693 *ExpandedName
= PathName
;
1694 PathName
->Length
= (USHORT
)Length
;
1699 ASSERT(Length
>= sizeof(WCHAR
));
1701 /* Allocate a string */
1702 Status
= LdrpAllocateUnicodeString(FullPathName
, Length
- sizeof(WCHAR
));
1703 if (!NT_SUCCESS(Status
)) goto Quickie
;
1705 /* Now get the full path again */
1707 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1708 FullPathName
->Length
,
1709 FullPathName
->Buffer
,
1716 if (!(Length
) || (Length
> FullPathName
->Length
))
1719 LdrpFreeUnicodeString(FullPathName
);
1720 Status
= STATUS_NAME_TOO_LONG
;
1724 /* Return the expanded name */
1725 *ExpandedName
= FullPathName
;
1726 FullPathName
->Length
= (USHORT
)Length
;
1730 /* FIXME: Unlock the PEB */
1731 //RtlLeaveCriticalSection(&FastPebLock);
1733 /* Display debug output if snaps are on */
1736 /* Check which output to use -- failure or success */
1737 if (NT_SUCCESS(Status
))
1739 DbgPrintEx(81, //DPFLTR_LDR_ID,
1741 "LDR: %s - Expanded to %wZ\n",
1747 DbgPrintEx(81, //DPFLTR_LDR_ID,
1749 "LDR: %s - Failed to expand %wZ; 0x%08x\n",
1756 /* If we failed, return NULL */
1757 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1765 LdrpSearchPath(IN PWCHAR
*SearchPath
,
1767 IN PUNICODE_STRING PathName
,
1768 IN PUNICODE_STRING FullPathName
,
1769 IN PUNICODE_STRING
*ExpandedName
)
1771 BOOLEAN TryAgain
= FALSE
;
1772 PWCHAR ActualSearchPath
= *SearchPath
;
1773 UNICODE_STRING TestName
;
1775 PWCHAR Buffer
, BufEnd
= NULL
;
1780 /* Check if we don't have a search path */
1781 if (!ActualSearchPath
) *SearchPath
= LdrpDefaultPath
.Buffer
;
1783 /* Display debug output if snaps are on */
1786 DbgPrintEx(81, //DPFLTR_LDR_ID,
1788 "LDR: %s - Looking for %ws in %ws\n",
1794 /* Check if we're dealing with a relative path */
1795 if (RtlDetermineDosPathNameType_U(DllName
) != RtlPathTypeRelative
)
1797 /* Good, we're not. Create the name string */
1798 Status
= RtlInitUnicodeStringEx(&TestName
, DllName
);
1799 if (!NT_SUCCESS(Status
)) goto Quickie
;
1801 /* Make sure it exists */
1803 if (!RtlDoesFileExists_UstrEx(&TestName
, TRUE
))
1805 /* It doesn't, fail */
1806 Status
= STATUS_DLL_NOT_FOUND
;
1811 /* Resolve the full name */
1812 Status
= LdrpResolveFullName(&TestName
,
1819 /* FIXME: Handle relative case semicolon-lookup here */
1821 /* Calculate length */
1822 Length
+= (ULONG
)wcslen(DllName
) + sizeof(UNICODE_NULL
);
1823 if (Length
> UNICODE_STRING_MAX_CHARS
)
1825 /* Too long, fail */
1826 Status
= STATUS_NAME_TOO_LONG
;
1830 /* Allocate buffer */
1831 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
1835 Status
= STATUS_NO_MEMORY
;
1839 /* FIXME: Setup TestName here */
1840 Status
= STATUS_NOT_FOUND
;
1846 p
= *ActualSearchPath
;
1847 if (!(p
) || (p
== ';'))
1849 /* FIXME: We don't have a character, or is a semicolon.*/
1851 /* Display debug output if snaps are on */
1854 DbgPrintEx(81, //DPFLTR_LDR_ID,
1856 "LDR: %s - Looking for %ws\n",
1862 TestName
.Length
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
);
1864 ASSERT(TestName
.Length
< TestName
.MaximumLength
);
1867 /* Check if the file exists */
1869 if (RtlDoesFileExists_UstrEx(&TestName
, FALSE
))
1872 /* It does. Reallocate the buffer */
1873 TestName
.MaximumLength
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
) + sizeof(WCHAR
);
1874 TestName
.Buffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
1877 TestName
.MaximumLength
);
1878 if (!TestName
.Buffer
)
1880 /* Keep the old one */
1881 TestName
.Buffer
= Buffer
;
1886 Buffer
= TestName
.Buffer
;
1889 /* Make sure we have a buffer at least */
1890 ASSERT(TestName
.Buffer
);
1892 /* Resolve the name */
1893 *SearchPath
= ActualSearchPath
++;
1894 Status
= LdrpResolveFullName(&TestName
,
1901 /* Update buffer end */
1904 /* Update string position */
1905 //pp = ActualSearchPath++;
1909 /* Otherwise, write the character */
1914 /* Check if the string is empty, meaning we're done */
1915 if (!(*ActualSearchPath
)) TryAgain
= TRUE
;
1917 /* Advance in the string */
1919 } while (!TryAgain
);
1921 /* Check if we had a buffer and free it */
1922 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1925 /* Check if we got here through failure */
1926 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1928 /* Display debug output if snaps are on */
1931 /* Check which output to use -- failure or success */
1932 if (NT_SUCCESS(Status
))
1934 DbgPrintEx(81, //DPFLTR_LDR_ID,
1936 "LDR: %s - Returning %wZ\n",
1942 DbgPrintEx(81, //DPFLTR_LDR_ID,
1944 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1957 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1960 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1961 IN PUNICODE_STRING DllName
,
1963 IN BOOLEAN RedirectedDll
,
1964 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1967 PLIST_ENTRY ListHead
, ListEntry
;
1968 PLDR_DATA_TABLE_ENTRY CurEntry
;
1969 BOOLEAN FullPath
= FALSE
;
1972 UNICODE_STRING FullDllName
, NtPathName
;
1974 OBJECT_ATTRIBUTES ObjectAttributes
;
1976 HANDLE FileHandle
, SectionHandle
;
1977 IO_STATUS_BLOCK Iosb
;
1978 PVOID ViewBase
= NULL
;
1979 SIZE_T ViewSize
= 0;
1980 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1981 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"", DllName
, Flag
, RedirectedDll
, LdrEntry
);
1983 /* Check if a dll name was provided */
1984 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
1986 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1987 /* FIXME: Warning, code does not support redirection at all */
1989 /* Look in the hash table if flag was set */
1993 /* Get hash index */
1994 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
1996 /* Traverse that list */
1997 ListHead
= &LdrpHashTable
[HashIndex
];
1998 ListEntry
= ListHead
->Flink
;
1999 while (ListEntry
!= ListHead
)
2001 /* Get the current entry */
2002 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2004 /* Check base name of that module */
2005 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
2007 /* It matches, return it */
2008 *LdrEntry
= CurEntry
;
2012 /* Advance to the next entry */
2013 ListEntry
= ListEntry
->Flink
;
2016 /* Module was not found, return failure */
2020 /* Check if there is a full path in this DLL */
2021 wc
= DllName
->Buffer
;
2024 /* Check for a slash in the current position*/
2025 if ((*wc
== L
'\\') || (*wc
== L
'/'))
2027 /* Found the slash, so dll name contains path */
2030 /* Setup full dll name string */
2031 FullDllName
.Buffer
= NameBuf
;
2033 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2034 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
2037 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
2041 /* Check if that was successful */
2042 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
2044 /* HACK: Try to find active context dll */
2045 Status
= find_actctx_dll(DllName
->Buffer
, FullDllName
.Buffer
);
2046 if(Status
== STATUS_SUCCESS
)
2048 Length
= wcslen(FullDllName
.Buffer
) * sizeof(WCHAR
);
2049 DPRINT1("found %S for %S\n", FullDllName
.Buffer
, DllName
->Buffer
);
2056 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
2057 DllName
->Buffer
, Length
);
2060 /* Return failure */
2065 /* Full dll name is found */
2066 FullDllName
.Length
= Length
;
2067 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
2074 /* Go check the hash table */
2081 /* FIXME: Warning, activation context missing */
2082 /* NOTE: From here on down, everything looks good */
2084 /* Loop the module list */
2085 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2086 ListEntry
= ListHead
->Flink
;
2087 while (ListEntry
!= ListHead
)
2089 /* Get the current entry and advance to the next one */
2090 CurEntry
= CONTAINING_RECORD(ListEntry
,
2091 LDR_DATA_TABLE_ENTRY
,
2093 ListEntry
= ListEntry
->Flink
;
2095 /* Check if it's being unloaded */
2096 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
2098 /* Check if name matches */
2099 if (RtlEqualUnicodeString(&FullDllName
,
2100 &CurEntry
->FullDllName
,
2104 *LdrEntry
= CurEntry
;
2109 /* Convert given path to NT path */
2110 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
2115 /* Fail if conversion failed */
2119 /* Initialize object attributes and open it */
2120 InitializeObjectAttributes(&ObjectAttributes
,
2122 OBJ_CASE_INSENSITIVE
,
2125 Status
= NtOpenFile(&FileHandle
,
2126 SYNCHRONIZE
| FILE_EXECUTE
,
2129 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2130 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
2132 /* Free NT path name */
2133 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
2135 /* If opening the file failed - return failure */
2136 if (!NT_SUCCESS(Status
)) return FALSE
;
2138 /* Create a section for this file */
2139 Status
= NtCreateSection(&SectionHandle
,
2141 SECTION_MAP_EXECUTE
|
2149 /* Close file handle */
2150 NtClose(FileHandle
);
2152 /* If creating section failed - return failure */
2153 if (!NT_SUCCESS(Status
)) return FALSE
;
2155 /* Map view of this section */
2156 Status
= ZwMapViewOfSection(SectionHandle
,
2167 /* Close section handle */
2168 NtClose(SectionHandle
);
2170 /* If section mapping failed - return failure */
2171 if (!NT_SUCCESS(Status
)) return FALSE
;
2173 /* Get pointer to the NT header of this section */
2174 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
2175 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
2177 /* Unmap the section and fail */
2178 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2182 /* Go through the list of modules again */
2183 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2184 ListEntry
= ListHead
->Flink
;
2185 while (ListEntry
!= ListHead
)
2187 /* Get the current entry and advance to the next one */
2188 CurEntry
= CONTAINING_RECORD(ListEntry
,
2189 LDR_DATA_TABLE_ENTRY
,
2191 ListEntry
= ListEntry
->Flink
;
2193 /* Check if it's in the process of being unloaded */
2194 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
2196 /* The header is untrusted, use SEH */
2199 /* Check if timedate stamp and sizes match */
2200 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
2201 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
2203 /* Time, date and size match. Let's compare their headers */
2204 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
2205 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
2207 /* Headers match too! Finally ask the kernel to compare mapped files */
2208 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
2209 if (NT_SUCCESS(Status
))
2211 /* This is our entry!, unmap and return success */
2212 *LdrEntry
= CurEntry
;
2213 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2214 _SEH2_YIELD(return TRUE
;)
2219 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
2226 /* Unmap the section and fail */
2227 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2233 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
2234 IN PANSI_STRING Name
,
2236 OUT PVOID
*ProcedureAddress
,
2237 IN BOOLEAN ExecuteInit
)
2239 NTSTATUS Status
= STATUS_SUCCESS
;
2240 UCHAR ImportBuffer
[64];
2241 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2242 IMAGE_THUNK_DATA Thunk
;
2244 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
2245 PIMAGE_EXPORT_DIRECTORY ExportDir
;
2246 ULONG ExportDirSize
, Length
;
2249 /* Show debug message */
2250 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
2252 /* Check if we got a name */
2255 /* Show debug message */
2256 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
2258 /* Make sure it's not too long */
2259 Length
= Name
->Length
+
2261 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
2262 if (Length
> UNICODE_STRING_MAX_BYTES
)
2264 /* Won't have enough space to add the hint */
2265 return STATUS_NAME_TOO_LONG
;
2268 /* Check if our buffer is large enough */
2269 if (Name
->Length
> sizeof(ImportBuffer
))
2271 /* Allocate from heap, plus 2 bytes for the Hint */
2272 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
2278 /* Use our internal buffer */
2279 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
2282 /* Clear the hint */
2283 ImportName
->Hint
= 0;
2285 /* Copy the name and null-terminate it */
2286 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
2287 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
2289 /* Clear the high bit */
2290 ImageBase
= ImportName
;
2291 Thunk
.u1
.AddressOfData
= 0;
2295 /* Do it by ordinal */
2298 /* Show debug message */
2299 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
2301 /* Make sure an ordinal was given */
2305 DPRINT1("No ordinal and no name\n");
2306 return STATUS_INVALID_PARAMETER
;
2309 /* Set the orginal flag in the thunk */
2310 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
2313 /* Acquire lock unless we are initting */
2314 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2318 /* Try to find the loaded DLL */
2319 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2322 DPRINT1("Invalid base address %p\n", BaseAddress
);
2323 Status
= STATUS_DLL_NOT_FOUND
;
2324 _SEH2_YIELD(goto Quickie
;)
2327 /* Get the pointer to the export directory */
2328 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2330 IMAGE_DIRECTORY_ENTRY_EXPORT
,
2335 DPRINT1("Image %wZ has no exports, but were trying to get procedure %s. BaseAddress asked %p, got entry BA %p\n", &LdrEntry
->BaseDllName
, Name
? Name
->Buffer
: NULL
, BaseAddress
, LdrEntry
->DllBase
);
2336 Status
= STATUS_PROCEDURE_NOT_FOUND
;
2337 _SEH2_YIELD(goto Quickie
;)
2340 /* Now get the thunk */
2341 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
2350 /* Finally, see if we're supposed to run the init routines */
2351 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
2354 * It's possible a forwarded entry had us load the DLL. In that case,
2355 * then we will call its DllMain. Use the last loaded DLL for this.
2357 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
2358 LdrEntry
= CONTAINING_RECORD(Entry
,
2359 LDR_DATA_TABLE_ENTRY
,
2360 InInitializationOrderModuleList
);
2362 /* Make sure we didn't process it yet*/
2363 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2365 /* Call the init routine */
2368 Status
= LdrpRunInitializeRoutines(NULL
);
2370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2372 /* Get the exception code */
2373 Status
= _SEH2_GetExceptionCode();
2379 /* Make sure we're OK till here */
2380 if (NT_SUCCESS(Status
))
2382 /* Return the address */
2383 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
2386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2388 /* Just ignore exceptions */
2394 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
2396 /* We allocated from heap, free it */
2397 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
2400 /* Release the CS if we entered it */
2401 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2409 LdrpLoadDll(IN BOOLEAN Redirected
,
2410 IN PWSTR DllPath OPTIONAL
,
2411 IN PULONG DllCharacteristics OPTIONAL
,
2412 IN PUNICODE_STRING DllName
,
2413 OUT PVOID
*BaseAddress
,
2414 IN BOOLEAN CallInit
)
2416 PPEB Peb
= NtCurrentPeb();
2417 NTSTATUS Status
= STATUS_SUCCESS
;
2419 BOOLEAN GotExtension
;
2421 WCHAR NameBuffer
[MAX_PATH
+ 6];
2422 UNICODE_STRING RawDllName
;
2423 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2424 BOOLEAN InInit
= LdrpInLdrInit
;
2426 /* Save the Raw DLL Name */
2427 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
2428 RtlInitEmptyUnicodeString(&RawDllName
, NameBuffer
, sizeof(NameBuffer
));
2429 RtlCopyUnicodeString(&RawDllName
, DllName
);
2431 /* Find the extension, if present */
2432 p
= DllName
->Buffer
+ DllName
->Length
/ sizeof(WCHAR
) - 1;
2433 GotExtension
= FALSE
;
2434 while (p
>= DllName
->Buffer
)
2439 GotExtension
= TRUE
;
2442 else if (c
== L
'\\')
2448 /* If no extension was found, add the default extension */
2451 /* Check that we have space to add one */
2452 if ((DllName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
2455 /* No space to add the extension */
2456 DbgPrintEx(81, //DPFLTR_LDR_ID,
2458 "LDR: %s - Dll name missing extension; with extension "
2459 "added the name is too long\n"
2460 " DllName: (@ %p) \"%wZ\"\n"
2461 " DllName->Length: %u\n",
2466 return STATUS_NAME_TOO_LONG
;
2469 /* Add it. Needs to be null terminated, thus the length check above */
2470 (VOID
)RtlAppendUnicodeStringToString(&RawDllName
,
2471 &LdrApiDefaultExtension
);
2474 /* Check for init flag and acquire lock */
2475 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2477 /* Show debug message */
2480 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
2482 DllPath
? DllPath
: L
"");
2485 /* Check if the DLL is already loaded */
2486 if (!LdrpCheckForLoadedDll(DllPath
,
2493 Status
= LdrpMapDll(DllPath
,
2500 if (!NT_SUCCESS(Status
)) goto Quickie
;
2502 /* FIXME: Need to mark the DLL range for the stack DB */
2503 //RtlpStkMarkDllRange(LdrEntry);
2505 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2506 if ((DllCharacteristics
) &&
2507 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
2509 /* This is not a DLL, so remove such data */
2510 LdrEntry
->EntryPoint
= NULL
;
2511 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
2514 /* Make sure it's a DLL */
2515 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2517 /* Check if this is a .NET Image */
2518 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
2520 /* Walk the Import Descriptor */
2521 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
2524 /* Update load count, unless it's locked */
2525 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2526 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2528 /* Check if we failed */
2529 if (!NT_SUCCESS(Status
))
2531 /* Clear entrypoint, and insert into list */
2532 LdrEntry
->EntryPoint
= NULL
;
2533 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2534 &LdrEntry
->InInitializationOrderModuleList
);
2536 /* Cancel the load */
2537 LdrpClearLoadInProgress();
2539 /* Unload the DLL */
2542 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2543 "import descriptors",
2547 LdrUnloadDll(LdrEntry
->DllBase
);
2549 /* Return the error */
2553 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2555 /* Increase load count */
2556 LdrEntry
->LoadCount
++;
2559 /* Insert it into the list */
2560 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2561 &LdrEntry
->InInitializationOrderModuleList
);
2563 /* If we have to run the entrypoint, make sure the DB is ready */
2564 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2566 /* FIXME: Notify Shim Engine */
2570 //ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
2571 //ShimLoadCallback(LdrEntry);
2574 /* Run the init routine */
2575 Status
= LdrpRunInitializeRoutines(NULL
);
2576 if (!NT_SUCCESS(Status
))
2578 /* Failed, unload the DLL */
2581 DbgPrint("LDR: Unloading %wZ because either its init "
2582 "routine or one of its static imports failed; "
2583 "status = 0x%08lx\n",
2587 LdrUnloadDll(LdrEntry
->DllBase
);
2592 /* The DB isn't ready, which means we were loaded because of a forwarder */
2593 Status
= STATUS_SUCCESS
;
2598 /* We were already loaded. Are we a DLL? */
2599 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2601 /* Increase load count */
2602 LdrEntry
->LoadCount
++;
2603 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2605 /* Clear the load in progress */
2606 LdrpClearLoadInProgress();
2610 /* Not a DLL, just increase the load count */
2611 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2616 /* Release the lock */
2617 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2619 /* Check for success */
2620 if (NT_SUCCESS(Status
))
2622 /* Return the base address */
2623 *BaseAddress
= LdrEntry
->DllBase
;
2628 *BaseAddress
= NULL
;
2637 LdrpClearLoadInProgress(VOID
)
2639 PLIST_ENTRY ListHead
, Entry
;
2640 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2641 ULONG ModulesCount
= 0;
2643 /* Traverse the init list */
2644 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2645 Entry
= ListHead
->Flink
;
2646 while (Entry
!= ListHead
)
2648 /* Get the loader entry */
2649 LdrEntry
= CONTAINING_RECORD(Entry
,
2650 LDR_DATA_TABLE_ENTRY
,
2651 InInitializationOrderModuleList
);
2653 /* Clear load in progress flag */
2654 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2656 /* Check for modules with entry point count but not processed yet */
2657 if ((LdrEntry
->EntryPoint
) &&
2658 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2660 /* Increase counter */
2664 /* Advance to the next entry */
2665 Entry
= Entry
->Flink
;
2668 /* Return final count */
2669 return ModulesCount
;