2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/ntdll/ldr/ldrpe.c
5 * PURPOSE: Loader Functions dealing low-level PE Format structures
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine
;
21 /* FUNCTIONS *****************************************************************/
26 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry
,
27 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry
,
28 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry
,
29 IN BOOLEAN EntriesValid
)
33 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
34 PIMAGE_NT_HEADERS NtHeader
;
35 PIMAGE_SECTION_HEADER SectionHeader
;
36 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
38 ULONG ForwarderChain
, i
, Rva
, OldProtect
, IatSize
, ExportSize
;
40 DPRINT("LdrpSnapIAT(%wZ %wZ %p %u)\n", &ExportLdrEntry
->BaseDllName
, &ImportLdrEntry
->BaseDllName
, IatEntry
, EntriesValid
);
42 /* Get export directory */
43 ExportDirectory
= RtlImageDirectoryEntryToData(ExportLdrEntry
->DllBase
,
45 IMAGE_DIRECTORY_ENTRY_EXPORT
,
48 /* Make sure it has one */
52 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
53 &ExportLdrEntry
->BaseDllName
);
54 return STATUS_INVALID_IMAGE_FORMAT
;
58 Iat
= RtlImageDirectoryEntryToData(ImportLdrEntry
->DllBase
,
60 IMAGE_DIRECTORY_ENTRY_IAT
,
64 /* Check if we don't have one */
67 /* Get the NT Header and the first section */
68 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
69 if (!NtHeader
) return STATUS_INVALID_IMAGE_FORMAT
;
70 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
72 /* Get the RVA of the import directory */
73 Rva
= NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
75 /* Make sure we got one */
78 /* Loop all the sections */
79 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
81 /* Check if we are inside this section */
82 if ((Rva
>= SectionHeader
->VirtualAddress
) &&
83 (Rva
< (SectionHeader
->VirtualAddress
+
84 SectionHeader
->SizeOfRawData
)))
86 /* We are, so set the IAT here */
87 Iat
= (PVOID
)((ULONG_PTR
)(ImportLdrEntry
->DllBase
) +
88 SectionHeader
->VirtualAddress
);
91 IatSize
= SectionHeader
->Misc
.VirtualSize
;
93 /* Deal with Watcom and other retarded compilers */
94 if (!IatSize
) IatSize
= SectionHeader
->SizeOfRawData
;
96 /* Found it, get out */
100 /* No match, move to the next section */
105 /* If we still don't have an IAT, that's bad */
109 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
110 &ImportLdrEntry
->BaseDllName
,
111 ImportLdrEntry
->DllBase
);
112 return STATUS_INVALID_IMAGE_FORMAT
;
115 /* Set the right size */
116 ImportSize
= IatSize
;
119 /* Unprotect the IAT */
120 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
125 if (!NT_SUCCESS(Status
))
128 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
129 &ImportLdrEntry
->BaseDllName
,
134 /* Check if the Thunks are already valid */
137 /* We'll only do forwarders. Get the import name */
138 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+ IatEntry
->Name
);
140 /* Get the list of forwarders */
141 ForwarderChain
= IatEntry
->ForwarderChain
;
144 while (ForwarderChain
!= -1)
146 /* Get the cached thunk VA*/
147 OriginalThunk
= (PIMAGE_THUNK_DATA
)
148 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
149 IatEntry
->OriginalFirstThunk
+
150 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
152 /* Get the first thunk */
153 FirstThunk
= (PIMAGE_THUNK_DATA
)
154 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
155 IatEntry
->FirstThunk
+
156 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
158 /* Get the Forwarder from the thunk */
159 ForwarderChain
= (ULONG
)FirstThunk
->u1
.Ordinal
;
164 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
165 ImportLdrEntry
->DllBase
,
173 /* Move to the next thunk */
175 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
177 /* Fail with the SEH error */
178 Status
= _SEH2_GetExceptionCode();
181 /* If we messed up, exit */
182 if (!NT_SUCCESS(Status
)) break;
185 else if (IatEntry
->FirstThunk
)
187 /* Full snapping. Get the First thunk */
188 FirstThunk
= (PIMAGE_THUNK_DATA
)
189 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
190 IatEntry
->FirstThunk
);
192 /* Get the NT Header */
193 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
195 /* Get the Original thunk VA, watch out for weird images */
196 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
197 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
199 /* Refuse it, this is a strange linked file */
200 OriginalThunk
= FirstThunk
;
204 /* Get the address from the field and convert to VA */
205 OriginalThunk
= (PIMAGE_THUNK_DATA
)
206 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
207 IatEntry
->OriginalFirstThunk
);
210 /* Get the Import name VA */
211 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
214 /* Loop while it's valid */
215 while (OriginalThunk
->u1
.AddressOfData
)
220 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
221 ImportLdrEntry
->DllBase
,
232 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
234 /* Fail with the SEH error */
235 Status
= _SEH2_GetExceptionCode();
238 /* If we failed the snap, break out */
239 if (!NT_SUCCESS(Status
)) break;
243 /* Protect the IAT again */
244 NtProtectVirtualMemory(NtCurrentProcess(),
250 /* Also flush out the cache */
251 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
253 /* Return to Caller */
259 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
260 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
261 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR
*BoundEntryPtr
,
262 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
264 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
266 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
267 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
268 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
269 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
270 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
271 PPEB Peb
= NtCurrentPeb();
274 /* Get the pointer to the bound entry */
275 BoundEntry
= *BoundEntryPtr
;
277 /* Get the name's VA */
278 BoundImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
280 /* Show debug message */
283 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
286 /* Load the module for this entry */
287 Status
= LdrpLoadImportModule(DllPath
,
291 if (!NT_SUCCESS(Status
))
293 /* Show debug message */
296 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
297 &LdrEntry
->BaseDllName
,
304 /* Check if it wasn't already loaded */
307 /* Add it to our list */
308 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
309 &DllLdrEntry
->InInitializationOrderLinks
);
312 /* Check if the Bound Entry is now invalid */
313 if ((BoundEntry
->TimeDateStamp
!= DllLdrEntry
->TimeDateStamp
) ||
314 (DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
316 /* Show debug message */
319 DPRINT1("LDR: %wZ has stale binding to %s\n",
320 &LdrEntry
->BaseDllName
,
324 /* Remember it's become stale */
329 /* Show debug message */
332 DPRINT1("LDR: %wZ has correct binding to %s\n",
333 &LdrEntry
->BaseDllName
,
337 /* Remember it's valid */
341 /* Get the forwarders */
342 ForwarderEntry
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
345 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
348 ForwarderName
= (LPSTR
)FirstEntry
+ ForwarderEntry
->OffsetModuleName
;
350 /* Show debug message */
353 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
354 &LdrEntry
->BaseDllName
,
356 &DllLdrEntry
->BaseDllName
);
359 /* Load the module */
360 Status
= LdrpLoadImportModule(DllPath
,
364 if (NT_SUCCESS(Status
))
366 /* Loaded it, was it already loaded? */
369 /* Add it to our list */
370 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
371 &ForwarderLdrEntry
->InInitializationOrderLinks
);
375 /* Check if the Bound Entry is now invalid */
376 if (!(NT_SUCCESS(Status
)) ||
377 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
378 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
380 /* Show debug message */
383 DPRINT1("LDR: %wZ has stale binding to %s\n",
384 &LdrEntry
->BaseDllName
,
388 /* Remember it's become stale */
393 /* Show debug message */
396 DPRINT1("LDR: %wZ has correct binding to %s\n",
397 &LdrEntry
->BaseDllName
,
401 /* Remember it's valid */
405 /* Move to the next one */
409 /* Set the next bound entry to the forwarder */
410 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
412 /* Check if the binding was stale */
415 /* It was, so find the IAT entry for it */
417 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
419 IMAGE_DIRECTORY_ENTRY_IMPORT
,
422 /* Make sure it has a name */
423 while (ImportEntry
->Name
)
426 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
429 if (!_stricmp(ImportName
, BoundImportName
)) break;
431 /* Move to next entry */
435 /* If we didn't find a name, fail */
436 if (!ImportEntry
->Name
)
438 /* Show debug message */
441 DPRINT1("LDR: LdrpWalkImportTable - failing with"
442 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
446 Status
= STATUS_OBJECT_NAME_INVALID
;
450 /* Show debug message */
453 DPRINT1("LDR: Stale Bind %s from %wZ\n",
455 &LdrEntry
->BaseDllName
);
458 /* Snap the IAT Entry*/
459 Status
= LdrpSnapIAT(DllLdrEntry
,
464 /* Make sure we didn't fail */
465 if (!NT_SUCCESS(Status
))
467 /* Show debug message */
470 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
471 &LdrEntry
->BaseDllName
,
482 Status
= STATUS_SUCCESS
;
485 /* Write where we are now and return */
486 *BoundEntryPtr
= FirstEntry
;
492 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
493 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
494 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
496 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
499 /* Make sure we have a name */
500 while (BoundEntry
->OffsetModuleName
)
502 /* Parse this descriptor */
503 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
507 if (!NT_SUCCESS(Status
)) return Status
;
511 return STATUS_SUCCESS
;
516 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
517 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
518 IN PIMAGE_IMPORT_DESCRIPTOR
*ImportEntry
)
522 BOOLEAN AlreadyLoaded
= FALSE
;
523 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
524 PIMAGE_THUNK_DATA FirstThunk
;
525 PPEB Peb
= NtCurrentPeb();
527 /* Get the import name's VA */
528 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ (*ImportEntry
)->Name
);
530 /* Get the first thunk */
531 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
532 (*ImportEntry
)->FirstThunk
);
534 /* Make sure it's valid */
535 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
537 /* Show debug message */
540 DPRINT1("LDR: %s used by %wZ\n",
542 &LdrEntry
->BaseDllName
);
545 /* Load the module associated to it */
546 Status
= LdrpLoadImportModule(DllPath
,
550 if (!NT_SUCCESS(Status
))
555 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
556 "on import %s with status %x\n",
565 /* Show debug message */
568 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
569 &LdrEntry
->BaseDllName
,
573 /* Check if it wasn't already loaded */
577 /* Add the DLL to our list */
578 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
579 &DllLdrEntry
->InInitializationOrderLinks
);
582 /* Now snap the IAT Entry */
583 Status
= LdrpSnapIAT(DllLdrEntry
, LdrEntry
, *ImportEntry
, FALSE
);
584 if (!NT_SUCCESS(Status
))
589 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
601 return STATUS_SUCCESS
;
606 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
607 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
608 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
612 /* Check for Name and Thunk */
613 while ((ImportEntry
->Name
) && (ImportEntry
->FirstThunk
))
615 /* Parse this descriptor */
616 Status
= LdrpHandleOneOldFormatImportDescriptor(DllPath
,
619 if (!NT_SUCCESS(Status
)) return Status
;
623 return STATUS_SUCCESS
;
628 LdrpNameToOrdinal(IN LPSTR ImportName
,
629 IN ULONG NumberOfNames
,
632 IN PUSHORT OrdinalTable
)
634 LONG Start
, End
, Next
, CmpResult
;
636 /* Use classical binary search to find the ordinal */
638 End
= NumberOfNames
- 1;
641 /* Next will be exactly between Start and End */
642 Next
= (Start
+ End
) >> 1;
644 /* Compare this name with the one we need to find */
645 CmpResult
= strcmp(ImportName
, (PCHAR
)((ULONG_PTR
)ExportBase
+ NameTable
[Next
]));
647 /* We found our entry if result is 0 */
648 if (!CmpResult
) break;
650 /* We didn't find, update our range then */
655 else if (CmpResult
> 0)
661 /* If end is before start, then the search failed */
662 if (End
< Start
) return -1;
664 /* Return found name */
665 return OrdinalTable
[Next
];
670 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
671 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
673 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
674 PPEB Peb
= NtCurrentPeb();
675 NTSTATUS Status
= STATUS_SUCCESS
, Status2
;
676 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
677 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
678 ULONG BoundSize
, IatSize
;
680 DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry
->BaseDllName
, LdrEntry
, DllPath
);
682 /* Set up the Act Ctx */
683 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
684 ActCtx
.Size
= sizeof(ActCtx
);
685 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
687 /* Check if we have a manifest prober routine */
688 if (LdrpManifestProberRoutine
)
690 /* Probe the DLL for its manifest. Some details are omitted */
691 Status2
= LdrpManifestProberRoutine(LdrEntry
->DllBase
, LdrEntry
->FullDllName
.Buffer
, &LdrEntry
->EntryPointActivationContext
);
693 if (!NT_SUCCESS(Status2
) &&
694 Status2
!= STATUS_NO_SUCH_FILE
&&
695 Status2
!= STATUS_RESOURCE_DATA_NOT_FOUND
&&
696 Status2
!= STATUS_RESOURCE_TYPE_NOT_FOUND
&&
697 Status2
!= STATUS_RESOURCE_NAME_NOT_FOUND
&&
698 Status2
!= STATUS_RESOURCE_LANG_NOT_FOUND
)
700 /* Some serious issue */
701 //Status = Status2; // FIXME: Ignore that error for now
702 DbgPrintEx(DPFLTR_SXS_ID
,
703 DPFLTR_WARNING_LEVEL
,
704 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its "
705 "manifest, ntstatus = 0x%08lx\n",
706 &LdrEntry
->FullDllName
, Status2
);
710 /* Check if we failed above */
711 if (!NT_SUCCESS(Status
)) return Status
;
713 /* Get the Active ActCtx */
714 if (!LdrEntry
->EntryPointActivationContext
)
716 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
718 if (!NT_SUCCESS(Status
))
721 DbgPrintEx(DPFLTR_SXS_ID
,
722 DPFLTR_WARNING_LEVEL
,
723 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
730 /* Activate the ActCtx */
731 RtlActivateActivationContextUnsafeFast(&ActCtx
,
732 LdrEntry
->EntryPointActivationContext
);
734 /* Check if we were redirected */
735 if (!(LdrEntry
->Flags
& LDRP_REDIRECTED
))
737 /* Get the Bound IAT */
738 BoundEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
740 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
744 /* Get the regular IAT, for fallback */
745 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
747 IMAGE_DIRECTORY_ENTRY_IMPORT
,
750 /* Check if we got at least one */
751 if ((BoundEntry
) || (ImportEntry
))
753 /* Do we have a Bound IAT */
756 /* Handle the descriptor */
757 Status
= LdrpHandleNewFormatImportDescriptors(DllPath
,
763 /* Handle the descriptor */
764 Status
= LdrpHandleOldFormatImportDescriptors(DllPath
,
769 /* Check the status of the handlers */
770 if (NT_SUCCESS(Status
))
772 /* Check for Per-DLL Heap Tagging */
773 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAG_BY_DLL
)
776 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
779 /* Check if Page Heap was enabled */
780 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
782 /* Initialize target DLL */
783 AVrfPageHeapDllNotification(LdrEntry
);
786 /* Check if Application Verifier was enabled */
787 if (Peb
->NtGlobalFlag
& FLG_APPLICATION_VERIFIER
)
789 AVrfDllLoadNotification(LdrEntry
);
792 /* Just to be safe */
793 Status
= STATUS_SUCCESS
;
797 /* Release the activation context */
798 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
800 DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry
->BaseDllName
, LdrEntry
);
808 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
810 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
811 OUT PBOOLEAN Existing
)
813 ANSI_STRING AnsiString
;
814 PUNICODE_STRING ImpDescName
;
816 BOOLEAN GotExtension
;
819 PPEB Peb
= RtlGetCurrentPeb();
820 PTEB Teb
= NtCurrentTeb();
821 UNICODE_STRING RedirectedImpDescName
;
822 BOOLEAN RedirectedDll
;
824 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p)\n", DllPath
, ImportName
, DataTableEntry
, Existing
);
826 RedirectedDll
= FALSE
;
827 RtlInitEmptyUnicodeString(&RedirectedImpDescName
, NULL
, 0);
829 /* Convert import descriptor name to unicode string */
830 ImpDescName
= &Teb
->StaticUnicodeString
;
831 RtlInitAnsiString(&AnsiString
, ImportName
);
832 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
833 if (!NT_SUCCESS(Status
)) return Status
;
835 /* Find the extension, if present */
836 p
= ImpDescName
->Buffer
+ ImpDescName
->Length
/ sizeof(WCHAR
) - 1;
837 GotExtension
= FALSE
;
838 while (p
>= ImpDescName
->Buffer
)
852 /* If no extension was found, add the default extension */
855 /* Check that we have space to add one */
856 if ((ImpDescName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
857 sizeof(Teb
->StaticUnicodeBuffer
))
859 /* No space to add the extension */
860 DbgPrintEx(DPFLTR_LDR_ID
,
862 "LDR: %s - Dll name missing extension; with extension "
863 "added the name is too long\n"
864 " ImpDescName: (@ %p) \"%wZ\"\n"
865 " ImpDescName->Length: %u\n",
869 ImpDescName
->Length
);
870 return STATUS_NAME_TOO_LONG
;
873 /* Add it. Needs to be null terminated, thus the length check above */
874 (VOID
)RtlAppendUnicodeStringToString(ImpDescName
,
875 &LdrApiDefaultExtension
);
878 /* Check if the SxS Assemblies specify another file */
879 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
881 &LdrApiDefaultExtension
,
883 &RedirectedImpDescName
,
890 if (NT_SUCCESS(Status
))
893 RedirectedDll
= TRUE
;
895 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
897 /* Unrecoverable SxS failure */
898 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status
, ImpDescName
);
902 /* Check if it's loaded */
903 if (LdrpCheckForLoadedDll(DllPath
,
909 /* It's already existing in the list */
911 Status
= STATUS_SUCCESS
;
915 /* We're loading it for the first time */
919 Status
= LdrpMapDll(DllPath
,
926 if (!NT_SUCCESS(Status
))
928 DPRINT1("LDR: LdrpMapDll failed with status %x for dll %wZ\n", Status
, ImpDescName
);
932 /* Walk its import descriptor table */
933 Status
= LdrpWalkImportDescriptor(DllPath
,
935 if (!NT_SUCCESS(Status
))
937 /* Add it to the in-init-order list in case of failure */
938 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
939 &(*DataTableEntry
)->InInitializationOrderLinks
);
943 RtlFreeUnicodeString(&RedirectedImpDescName
);
950 LdrpSnapThunk(IN PVOID ExportBase
,
952 IN PIMAGE_THUNK_DATA OriginalThunk
,
953 IN OUT PIMAGE_THUNK_DATA Thunk
,
954 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
961 ULONG OriginalOrdinal
= 0;
962 PIMAGE_IMPORT_BY_NAME AddressOfData
;
964 PUSHORT OrdinalTable
;
965 LPSTR ImportName
= NULL
, DotPosition
;
968 ULONG_PTR HardErrorParameters
[3];
969 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
970 ANSI_STRING TempString
;
973 PULONG AddressOfFunctions
;
974 UNICODE_STRING TempUString
;
975 ANSI_STRING ForwarderName
;
976 PANSI_STRING ForwardName
;
977 PVOID ForwarderHandle
;
978 ULONG ForwardOrdinal
;
980 /* Check if the snap is by ordinal */
981 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
983 /* Get the ordinal number, and its normalized version */
984 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
985 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportDirectory
->Base
);
989 /* First get the data VA */
990 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
991 ((ULONG_PTR
)ImportBase
+
992 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
995 ImportName
= (LPSTR
)AddressOfData
->Name
;
997 /* Now get the VA of the Name and Ordinal Tables */
998 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
999 (ULONG_PTR
)ExportDirectory
->AddressOfNames
);
1000 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
1001 (ULONG_PTR
)ExportDirectory
->AddressOfNameOrdinals
);
1004 Hint
= AddressOfData
->Hint
;
1006 /* Try to get a match by using the hint */
1007 if (((ULONG
)Hint
< ExportDirectory
->NumberOfNames
) &&
1008 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
1010 /* We got a match, get the Ordinal from the hint */
1011 Ordinal
= OrdinalTable
[Hint
];
1015 /* Well bummer, hint didn't work, do it the long way */
1016 Ordinal
= LdrpNameToOrdinal(ImportName
,
1017 ExportDirectory
->NumberOfNames
,
1024 /* Check if the ordinal is invalid */
1025 if ((ULONG
)Ordinal
>= ExportDirectory
->NumberOfFunctions
)
1028 /* Is this a static snap? */
1031 UNICODE_STRING SnapTarget
;
1032 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1034 /* What was the module we were searching in */
1035 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
1037 /* What was the module we were searching for */
1038 if (LdrpCheckForLoadedDllHandle(ImportBase
, &LdrEntry
))
1039 SnapTarget
= LdrEntry
->BaseDllName
;
1041 RtlInitUnicodeString(&SnapTarget
, L
"Unknown");
1043 /* Inform the debug log */
1045 DPRINT1("Failed to snap ordinal %Z!0x%x for %wZ\n", &TempString
, OriginalOrdinal
, &SnapTarget
);
1047 DPRINT1("Failed to snap %Z!%s for %wZ\n", &TempString
, ImportName
, &SnapTarget
);
1049 /* These are critical errors. Setup a string for the DLL name */
1050 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
1052 /* Set it as the parameter */
1053 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
1056 /* Check if we have an ordinal */
1059 /* Then set the ordinal as the 1st parameter */
1060 HardErrorParameters
[0] = OriginalOrdinal
;
1064 /* We don't, use the entrypoint. Set up a string for it */
1065 RtlInitAnsiString(&TempString
, ImportName
);
1066 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
1070 /* Set it as the parameter */
1071 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
1075 /* Raise the error */
1076 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1077 STATUS_ENTRYPOINT_NOT_FOUND
,
1080 HardErrorParameters
,
1084 /* Increase the error count */
1085 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1087 /* Free our string */
1088 RtlFreeUnicodeString(&HardErrorDllName
);
1091 /* Free our second string. Return entrypoint error */
1092 RtlFreeUnicodeString(&HardErrorEntryPointName
);
1093 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
1096 /* Return ordinal error */
1097 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
1101 /* Inform the debug log */
1103 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
1105 DPRINT("Non-fatal: Failed to snap %s\n", ImportName
);
1108 /* Set this as a bad DLL */
1109 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
1111 /* Return the right error code */
1112 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1113 STATUS_ENTRYPOINT_NOT_FOUND
;
1117 /* The ordinal seems correct, get the AddressOfFunctions VA */
1118 AddressOfFunctions
= (PULONG
)
1119 ((ULONG_PTR
)ExportBase
+
1120 (ULONG_PTR
)ExportDirectory
->AddressOfFunctions
);
1122 /* Write the function pointer*/
1123 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
1125 /* Make sure it's within the exports */
1126 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
1127 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
1129 /* Get the Import and Forwarder Names */
1130 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
1132 DotPosition
= strchr(ImportName
, '.');
1133 ASSERT(DotPosition
!= NULL
);
1137 ForwarderName
.Buffer
= ImportName
;
1138 ForwarderName
.Length
= (USHORT
)(DotPosition
- ImportName
);
1139 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
1140 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
1144 /* Make sure the conversion was OK */
1145 if (NT_SUCCESS(Status
))
1147 WCHAR StringBuffer
[MAX_PATH
];
1148 UNICODE_STRING StaticString
, *RedirectedImportName
;
1149 BOOLEAN Redirected
= FALSE
;
1151 RtlInitEmptyUnicodeString(&StaticString
, StringBuffer
, sizeof(StringBuffer
));
1153 /* Check if the SxS Assemblies specify another file */
1154 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
1156 &LdrApiDefaultExtension
,
1159 &RedirectedImportName
,
1163 if (NT_SUCCESS(Status
))
1167 DPRINT1("LDR: %Z got redirected to %wZ\n", &ForwarderName
, RedirectedImportName
);
1174 RedirectedImportName
= &TempUString
;
1177 /* Load the forwarder */
1178 Status
= LdrpLoadDll(Redirected
,
1181 RedirectedImportName
,
1185 RtlFreeUnicodeString(&TempUString
);
1188 /* If the load or conversion failed, use the failure path */
1189 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1191 /* Now set up a name for the actual forwarder dll */
1192 RtlInitAnsiString(&ForwarderName
,
1193 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
1195 /* Check if it's an ordinal forward */
1196 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
1198 /* We don't have an actual function name */
1201 /* Convert the string into an ordinal */
1202 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
1206 /* If this fails, then error out */
1207 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1211 /* Import by name */
1212 ForwardName
= &ForwarderName
;
1216 /* Get the pointer */
1217 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1220 (PVOID
*)&Thunk
->u1
.Function
,
1222 /* If this fails, then error out */
1223 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1227 /* It's not within the exports, let's hope it's valid */
1228 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1231 /* If we got here, then it's success */
1232 Status
= STATUS_SUCCESS
;