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
);
1863 ASSERT(TestName
.Length
< TestName
.MaximumLength
);
1865 /* Check if the file exists */
1867 if (RtlDoesFileExists_UstrEx(&TestName
, FALSE
))
1870 /* It does. Reallocate the buffer */
1871 TestName
.MaximumLength
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
) + sizeof(WCHAR
);
1872 TestName
.Buffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
1875 TestName
.MaximumLength
);
1876 if (!TestName
.Buffer
)
1878 /* Keep the old one */
1879 TestName
.Buffer
= Buffer
;
1884 Buffer
= TestName
.Buffer
;
1887 /* Make sure we have a buffer at least */
1888 ASSERT(TestName
.Buffer
);
1890 /* Resolve the name */
1891 *SearchPath
= ActualSearchPath
++;
1892 Status
= LdrpResolveFullName(&TestName
,
1899 /* Update buffer end */
1902 /* Update string position */
1903 //pp = ActualSearchPath++;
1907 /* Otherwise, write the character */
1912 /* Check if the string is empty, meaning we're done */
1913 if (!(*ActualSearchPath
)) TryAgain
= TRUE
;
1915 /* Advance in the string */
1917 } while (!TryAgain
);
1919 /* Check if we had a buffer and free it */
1920 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1923 /* Check if we got here through failure */
1924 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1926 /* Display debug output if snaps are on */
1929 /* Check which output to use -- failure or success */
1930 if (NT_SUCCESS(Status
))
1932 DbgPrintEx(81, //DPFLTR_LDR_ID,
1934 "LDR: %s - Returning %wZ\n",
1940 DbgPrintEx(81, //DPFLTR_LDR_ID,
1942 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1955 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1958 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1959 IN PUNICODE_STRING DllName
,
1961 IN BOOLEAN RedirectedDll
,
1962 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1965 PLIST_ENTRY ListHead
, ListEntry
;
1966 PLDR_DATA_TABLE_ENTRY CurEntry
;
1967 BOOLEAN FullPath
= FALSE
;
1970 UNICODE_STRING FullDllName
, NtPathName
;
1972 OBJECT_ATTRIBUTES ObjectAttributes
;
1974 HANDLE FileHandle
, SectionHandle
;
1975 IO_STATUS_BLOCK Iosb
;
1976 PVOID ViewBase
= NULL
;
1977 SIZE_T ViewSize
= 0;
1978 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1979 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"", DllName
, Flag
, RedirectedDll
, LdrEntry
);
1981 /* Check if a dll name was provided */
1982 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
1984 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1985 /* FIXME: Warning, code does not support redirection at all */
1987 /* Look in the hash table if flag was set */
1991 /* Get hash index */
1992 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
1994 /* Traverse that list */
1995 ListHead
= &LdrpHashTable
[HashIndex
];
1996 ListEntry
= ListHead
->Flink
;
1997 while (ListEntry
!= ListHead
)
1999 /* Get the current entry */
2000 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2002 /* Check base name of that module */
2003 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
2005 /* It matches, return it */
2006 *LdrEntry
= CurEntry
;
2010 /* Advance to the next entry */
2011 ListEntry
= ListEntry
->Flink
;
2014 /* Module was not found, return failure */
2018 /* Check if there is a full path in this DLL */
2019 wc
= DllName
->Buffer
;
2022 /* Check for a slash in the current position*/
2023 if ((*wc
== L
'\\') || (*wc
== L
'/'))
2025 /* Found the slash, so dll name contains path */
2028 /* Setup full dll name string */
2029 FullDllName
.Buffer
= NameBuf
;
2031 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2032 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
2035 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
2039 /* Check if that was successful */
2040 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
2042 /* HACK: Try to find active context dll */
2043 Status
= find_actctx_dll(DllName
->Buffer
, FullDllName
.Buffer
);
2044 if(Status
== STATUS_SUCCESS
)
2046 Length
= wcslen(FullDllName
.Buffer
) * sizeof(WCHAR
);
2047 DPRINT1("found %S for %S\n", FullDllName
.Buffer
, DllName
->Buffer
);
2054 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
2055 DllName
->Buffer
, Length
);
2058 /* Return failure */
2063 /* Full dll name is found */
2064 FullDllName
.Length
= Length
;
2065 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
2072 /* Go check the hash table */
2079 /* FIXME: Warning, activation context missing */
2080 /* NOTE: From here on down, everything looks good */
2082 /* Loop the module list */
2083 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2084 ListEntry
= ListHead
->Flink
;
2085 while (ListEntry
!= ListHead
)
2087 /* Get the current entry and advance to the next one */
2088 CurEntry
= CONTAINING_RECORD(ListEntry
,
2089 LDR_DATA_TABLE_ENTRY
,
2091 ListEntry
= ListEntry
->Flink
;
2093 /* Check if it's being unloaded */
2094 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
2096 /* Check if name matches */
2097 if (RtlEqualUnicodeString(&FullDllName
,
2098 &CurEntry
->FullDllName
,
2102 *LdrEntry
= CurEntry
;
2107 /* Convert given path to NT path */
2108 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
2113 /* Fail if conversion failed */
2117 /* Initialize object attributes and open it */
2118 InitializeObjectAttributes(&ObjectAttributes
,
2120 OBJ_CASE_INSENSITIVE
,
2123 Status
= NtOpenFile(&FileHandle
,
2124 SYNCHRONIZE
| FILE_EXECUTE
,
2127 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2128 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
2130 /* Free NT path name */
2131 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
2133 /* If opening the file failed - return failure */
2134 if (!NT_SUCCESS(Status
)) return FALSE
;
2136 /* Create a section for this file */
2137 Status
= NtCreateSection(&SectionHandle
,
2139 SECTION_MAP_EXECUTE
|
2147 /* Close file handle */
2148 NtClose(FileHandle
);
2150 /* If creating section failed - return failure */
2151 if (!NT_SUCCESS(Status
)) return FALSE
;
2153 /* Map view of this section */
2154 Status
= ZwMapViewOfSection(SectionHandle
,
2165 /* Close section handle */
2166 NtClose(SectionHandle
);
2168 /* If section mapping failed - return failure */
2169 if (!NT_SUCCESS(Status
)) return FALSE
;
2171 /* Get pointer to the NT header of this section */
2172 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
2173 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
2175 /* Unmap the section and fail */
2176 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2180 /* Go through the list of modules again */
2181 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2182 ListEntry
= ListHead
->Flink
;
2183 while (ListEntry
!= ListHead
)
2185 /* Get the current entry and advance to the next one */
2186 CurEntry
= CONTAINING_RECORD(ListEntry
,
2187 LDR_DATA_TABLE_ENTRY
,
2189 ListEntry
= ListEntry
->Flink
;
2191 /* Check if it's in the process of being unloaded */
2192 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
2194 /* The header is untrusted, use SEH */
2197 /* Check if timedate stamp and sizes match */
2198 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
2199 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
2201 /* Time, date and size match. Let's compare their headers */
2202 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
2203 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
2205 /* Headers match too! Finally ask the kernel to compare mapped files */
2206 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
2207 if (!NT_SUCCESS(Status
))
2209 /* Almost identical, but not quite, keep trying */
2210 _SEH2_YIELD(continue;)
2214 /* This is our entry!, unmap and return success */
2215 *LdrEntry
= CurEntry
;
2216 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2217 _SEH2_YIELD(return TRUE
;)
2222 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
2229 /* Unmap the section and fail */
2230 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2236 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
2237 IN PANSI_STRING Name
,
2239 OUT PVOID
*ProcedureAddress
,
2240 IN BOOLEAN ExecuteInit
)
2242 NTSTATUS Status
= STATUS_SUCCESS
;
2243 UCHAR ImportBuffer
[64];
2244 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2245 IMAGE_THUNK_DATA Thunk
;
2247 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
2248 PIMAGE_EXPORT_DIRECTORY ExportDir
;
2249 ULONG ExportDirSize
, Length
;
2252 /* Show debug message */
2253 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
2255 /* Check if we got a name */
2258 /* Show debug message */
2259 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
2261 /* Make sure it's not too long */
2262 Length
= Name
->Length
+
2264 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
2265 if (Length
> UNICODE_STRING_MAX_BYTES
)
2267 /* Won't have enough space to add the hint */
2268 return STATUS_NAME_TOO_LONG
;
2271 /* Check if our buffer is large enough */
2272 if (Name
->Length
> sizeof(ImportBuffer
))
2274 /* Allocate from heap, plus 2 bytes for the Hint */
2275 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
2281 /* Use our internal buffer */
2282 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
2285 /* Clear the hint */
2286 ImportName
->Hint
= 0;
2288 /* Copy the name and null-terminate it */
2289 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
2290 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
2292 /* Clear the high bit */
2293 ImageBase
= ImportName
;
2294 Thunk
.u1
.AddressOfData
= 0;
2298 /* Do it by ordinal */
2301 /* Show debug message */
2302 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
2304 /* Make sure an ordinal was given */
2308 DPRINT1("No ordinal and no name\n");
2309 return STATUS_INVALID_PARAMETER
;
2312 /* Set the orginal flag in the thunk */
2313 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
2316 /* Acquire lock unless we are initting */
2317 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2321 /* Try to find the loaded DLL */
2322 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2325 DPRINT1("Invalid base address %p\n", BaseAddress
);
2326 Status
= STATUS_DLL_NOT_FOUND
;
2327 _SEH2_YIELD(goto Quickie
;)
2330 /* Get the pointer to the export directory */
2331 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2333 IMAGE_DIRECTORY_ENTRY_EXPORT
,
2338 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
);
2339 Status
= STATUS_PROCEDURE_NOT_FOUND
;
2340 _SEH2_YIELD(goto Quickie
;)
2343 /* Now get the thunk */
2344 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
2353 /* Finally, see if we're supposed to run the init routines */
2354 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
2357 * It's possible a forwarded entry had us load the DLL. In that case,
2358 * then we will call its DllMain. Use the last loaded DLL for this.
2360 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
2361 LdrEntry
= CONTAINING_RECORD(Entry
,
2362 LDR_DATA_TABLE_ENTRY
,
2363 InInitializationOrderModuleList
);
2365 /* Make sure we didn't process it yet*/
2366 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2368 /* Call the init routine */
2371 Status
= LdrpRunInitializeRoutines(NULL
);
2373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2375 /* Get the exception code */
2376 Status
= _SEH2_GetExceptionCode();
2382 /* Make sure we're OK till here */
2383 if (NT_SUCCESS(Status
))
2385 /* Return the address */
2386 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
2389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2391 /* Just ignore exceptions */
2397 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
2399 /* We allocated from heap, free it */
2400 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
2403 /* Release the CS if we entered it */
2404 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2412 LdrpLoadDll(IN BOOLEAN Redirected
,
2413 IN PWSTR DllPath OPTIONAL
,
2414 IN PULONG DllCharacteristics OPTIONAL
,
2415 IN PUNICODE_STRING DllName
,
2416 OUT PVOID
*BaseAddress
,
2417 IN BOOLEAN CallInit
)
2419 PPEB Peb
= NtCurrentPeb();
2420 NTSTATUS Status
= STATUS_SUCCESS
;
2423 WCHAR NameBuffer
[266];
2425 UNICODE_STRING RawDllNameString
;
2426 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2427 BOOLEAN InInit
= LdrpInLdrInit
;
2429 /* Find the name without the extension */
2430 p1
= DllName
->Buffer
;
2439 else if (c
== L
'\\')
2445 /* Save the Raw DLL Name */
2446 RawDllName
= NameBuffer
;
2447 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
2448 RtlMoveMemory(RawDllName
, DllName
->Buffer
, DllName
->Length
);
2450 /* Check if no extension was found or if we got a slash */
2451 if (!(p2
) || (*p2
== '\\'))
2453 /* Check that we have space to add one */
2454 if ((DllName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
2457 /* No space to add the extension */
2458 DbgPrintEx(81, //DPFLTR_LDR_ID,
2460 "LDR: %s - Dll name missing extension; with extension "
2461 "added the name is too long\n"
2462 " DllName: (@ %p) \"%wZ\"\n"
2463 " DllName->Length: %u\n",
2468 return STATUS_NAME_TOO_LONG
;
2471 /* FIXME: CLEAN THIS UP WITH Rtl String Functions */
2473 RtlMoveMemory((PVOID
)((ULONG_PTR
)RawDllName
+ DllName
->Length
),
2474 LdrApiDefaultExtension
.Buffer
,
2475 LdrApiDefaultExtension
.Length
);
2477 /* Save the length to a unicode string */
2478 RawDllNameString
.Length
= DllName
->Length
+ LdrApiDefaultExtension
.Length
;
2480 /* Null terminate it */
2481 RawDllName
[RawDllNameString
.Length
/ sizeof(WCHAR
)] = 0;
2485 /* Null terminate it */
2486 RawDllName
[DllName
->Length
/ sizeof(WCHAR
)] = 0;
2488 /* Save the length to a unicode string */
2489 RawDllNameString
.Length
= DllName
->Length
;
2492 /* Now create a unicode string for the DLL's name */
2493 RawDllNameString
.MaximumLength
= sizeof(NameBuffer
);
2494 RawDllNameString
.Buffer
= NameBuffer
;
2496 /* Check for init flag and acquire lock */
2497 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2499 /* Show debug message */
2502 DPRINT1("LDR: LdrLoadDll, loading %ws from %ws\n",
2504 DllPath
? DllPath
: L
"");
2507 /* Check if the DLL is already loaded */
2508 if (!LdrpCheckForLoadedDll(DllPath
,
2515 Status
= LdrpMapDll(DllPath
,
2522 if (!NT_SUCCESS(Status
)) goto Quickie
;
2524 /* FIXME: Need to mark the DLL range for the stack DB */
2525 //RtlpStkMarkDllRange(LdrEntry);
2527 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2528 if ((DllCharacteristics
) &&
2529 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
2531 /* This is not a DLL, so remove such data */
2532 LdrEntry
->EntryPoint
= NULL
;
2533 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
2536 /* Make sure it's a DLL */
2537 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2539 /* Check if this is a .NET Image */
2540 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
2542 /* Walk the Import Descriptor */
2543 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
2546 /* Update load count, unless it's locked */
2547 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2548 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2550 /* Check if we failed */
2551 if (!NT_SUCCESS(Status
))
2553 /* Clear entrypoint, and insert into list */
2554 LdrEntry
->EntryPoint
= NULL
;
2555 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2556 &LdrEntry
->InInitializationOrderModuleList
);
2558 /* Cancel the load */
2559 LdrpClearLoadInProgress();
2561 /* Unload the DLL */
2564 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2565 "import descriptors",
2569 LdrUnloadDll(LdrEntry
->DllBase
);
2571 /* Return the error */
2575 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2577 /* Increase load count */
2578 LdrEntry
->LoadCount
++;
2581 /* Insert it into the list */
2582 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2583 &LdrEntry
->InInitializationOrderModuleList
);
2585 /* If we have to run the entrypoint, make sure the DB is ready */
2586 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2588 /* FIXME: Notify Shim Engine */
2592 //ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
2593 //ShimLoadCallback(LdrEntry);
2596 /* Run the init routine */
2597 Status
= LdrpRunInitializeRoutines(NULL
);
2598 if (!NT_SUCCESS(Status
))
2600 /* Failed, unload the DLL */
2603 DbgPrint("LDR: Unloading %wZ because either its init "
2604 "routine or one of its static imports failed; "
2605 "status = 0x%08lx\n",
2609 LdrUnloadDll(LdrEntry
->DllBase
);
2614 /* The DB isn't ready, which means we were loaded because of a forwarder */
2615 Status
= STATUS_SUCCESS
;
2620 /* We were already loaded. Are we a DLL? */
2621 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2623 /* Increase load count */
2624 LdrEntry
->LoadCount
++;
2625 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2627 /* Clear the load in progress */
2628 LdrpClearLoadInProgress();
2632 /* Not a DLL, just increase the load count */
2633 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2638 /* Release the lock */
2639 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2641 /* Check for success */
2642 if (NT_SUCCESS(Status
))
2644 /* Return the base address */
2645 *BaseAddress
= LdrEntry
->DllBase
;
2650 *BaseAddress
= NULL
;
2659 LdrpClearLoadInProgress(VOID
)
2661 PLIST_ENTRY ListHead
, Entry
;
2662 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2663 ULONG ModulesCount
= 0;
2665 /* Traverse the init list */
2666 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2667 Entry
= ListHead
->Flink
;
2668 while (Entry
!= ListHead
)
2670 /* Get the loader entry */
2671 LdrEntry
= CONTAINING_RECORD(Entry
,
2672 LDR_DATA_TABLE_ENTRY
,
2673 InInitializationOrderModuleList
);
2675 /* Clear load in progress flag */
2676 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2678 /* Check for modules with entry point count but not processed yet */
2679 if ((LdrEntry
->EntryPoint
) &&
2680 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2682 /* Increase counter */
2686 /* Advance to the next entry */
2687 Entry
= Entry
->Flink
;
2690 /* Return final count */
2691 return ModulesCount
;