2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrutils.c
5 * PURPOSE: Internal Loader Utility Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache
, LdrpGetModuleHandleCache
;
20 BOOLEAN g_ShimsEnabled
;
22 /* FUNCTIONS *****************************************************************/
24 /* NOTE: Remove those two once our actctx support becomes better */
25 NTSTATUS
create_module_activation_context( LDR_DATA_TABLE_ENTRY
*module
)
28 LDR_RESOURCE_INFO info
;
29 IMAGE_RESOURCE_DATA_ENTRY
*entry
;
31 info
.Type
= (ULONG
)RT_MANIFEST
;
32 info
.Name
= (ULONG
)ISOLATIONAWARE_MANIFEST_RESOURCE_ID
;
34 if (!(status
= LdrFindResource_U( module
->DllBase
, &info
, 3, &entry
)))
37 ctx
.cbSize
= sizeof(ctx
);
39 ctx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_HMODULE_VALID
;
40 ctx
.hModule
= module
->DllBase
;
41 ctx
.lpResourceName
= (LPCWSTR
)ISOLATIONAWARE_MANIFEST_RESOURCE_ID
;
42 status
= RtlCreateActivationContext(0, (PVOID
)&ctx
, 0, NULL
, NULL
, &module
->EntryPointActivationContext
);
47 NTSTATUS
find_actctx_dll( LPCWSTR libname
, WCHAR
*fullname
)
49 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\'};
50 static const WCHAR dotManifestW
[] = {'.','m','a','n','i','f','e','s','t',0};
52 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*info
;
53 ACTCTX_SECTION_KEYED_DATA data
;
56 SIZE_T needed
, size
= 1024;
59 RtlInitUnicodeString( &nameW
, libname
);
60 data
.cbSize
= sizeof(data
);
61 status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
62 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
64 if (status
!= STATUS_SUCCESS
) return status
;
68 if (!(info
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
70 status
= STATUS_NO_MEMORY
;
73 status
= RtlQueryInformationActivationContext( 0, data
.hActCtx
, &data
.ulAssemblyRosterIndex
,
74 AssemblyDetailedInformationInActivationContext
,
75 info
, size
, &needed
);
76 if (status
== STATUS_SUCCESS
) break;
77 if (status
!= STATUS_BUFFER_TOO_SMALL
) goto done
;
78 RtlFreeHeap( RtlGetProcessHeap(), 0, info
);
82 DPRINT("manifestpath === %S\n", info
->lpAssemblyManifestPath
);
83 DPRINT("DirectoryName === %S\n", info
->lpAssemblyDirectoryName
);
84 if (!info
->lpAssemblyManifestPath
|| !info
->lpAssemblyDirectoryName
)
86 status
= STATUS_SXS_KEY_NOT_FOUND
;
90 if ((p
= wcsrchr( info
->lpAssemblyManifestPath
, '\\' )))
92 DWORD dirlen
= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
95 if (_wcsnicmp( p
, info
->lpAssemblyDirectoryName
, dirlen
) || wcsicmp( p
+ dirlen
, dotManifestW
))
97 /* manifest name does not match directory name, so it's not a global
98 * windows/winsxs manifest; use the manifest directory name instead */
99 dirlen
= p
- info
->lpAssemblyManifestPath
;
100 needed
= (dirlen
+ 1) * sizeof(WCHAR
) + nameW
.Length
;
103 /*if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
105 status = STATUS_NO_MEMORY;
108 memcpy( p
, info
->lpAssemblyManifestPath
, dirlen
* sizeof(WCHAR
) );
110 wcscpy( p
, libname
);
115 needed
= (wcslen(SharedUserData
->NtSystemRoot
) * sizeof(WCHAR
) +
116 sizeof(winsxsW
) + info
->ulAssemblyDirectoryNameLength
+ nameW
.Length
+ 2*sizeof(WCHAR
));
119 //if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
121 //status = STATUS_NO_MEMORY;
124 wcscpy( p
, SharedUserData
->NtSystemRoot
);
126 memcpy( p
, winsxsW
, sizeof(winsxsW
) );
127 p
+= sizeof(winsxsW
) / sizeof(WCHAR
);
128 memcpy( p
, info
->lpAssemblyDirectoryName
, info
->ulAssemblyDirectoryNameLength
);
129 p
+= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
131 wcscpy( p
, libname
);
134 RtlFreeHeap( RtlGetProcessHeap(), 0, info
);
135 RtlReleaseActivationContext( data
.hActCtx
);
136 DPRINT("%S\n", fullname
);
143 LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut
,
148 ASSERT(Length
<= UNICODE_STRING_MAX_BYTES
);
151 StringOut
->Length
= 0;
153 /* Make sure it's not mis-aligned */
157 StringOut
->Buffer
= NULL
;
158 StringOut
->MaximumLength
= 0;
159 return STATUS_INVALID_PARAMETER
;
162 /* Allocate the string*/
163 StringOut
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
165 StringOut
->Length
+ sizeof(WCHAR
));
166 if (!StringOut
->Buffer
)
169 StringOut
->MaximumLength
= 0;
170 return STATUS_NO_MEMORY
;
173 /* Null-terminate it */
174 StringOut
->Buffer
[StringOut
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
176 /* Check if this is a maximum-sized string */
177 if (StringOut
->Length
!= UNICODE_STRING_MAX_BYTES
)
179 /* It's not, so set the maximum length to be one char more */
180 StringOut
->MaximumLength
= StringOut
->Length
+ sizeof(UNICODE_NULL
);
184 /* The length is already the maximum possible */
185 StringOut
->MaximumLength
= UNICODE_STRING_MAX_BYTES
;
189 return STATUS_SUCCESS
;
194 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn
)
196 ASSERT(StringIn
!= NULL
);
198 /* If Buffer is not NULL - free it */
199 if (StringIn
->Buffer
)
201 RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn
->Buffer
);
205 RtlInitEmptyUnicodeString(StringIn
, NULL
, 0);
209 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint
,
210 IN PVOID BaseAddress
,
215 return EntryPoint(BaseAddress
, Reason
, Context
);
218 /* NOTE: This function is broken */
221 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
223 OUT PUNICODE_STRING UpdateString
)
225 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder
;
226 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
227 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
228 PIMAGE_THUNK_DATA FirstThunk
;
229 PLDR_DATA_TABLE_ENTRY Entry
;
230 PUNICODE_STRING ImportNameUnic
;
231 ANSI_STRING ImportNameAnsi
;
237 /* Check the action we need to perform */
238 if (Flags
== LDRP_UPDATE_REFCOUNT
)
240 /* Make sure entry is not being loaded already */
241 if (LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
)
244 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
246 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
248 /* Make sure the entry is not being unloaded already */
249 if (LdrEntry
->Flags
& LDRP_UNLOAD_IN_PROGRESS
)
252 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
255 /* Go through all bound DLLs and dereference them */
256 ImportNameUnic
= &NtCurrentTeb()->StaticUnicodeString
;
258 /* Try to get the new import entry */
259 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
261 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
266 /* Set entry flags if refing/derefing */
267 if (Flags
== LDRP_UPDATE_REFCOUNT
)
268 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
269 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
270 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
272 while (BoundEntry
->OffsetModuleName
)
274 /* Get pointer to the current import name */
275 ImportName
= (PCHAR
)BoundEntry
+ BoundEntry
->OffsetModuleName
;
277 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
278 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
280 if (NT_SUCCESS(Status
))
282 if (LdrpCheckForLoadedDll(NULL
,
288 if (Entry
->LoadCount
!= 0xFFFF)
290 /* Perform the required action */
293 case LDRP_UPDATE_REFCOUNT
:
296 case LDRP_UPDATE_DEREFCOUNT
:
299 case LDRP_UPDATE_PIN
:
300 Entry
->LoadCount
= 0xFFFF;
307 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
311 /* Recurse into this entry */
312 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
316 /* Go through forwarders */
317 NewImportForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
318 for (i
=0; i
<BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
320 ImportName
= (PCHAR
)BoundEntry
+ NewImportForwarder
->OffsetModuleName
;
322 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
323 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
324 if (NT_SUCCESS(Status
))
326 if (LdrpCheckForLoadedDll(NULL
,
332 if (Entry
->LoadCount
!= 0xFFFF)
334 /* Perform the required action */
337 case LDRP_UPDATE_REFCOUNT
:
340 case LDRP_UPDATE_DEREFCOUNT
:
343 case LDRP_UPDATE_PIN
:
344 Entry
->LoadCount
= 0xFFFF;
351 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
355 /* Recurse into this entry */
356 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
360 NewImportForwarder
++;
363 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)NewImportForwarder
;
370 /* Check oldstyle import descriptor */
371 ImportEntry
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
373 IMAGE_DIRECTORY_ENTRY_IMPORT
,
377 /* There is old one, so go through its entries */
378 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
380 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->FirstThunk
);
382 /* Skip this entry if needed */
383 if (!FirstThunk
->u1
.Function
)
389 ImportName
= (PSZ
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
391 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
392 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
393 if (NT_SUCCESS(Status
))
395 if (LdrpCheckForLoadedDll(NULL
,
401 if (Entry
->LoadCount
!= 0xFFFF)
403 /* Perform the required action */
406 case LDRP_UPDATE_REFCOUNT
:
409 case LDRP_UPDATE_DEREFCOUNT
:
412 case LDRP_UPDATE_PIN
:
413 Entry
->LoadCount
= 0xFFFF;
420 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
425 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
429 /* Go to the next entry */
437 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
440 WCHAR Buffer
[MAX_PATH
];
441 UNICODE_STRING UpdateString
;
443 /* Setup the string and call the extended API */
444 RtlInitEmptyUnicodeString(&UpdateString
, Buffer
, sizeof(Buffer
));
445 LdrpUpdateLoadCount3(LdrEntry
, Flags
, &UpdateString
);
450 LdrpCallTlsInitializers(IN PVOID BaseAddress
,
453 PIMAGE_TLS_DIRECTORY TlsDirectory
;
454 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
457 /* Get the TLS Directory */
458 TlsDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
460 IMAGE_DIRECTORY_ENTRY_TLS
,
463 /* Protect against invalid pointers */
466 /* Make sure it's valid */
470 Array
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
;
476 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
477 BaseAddress
, TlsDirectory
, Array
);
483 /* Get the TLS Entrypoint */
489 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
490 BaseAddress
, Callback
);
494 LdrpCallInitRoutine((PDLL_INIT_ROUTINE
)Callback
,
502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
511 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName
,
514 /* Not implemented */
515 return STATUS_SUCCESS
;
520 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
522 IN PULONG DllCharacteristics OPTIONAL
,
523 OUT PHANDLE SectionHandle
)
527 OBJECT_ATTRIBUTES ObjectAttributes
;
528 IO_STATUS_BLOCK IoStatusBlock
;
529 ULONG_PTR HardErrorParameters
[1];
531 SECTION_IMAGE_INFORMATION SectionImageInfo
;
533 /* Check if we don't already have a handle */
536 /* Create the object attributes */
537 InitializeObjectAttributes(&ObjectAttributes
,
539 OBJ_CASE_INSENSITIVE
,
544 Status
= NtOpenFile(&FileHandle
,
545 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
548 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
549 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
551 /* Check if we failed */
552 if (!NT_SUCCESS(Status
))
554 /* Attempt to open for execute only */
555 Status
= NtOpenFile(&FileHandle
,
556 SYNCHRONIZE
| FILE_EXECUTE
,
559 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
560 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
562 /* Check if this failed too */
563 if (!NT_SUCCESS(Status
))
565 /* Show debug message */
568 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
572 /* Make sure to return an expected status code */
573 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
575 /* Callers expect this instead */
576 Status
= STATUS_DLL_NOT_FOUND
;
579 /* Return an empty section handle */
580 *SectionHandle
= NULL
;
587 /* Use the handle we already have */
588 FileHandle
= DllHandle
;
591 /* Create a section for the DLL */
592 Status
= NtCreateSection(SectionHandle
,
593 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
594 SECTION_MAP_WRITE
| SECTION_QUERY
,
601 /* If mapping failed, raise a hard error */
602 if (!NT_SUCCESS(Status
))
604 /* Forget the handle */
605 *SectionHandle
= NULL
;
607 /* Give the DLL name */
608 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
610 /* Raise the error */
611 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
618 /* Increment the error count */
619 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
622 /* Check for Safer restrictions */
623 if (DllCharacteristics
&&
624 !(*DllCharacteristics
& IMAGE_FILE_SYSTEM
))
626 /* Make sure it's executable */
627 Status
= ZwQuerySection(*SectionHandle
,
628 SectionImageInformation
,
630 sizeof(SECTION_IMAGE_INFORMATION
),
632 if (NT_SUCCESS(Status
))
634 /* Bypass the check for .NET images */
635 if (!(SectionImageInfo
.LoaderFlags
& IMAGE_LOADER_FLAGS_COMPLUS
))
637 /* Check with Safer */
638 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
639 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
641 /* Show debug message */
644 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
648 /* Failure case, close section handle */
649 NtClose(*SectionHandle
);
650 *SectionHandle
= NULL
;
656 /* Failure case, close section handle */
657 NtClose(*SectionHandle
);
658 *SectionHandle
= NULL
;
662 /* Close the file handle, we don't need it */
669 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
672 LdrpResolveDllName(PWSTR DllPath
,
674 PUNICODE_STRING FullDllName
,
675 PUNICODE_STRING BaseDllName
)
677 PWCHAR NameBuffer
, p1
, p2
= 0;
682 /* Allocate space for full DLL name */
683 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize
+ sizeof(UNICODE_NULL
));
684 if (!FullDllName
->Buffer
) return FALSE
;
686 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
691 &BaseDllName
->Buffer
);
693 if (!Length
|| Length
> BufSize
)
695 /* HACK: Try to find active context dll */
696 Status
= find_actctx_dll(DllName
, FullDllName
->Buffer
);
697 if(Status
== STATUS_SUCCESS
)
699 Length
= wcslen(FullDllName
->Buffer
) * sizeof(WCHAR
);
700 DPRINT1("found %S for %S\n", FullDllName
->Buffer
, DllName
);
704 /* NOTE: This code should remain after removing the hack */
707 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
708 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
711 RtlFreeUnicodeString(FullDllName
);
716 /* Construct full DLL name */
717 FullDllName
->Length
= Length
;
718 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
720 /* Allocate a new buffer */
721 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
724 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
728 /* Copy over the contents from the previous one and free it */
729 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
730 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
731 FullDllName
->Buffer
= NameBuffer
;
733 /* Find last backslash */
734 p1
= FullDllName
->Buffer
;
743 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
751 /* Calculate remaining length */
754 /* Construct base DLL name */
755 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
756 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
757 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName
->MaximumLength
);
759 if (!BaseDllName
->Buffer
)
761 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
765 /* Copy base dll name to the new buffer */
766 RtlMoveMemory(BaseDllName
->Buffer
,
768 BaseDllName
->Length
);
770 /* Null-terminate the string */
771 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
778 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase
)
780 PIMAGE_NT_HEADERS NtHeaders
;
781 ULONG_PTR EntryPoint
= 0;
783 /* Get entry point offset from NT headers */
784 NtHeaders
= RtlImageNtHeader(ImageBase
);
788 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
789 if (EntryPoint
) EntryPoint
+= (ULONG_PTR
)ImageBase
;
792 /* Return calculated pointer (or zero in case of failure) */
793 return (PVOID
)EntryPoint
;
796 /* NOTE: This function is partially missing SxS */
799 LdrpCheckForKnownDll(PWSTR DllName
,
800 PUNICODE_STRING FullDllName
,
801 PUNICODE_STRING BaseDllName
,
802 HANDLE
*SectionHandle
)
804 OBJECT_ATTRIBUTES ObjectAttributes
;
805 HANDLE Section
= NULL
;
806 UNICODE_STRING DllNameUnic
;
811 /* Zero initialize provided parameters */
812 if (SectionHandle
) *SectionHandle
= 0;
816 FullDllName
->Length
= 0;
817 FullDllName
->MaximumLength
= 0;
818 FullDllName
->Buffer
= NULL
;
823 BaseDllName
->Length
= 0;
824 BaseDllName
->MaximumLength
= 0;
825 BaseDllName
->Buffer
= NULL
;
828 /* If any of these three params are missing then fail */
829 if (!SectionHandle
|| !FullDllName
|| !BaseDllName
)
830 return STATUS_INVALID_PARAMETER
;
832 /* Check the Loader Lock */
833 LdrpEnsureLoaderLockIsHeld();
835 /* Upgrade DllName to a unicode string */
836 RtlInitUnicodeString(&DllNameUnic
, DllName
);
838 /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
840 /* Get the activation context */
841 Status
= RtlFindActivationContextSectionString(0,
843 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
847 /* Check if it's a SxS or not */
848 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
849 Status
== STATUS_SXS_KEY_NOT_FOUND
)
851 /* NOTE: Here it's beneficial to allocate one big unicode string
852 using LdrpAllocateUnicodeString instead of fragmenting the heap
853 with two allocations as it's done now. */
855 /* Set up BaseDllName */
856 BaseDllName
->Length
= DllNameUnic
.Length
;
857 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
858 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
860 DllNameUnic
.MaximumLength
);
861 if (!BaseDllName
->Buffer
)
863 Status
= STATUS_NO_MEMORY
;
867 /* Copy the contents there */
868 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
870 /* Set up FullDllName */
871 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
872 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
873 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
874 if (!FullDllName
->Buffer
)
876 Status
= STATUS_NO_MEMORY
;
880 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
882 /* Put a slash there */
883 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
888 /* Set up DllNameUnic for a relative path */
889 DllNameUnic
.Buffer
= (PWSTR
)p1
;
890 DllNameUnic
.Length
= BaseDllName
->Length
;
891 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
893 /* Copy the contents */
894 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
896 /* There are all names, init attributes and open the section */
897 InitializeObjectAttributes(&ObjectAttributes
,
899 OBJ_CASE_INSENSITIVE
,
900 LdrpKnownDllObjectDirectory
,
903 Status
= NtOpenSection(&Section
,
904 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
906 if (!NT_SUCCESS(Status
))
908 /* Clear status in case it was just not found */
909 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) Status
= STATUS_SUCCESS
;
913 /* Pass section handle to the caller and return success */
914 *SectionHandle
= Section
;
915 return STATUS_SUCCESS
;
919 /* Close section object if it was opened */
920 if (Section
) NtClose(Section
);
922 /* Free string resources */
923 if (BaseDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
924 if (FullDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
932 LdrpSetProtection(PVOID ViewBase
,
935 PIMAGE_NT_HEADERS NtHeaders
;
936 PIMAGE_SECTION_HEADER Section
;
940 ULONG NewProtection
, OldProtection
, i
;
942 /* Get the NT headers */
943 NtHeaders
= RtlImageNtHeader(ViewBase
);
944 if (!NtHeaders
) return STATUS_INVALID_IMAGE_FORMAT
;
946 /* Compute address of the first section header */
947 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
949 /* Go through all sections */
950 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
952 /* Check for read-only non-zero section */
953 if ((Section
->SizeOfRawData
) &&
954 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
956 /* Check if we are setting or restoring protection */
959 /* Set it to either EXECUTE or READONLY */
960 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
962 NewProtection
= PAGE_EXECUTE
;
966 NewProtection
= PAGE_READONLY
;
969 /* Add PAGE_NOCACHE if needed */
970 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
972 NewProtection
|= PAGE_NOCACHE
;
977 /* Enable write access */
978 NewProtection
= PAGE_READWRITE
;
981 /* Get the section VA */
982 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
983 SectionSize
= Section
->SizeOfRawData
;
987 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
992 if (!NT_SUCCESS(Status
)) return Status
;
996 /* Move to the next section */
1000 /* Flush instruction cache if necessary */
1001 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
1002 return STATUS_SUCCESS
;
1005 /* NOTE: Not yet reviewed */
1008 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
1010 IN PWSTR DllName OPTIONAL
,
1011 IN PULONG DllCharacteristics
,
1013 IN BOOLEAN Redirect
,
1014 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
1016 PTEB Teb
= NtCurrentTeb();
1017 PPEB Peb
= NtCurrentPeb();
1018 PWCHAR p1
= DllName
;
1020 BOOLEAN KnownDll
= FALSE
;
1021 UNICODE_STRING FullDllName
, BaseDllName
;
1022 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
1023 UNICODE_STRING NtPathDllName
;
1024 ULONG_PTR HardErrorParameters
[2];
1025 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
1027 SIZE_T ViewSize
= 0;
1028 PVOID ViewBase
= NULL
;
1029 PVOID ArbitraryUserPointer
;
1030 PIMAGE_NT_HEADERS NtHeaders
;
1031 NTSTATUS HardErrorStatus
, Status
;
1032 BOOLEAN OverlapDllFound
= FALSE
;
1033 ULONG_PTR ImageBase
, ImageEnd
;
1034 PLIST_ENTRY ListHead
, NextEntry
;
1035 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
1036 ULONG_PTR CandidateBase
, CandidateEnd
;
1037 UNICODE_STRING OverlapDll
;
1038 BOOLEAN RelocatableDll
= TRUE
;
1039 UNICODE_STRING IllegalDll
;
1041 ULONG RelocDataSize
= 0;
1043 // FIXME: AppCompat stuff is missing
1047 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
1049 SearchPath
? SearchPath
: L
"");
1052 /* Check if we have a known dll directory */
1053 if (LdrpKnownDllObjectDirectory
)
1055 /* Check if the path is full */
1059 if (TempChar
== '\\' || TempChar
== '/' )
1061 /* Complete path, don't do Known Dll lookup */
1066 /* Try to find a Known DLL */
1067 Status
= LdrpCheckForKnownDll(DllName
,
1072 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_DLL_NOT_FOUND
))
1075 DbgPrintEx(DPFLTR_LDR_ID
,
1077 "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
1088 /* Check if the Known DLL Check returned something */
1091 /* It didn't, so try to resolve the name now */
1092 if (LdrpResolveDllName(SearchPath
,
1097 /* Got a name, display a message */
1100 DPRINT1("LDR: Loading (%s) %wZ\n",
1101 Static
? "STATIC" : "DYNAMIC",
1105 /* Convert to NT Name */
1106 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1111 /* Path was invalid */
1112 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1115 /* Create a section for this dLL */
1116 Status
= LdrpCreateDllSection(&NtPathDllName
,
1121 /* Free the NT Name */
1122 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
1125 if (!NT_SUCCESS(Status
))
1127 /* Free the name strings and return */
1128 RtlFreeUnicodeString(&FullDllName
);
1129 RtlFreeUnicodeString(&BaseDllName
);
1135 /* We couldn't resolve the name, is this a static load? */
1139 * This is BAD! Static loads are CRITICAL. Bugcheck!
1140 * Initialize the strings for the error
1142 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
1143 RtlInitUnicodeString(&HardErrorDllPath
,
1144 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
1146 /* Set them as error parameters */
1147 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
1148 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
1150 /* Raise the hard error */
1151 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
1154 HardErrorParameters
,
1158 /* We're back, where we initializing? */
1159 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1162 /* Return failure */
1163 return STATUS_DLL_NOT_FOUND
;
1168 /* We have a section handle, so this is a known dll */
1172 /* Stuff the image name in the TIB, for the debugger */
1173 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1174 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1179 Status
= NtMapViewOfSection(SectionHandle
,
1191 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1193 /* Fail if we couldn't map it */
1194 if (!NT_SUCCESS(Status
))
1196 /* Close and return */
1197 NtClose(SectionHandle
);
1201 /* Get the NT Header */
1202 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
1204 /* Invalid image, unmap, close handle and fail */
1205 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1206 NtClose(SectionHandle
);
1207 return STATUS_INVALID_IMAGE_FORMAT
;
1210 // FIXME: .NET support is missing
1212 /* Allocate an entry */
1213 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
1215 /* Invalid image, unmap, close handle and fail */
1216 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1217 NtClose(SectionHandle
);
1218 return STATUS_NO_MEMORY
;
1221 /* Setup the entry */
1222 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
1223 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
1224 LdrEntry
->LoadCount
= 0;
1225 LdrEntry
->FullDllName
= FullDllName
;
1226 LdrEntry
->BaseDllName
= BaseDllName
;
1227 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
1229 /* Show debug message */
1232 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
1237 /* Insert this entry */
1238 LdrpInsertMemoryTableEntry(LdrEntry
);
1240 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
1242 /* Check for invalid CPU Image */
1243 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1245 /* Load our header */
1246 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1248 /* Assume defaults if we don't have to run the Hard Error path */
1249 HardErrorStatus
= STATUS_SUCCESS
;
1250 Response
= ResponseCancel
;
1252 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1253 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1255 /* Reset the entrypoint, save our Dll Name */
1256 LdrEntry
->EntryPoint
= 0;
1257 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1259 /* Raise the error */
1260 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1263 HardErrorParameters
,
1268 /* Check if the user pressed cancel */
1269 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1271 /* Remove the DLL from the lists */
1272 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1273 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1274 RemoveEntryList(&LdrEntry
->HashLinks
);
1276 /* Remove the LDR Entry */
1277 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry
);
1279 /* Unmap and close section */
1280 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1281 NtClose(SectionHandle
);
1283 /* Did we do a hard error? */
1284 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1286 /* Yup, so increase fatal error count if we are initializing */
1287 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1290 /* Return failure */
1291 return STATUS_INVALID_IMAGE_FORMAT
;
1296 /* The image was valid. Is it a DLL? */
1297 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1299 /* Set the DLL Flag */
1300 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1303 /* If we're not a DLL, clear the entrypoint */
1304 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1306 LdrEntry
->EntryPoint
= 0;
1310 /* Return it for the caller */
1311 *DataTableEntry
= LdrEntry
;
1313 /* Check if we loaded somewhere else */
1314 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1316 /* Write the flag */
1317 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1319 /* Find our region */
1320 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1321 ImageEnd
= ImageBase
+ ViewSize
;
1323 DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p -> %p)\n", DllName
, (PVOID
)ImageBase
, ViewBase
);
1325 /* Scan all the modules */
1326 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1327 NextEntry
= ListHead
->Flink
;
1328 while (NextEntry
!= ListHead
)
1331 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1332 LDR_DATA_TABLE_ENTRY
,
1334 NextEntry
= NextEntry
->Flink
;
1336 /* Get the entry's bounds */
1337 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1338 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1340 /* Make sure this entry isn't unloading */
1341 if (!CandidateEntry
->InMemoryOrderModuleList
.Flink
) continue;
1343 /* Check if our regions are colliding */
1344 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1345 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1346 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1348 /* Found who is overlapping */
1349 OverlapDllFound
= TRUE
;
1350 OverlapDll
= CandidateEntry
->FullDllName
;
1355 /* Check if we found the DLL overlapping with us */
1356 if (!OverlapDllFound
)
1358 /* It's not another DLL, it's memory already here */
1359 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1362 DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll
);
1364 /* Are we dealing with a DLL? */
1365 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1367 /* Check if relocs were stripped */
1368 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1370 /* Get the relocation data */
1371 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1373 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1376 /* Does the DLL not have any? */
1377 if (!RelocData
&& !RelocDataSize
)
1379 /* We'll allow this and simply continue */
1384 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1385 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1386 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1388 /* Can't relocate user32 */
1389 RelocatableDll
= FALSE
;
1393 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1394 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1396 /* Can't relocate kernel32 */
1397 RelocatableDll
= FALSE
;
1401 /* Known DLLs are not allowed to be relocated */
1402 if (KnownDll
&& !RelocatableDll
)
1404 /* Setup for hard error */
1405 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1406 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1408 /* Raise the error */
1409 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1412 HardErrorParameters
,
1416 /* If initializing, increase the error count */
1417 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1419 /* Don't do relocation */
1420 Status
= STATUS_CONFLICTING_ADDRESSES
;
1424 /* Change the protection to prepare for relocation */
1425 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1427 /* Make sure we changed the protection */
1428 if (NT_SUCCESS(Status
))
1430 /* Do the relocation */
1431 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1432 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1434 if (NT_SUCCESS(Status
))
1436 /* Stuff the image name in the TIB, for the debugger */
1437 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1438 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1441 Status
= NtMapViewOfSection(SectionHandle
,
1453 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1455 /* Return the protection */
1456 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1460 /* Handle any kind of failure */
1461 if (!NT_SUCCESS(Status
))
1463 /* Remove it from the lists */
1464 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1465 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1466 RemoveEntryList(&LdrEntry
->HashLinks
);
1468 /* Unmap it, clear the entry */
1469 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1473 /* Show debug message */
1476 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1477 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1483 /* Not a DLL, or no relocation needed */
1484 Status
= STATUS_SUCCESS
;
1486 /* Stuff the image name in the TIB, for the debugger */
1487 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1488 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1491 Status
= NtMapViewOfSection(SectionHandle
,
1503 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1505 /* Show debug message */
1508 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1513 // FIXME: LdrpCheckCorImage() is missing
1515 /* Check if this is an SMP Machine and a DLL */
1516 if ((LdrpNumberOfProcessors
> 1) &&
1517 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1519 /* Validate the image for MP */
1520 LdrpValidateImageForMp(LdrEntry
);
1523 // FIXME: LdrpCorUnloadImage() is missing
1525 /* Close section and return status */
1526 NtClose(SectionHandle
);
1530 PLDR_DATA_TABLE_ENTRY
1532 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1534 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1535 PIMAGE_NT_HEADERS NtHeader
;
1537 /* Make sure the header is valid */
1538 NtHeader
= RtlImageNtHeader(BaseAddress
);
1539 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1543 /* Allocate an entry */
1544 LdrEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
1546 sizeof(LDR_DATA_TABLE_ENTRY
));
1548 /* Make sure we got one */
1552 LdrEntry
->DllBase
= BaseAddress
;
1553 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1554 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1555 LdrEntry
->PatchInformation
= NULL
;
1559 /* Return the entry */
1565 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1567 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1570 /* Insert into hash table */
1571 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1572 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1574 /* Insert into other lists */
1575 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1576 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderModuleList
);
1581 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry
)
1584 ASSERT(Entry
!= NULL
);
1586 /* Release the activation context if it exists and wasn't already released */
1587 if ((Entry
->EntryPointActivationContext
) &&
1588 (Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
))
1590 /* Mark it as invalid */
1591 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1592 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1595 /* Release the full dll name string */
1596 if (Entry
->FullDllName
.Buffer
) LdrpFreeUnicodeString(&Entry
->FullDllName
);
1598 /* Finally free the entry's memory */
1599 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry
);
1604 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1605 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1607 PLDR_DATA_TABLE_ENTRY Current
;
1608 PLIST_ENTRY ListHead
, Next
;
1610 /* Check the cache first */
1611 if ((LdrpLoadedDllHandleCache
) &&
1612 (LdrpLoadedDllHandleCache
->DllBase
== Base
))
1614 /* We got lucky, return the cached entry */
1615 *LdrEntry
= LdrpLoadedDllHandleCache
;
1619 /* Time for a lookup */
1620 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1621 Next
= ListHead
->Flink
;
1622 while (Next
!= ListHead
)
1624 /* Get the current entry */
1625 Current
= CONTAINING_RECORD(Next
,
1626 LDR_DATA_TABLE_ENTRY
,
1629 /* Make sure it's not unloading and check for a match */
1630 if ((Current
->InMemoryOrderModuleList
.Flink
) && (Base
== Current
->DllBase
))
1633 LdrpLoadedDllHandleCache
= Current
;
1636 *LdrEntry
= Current
;
1640 /* Move to the next one */
1650 LdrpResolveFullName(IN PUNICODE_STRING OriginalName
,
1651 IN PUNICODE_STRING PathName
,
1652 IN PUNICODE_STRING FullPathName
,
1653 IN PUNICODE_STRING
*ExpandedName
)
1655 NTSTATUS Status
= STATUS_SUCCESS
;
1656 // RTL_PATH_TYPE PathType;
1657 // BOOLEAN InvalidName;
1660 /* Display debug output if snaps are on */
1663 DbgPrintEx(DPFLTR_LDR_ID
,
1665 "LDR: %s - Expanding full name of %wZ\n",
1670 /* FIXME: Lock the PEB */
1671 //RtlEnterCriticalSection(&FastPebLock);
1673 /* Get the path name */
1674 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1683 if (!(Length
) || (Length
> UNICODE_STRING_MAX_BYTES
))
1686 Status
= STATUS_NAME_TOO_LONG
;
1690 /* Check if the length hasn't changed */
1691 if (Length
<= PathName
->Length
)
1693 /* Return the same thing */
1694 *ExpandedName
= PathName
;
1695 PathName
->Length
= (USHORT
)Length
;
1700 ASSERT(Length
>= sizeof(WCHAR
));
1702 /* Allocate a string */
1703 Status
= LdrpAllocateUnicodeString(FullPathName
, Length
- sizeof(WCHAR
));
1704 if (!NT_SUCCESS(Status
)) goto Quickie
;
1706 /* Now get the full path again */
1708 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1709 FullPathName
->Length
,
1710 FullPathName
->Buffer
,
1717 if (!(Length
) || (Length
> FullPathName
->Length
))
1720 LdrpFreeUnicodeString(FullPathName
);
1721 Status
= STATUS_NAME_TOO_LONG
;
1725 /* Return the expanded name */
1726 *ExpandedName
= FullPathName
;
1727 FullPathName
->Length
= (USHORT
)Length
;
1731 /* FIXME: Unlock the PEB */
1732 //RtlLeaveCriticalSection(&FastPebLock);
1734 /* Display debug output if snaps are on */
1737 /* Check which output to use -- failure or success */
1738 if (NT_SUCCESS(Status
))
1740 DbgPrintEx(DPFLTR_LDR_ID
,
1742 "LDR: %s - Expanded to %wZ\n",
1748 DbgPrintEx(DPFLTR_LDR_ID
,
1750 "LDR: %s - Failed to expand %wZ; 0x%08x\n",
1757 /* If we failed, return NULL */
1758 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1766 LdrpSearchPath(IN PWCHAR
*SearchPath
,
1768 IN PUNICODE_STRING PathName
,
1769 IN PUNICODE_STRING FullPathName
,
1770 IN PUNICODE_STRING
*ExpandedName
)
1772 BOOLEAN TryAgain
= FALSE
;
1773 PWCHAR ActualSearchPath
= *SearchPath
;
1774 UNICODE_STRING TestName
;
1776 PWCHAR Buffer
, BufEnd
= NULL
;
1781 /* Check if we don't have a search path */
1782 if (!ActualSearchPath
) *SearchPath
= LdrpDefaultPath
.Buffer
;
1784 /* Display debug output if snaps are on */
1787 DbgPrintEx(DPFLTR_LDR_ID
,
1789 "LDR: %s - Looking for %ws in %ws\n",
1795 /* Check if we're dealing with a relative path */
1796 if (RtlDetermineDosPathNameType_U(DllName
) != RtlPathTypeRelative
)
1798 /* Good, we're not. Create the name string */
1799 Status
= RtlInitUnicodeStringEx(&TestName
, DllName
);
1800 if (!NT_SUCCESS(Status
)) goto Quickie
;
1802 /* Make sure it exists */
1804 if (!RtlDoesFileExists_UstrEx(&TestName
, TRUE
))
1806 /* It doesn't, fail */
1807 Status
= STATUS_DLL_NOT_FOUND
;
1812 /* Resolve the full name */
1813 Status
= LdrpResolveFullName(&TestName
,
1820 /* FIXME: Handle relative case semicolon-lookup here */
1822 /* Calculate length */
1823 Length
+= (ULONG
)wcslen(DllName
) + 1;
1824 if (Length
> UNICODE_STRING_MAX_CHARS
)
1826 /* Too long, fail */
1827 Status
= STATUS_NAME_TOO_LONG
;
1831 /* Allocate buffer */
1832 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
1836 Status
= STATUS_NO_MEMORY
;
1840 /* FIXME: Setup TestName here */
1841 Status
= STATUS_NOT_FOUND
;
1847 p
= *ActualSearchPath
;
1848 if (!(p
) || (p
== ';'))
1850 /* FIXME: We don't have a character, or is a semicolon.*/
1852 /* Display debug output if snaps are on */
1855 DbgPrintEx(DPFLTR_LDR_ID
,
1857 "LDR: %s - Looking for %ws\n",
1863 TestName
.Length
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
);
1865 ASSERT(TestName
.Length
< TestName
.MaximumLength
);
1868 /* Check if the file exists */
1870 if (RtlDoesFileExists_UstrEx(&TestName
, FALSE
))
1873 /* It does. Reallocate the buffer */
1874 TestName
.MaximumLength
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
) + sizeof(WCHAR
);
1875 TestName
.Buffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
1878 TestName
.MaximumLength
);
1879 if (!TestName
.Buffer
)
1881 /* Keep the old one */
1882 TestName
.Buffer
= Buffer
;
1887 Buffer
= TestName
.Buffer
;
1890 /* Make sure we have a buffer at least */
1891 ASSERT(TestName
.Buffer
);
1893 /* Resolve the name */
1894 *SearchPath
= ActualSearchPath
++;
1895 Status
= LdrpResolveFullName(&TestName
,
1902 /* Update buffer end */
1905 /* Update string position */
1906 //pp = ActualSearchPath++;
1910 /* Otherwise, write the character */
1915 /* Check if the string is empty, meaning we're done */
1916 if (!(*ActualSearchPath
)) TryAgain
= TRUE
;
1918 /* Advance in the string */
1920 } while (!TryAgain
);
1922 /* Check if we had a buffer and free it */
1923 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1926 /* Check if we got here through failure */
1927 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1929 /* Display debug output if snaps are on */
1932 /* Check which output to use -- failure or success */
1933 if (NT_SUCCESS(Status
))
1935 DbgPrintEx(DPFLTR_LDR_ID
,
1937 "LDR: %s - Returning %wZ\n",
1943 DbgPrintEx(DPFLTR_LDR_ID
,
1945 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1958 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1961 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1962 IN PUNICODE_STRING DllName
,
1964 IN BOOLEAN RedirectedDll
,
1965 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1968 PLIST_ENTRY ListHead
, ListEntry
;
1969 PLDR_DATA_TABLE_ENTRY CurEntry
;
1970 BOOLEAN FullPath
= FALSE
;
1973 UNICODE_STRING FullDllName
, NtPathName
;
1975 OBJECT_ATTRIBUTES ObjectAttributes
;
1977 HANDLE FileHandle
, SectionHandle
;
1978 IO_STATUS_BLOCK Iosb
;
1979 PVOID ViewBase
= NULL
;
1980 SIZE_T ViewSize
= 0;
1981 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1982 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"", DllName
, Flag
, RedirectedDll
, LdrEntry
);
1984 /* Check if a dll name was provided */
1985 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
1987 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1988 /* FIXME: Warning, code does not support redirection at all */
1990 /* Look in the hash table if flag was set */
1994 /* Get hash index */
1995 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
1997 /* Traverse that list */
1998 ListHead
= &LdrpHashTable
[HashIndex
];
1999 ListEntry
= ListHead
->Flink
;
2000 while (ListEntry
!= ListHead
)
2002 /* Get the current entry */
2003 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2005 /* Check base name of that module */
2006 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
2008 /* It matches, return it */
2009 *LdrEntry
= CurEntry
;
2013 /* Advance to the next entry */
2014 ListEntry
= ListEntry
->Flink
;
2017 /* Module was not found, return failure */
2021 /* Check if there is a full path in this DLL */
2022 wc
= DllName
->Buffer
;
2025 /* Check for a slash in the current position*/
2026 if ((*wc
== L
'\\') || (*wc
== L
'/'))
2028 /* Found the slash, so dll name contains path */
2031 /* Setup full dll name string */
2032 FullDllName
.Buffer
= NameBuf
;
2034 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2035 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
2038 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
2042 /* Check if that was successful */
2043 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
2045 /* HACK: Try to find active context dll */
2046 Status
= find_actctx_dll(DllName
->Buffer
, FullDllName
.Buffer
);
2047 if(Status
== STATUS_SUCCESS
)
2049 Length
= wcslen(FullDllName
.Buffer
) * sizeof(WCHAR
);
2050 DPRINT1("found %S for %S\n", FullDllName
.Buffer
, DllName
->Buffer
);
2057 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n",
2061 /* Return failure */
2066 /* Full dll name is found */
2067 FullDllName
.Length
= Length
;
2068 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
2075 /* Go check the hash table */
2082 /* FIXME: Warning, activation context missing */
2083 /* NOTE: From here on down, everything looks good */
2085 /* Loop the module list */
2086 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2087 ListEntry
= ListHead
->Flink
;
2088 while (ListEntry
!= ListHead
)
2090 /* Get the current entry and advance to the next one */
2091 CurEntry
= CONTAINING_RECORD(ListEntry
,
2092 LDR_DATA_TABLE_ENTRY
,
2094 ListEntry
= ListEntry
->Flink
;
2096 /* Check if it's being unloaded */
2097 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
2099 /* Check if name matches */
2100 if (RtlEqualUnicodeString(&FullDllName
,
2101 &CurEntry
->FullDllName
,
2105 *LdrEntry
= CurEntry
;
2110 /* Convert given path to NT path */
2111 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
2116 /* Fail if conversion failed */
2120 /* Initialize object attributes and open it */
2121 InitializeObjectAttributes(&ObjectAttributes
,
2123 OBJ_CASE_INSENSITIVE
,
2126 Status
= NtOpenFile(&FileHandle
,
2127 SYNCHRONIZE
| FILE_EXECUTE
,
2130 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2131 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
2133 /* Free NT path name */
2134 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
2136 /* If opening the file failed - return failure */
2137 if (!NT_SUCCESS(Status
)) return FALSE
;
2139 /* Create a section for this file */
2140 Status
= NtCreateSection(&SectionHandle
,
2142 SECTION_MAP_EXECUTE
|
2150 /* Close file handle */
2151 NtClose(FileHandle
);
2153 /* If creating section failed - return failure */
2154 if (!NT_SUCCESS(Status
)) return FALSE
;
2156 /* Map view of this section */
2157 Status
= ZwMapViewOfSection(SectionHandle
,
2168 /* Close section handle */
2169 NtClose(SectionHandle
);
2171 /* If section mapping failed - return failure */
2172 if (!NT_SUCCESS(Status
)) return FALSE
;
2174 /* Get pointer to the NT header of this section */
2175 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
2176 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
2178 /* Unmap the section and fail */
2179 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2183 /* Go through the list of modules again */
2184 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2185 ListEntry
= ListHead
->Flink
;
2186 while (ListEntry
!= ListHead
)
2188 /* Get the current entry and advance to the next one */
2189 CurEntry
= CONTAINING_RECORD(ListEntry
,
2190 LDR_DATA_TABLE_ENTRY
,
2192 ListEntry
= ListEntry
->Flink
;
2194 /* Check if it's in the process of being unloaded */
2195 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
2197 /* The header is untrusted, use SEH */
2200 /* Check if timedate stamp and sizes match */
2201 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
2202 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
2204 /* Time, date and size match. Let's compare their headers */
2205 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
2206 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
2208 /* Headers match too! Finally ask the kernel to compare mapped files */
2209 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
2210 if (NT_SUCCESS(Status
))
2212 /* This is our entry!, unmap and return success */
2213 *LdrEntry
= CurEntry
;
2214 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2215 _SEH2_YIELD(return TRUE
;)
2220 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
2227 /* Unmap the section and fail */
2228 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2234 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
2235 IN PANSI_STRING Name
,
2237 OUT PVOID
*ProcedureAddress
,
2238 IN BOOLEAN ExecuteInit
)
2240 NTSTATUS Status
= STATUS_SUCCESS
;
2241 UCHAR ImportBuffer
[64];
2242 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2243 IMAGE_THUNK_DATA Thunk
;
2245 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
2246 PIMAGE_EXPORT_DIRECTORY ExportDir
;
2247 ULONG ExportDirSize
, Length
;
2250 /* Show debug message */
2251 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
2253 /* Check if we got a name */
2256 /* Show debug message */
2257 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
2259 /* Make sure it's not too long */
2260 Length
= Name
->Length
+
2262 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
2263 if (Length
> UNICODE_STRING_MAX_BYTES
)
2265 /* Won't have enough space to add the hint */
2266 return STATUS_NAME_TOO_LONG
;
2269 /* Check if our buffer is large enough */
2270 if (Length
> sizeof(ImportBuffer
))
2272 /* Allocate from heap, plus 2 bytes for the Hint */
2273 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
2279 /* Use our internal buffer */
2280 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
2283 /* Clear the hint */
2284 ImportName
->Hint
= 0;
2286 /* Copy the name and null-terminate it */
2287 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
2288 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
2290 /* Clear the high bit */
2291 ImageBase
= ImportName
;
2292 Thunk
.u1
.AddressOfData
= 0;
2296 /* Do it by ordinal */
2299 /* Show debug message */
2300 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
2302 /* Make sure an ordinal was given */
2306 DPRINT1("No ordinal and no name\n");
2307 return STATUS_INVALID_PARAMETER
;
2310 /* Set the orginal flag in the thunk */
2311 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
2314 /* Acquire lock unless we are initting */
2315 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2319 /* Try to find the loaded DLL */
2320 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2323 DPRINT1("Invalid base address %p\n", BaseAddress
);
2324 Status
= STATUS_DLL_NOT_FOUND
;
2325 _SEH2_YIELD(goto Quickie
;)
2328 /* Get the pointer to the export directory */
2329 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2331 IMAGE_DIRECTORY_ENTRY_EXPORT
,
2336 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n",
2337 &LdrEntry
->BaseDllName
, &Name
, BaseAddress
, LdrEntry
->DllBase
);
2338 Status
= STATUS_PROCEDURE_NOT_FOUND
;
2339 _SEH2_YIELD(goto Quickie
;)
2342 /* Now get the thunk */
2343 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
2352 /* Finally, see if we're supposed to run the init routines */
2353 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
2356 * It's possible a forwarded entry had us load the DLL. In that case,
2357 * then we will call its DllMain. Use the last loaded DLL for this.
2359 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
2360 LdrEntry
= CONTAINING_RECORD(Entry
,
2361 LDR_DATA_TABLE_ENTRY
,
2362 InInitializationOrderModuleList
);
2364 /* Make sure we didn't process it yet*/
2365 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2367 /* Call the init routine */
2370 Status
= LdrpRunInitializeRoutines(NULL
);
2372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2374 /* Get the exception code */
2375 Status
= _SEH2_GetExceptionCode();
2381 /* Make sure we're OK till here */
2382 if (NT_SUCCESS(Status
))
2384 /* Return the address */
2385 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
2388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2390 /* Just ignore exceptions */
2396 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
2398 /* We allocated from heap, free it */
2399 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
2402 /* Release the CS if we entered it */
2403 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2411 LdrpLoadDll(IN BOOLEAN Redirected
,
2412 IN PWSTR DllPath OPTIONAL
,
2413 IN PULONG DllCharacteristics OPTIONAL
,
2414 IN PUNICODE_STRING DllName
,
2415 OUT PVOID
*BaseAddress
,
2416 IN BOOLEAN CallInit
)
2418 PPEB Peb
= NtCurrentPeb();
2419 NTSTATUS Status
= STATUS_SUCCESS
;
2421 BOOLEAN GotExtension
;
2423 WCHAR NameBuffer
[MAX_PATH
+ 6];
2424 UNICODE_STRING RawDllName
;
2425 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2426 BOOLEAN InInit
= LdrpInLdrInit
;
2428 /* Save the Raw DLL Name */
2429 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
2430 RtlInitEmptyUnicodeString(&RawDllName
, NameBuffer
, sizeof(NameBuffer
));
2431 RtlCopyUnicodeString(&RawDllName
, DllName
);
2433 /* Find the extension, if present */
2434 p
= DllName
->Buffer
+ DllName
->Length
/ sizeof(WCHAR
) - 1;
2435 GotExtension
= FALSE
;
2436 while (p
>= DllName
->Buffer
)
2441 GotExtension
= TRUE
;
2444 else if (c
== L
'\\')
2450 /* If no extension was found, add the default extension */
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(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 /* Add it. Needs to be null terminated, thus the length check above */
2472 (VOID
)RtlAppendUnicodeStringToString(&RawDllName
,
2473 &LdrApiDefaultExtension
);
2476 /* Check for init flag and acquire lock */
2477 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2479 /* Show debug message */
2482 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
2484 DllPath
? DllPath
: L
"");
2487 /* Check if the DLL is already loaded */
2488 if (!LdrpCheckForLoadedDll(DllPath
,
2495 Status
= LdrpMapDll(DllPath
,
2502 if (!NT_SUCCESS(Status
)) goto Quickie
;
2504 /* FIXME: Need to mark the DLL range for the stack DB */
2505 //RtlpStkMarkDllRange(LdrEntry);
2507 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2508 if ((DllCharacteristics
) &&
2509 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
2511 /* This is not a DLL, so remove such data */
2512 LdrEntry
->EntryPoint
= NULL
;
2513 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
2516 /* Make sure it's a DLL */
2517 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2519 /* Check if this is a .NET Image */
2520 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
2522 /* Walk the Import Descriptor */
2523 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
2526 /* Update load count, unless it's locked */
2527 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2528 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2530 /* Check if we failed */
2531 if (!NT_SUCCESS(Status
))
2533 /* Clear entrypoint, and insert into list */
2534 LdrEntry
->EntryPoint
= NULL
;
2535 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2536 &LdrEntry
->InInitializationOrderModuleList
);
2538 /* Cancel the load */
2539 LdrpClearLoadInProgress();
2541 /* Unload the DLL */
2544 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2545 "import descriptors",
2549 LdrUnloadDll(LdrEntry
->DllBase
);
2551 /* Return the error */
2555 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2557 /* Increase load count */
2558 LdrEntry
->LoadCount
++;
2561 /* Insert it into the list */
2562 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2563 &LdrEntry
->InInitializationOrderModuleList
);
2565 /* If we have to run the entrypoint, make sure the DB is ready */
2566 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2568 /* FIXME: Notify Shim Engine */
2572 //ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
2573 //ShimLoadCallback(LdrEntry);
2576 /* Run the init routine */
2577 Status
= LdrpRunInitializeRoutines(NULL
);
2578 if (!NT_SUCCESS(Status
))
2580 /* Failed, unload the DLL */
2583 DbgPrint("LDR: Unloading %wZ because either its init "
2584 "routine or one of its static imports failed; "
2585 "status = 0x%08lx\n",
2589 LdrUnloadDll(LdrEntry
->DllBase
);
2594 /* The DB isn't ready, which means we were loaded because of a forwarder */
2595 Status
= STATUS_SUCCESS
;
2600 /* We were already loaded. Are we a DLL? */
2601 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2603 /* Increase load count */
2604 LdrEntry
->LoadCount
++;
2605 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2607 /* Clear the load in progress */
2608 LdrpClearLoadInProgress();
2612 /* Not a DLL, just increase the load count */
2613 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2618 /* Release the lock */
2619 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2621 /* Check for success */
2622 if (NT_SUCCESS(Status
))
2624 /* Return the base address */
2625 *BaseAddress
= LdrEntry
->DllBase
;
2630 *BaseAddress
= NULL
;
2639 LdrpClearLoadInProgress(VOID
)
2641 PLIST_ENTRY ListHead
, Entry
;
2642 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2643 ULONG ModulesCount
= 0;
2645 /* Traverse the init list */
2646 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2647 Entry
= ListHead
->Flink
;
2648 while (Entry
!= ListHead
)
2650 /* Get the loader entry */
2651 LdrEntry
= CONTAINING_RECORD(Entry
,
2652 LDR_DATA_TABLE_ENTRY
,
2653 InInitializationOrderModuleList
);
2655 /* Clear load in progress flag */
2656 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2658 /* Check for modules with entry point count but not processed yet */
2659 if ((LdrEntry
->EntryPoint
) &&
2660 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2662 /* Increase counter */
2666 /* Advance to the next entry */
2667 Entry
= Entry
->Flink
;
2670 /* Return final count */
2671 return ModulesCount
;