2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrutils.c
5 * PURPOSE: Internal Loader Utility Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache
, LdrpGetModuleHandleCache
;
21 BOOLEAN g_ShimsEnabled
;
22 PVOID g_pShimEngineModule
;
23 PVOID g_pfnSE_DllLoaded
;
24 PVOID g_pfnSE_DllUnloaded
;
25 PVOID g_pfnSE_InstallBeforeInit
;
26 PVOID g_pfnSE_InstallAfterInit
;
27 PVOID g_pfnSE_ProcessDying
;
29 /* FUNCTIONS *****************************************************************/
31 /* NOTE: Remove this one once our actctx support becomes better */
32 NTSTATUS
find_actctx_dll( LPCWSTR libname
, WCHAR
*fullname
)
34 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\'};
35 static const WCHAR dotManifestW
[] = {'.','m','a','n','i','f','e','s','t',0};
37 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*info
;
38 ACTCTX_SECTION_KEYED_DATA data
;
41 SIZE_T needed
, size
= 1024;
44 RtlInitUnicodeString( &nameW
, libname
);
45 data
.cbSize
= sizeof(data
);
46 status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
47 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
49 if (status
!= STATUS_SUCCESS
) return status
;
53 if (!(info
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
55 status
= STATUS_NO_MEMORY
;
58 status
= RtlQueryInformationActivationContext( 0, data
.hActCtx
, &data
.ulAssemblyRosterIndex
,
59 AssemblyDetailedInformationInActivationContext
,
60 info
, size
, &needed
);
61 if (status
== STATUS_SUCCESS
) break;
62 if (status
!= STATUS_BUFFER_TOO_SMALL
) goto done
;
63 RtlFreeHeap( RtlGetProcessHeap(), 0, info
);
67 DPRINT("manifestpath === %S\n", info
->lpAssemblyManifestPath
);
68 DPRINT("DirectoryName === %S\n", info
->lpAssemblyDirectoryName
);
69 if (!info
->lpAssemblyManifestPath
|| !info
->lpAssemblyDirectoryName
)
71 status
= STATUS_SXS_KEY_NOT_FOUND
;
75 if ((p
= wcsrchr( info
->lpAssemblyManifestPath
, '\\' )))
77 DWORD dirlen
= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
80 if (_wcsnicmp( p
, info
->lpAssemblyDirectoryName
, dirlen
) || wcsicmp( p
+ dirlen
, dotManifestW
))
82 /* manifest name does not match directory name, so it's not a global
83 * windows/winsxs manifest; use the manifest directory name instead */
84 dirlen
= p
- info
->lpAssemblyManifestPath
;
85 needed
= (dirlen
+ 1) * sizeof(WCHAR
) + nameW
.Length
;
88 /*if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
90 status = STATUS_NO_MEMORY;
93 memcpy( p
, info
->lpAssemblyManifestPath
, dirlen
* sizeof(WCHAR
) );
100 needed
= (wcslen(SharedUserData
->NtSystemRoot
) * sizeof(WCHAR
) +
101 sizeof(winsxsW
) + info
->ulAssemblyDirectoryNameLength
+ nameW
.Length
+ 2*sizeof(WCHAR
));
104 //if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
106 //status = STATUS_NO_MEMORY;
109 wcscpy( p
, SharedUserData
->NtSystemRoot
);
111 memcpy( p
, winsxsW
, sizeof(winsxsW
) );
112 p
+= sizeof(winsxsW
) / sizeof(WCHAR
);
113 memcpy( p
, info
->lpAssemblyDirectoryName
, info
->ulAssemblyDirectoryNameLength
);
114 p
+= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
116 wcscpy( p
, libname
);
119 RtlFreeHeap( RtlGetProcessHeap(), 0, info
);
120 RtlReleaseActivationContext( data
.hActCtx
);
121 DPRINT("%S\n", fullname
);
128 LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut
,
133 ASSERT(Length
<= UNICODE_STRING_MAX_BYTES
);
136 StringOut
->Length
= 0;
138 /* Make sure it's not mis-aligned */
142 StringOut
->Buffer
= NULL
;
143 StringOut
->MaximumLength
= 0;
144 return STATUS_INVALID_PARAMETER
;
147 /* Allocate the string*/
148 StringOut
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
150 StringOut
->Length
+ sizeof(WCHAR
));
151 if (!StringOut
->Buffer
)
154 StringOut
->MaximumLength
= 0;
155 return STATUS_NO_MEMORY
;
158 /* Null-terminate it */
159 StringOut
->Buffer
[StringOut
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
161 /* Check if this is a maximum-sized string */
162 if (StringOut
->Length
!= UNICODE_STRING_MAX_BYTES
)
164 /* It's not, so set the maximum length to be one char more */
165 StringOut
->MaximumLength
= StringOut
->Length
+ sizeof(UNICODE_NULL
);
169 /* The length is already the maximum possible */
170 StringOut
->MaximumLength
= UNICODE_STRING_MAX_BYTES
;
174 return STATUS_SUCCESS
;
179 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn
)
181 ASSERT(StringIn
!= NULL
);
183 /* If Buffer is not NULL - free it */
184 if (StringIn
->Buffer
)
186 RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn
->Buffer
);
190 RtlInitEmptyUnicodeString(StringIn
, NULL
, 0);
195 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint
,
196 IN PVOID BaseAddress
,
201 return EntryPoint(BaseAddress
, Reason
, Context
);
204 /* NOTE: This function is broken */
207 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
209 OUT PUNICODE_STRING UpdateString
)
211 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder
;
212 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
;
213 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
214 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
215 PIMAGE_THUNK_DATA FirstThunk
;
216 PLDR_DATA_TABLE_ENTRY Entry
;
217 PUNICODE_STRING ImportNameUnic
;
218 ANSI_STRING ImportNameAnsi
;
224 /* Check the action we need to perform */
225 if ((Flags
== LDRP_UPDATE_REFCOUNT
) || (Flags
== LDRP_UPDATE_PIN
))
227 /* Make sure entry is not being loaded already */
228 if (LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
)
231 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
233 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
235 /* Make sure the entry is not being unloaded already */
236 if (LdrEntry
->Flags
& LDRP_UNLOAD_IN_PROGRESS
)
239 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
242 /* Go through all bound DLLs and dereference them */
243 ImportNameUnic
= &NtCurrentTeb()->StaticUnicodeString
;
245 /* Try to get the new import entry */
246 FirstEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
248 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
253 /* Set entry flags if refing/derefing */
254 if (Flags
== LDRP_UPDATE_REFCOUNT
)
255 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
256 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
257 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
259 BoundEntry
= FirstEntry
;
260 while (BoundEntry
->OffsetModuleName
)
262 /* Get pointer to the current import name */
263 ImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
265 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
266 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
268 if (NT_SUCCESS(Status
))
270 if (LdrpCheckForLoadedDll(NULL
,
276 if (Entry
->LoadCount
!= 0xFFFF)
278 /* Perform the required action */
281 case LDRP_UPDATE_REFCOUNT
:
284 case LDRP_UPDATE_DEREFCOUNT
:
287 case LDRP_UPDATE_PIN
:
288 Entry
->LoadCount
= 0xFFFF;
295 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
299 /* Recurse into this entry */
300 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
304 /* Go through forwarders */
305 NewImportForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
306 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
308 ImportName
= (LPSTR
)FirstEntry
+ NewImportForwarder
->OffsetModuleName
;
310 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
311 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
312 if (NT_SUCCESS(Status
))
314 if (LdrpCheckForLoadedDll(NULL
,
320 if (Entry
->LoadCount
!= 0xFFFF)
322 /* Perform the required action */
325 case LDRP_UPDATE_REFCOUNT
:
328 case LDRP_UPDATE_DEREFCOUNT
:
331 case LDRP_UPDATE_PIN
:
332 Entry
->LoadCount
= 0xFFFF;
339 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
343 /* Recurse into this entry */
344 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
348 NewImportForwarder
++;
351 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)NewImportForwarder
;
358 /* Check oldstyle import descriptor */
359 ImportEntry
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
361 IMAGE_DIRECTORY_ENTRY_IMPORT
,
365 /* There is old one, so go through its entries */
366 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
368 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->FirstThunk
);
370 /* Skip this entry if needed */
371 if (!FirstThunk
->u1
.Function
)
377 ImportName
= (PSZ
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
379 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
380 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
381 if (NT_SUCCESS(Status
))
383 if (LdrpCheckForLoadedDll(NULL
,
389 if (Entry
->LoadCount
!= 0xFFFF)
391 /* Perform the required action */
394 case LDRP_UPDATE_REFCOUNT
:
397 case LDRP_UPDATE_DEREFCOUNT
:
400 case LDRP_UPDATE_PIN
:
401 Entry
->LoadCount
= 0xFFFF;
408 DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
413 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
417 /* Go to the next entry */
425 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
428 WCHAR Buffer
[MAX_PATH
];
429 UNICODE_STRING UpdateString
;
431 /* Setup the string and call the extended API */
432 RtlInitEmptyUnicodeString(&UpdateString
, Buffer
, sizeof(Buffer
));
433 LdrpUpdateLoadCount3(LdrEntry
, Flags
, &UpdateString
);
438 LdrpCallTlsInitializers(IN PVOID BaseAddress
,
441 PIMAGE_TLS_DIRECTORY TlsDirectory
;
442 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
445 /* Get the TLS Directory */
446 TlsDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
448 IMAGE_DIRECTORY_ENTRY_TLS
,
451 /* Protect against invalid pointers */
454 /* Make sure it's valid */
458 Array
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
;
464 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
465 BaseAddress
, TlsDirectory
, Array
);
471 /* Get the TLS Entrypoint */
477 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
478 BaseAddress
, Callback
);
482 LdrpCallInitRoutine((PDLL_INIT_ROUTINE
)Callback
,
490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
499 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName
,
502 /* Not implemented */
503 return STATUS_SUCCESS
;
508 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
510 IN PULONG DllCharacteristics OPTIONAL
,
511 OUT PHANDLE SectionHandle
)
515 OBJECT_ATTRIBUTES ObjectAttributes
;
516 IO_STATUS_BLOCK IoStatusBlock
;
517 ULONG_PTR HardErrorParameters
[1];
519 SECTION_IMAGE_INFORMATION SectionImageInfo
;
521 /* Check if we don't already have a handle */
524 /* Create the object attributes */
525 InitializeObjectAttributes(&ObjectAttributes
,
527 OBJ_CASE_INSENSITIVE
,
532 Status
= NtOpenFile(&FileHandle
,
533 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
536 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
537 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
539 /* Check if we failed */
540 if (!NT_SUCCESS(Status
))
542 /* Attempt to open for execute only */
543 Status
= NtOpenFile(&FileHandle
,
544 SYNCHRONIZE
| FILE_EXECUTE
,
547 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
548 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
550 /* Check if this failed too */
551 if (!NT_SUCCESS(Status
))
553 /* Show debug message */
556 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
560 /* Make sure to return an expected status code */
561 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
563 /* Callers expect this instead */
564 Status
= STATUS_DLL_NOT_FOUND
;
567 /* Return an empty section handle */
568 *SectionHandle
= NULL
;
575 /* Use the handle we already have */
576 FileHandle
= DllHandle
;
579 /* Create a section for the DLL */
580 Status
= NtCreateSection(SectionHandle
,
581 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
582 SECTION_MAP_WRITE
| SECTION_QUERY
,
589 /* If mapping failed, raise a hard error */
590 if (!NT_SUCCESS(Status
))
592 /* Forget the handle */
593 *SectionHandle
= NULL
;
595 /* Give the DLL name */
596 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
598 /* Raise the error */
599 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
606 /* Increment the error count */
607 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
610 /* Check for Safer restrictions */
611 if (DllCharacteristics
&&
612 !(*DllCharacteristics
& IMAGE_FILE_SYSTEM
))
614 /* Make sure it's executable */
615 Status
= ZwQuerySection(*SectionHandle
,
616 SectionImageInformation
,
618 sizeof(SECTION_IMAGE_INFORMATION
),
620 if (NT_SUCCESS(Status
))
622 /* Bypass the check for .NET images */
623 if (!(SectionImageInfo
.LoaderFlags
& IMAGE_LOADER_FLAGS_COMPLUS
))
625 /* Check with Safer */
626 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
627 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
629 /* Show debug message */
632 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
636 /* Failure case, close section handle */
637 NtClose(*SectionHandle
);
638 *SectionHandle
= NULL
;
644 /* Failure case, close section handle */
645 NtClose(*SectionHandle
);
646 *SectionHandle
= NULL
;
650 /* Close the file handle, we don't need it */
657 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
660 LdrpResolveDllName(PWSTR DllPath
,
662 PUNICODE_STRING FullDllName
,
663 PUNICODE_STRING BaseDllName
)
665 PWCHAR NameBuffer
, p1
, p2
= 0;
670 /* Allocate space for full DLL name */
671 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize
+ sizeof(UNICODE_NULL
));
672 if (!FullDllName
->Buffer
) return FALSE
;
674 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
679 &BaseDllName
->Buffer
);
681 if (!Length
|| Length
> BufSize
)
683 /* HACK: Try to find active context dll */
684 Status
= find_actctx_dll(DllName
, FullDllName
->Buffer
);
685 if(Status
== STATUS_SUCCESS
)
687 Length
= wcslen(FullDllName
->Buffer
) * sizeof(WCHAR
);
688 DPRINT1("found %S for %S\n", FullDllName
->Buffer
, DllName
);
692 /* NOTE: This code should remain after removing the hack */
695 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
696 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
699 RtlFreeUnicodeString(FullDllName
);
704 /* Construct full DLL name */
705 FullDllName
->Length
= Length
;
706 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
708 /* Allocate a new buffer */
709 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
712 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
716 /* Copy over the contents from the previous one and free it */
717 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
718 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
719 FullDllName
->Buffer
= NameBuffer
;
721 /* Find last backslash */
722 p1
= FullDllName
->Buffer
;
731 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
739 /* Calculate remaining length */
742 /* Construct base DLL name */
743 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
744 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
745 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName
->MaximumLength
);
747 if (!BaseDllName
->Buffer
)
749 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
753 /* Copy base dll name to the new buffer */
754 RtlMoveMemory(BaseDllName
->Buffer
,
756 BaseDllName
->Length
);
758 /* Null-terminate the string */
759 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
766 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase
)
768 PIMAGE_NT_HEADERS NtHeaders
;
769 ULONG_PTR EntryPoint
= 0;
771 /* Get entry point offset from NT headers */
772 NtHeaders
= RtlImageNtHeader(ImageBase
);
776 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
777 if (EntryPoint
) EntryPoint
+= (ULONG_PTR
)ImageBase
;
780 /* Return calculated pointer (or zero in case of failure) */
781 return (PVOID
)EntryPoint
;
784 /* NOTE: This function is partially missing SxS */
787 LdrpCheckForKnownDll(PWSTR DllName
,
788 PUNICODE_STRING FullDllName
,
789 PUNICODE_STRING BaseDllName
,
790 HANDLE
*SectionHandle
)
792 OBJECT_ATTRIBUTES ObjectAttributes
;
793 HANDLE Section
= NULL
;
794 UNICODE_STRING DllNameUnic
;
799 /* Zero initialize provided parameters */
800 if (SectionHandle
) *SectionHandle
= 0;
804 FullDllName
->Length
= 0;
805 FullDllName
->MaximumLength
= 0;
806 FullDllName
->Buffer
= NULL
;
811 BaseDllName
->Length
= 0;
812 BaseDllName
->MaximumLength
= 0;
813 BaseDllName
->Buffer
= NULL
;
816 /* If any of these three params are missing then fail */
817 if (!SectionHandle
|| !FullDllName
|| !BaseDllName
)
818 return STATUS_INVALID_PARAMETER
;
820 /* Check the Loader Lock */
821 LdrpEnsureLoaderLockIsHeld();
823 /* Upgrade DllName to a unicode string */
824 RtlInitUnicodeString(&DllNameUnic
, DllName
);
826 /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
828 /* Get the activation context */
829 Status
= RtlFindActivationContextSectionString(0,
831 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
835 /* Check if it's a SxS or not */
836 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
837 Status
== STATUS_SXS_KEY_NOT_FOUND
)
839 /* NOTE: Here it's beneficial to allocate one big unicode string
840 using LdrpAllocateUnicodeString instead of fragmenting the heap
841 with two allocations as it's done now. */
843 /* Set up BaseDllName */
844 BaseDllName
->Length
= DllNameUnic
.Length
;
845 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
846 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
848 DllNameUnic
.MaximumLength
);
849 if (!BaseDllName
->Buffer
)
851 Status
= STATUS_NO_MEMORY
;
855 /* Copy the contents there */
856 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
858 /* Set up FullDllName */
859 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
860 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
861 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
862 if (!FullDllName
->Buffer
)
864 Status
= STATUS_NO_MEMORY
;
868 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
870 /* Put a slash there */
871 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
876 /* Set up DllNameUnic for a relative path */
877 DllNameUnic
.Buffer
= (PWSTR
)p1
;
878 DllNameUnic
.Length
= BaseDllName
->Length
;
879 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
881 /* Copy the contents */
882 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
884 /* There are all names, init attributes and open the section */
885 InitializeObjectAttributes(&ObjectAttributes
,
887 OBJ_CASE_INSENSITIVE
,
888 LdrpKnownDllObjectDirectory
,
891 Status
= NtOpenSection(&Section
,
892 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
894 if (!NT_SUCCESS(Status
))
896 /* Clear status in case it was just not found */
897 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) Status
= STATUS_SUCCESS
;
901 /* Pass section handle to the caller and return success */
902 *SectionHandle
= Section
;
903 return STATUS_SUCCESS
;
907 /* Close section object if it was opened */
908 if (Section
) NtClose(Section
);
910 /* Free string resources */
911 if (BaseDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
912 if (FullDllName
->Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
920 LdrpSetProtection(PVOID ViewBase
,
923 PIMAGE_NT_HEADERS NtHeaders
;
924 PIMAGE_SECTION_HEADER Section
;
928 ULONG NewProtection
, OldProtection
, i
;
930 /* Get the NT headers */
931 NtHeaders
= RtlImageNtHeader(ViewBase
);
932 if (!NtHeaders
) return STATUS_INVALID_IMAGE_FORMAT
;
934 /* Compute address of the first section header */
935 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
937 /* Go through all sections */
938 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
940 /* Check for read-only non-zero section */
941 if ((Section
->SizeOfRawData
) &&
942 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
944 /* Check if we are setting or restoring protection */
947 /* Set it to either EXECUTE or READONLY */
948 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
950 NewProtection
= PAGE_EXECUTE
;
954 NewProtection
= PAGE_READONLY
;
957 /* Add PAGE_NOCACHE if needed */
958 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
960 NewProtection
|= PAGE_NOCACHE
;
965 /* Enable write access */
966 NewProtection
= PAGE_READWRITE
;
969 /* Get the section VA */
970 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
971 SectionSize
= Section
->SizeOfRawData
;
975 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
980 if (!NT_SUCCESS(Status
)) return Status
;
984 /* Move to the next section */
988 /* Flush instruction cache if necessary */
989 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
990 return STATUS_SUCCESS
;
993 /* NOTE: Not yet reviewed */
996 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
998 IN PWSTR DllName OPTIONAL
,
999 IN PULONG DllCharacteristics
,
1001 IN BOOLEAN Redirect
,
1002 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
1004 PTEB Teb
= NtCurrentTeb();
1005 PPEB Peb
= NtCurrentPeb();
1006 PWCHAR p1
= DllName
;
1008 BOOLEAN KnownDll
= FALSE
;
1009 UNICODE_STRING FullDllName
, BaseDllName
;
1010 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
1011 UNICODE_STRING NtPathDllName
;
1012 ULONG_PTR HardErrorParameters
[2];
1013 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
1015 SIZE_T ViewSize
= 0;
1016 PVOID ViewBase
= NULL
;
1017 PVOID ArbitraryUserPointer
;
1018 PIMAGE_NT_HEADERS NtHeaders
;
1019 NTSTATUS HardErrorStatus
, Status
;
1020 BOOLEAN OverlapDllFound
= FALSE
;
1021 ULONG_PTR ImageBase
, ImageEnd
;
1022 PLIST_ENTRY ListHead
, NextEntry
;
1023 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
1024 ULONG_PTR CandidateBase
, CandidateEnd
;
1025 UNICODE_STRING OverlapDll
;
1026 BOOLEAN RelocatableDll
= TRUE
;
1027 UNICODE_STRING IllegalDll
;
1029 ULONG RelocDataSize
= 0;
1031 // FIXME: AppCompat stuff is missing
1035 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
1037 SearchPath
? SearchPath
: L
"");
1040 /* Check if we have a known dll directory */
1041 if (LdrpKnownDllObjectDirectory
)
1043 /* Check if the path is full */
1047 if (TempChar
== '\\' || TempChar
== '/' )
1049 /* Complete path, don't do Known Dll lookup */
1054 /* Try to find a Known DLL */
1055 Status
= LdrpCheckForKnownDll(DllName
,
1060 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_DLL_NOT_FOUND
))
1063 DbgPrintEx(DPFLTR_LDR_ID
,
1065 "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
1076 /* Check if the Known DLL Check returned something */
1079 /* It didn't, so try to resolve the name now */
1080 if (LdrpResolveDllName(SearchPath
,
1085 /* Got a name, display a message */
1088 DPRINT1("LDR: Loading (%s) %wZ\n",
1089 Static
? "STATIC" : "DYNAMIC",
1093 /* Convert to NT Name */
1094 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1099 /* Path was invalid */
1100 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1103 /* Create a section for this dLL */
1104 Status
= LdrpCreateDllSection(&NtPathDllName
,
1109 /* Free the NT Name */
1110 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
1113 if (!NT_SUCCESS(Status
))
1115 /* Free the name strings and return */
1116 RtlFreeUnicodeString(&FullDllName
);
1117 RtlFreeUnicodeString(&BaseDllName
);
1123 /* We couldn't resolve the name, is this a static load? */
1127 * This is BAD! Static loads are CRITICAL. Bugcheck!
1128 * Initialize the strings for the error
1130 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
1131 RtlInitUnicodeString(&HardErrorDllPath
,
1132 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
1134 /* Set them as error parameters */
1135 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
1136 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
1138 /* Raise the hard error */
1139 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
1142 HardErrorParameters
,
1146 /* We're back, where we initializing? */
1147 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1150 /* Return failure */
1151 return STATUS_DLL_NOT_FOUND
;
1156 /* We have a section handle, so this is a known dll */
1160 /* Stuff the image name in the TIB, for the debugger */
1161 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1162 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1167 Status
= NtMapViewOfSection(SectionHandle
,
1179 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1181 /* Fail if we couldn't map it */
1182 if (!NT_SUCCESS(Status
))
1184 /* Close and return */
1185 NtClose(SectionHandle
);
1189 /* Get the NT Header */
1190 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
1192 /* Invalid image, unmap, close handle and fail */
1193 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1194 NtClose(SectionHandle
);
1195 return STATUS_INVALID_IMAGE_FORMAT
;
1198 // FIXME: .NET support is missing
1200 /* Allocate an entry */
1201 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
1203 /* Invalid image, unmap, close handle and fail */
1204 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1205 NtClose(SectionHandle
);
1206 return STATUS_NO_MEMORY
;
1209 /* Setup the entry */
1210 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
1211 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
1212 LdrEntry
->LoadCount
= 0;
1213 LdrEntry
->FullDllName
= FullDllName
;
1214 LdrEntry
->BaseDllName
= BaseDllName
;
1215 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
1217 /* Show debug message */
1220 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
1225 /* Insert this entry */
1226 LdrpInsertMemoryTableEntry(LdrEntry
);
1228 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
1230 /* Check for invalid CPU Image */
1231 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1233 /* Load our header */
1234 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1236 /* Assume defaults if we don't have to run the Hard Error path */
1237 HardErrorStatus
= STATUS_SUCCESS
;
1238 Response
= ResponseCancel
;
1240 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1241 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1243 /* Reset the entrypoint, save our Dll Name */
1244 LdrEntry
->EntryPoint
= 0;
1245 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1247 /* Raise the error */
1248 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1251 HardErrorParameters
,
1256 /* Check if the user pressed cancel */
1257 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1259 /* Remove the DLL from the lists */
1260 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1261 RemoveEntryList(&LdrEntry
->InMemoryOrderLinks
);
1262 RemoveEntryList(&LdrEntry
->HashLinks
);
1264 /* Remove the LDR Entry */
1265 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry
);
1267 /* Unmap and close section */
1268 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1269 NtClose(SectionHandle
);
1271 /* Did we do a hard error? */
1272 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1274 /* Yup, so increase fatal error count if we are initializing */
1275 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1278 /* Return failure */
1279 return STATUS_INVALID_IMAGE_FORMAT
;
1284 /* The image was valid. Is it a DLL? */
1285 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1287 /* Set the DLL Flag */
1288 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1291 /* If we're not a DLL, clear the entrypoint */
1292 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1294 LdrEntry
->EntryPoint
= 0;
1298 /* Return it for the caller */
1299 *DataTableEntry
= LdrEntry
;
1301 /* Check if we loaded somewhere else */
1302 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1304 /* Write the flag */
1305 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1307 /* Find our region */
1308 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1309 ImageEnd
= ImageBase
+ ViewSize
;
1311 DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p-%p -> %p)\n", DllName
, (PVOID
)ImageBase
, (PVOID
)ImageEnd
, ViewBase
);
1313 /* Scan all the modules */
1314 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1315 NextEntry
= ListHead
->Flink
;
1316 while (NextEntry
!= ListHead
)
1319 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1320 LDR_DATA_TABLE_ENTRY
,
1322 NextEntry
= NextEntry
->Flink
;
1324 /* Get the entry's bounds */
1325 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1326 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1328 /* Make sure this entry isn't unloading */
1329 if (!CandidateEntry
->InMemoryOrderLinks
.Flink
) continue;
1331 /* Check if our regions are colliding */
1332 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1333 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1334 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1336 /* Found who is overlapping */
1337 OverlapDllFound
= TRUE
;
1338 OverlapDll
= CandidateEntry
->FullDllName
;
1343 /* Check if we found the DLL overlapping with us */
1344 if (!OverlapDllFound
)
1346 /* It's not another DLL, it's memory already here */
1347 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1350 DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll
);
1352 /* Are we dealing with a DLL? */
1353 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1355 /* Check if relocs were stripped */
1356 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1358 /* Get the relocation data */
1359 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1361 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1364 /* Does the DLL not have any? */
1365 if (!RelocData
&& !RelocDataSize
)
1367 /* We'll allow this and simply continue */
1372 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1373 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1374 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1376 /* Can't relocate user32 */
1377 RelocatableDll
= FALSE
;
1381 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1382 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1384 /* Can't relocate kernel32 */
1385 RelocatableDll
= FALSE
;
1389 /* Known DLLs are not allowed to be relocated */
1390 if (KnownDll
&& !RelocatableDll
)
1392 /* Setup for hard error */
1393 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1394 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1396 /* Raise the error */
1397 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1400 HardErrorParameters
,
1404 /* If initializing, increase the error count */
1405 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1407 /* Don't do relocation */
1408 Status
= STATUS_CONFLICTING_ADDRESSES
;
1412 /* Change the protection to prepare for relocation */
1413 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1415 /* Make sure we changed the protection */
1416 if (NT_SUCCESS(Status
))
1418 /* Do the relocation */
1419 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1420 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1422 if (NT_SUCCESS(Status
))
1424 /* Stuff the image name in the TIB, for the debugger */
1425 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1426 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1429 Status
= NtMapViewOfSection(SectionHandle
,
1441 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1443 /* Return the protection */
1444 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1448 /* Handle any kind of failure */
1449 if (!NT_SUCCESS(Status
))
1451 /* Remove it from the lists */
1452 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1453 RemoveEntryList(&LdrEntry
->InMemoryOrderLinks
);
1454 RemoveEntryList(&LdrEntry
->HashLinks
);
1456 /* Unmap it, clear the entry */
1457 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1461 /* Show debug message */
1464 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1465 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1471 /* Not a DLL, or no relocation needed */
1472 Status
= STATUS_SUCCESS
;
1474 /* Stuff the image name in the TIB, for the debugger */
1475 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1476 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1479 Status
= NtMapViewOfSection(SectionHandle
,
1491 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1493 /* Show debug message */
1496 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1501 // FIXME: LdrpCheckCorImage() is missing
1503 /* Check if this is an SMP Machine and a DLL */
1504 if ((LdrpNumberOfProcessors
> 1) &&
1505 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1507 /* Validate the image for MP */
1508 LdrpValidateImageForMp(LdrEntry
);
1511 // FIXME: LdrpCorUnloadImage() is missing
1513 /* Close section and return status */
1514 NtClose(SectionHandle
);
1518 PLDR_DATA_TABLE_ENTRY
1520 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1522 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1523 PIMAGE_NT_HEADERS NtHeader
;
1525 /* Make sure the header is valid */
1526 NtHeader
= RtlImageNtHeader(BaseAddress
);
1527 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1531 /* Allocate an entry */
1532 LdrEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
1534 sizeof(LDR_DATA_TABLE_ENTRY
));
1536 /* Make sure we got one */
1540 LdrEntry
->DllBase
= BaseAddress
;
1541 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1542 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1543 LdrEntry
->PatchInformation
= NULL
;
1547 /* Return the entry */
1553 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1555 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1558 /* Insert into hash table */
1559 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1560 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1562 /* Insert into other lists */
1563 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1564 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderLinks
);
1569 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry
)
1572 ASSERT(Entry
!= NULL
);
1574 /* Release the activation context if it exists and wasn't already released */
1575 if ((Entry
->EntryPointActivationContext
) &&
1576 (Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
))
1578 /* Mark it as invalid */
1579 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1580 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1583 /* Release the full dll name string */
1584 if (Entry
->FullDllName
.Buffer
) LdrpFreeUnicodeString(&Entry
->FullDllName
);
1586 /* Finally free the entry's memory */
1587 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry
);
1592 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1593 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1595 PLDR_DATA_TABLE_ENTRY Current
;
1596 PLIST_ENTRY ListHead
, Next
;
1598 /* Check the cache first */
1599 if ((LdrpLoadedDllHandleCache
) &&
1600 (LdrpLoadedDllHandleCache
->DllBase
== Base
))
1602 /* We got lucky, return the cached entry */
1603 *LdrEntry
= LdrpLoadedDllHandleCache
;
1607 /* Time for a lookup */
1608 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1609 Next
= ListHead
->Flink
;
1610 while (Next
!= ListHead
)
1612 /* Get the current entry */
1613 Current
= CONTAINING_RECORD(Next
,
1614 LDR_DATA_TABLE_ENTRY
,
1617 /* Make sure it's not unloading and check for a match */
1618 if ((Current
->InMemoryOrderLinks
.Flink
) && (Base
== Current
->DllBase
))
1621 LdrpLoadedDllHandleCache
= Current
;
1624 *LdrEntry
= Current
;
1628 /* Move to the next one */
1638 LdrpResolveFullName(IN PUNICODE_STRING OriginalName
,
1639 IN PUNICODE_STRING PathName
,
1640 IN PUNICODE_STRING FullPathName
,
1641 IN PUNICODE_STRING
*ExpandedName
)
1643 NTSTATUS Status
= STATUS_SUCCESS
;
1644 // RTL_PATH_TYPE PathType;
1645 // BOOLEAN InvalidName;
1648 /* Display debug output if snaps are on */
1651 DbgPrintEx(DPFLTR_LDR_ID
,
1653 "LDR: %s - Expanding full name of %wZ\n",
1658 /* FIXME: Lock the PEB */
1659 //RtlEnterCriticalSection(&FastPebLock);
1661 /* Get the path name */
1662 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1671 if (!(Length
) || (Length
> UNICODE_STRING_MAX_BYTES
))
1674 Status
= STATUS_NAME_TOO_LONG
;
1678 /* Check if the length hasn't changed */
1679 if (Length
<= PathName
->Length
)
1681 /* Return the same thing */
1682 *ExpandedName
= PathName
;
1683 PathName
->Length
= (USHORT
)Length
;
1688 ASSERT(Length
>= sizeof(WCHAR
));
1690 /* Allocate a string */
1691 Status
= LdrpAllocateUnicodeString(FullPathName
, Length
- sizeof(WCHAR
));
1692 if (!NT_SUCCESS(Status
)) goto Quickie
;
1694 /* Now get the full path again */
1696 Length
= RtlGetFullPathName_Ustr(OriginalName
,
1697 FullPathName
->Length
,
1698 FullPathName
->Buffer
,
1705 if (!(Length
) || (Length
> FullPathName
->Length
))
1708 LdrpFreeUnicodeString(FullPathName
);
1709 Status
= STATUS_NAME_TOO_LONG
;
1713 /* Return the expanded name */
1714 *ExpandedName
= FullPathName
;
1715 FullPathName
->Length
= (USHORT
)Length
;
1719 /* FIXME: Unlock the PEB */
1720 //RtlLeaveCriticalSection(&FastPebLock);
1722 /* Display debug output if snaps are on */
1725 /* Check which output to use -- failure or success */
1726 if (NT_SUCCESS(Status
))
1728 DbgPrintEx(DPFLTR_LDR_ID
,
1730 "LDR: %s - Expanded to %wZ\n",
1736 DbgPrintEx(DPFLTR_LDR_ID
,
1738 "LDR: %s - Failed to expand %wZ; 0x%08x\n",
1745 /* If we failed, return NULL */
1746 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1754 LdrpSearchPath(IN PWCHAR
*SearchPath
,
1756 IN PUNICODE_STRING PathName
,
1757 IN PUNICODE_STRING FullPathName
,
1758 IN PUNICODE_STRING
*ExpandedName
)
1760 BOOLEAN TryAgain
= FALSE
;
1761 PWCHAR ActualSearchPath
= *SearchPath
;
1762 UNICODE_STRING TestName
;
1764 PWCHAR Buffer
, BufEnd
= NULL
;
1769 /* Check if we don't have a search path */
1770 if (!ActualSearchPath
) *SearchPath
= LdrpDefaultPath
.Buffer
;
1772 /* Display debug output if snaps are on */
1775 DbgPrintEx(DPFLTR_LDR_ID
,
1777 "LDR: %s - Looking for %ws in %ws\n",
1783 /* Check if we're dealing with a relative path */
1784 if (RtlDetermineDosPathNameType_U(DllName
) != RtlPathTypeRelative
)
1786 /* Good, we're not. Create the name string */
1787 Status
= RtlInitUnicodeStringEx(&TestName
, DllName
);
1788 if (!NT_SUCCESS(Status
)) goto Quickie
;
1790 /* Make sure it exists */
1792 if (!RtlDoesFileExists_UstrEx(&TestName
, TRUE
))
1794 /* It doesn't, fail */
1795 Status
= STATUS_DLL_NOT_FOUND
;
1800 /* Resolve the full name */
1801 Status
= LdrpResolveFullName(&TestName
,
1808 /* FIXME: Handle relative case semicolon-lookup here */
1810 /* Calculate length */
1811 Length
+= (ULONG
)wcslen(DllName
) + 1;
1812 if (Length
> UNICODE_STRING_MAX_CHARS
)
1814 /* Too long, fail */
1815 Status
= STATUS_NAME_TOO_LONG
;
1819 /* Allocate buffer */
1820 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
1824 Status
= STATUS_NO_MEMORY
;
1828 /* FIXME: Setup TestName here */
1829 Status
= STATUS_NOT_FOUND
;
1835 p
= *ActualSearchPath
;
1836 if (!(p
) || (p
== ';'))
1838 /* FIXME: We don't have a character, or is a semicolon.*/
1840 /* Display debug output if snaps are on */
1843 DbgPrintEx(DPFLTR_LDR_ID
,
1845 "LDR: %s - Looking for %ws\n",
1851 TestName
.Length
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
);
1853 ASSERT(TestName
.Length
< TestName
.MaximumLength
);
1856 /* Check if the file exists */
1858 if (RtlDoesFileExists_UstrEx(&TestName
, FALSE
))
1861 /* It does. Reallocate the buffer */
1862 TestName
.MaximumLength
= (USHORT
)ALIGN_DOWN((BufEnd
- Buffer
), WCHAR
) + sizeof(WCHAR
);
1863 TestName
.Buffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
1866 TestName
.MaximumLength
);
1867 if (!TestName
.Buffer
)
1869 /* Keep the old one */
1870 TestName
.Buffer
= Buffer
;
1875 Buffer
= TestName
.Buffer
;
1878 /* Make sure we have a buffer at least */
1879 ASSERT(TestName
.Buffer
);
1881 /* Resolve the name */
1882 *SearchPath
= ActualSearchPath
++;
1883 Status
= LdrpResolveFullName(&TestName
,
1890 /* Update buffer end */
1893 /* Update string position */
1894 //pp = ActualSearchPath++;
1898 /* Otherwise, write the character */
1903 /* Check if the string is empty, meaning we're done */
1904 if (!(*ActualSearchPath
)) TryAgain
= TRUE
;
1906 /* Advance in the string */
1908 } while (!TryAgain
);
1910 /* Check if we had a buffer and free it */
1911 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1914 /* Check if we got here through failure */
1915 if (!NT_SUCCESS(Status
)) *ExpandedName
= NULL
;
1917 /* Display debug output if snaps are on */
1920 /* Check which output to use -- failure or success */
1921 if (NT_SUCCESS(Status
))
1923 DbgPrintEx(DPFLTR_LDR_ID
,
1925 "LDR: %s - Returning %wZ\n",
1931 DbgPrintEx(DPFLTR_LDR_ID
,
1933 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1946 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1949 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1950 IN PUNICODE_STRING DllName
,
1952 IN BOOLEAN RedirectedDll
,
1953 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1956 PLIST_ENTRY ListHead
, ListEntry
;
1957 PLDR_DATA_TABLE_ENTRY CurEntry
;
1958 BOOLEAN FullPath
= FALSE
;
1961 UNICODE_STRING FullDllName
, NtPathName
;
1963 OBJECT_ATTRIBUTES ObjectAttributes
;
1965 HANDLE FileHandle
, SectionHandle
;
1966 IO_STATUS_BLOCK Iosb
;
1967 PVOID ViewBase
= NULL
;
1968 SIZE_T ViewSize
= 0;
1969 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1970 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"", DllName
, Flag
, RedirectedDll
, LdrEntry
);
1972 /* Check if a dll name was provided */
1973 if (!(DllName
->Buffer
) || !(DllName
->Buffer
[0])) return FALSE
;
1975 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1976 /* FIXME: Warning, code does not support redirection at all */
1978 /* Look in the hash table if flag was set */
1982 /* Get hash index */
1983 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
1985 /* Traverse that list */
1986 ListHead
= &LdrpHashTable
[HashIndex
];
1987 ListEntry
= ListHead
->Flink
;
1988 while (ListEntry
!= ListHead
)
1990 /* Get the current entry */
1991 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1993 /* Check base name of that module */
1994 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
1996 /* It matches, return it */
1997 *LdrEntry
= CurEntry
;
2001 /* Advance to the next entry */
2002 ListEntry
= ListEntry
->Flink
;
2005 /* Module was not found, return failure */
2009 /* Check if there is a full path in this DLL */
2010 wc
= DllName
->Buffer
;
2013 /* Check for a slash in the current position*/
2014 if ((*wc
== L
'\\') || (*wc
== L
'/'))
2016 /* Found the slash, so dll name contains path */
2019 /* Setup full dll name string */
2020 FullDllName
.Buffer
= NameBuf
;
2022 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2023 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
2026 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
2030 /* Check if that was successful */
2031 if (!(Length
) || (Length
> (sizeof(NameBuf
) - sizeof(UNICODE_NULL
))))
2033 /* HACK: Try to find active context dll */
2034 Status
= find_actctx_dll(DllName
->Buffer
, FullDllName
.Buffer
);
2035 if(Status
== STATUS_SUCCESS
)
2037 Length
= wcslen(FullDllName
.Buffer
) * sizeof(WCHAR
);
2038 DPRINT1("found %S for %S\n", FullDllName
.Buffer
, DllName
->Buffer
);
2045 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n",
2049 /* Return failure */
2054 /* Full dll name is found */
2055 FullDllName
.Length
= Length
;
2056 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
2063 /* Go check the hash table */
2070 /* FIXME: Warning, activation context missing */
2071 DPRINT("Warning, activation context missing\n");
2073 /* NOTE: From here on down, everything looks good */
2075 /* Loop the module list */
2076 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2077 ListEntry
= ListHead
->Flink
;
2078 while (ListEntry
!= ListHead
)
2080 /* Get the current entry and advance to the next one */
2081 CurEntry
= CONTAINING_RECORD(ListEntry
,
2082 LDR_DATA_TABLE_ENTRY
,
2084 ListEntry
= ListEntry
->Flink
;
2086 /* Check if it's being unloaded */
2087 if (!CurEntry
->InMemoryOrderLinks
.Flink
) continue;
2089 /* Check if name matches */
2090 if (RtlEqualUnicodeString(&FullDllName
,
2091 &CurEntry
->FullDllName
,
2095 *LdrEntry
= CurEntry
;
2100 /* Convert given path to NT path */
2101 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
2106 /* Fail if conversion failed */
2110 /* Initialize object attributes and open it */
2111 InitializeObjectAttributes(&ObjectAttributes
,
2113 OBJ_CASE_INSENSITIVE
,
2116 Status
= NtOpenFile(&FileHandle
,
2117 SYNCHRONIZE
| FILE_EXECUTE
,
2120 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2121 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
2123 /* Free NT path name */
2124 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
2126 /* If opening the file failed - return failure */
2127 if (!NT_SUCCESS(Status
)) return FALSE
;
2129 /* Create a section for this file */
2130 Status
= NtCreateSection(&SectionHandle
,
2132 SECTION_MAP_EXECUTE
|
2140 /* Close file handle */
2141 NtClose(FileHandle
);
2143 /* If creating section failed - return failure */
2144 if (!NT_SUCCESS(Status
)) return FALSE
;
2146 /* Map view of this section */
2147 Status
= ZwMapViewOfSection(SectionHandle
,
2158 /* Close section handle */
2159 NtClose(SectionHandle
);
2161 /* If section mapping failed - return failure */
2162 if (!NT_SUCCESS(Status
)) return FALSE
;
2164 /* Get pointer to the NT header of this section */
2165 Status
= RtlImageNtHeaderEx(0, ViewBase
, ViewSize
, &NtHeader
);
2166 if (!(NT_SUCCESS(Status
)) || !(NtHeader
))
2168 /* Unmap the section and fail */
2169 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2173 /* Go through the list of modules again */
2174 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2175 ListEntry
= ListHead
->Flink
;
2176 while (ListEntry
!= ListHead
)
2178 /* Get the current entry and advance to the next one */
2179 CurEntry
= CONTAINING_RECORD(ListEntry
,
2180 LDR_DATA_TABLE_ENTRY
,
2182 ListEntry
= ListEntry
->Flink
;
2184 /* Check if it's in the process of being unloaded */
2185 if (!CurEntry
->InMemoryOrderLinks
.Flink
) continue;
2187 /* The header is untrusted, use SEH */
2190 /* Check if timedate stamp and sizes match */
2191 if ((CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
) &&
2192 (CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
))
2194 /* Time, date and size match. Let's compare their headers */
2195 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
2196 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
2198 /* Headers match too! Finally ask the kernel to compare mapped files */
2199 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
2200 if (NT_SUCCESS(Status
))
2202 /* This is our entry!, unmap and return success */
2203 *LdrEntry
= CurEntry
;
2204 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2205 _SEH2_YIELD(return TRUE
;)
2210 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
2217 /* Unmap the section and fail */
2218 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2224 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
2225 IN PANSI_STRING Name
,
2227 OUT PVOID
*ProcedureAddress
,
2228 IN BOOLEAN ExecuteInit
)
2230 NTSTATUS Status
= STATUS_SUCCESS
;
2231 UCHAR ImportBuffer
[64];
2232 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2233 IMAGE_THUNK_DATA Thunk
;
2235 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
2236 PIMAGE_EXPORT_DIRECTORY ExportDir
;
2237 ULONG ExportDirSize
, Length
;
2240 /* Show debug message */
2241 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
2243 /* Check if we got a name */
2246 /* Show debug message */
2247 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
2249 /* Make sure it's not too long */
2250 Length
= Name
->Length
+
2252 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME
, Name
);
2253 if (Length
> UNICODE_STRING_MAX_BYTES
)
2255 /* Won't have enough space to add the hint */
2256 return STATUS_NAME_TOO_LONG
;
2259 /* Check if our buffer is large enough */
2260 if (Length
> sizeof(ImportBuffer
))
2262 /* Allocate from heap, plus 2 bytes for the Hint */
2263 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
2269 /* Use our internal buffer */
2270 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
2273 /* Clear the hint */
2274 ImportName
->Hint
= 0;
2276 /* Copy the name and null-terminate it */
2277 RtlCopyMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
2278 ImportName
->Name
[Name
->Length
] = ANSI_NULL
;
2280 /* Clear the high bit */
2281 ImageBase
= ImportName
;
2282 Thunk
.u1
.AddressOfData
= 0;
2286 /* Do it by ordinal */
2289 /* Show debug message */
2290 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
2292 /* Make sure an ordinal was given */
2296 DPRINT1("No ordinal and no name\n");
2297 return STATUS_INVALID_PARAMETER
;
2300 /* Set the original flag in the thunk */
2301 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
2304 /* Acquire lock unless we are initting */
2305 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2309 /* Try to find the loaded DLL */
2310 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2313 DPRINT1("Invalid base address %p\n", BaseAddress
);
2314 Status
= STATUS_DLL_NOT_FOUND
;
2315 _SEH2_YIELD(goto Quickie
;)
2318 /* Get the pointer to the export directory */
2319 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2321 IMAGE_DIRECTORY_ENTRY_EXPORT
,
2326 DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n",
2327 &LdrEntry
->BaseDllName
, Name
, BaseAddress
, LdrEntry
->DllBase
);
2328 Status
= STATUS_PROCEDURE_NOT_FOUND
;
2329 _SEH2_YIELD(goto Quickie
;)
2332 /* Now get the thunk */
2333 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
2342 /* Finally, see if we're supposed to run the init routines */
2343 if ((NT_SUCCESS(Status
)) && (ExecuteInit
))
2346 * It's possible a forwarded entry had us load the DLL. In that case,
2347 * then we will call its DllMain. Use the last loaded DLL for this.
2349 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
2350 LdrEntry
= CONTAINING_RECORD(Entry
,
2351 LDR_DATA_TABLE_ENTRY
,
2352 InInitializationOrderLinks
);
2354 /* Make sure we didn't process it yet*/
2355 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2357 /* Call the init routine */
2360 Status
= LdrpRunInitializeRoutines(NULL
);
2362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2364 /* Get the exception code */
2365 Status
= _SEH2_GetExceptionCode();
2371 /* Make sure we're OK till here */
2372 if (NT_SUCCESS(Status
))
2374 /* Return the address */
2375 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
2378 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2380 /* Just ignore exceptions */
2386 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
2388 /* We allocated from heap, free it */
2389 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
2392 /* Release the CS if we entered it */
2393 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
2401 LdrpLoadDll(IN BOOLEAN Redirected
,
2402 IN PWSTR DllPath OPTIONAL
,
2403 IN PULONG DllCharacteristics OPTIONAL
,
2404 IN PUNICODE_STRING DllName
,
2405 OUT PVOID
*BaseAddress
,
2406 IN BOOLEAN CallInit
)
2408 PPEB Peb
= NtCurrentPeb();
2409 NTSTATUS Status
= STATUS_SUCCESS
;
2411 BOOLEAN GotExtension
;
2413 WCHAR NameBuffer
[MAX_PATH
+ 6];
2414 UNICODE_STRING RawDllName
;
2415 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2416 BOOLEAN InInit
= LdrpInLdrInit
;
2418 /* Save the Raw DLL Name */
2419 if (DllName
->Length
>= sizeof(NameBuffer
)) return STATUS_NAME_TOO_LONG
;
2420 RtlInitEmptyUnicodeString(&RawDllName
, NameBuffer
, sizeof(NameBuffer
));
2421 RtlCopyUnicodeString(&RawDllName
, DllName
);
2423 /* Find the extension, if present */
2424 p
= DllName
->Buffer
+ DllName
->Length
/ sizeof(WCHAR
) - 1;
2425 GotExtension
= FALSE
;
2426 while (p
>= DllName
->Buffer
)
2431 GotExtension
= TRUE
;
2434 else if (c
== L
'\\')
2440 /* If no extension was found, add the default extension */
2443 /* Check that we have space to add one */
2444 if ((DllName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
2447 /* No space to add the extension */
2448 DbgPrintEx(DPFLTR_LDR_ID
,
2450 "LDR: %s - Dll name missing extension; with extension "
2451 "added the name is too long\n"
2452 " DllName: (@ %p) \"%wZ\"\n"
2453 " DllName->Length: %u\n",
2458 return STATUS_NAME_TOO_LONG
;
2461 /* Add it. Needs to be null terminated, thus the length check above */
2462 (VOID
)RtlAppendUnicodeStringToString(&RawDllName
,
2463 &LdrApiDefaultExtension
);
2466 /* Check for init flag and acquire lock */
2467 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
2469 /* Show debug message */
2472 DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
2474 DllPath
? DllPath
: L
"");
2477 /* Check if the DLL is already loaded */
2478 if (!LdrpCheckForLoadedDll(DllPath
,
2485 Status
= LdrpMapDll(DllPath
,
2492 if (!NT_SUCCESS(Status
)) goto Quickie
;
2494 /* FIXME: Need to mark the DLL range for the stack DB */
2495 //RtlpStkMarkDllRange(LdrEntry);
2497 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2498 if ((DllCharacteristics
) &&
2499 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
2501 /* This is not a DLL, so remove such data */
2502 LdrEntry
->EntryPoint
= NULL
;
2503 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
2506 /* Make sure it's a DLL */
2507 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2509 /* Check if this is a .NET Image */
2510 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
2512 /* Walk the Import Descriptor */
2513 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
2516 /* Update load count, unless it's locked */
2517 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2518 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2520 /* Check if we failed */
2521 if (!NT_SUCCESS(Status
))
2523 /* Clear entrypoint, and insert into list */
2524 LdrEntry
->EntryPoint
= NULL
;
2525 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2526 &LdrEntry
->InInitializationOrderLinks
);
2528 /* Cancel the load */
2529 LdrpClearLoadInProgress();
2531 /* Unload the DLL */
2534 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2535 "import descriptors\n",
2539 LdrUnloadDll(LdrEntry
->DllBase
);
2541 /* Return the error */
2545 else if (LdrEntry
->LoadCount
!= 0xFFFF)
2547 /* Increase load count */
2548 LdrEntry
->LoadCount
++;
2551 /* Insert it into the list */
2552 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
2553 &LdrEntry
->InInitializationOrderLinks
);
2555 /* If we have to run the entrypoint, make sure the DB is ready */
2556 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
2558 /* Notify Shim Engine */
2561 VOID (NTAPI
* SE_DllLoaded
)(PLDR_DATA_TABLE_ENTRY
) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded
);
2562 SE_DllLoaded(LdrEntry
);
2565 /* Run the init routine */
2566 Status
= LdrpRunInitializeRoutines(NULL
);
2567 if (!NT_SUCCESS(Status
))
2569 /* Failed, unload the DLL */
2572 DbgPrint("LDR: Unloading %wZ because either its init "
2573 "routine or one of its static imports failed; "
2574 "status = 0x%08lx\n",
2578 LdrUnloadDll(LdrEntry
->DllBase
);
2583 /* The DB isn't ready, which means we were loaded because of a forwarder */
2584 Status
= STATUS_SUCCESS
;
2589 /* We were already loaded. Are we a DLL? */
2590 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= 0xFFFF))
2592 /* Increase load count */
2593 LdrEntry
->LoadCount
++;
2594 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2596 /* Clear the load in progress */
2597 LdrpClearLoadInProgress();
2601 /* Not a DLL, just increase the load count */
2602 if (LdrEntry
->LoadCount
!= 0xFFFF) LdrEntry
->LoadCount
++;
2607 /* Release the lock */
2608 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2610 /* Check for success */
2611 if (NT_SUCCESS(Status
))
2613 /* Return the base address */
2614 *BaseAddress
= LdrEntry
->DllBase
;
2619 *BaseAddress
= NULL
;
2628 LdrpClearLoadInProgress(VOID
)
2630 PLIST_ENTRY ListHead
, Entry
;
2631 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2632 ULONG ModulesCount
= 0;
2634 /* Traverse the init list */
2635 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2636 Entry
= ListHead
->Flink
;
2637 while (Entry
!= ListHead
)
2639 /* Get the loader entry */
2640 LdrEntry
= CONTAINING_RECORD(Entry
,
2641 LDR_DATA_TABLE_ENTRY
,
2642 InInitializationOrderLinks
);
2644 /* Clear load in progress flag */
2645 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2647 /* Check for modules with entry point count but not processed yet */
2648 if ((LdrEntry
->EntryPoint
) &&
2649 !(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
2651 /* Increase counter */
2655 /* Advance to the next entry */
2656 Entry
= Entry
->Flink
;
2659 /* Return final count */
2660 return ModulesCount
;
2663 PVOID
LdrpGetShimEngineFunction(PCSZ FunctionName
)
2665 ANSI_STRING Function
;
2668 RtlInitAnsiString(&Function
, FunctionName
);
2669 Status
= LdrGetProcedureAddress(g_pShimEngineModule
, &Function
, 0, &Address
);
2670 return NT_SUCCESS(Status
) ? Address
: NULL
;
2675 LdrpGetShimEngineInterface()
2677 PVOID SE_DllLoaded
= LdrpGetShimEngineFunction("SE_DllLoaded");
2678 PVOID SE_DllUnloaded
= LdrpGetShimEngineFunction("SE_DllUnloaded");
2679 PVOID SE_InstallBeforeInit
= LdrpGetShimEngineFunction("SE_InstallBeforeInit");
2680 PVOID SE_InstallAfterInit
= LdrpGetShimEngineFunction("SE_InstallAfterInit");
2681 PVOID SE_ProcessDying
= LdrpGetShimEngineFunction("SE_ProcessDying");
2683 if (SE_DllLoaded
&& SE_DllUnloaded
&& SE_InstallBeforeInit
&& SE_InstallAfterInit
&& SE_ProcessDying
)
2685 g_pfnSE_DllLoaded
= RtlEncodeSystemPointer(SE_DllLoaded
);
2686 g_pfnSE_DllUnloaded
= RtlEncodeSystemPointer(SE_DllUnloaded
);
2687 g_pfnSE_InstallBeforeInit
= RtlEncodeSystemPointer(SE_InstallBeforeInit
);
2688 g_pfnSE_InstallAfterInit
= RtlEncodeSystemPointer(SE_InstallAfterInit
);
2689 g_pfnSE_ProcessDying
= RtlEncodeSystemPointer(SE_ProcessDying
);
2690 g_ShimsEnabled
= TRUE
;
2694 LdrpUnloadShimEngine();
2701 LdrpLoadShimEngine(IN PWSTR ImageName
, IN PUNICODE_STRING ProcessImage
, IN PVOID pShimData
)
2703 UNICODE_STRING ShimLibraryName
;
2706 RtlInitUnicodeString(&ShimLibraryName
, ImageName
);
2707 Status
= LdrpLoadDll(FALSE
, NULL
, NULL
, &ShimLibraryName
, &ShimLibrary
, TRUE
);
2708 if (NT_SUCCESS(Status
))
2710 g_pShimEngineModule
= ShimLibrary
;
2711 LdrpGetShimEngineInterface();
2714 VOID(NTAPI
*SE_InstallBeforeInit
)(PUNICODE_STRING
, PVOID
);
2715 SE_InstallBeforeInit
= RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit
);
2716 SE_InstallBeforeInit(ProcessImage
, pShimData
);
2723 LdrpUnloadShimEngine()
2725 /* Make sure we do not call into the shim engine anymore */
2726 g_ShimsEnabled
= FALSE
;
2727 LdrUnloadDll(g_pShimEngineModule
);
2728 g_pShimEngineModule
= NULL
;