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 *****************************************************************/
15 /* GLOBALS *******************************************************************/
16 ULONG LdrpFatalHardErrorCount
;
17 PVOID LdrpManifestProberRoutine
;
19 /* PROTOTYPES ****************************************************************/
21 #define IMAGE_REL_BASED_HIGH3ADJ 11
25 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
28 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
29 OUT PBOOLEAN Existing
);
31 /* FUNCTIONS *****************************************************************/
35 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry
,
36 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry
,
37 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry
,
38 IN BOOLEAN EntriesValid
)
40 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
45 //PPEB Peb = NtCurrentPeb();
47 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
50 PIMAGE_NT_HEADERS NtHeader
;
51 PIMAGE_SECTION_HEADER SectionHeader
;
55 DPRINT("LdrpSnapIAT(%wZ %wZ %p %d)\n", &ExportLdrEntry
->BaseDllName
, &ImportLdrEntry
->BaseDllName
, IatEntry
, EntriesValid
);
57 /* Get export directory */
58 ExportDirectory
= RtlImageDirectoryEntryToData(ExportLdrEntry
->DllBase
,
60 IMAGE_DIRECTORY_ENTRY_EXPORT
,
63 /* Make sure it has one */
64 if (!ExportDirectory
) return STATUS_INVALID_IMAGE_FORMAT
;
67 Iat
= RtlImageDirectoryEntryToData(ImportLdrEntry
->DllBase
,
69 IMAGE_DIRECTORY_ENTRY_IAT
,
73 /* Check if we don't have one */
76 /* Get the NT Header and the first section */
77 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
78 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
80 /* Get the RVA of the import directory */
81 Rva
= NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
83 /* Make sure we got one */
86 /* Loop all the sections */
87 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
89 /* Check if we are inside this section */
90 if ((Rva
>= SectionHeader
->VirtualAddress
) &&
91 (Rva
< (SectionHeader
->VirtualAddress
+
92 SectionHeader
->SizeOfRawData
)))
94 /* We are, so set the IAT here */
95 Iat
= (PVOID
)((ULONG_PTR
)(ImportLdrEntry
->DllBase
) +
96 SectionHeader
->VirtualAddress
);
99 IatSize
= SectionHeader
->Misc
.VirtualSize
;
101 /* Deal with Watcom and other retarded compilers */
104 IatSize
= SectionHeader
->SizeOfRawData
;
107 /* Found it, get out */
111 /* No match, move to the next section */
116 /* If we still don't have an IAT, that's bad */
117 if (!Iat
) return STATUS_INVALID_IMAGE_FORMAT
;
119 /* Set the right size */
120 ImportSize
= IatSize
;
123 /* Unprotect the IAT */
124 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
129 if (!NT_SUCCESS(Status
)) return Status
;
131 /* Check if the Thunks are already valid */
134 /* We'll only do forwarders. Get the import name */
135 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+ IatEntry
->Name
);
137 /* Get the list of forwaders */
138 ForwarderChain
= IatEntry
->ForwarderChain
;
141 while (ForwarderChain
!= -1)
143 /* Get the cached thunk VA*/
144 OriginalThunk
= (PIMAGE_THUNK_DATA
)
145 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
146 IatEntry
->OriginalFirstThunk
+
147 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
149 /* Get the first thunk */
150 FirstThunk
= (PIMAGE_THUNK_DATA
)
151 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
152 IatEntry
->FirstThunk
+
153 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
155 /* Get the Forwarder from the thunk */
156 ForwarderChain
= (ULONG
)FirstThunk
->u1
.Ordinal
;
161 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
162 ImportLdrEntry
->DllBase
,
170 /* Move to the next thunk */
172 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
174 /* Fail with the SEH error */
175 Status
= _SEH2_GetExceptionCode();
178 /* If we messed up, exit */
179 if (!NT_SUCCESS(Status
)) break;
182 else if (IatEntry
->FirstThunk
)
184 /* Full snapping. Get the First thunk */
185 FirstThunk
= (PIMAGE_THUNK_DATA
)
186 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
187 IatEntry
->FirstThunk
);
189 /* Get the NT Header */
190 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
192 /* Get the Original thunk VA, watch out for weird images */
193 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
194 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
196 /* Refuse it, this is a strange linked file */
197 OriginalThunk
= FirstThunk
;
201 /* Get the address from the field and convert to VA */
202 OriginalThunk
= (PIMAGE_THUNK_DATA
)
203 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
204 IatEntry
->OriginalFirstThunk
);
207 /* Get the Import name VA */
208 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
211 /* Loop while it's valid */
212 while (OriginalThunk
->u1
.AddressOfData
)
217 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
218 ImportLdrEntry
->DllBase
,
229 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
231 /* Fail with the SEH error */
232 Status
= _SEH2_GetExceptionCode();
235 /* If we failed the snap, break out */
236 if (!NT_SUCCESS(Status
)) break;
240 /* Protect the IAT again */
241 NtProtectVirtualMemory(NtCurrentProcess(),
247 /* Also flush out the cache */
248 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
250 /* Return to Caller */
256 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
257 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
258 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
,
259 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
261 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
263 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
264 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
265 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
266 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
267 PPEB Peb
= NtCurrentPeb();
270 /* Get the name's VA */
271 BoundImportName
= (LPSTR
)(BoundEntry
+ BoundEntry
->OffsetModuleName
);
273 /* Show debug mesage */
276 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
279 /* Load the module for this entry */
280 Status
= LdrpLoadImportModule(DllPath
,
285 if (!NT_SUCCESS(Status
))
287 /* Show debug message */
290 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
291 &LdrEntry
->BaseDllName
,
298 /* Check if it wasn't already loaded */
301 /* Add it to our list */
302 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
303 &DllLdrEntry
->InInitializationOrderModuleList
);
306 /* Check if the Bound Entry is now invalid */
307 if ((BoundEntry
->TimeDateStamp
!= DllLdrEntry
->TimeDateStamp
) ||
308 (DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
310 /* Show debug message */
313 DPRINT1("LDR: %wZ has stale binding to %s\n",
314 &DllLdrEntry
->BaseDllName
,
318 /* Remember it's become stale */
323 /* Show debug message */
326 DPRINT1("LDR: %wZ has correct binding to %s\n",
327 &DllLdrEntry
->BaseDllName
,
331 /* Remember it's valid */
335 /* Get the forwarders */
336 ForwarderEntry
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
339 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
342 ForwarderName
= (LPSTR
)(FirstEntry
+ ForwarderEntry
->OffsetModuleName
);
344 /* Show debug message */
347 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
348 &LdrEntry
->BaseDllName
,
350 &DllLdrEntry
->BaseDllName
);
353 /* Load the module */
354 Status
= LdrpLoadImportModule(DllPath
,
359 if (NT_SUCCESS(Status
))
361 /* Loaded it, was it already loaded? */
364 /* Add it to our list */
365 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
366 &ForwarderLdrEntry
->InInitializationOrderModuleList
);
370 /* Check if the Bound Entry is now invalid */
371 if (!(NT_SUCCESS(Status
)) ||
372 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
373 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
375 /* Show debug message */
378 DPRINT1("LDR: %wZ has stale binding to %s\n",
379 &ForwarderLdrEntry
->BaseDllName
,
383 /* Remember it's become stale */
388 /* Show debug message */
391 DPRINT1("LDR: %wZ has correct binding to %s\n",
392 &ForwarderLdrEntry
->BaseDllName
,
396 /* Remember it's valid */
400 /* Move to the next one */
404 /* Set the next bound entry to the forwarder */
405 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
407 /* Check if the binding was stale */
410 /* It was, so find the IAT entry for it */
411 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
413 IMAGE_DIRECTORY_ENTRY_IMPORT
,
416 /* Make sure it has a name */
417 while (ImportEntry
->Name
)
420 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
423 if (!_stricmp(ImportName
, BoundImportName
)) break;
425 /* Move to next entry */
429 /* If we didn't find a name, fail */
430 if (!ImportEntry
->Name
)
432 /* Show debug message */
435 DPRINT1("LDR: LdrpWalkImportTable - failing with"
436 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
440 Status
= STATUS_OBJECT_NAME_INVALID
;
444 /* Show debug message */
447 DPRINT1("LDR: Stale Bind %s from %wZ\n",
449 &LdrEntry
->BaseDllName
);
452 /* Snap the IAT Entry*/
453 Status
= LdrpSnapIAT(DllLdrEntry
,
458 /* Make sure we didn't fail */
459 if (!NT_SUCCESS(Status
))
461 /* Show debug message */
464 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
465 &LdrEntry
->BaseDllName
,
476 Status
= STATUS_SUCCESS
;
479 /* Write where we are now and return */
480 *BoundEntry
= *FirstEntry
;
486 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
487 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
488 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
490 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
493 /* Make sure we have a name */
494 while (BoundEntry
->OffsetModuleName
)
496 /* Parse this descriptor */
497 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
501 if (!NT_SUCCESS(Status
)) return Status
;
505 return STATUS_SUCCESS
;
510 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
511 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
512 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
517 BOOLEAN AlreadyLoaded
= FALSE
, StaticEntriesValid
= FALSE
, SkipSnap
= FALSE
;
518 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
519 PIMAGE_THUNK_DATA FirstThunk
;
520 PPEB Peb
= NtCurrentPeb();
522 /* Get the import name's VA */
523 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
525 /* Get the first thunk */
526 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
527 ImportEntry
->FirstThunk
);
529 /* Make sure it's valid */
530 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
532 /* Show debug message */
535 DPRINT1("LDR: %s used by %wZ\n",
537 &LdrEntry
->BaseDllName
);
540 /* Load the module associated to it */
541 Status
= LdrpLoadImportModule(DllPath
,
546 if (!NT_SUCCESS(Status
)) return Status
;
548 /* Show debug message */
551 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
552 &LdrEntry
->BaseDllName
,
556 /* Check if the image was bound when compiled */
557 if (ImportEntry
->OriginalFirstThunk
)
559 /* It was, so check if the static IAT entries are still valid */
560 if ((ImportEntry
->TimeDateStamp
) &&
561 (ImportEntry
->TimeDateStamp
== DllLdrEntry
->TimeDateStamp
) &&
562 (!(DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)))
564 /* Show debug message */
567 DPRINT1("LDR: Snap bypass %s from %wZ\n",
569 &LdrEntry
->BaseDllName
);
573 * They are still valid, so we can skip snapping them.
574 * Additionally, if we have no forwarders, we are totally
577 if (ImportEntry
->ForwarderChain
== -1)
579 /* Totally skip LdrpSnapIAT */
584 /* Set this so LdrpSnapIAT will only do forwarders */
585 StaticEntriesValid
= TRUE
;
590 /* Check if it wasn't already loaded */
593 /* Add the DLL to our list */
594 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
595 &DllLdrEntry
->InInitializationOrderModuleList
);
598 /* Check if we should snap at all */
601 /* Now snap the IAT Entry */
602 Status
= LdrpSnapIAT(DllLdrEntry
,
606 if (!NT_SUCCESS(Status
)) return Status
;
610 return STATUS_SUCCESS
;
615 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
616 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
617 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
621 /* Check for Name and Thunk */
622 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
624 /* Parse this descriptor */
625 Status
= LdrpHandleOneOldFormatImportDescriptor(DllPath
,
628 if (!NT_SUCCESS(Status
)) return Status
;
630 /* Move to the next entry */
635 return STATUS_SUCCESS
;
639 LdrpNameToOrdinal(LPSTR ImportName
,
643 PUSHORT OrdinalTable
)
651 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
652 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
654 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
655 PPEB Peb
= NtCurrentPeb();
656 NTSTATUS Status
= STATUS_SUCCESS
;
657 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
658 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
659 ULONG BoundSize
, IatSize
;
660 DPRINT1("LdrpWalkImportDescriptor('%S' %x)\n", DllPath
, LdrEntry
);
661 /* Set up the Act Ctx */
662 ActCtx
.Size
= sizeof(ActCtx
);
663 ActCtx
.Frame
.Flags
= 1;
664 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
666 /* Check if we have a manifest prober routine */
667 if (LdrpManifestProberRoutine
)
669 DPRINT1("We don't support manifests yet, much less prober routines\n");
672 /* Check if we failed above */
673 if (!NT_SUCCESS(Status
)) return Status
;
675 /* Get the Active ActCtx */
676 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
677 if (!NT_SUCCESS(Status
)) return Status
;
679 /* Activate the ActCtx */
680 RtlActivateActivationContextUnsafeFast(&ActCtx
,
681 LdrEntry
->EntryPointActivationContext
);
683 /* Check if we were directed */
684 if (!(LdrEntry
->Flags
& LDRP_REDIRECTED
))
686 /* Get the Bound IAT */
687 BoundEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
689 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
693 /* Get the regular IAT, for fallback */
694 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
696 IMAGE_DIRECTORY_ENTRY_IMPORT
,
699 /* Check if we got at least one */
700 if (BoundEntry
|| ImportEntry
)
702 /* Do we have a Bound IAT */
705 /* Handle the descriptor */
706 Status
= LdrpHandleNewFormatImportDescriptors(DllPath
,
712 /* Handle the descriptor */
713 Status
= LdrpHandleOldFormatImportDescriptors(DllPath
,
718 /* Check the status of the handlers */
719 if (NT_SUCCESS(Status
))
721 /* Check for Per-DLL Heap Tagging */
722 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAG_BY_DLL
)
725 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
728 /* Check if Page Heap was enabled */
729 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
732 DPRINT1("We don't support Page Heaps yet!\n");
735 /* Check if Application Verifier was enabled */
736 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
739 DPRINT1("We don't support Application Verifier yet!\n");
742 /* Just to be safe */
743 Status
= STATUS_SUCCESS
;
747 /* Release the activation context */
748 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
756 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
759 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
760 OUT PBOOLEAN Existing
)
762 ANSI_STRING AnsiString
;
763 PUNICODE_STRING ImpDescName
;
765 PPEB Peb
= RtlGetCurrentPeb();
766 PTEB Teb
= NtCurrentTeb();
767 DPRINT1("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath
, ImportName
, DllBase
, DataTableEntry
, Existing
);
768 /* Convert import descriptor name to unicode string */
769 ImpDescName
= &Teb
->StaticUnicodeString
;
770 RtlInitAnsiString(&AnsiString
, ImportName
);
771 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
772 if (!NT_SUCCESS(Status
)) return Status
;
774 /* Check if it's loaded */
775 if (LdrpCheckForLoadedDll(DllPath
,
781 /* It's already existing in the list */
783 return STATUS_SUCCESS
;
786 /* We're loading it for the first time */
790 Status
= LdrpMapDll(DllPath
,
798 if (!NT_SUCCESS(Status
)) return Status
;
800 /* Walk its import descriptor table */
801 Status
= LdrpWalkImportDescriptor(DllPath
,
803 if (!NT_SUCCESS(Status
))
805 /* Add it to the in-init-order list in case of failure */
806 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
807 &(*DataTableEntry
)->InInitializationOrderModuleList
);
815 LdrpSnapThunk(IN PVOID ExportBase
,
817 IN PIMAGE_THUNK_DATA OriginalThunk
,
818 IN OUT PIMAGE_THUNK_DATA Thunk
,
819 IN PIMAGE_EXPORT_DIRECTORY ExportEntry
,
826 ULONG OriginalOrdinal
= 0;
827 PIMAGE_IMPORT_BY_NAME AddressOfData
;
829 PUSHORT OrdinalTable
;
830 LPSTR ImportName
= NULL
;
833 ULONG_PTR HardErrorParameters
[3];
834 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
835 ANSI_STRING TempString
;
838 PULONG AddressOfFunctions
;
839 UNICODE_STRING TempUString
;
840 ANSI_STRING ForwarderName
;
841 PANSI_STRING ForwardName
;
842 PVOID ForwarderHandle
;
843 ULONG ForwardOrdinal
;
845 /* Check if the snap is by ordinal */
846 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
848 /* Get the ordinal number, and its normalized version */
849 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
850 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportEntry
->Base
);
854 /* First get the data VA */
855 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
856 ((ULONG_PTR
)ImportBase
+
857 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
860 ImportName
= (LPSTR
)AddressOfData
->Name
;
862 /* Now get the VA of the Name and Ordinal Tables */
863 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
864 (ULONG_PTR
)ExportEntry
->AddressOfNames
);
865 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
866 (ULONG_PTR
)ExportEntry
->AddressOfNameOrdinals
);
869 Hint
= AddressOfData
->Hint
;
871 /* Try to get a match by using the hint */
872 if (((ULONG
)Hint
< ExportEntry
->NumberOfNames
) &&
873 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
875 /* We got a match, get the Ordinal from the hint */
876 Ordinal
= OrdinalTable
[Hint
];
880 /* Well bummer, hint didn't work, do it the long way */
881 Ordinal
= LdrpNameToOrdinal(ImportName
,
882 ExportEntry
->NumberOfNames
,
889 /* Check if the ordinal is invalid */
890 if ((ULONG
)Ordinal
>= ExportEntry
->NumberOfFunctions
)
893 /* Is this a static snap? */
896 /* These are critical errors. Setup a string for the DLL name */
897 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
898 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
900 /* Set it as the parameter */
901 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
904 /* Check if we have an ordinal */
907 /* Then set the ordinal as the 1st parameter */
908 HardErrorParameters
[0] = OriginalOrdinal
;
912 /* We don't, use the entrypoint. Set up a string for it */
913 RtlInitAnsiString(&TempString
, ImportName
);
914 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
918 /* Set it as the parameter */
919 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
923 /* Raise the error */
924 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
925 STATUS_ENTRYPOINT_NOT_FOUND
,
932 /* Increase the error count */
933 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
935 /* Free our string */
936 RtlFreeUnicodeString(&HardErrorDllName
);
939 /* Free our second string. Return entrypoint error */
940 RtlFreeUnicodeString(&HardErrorEntryPointName
);
941 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
944 /* Return ordinal error */
945 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
948 /* Set this as a bad DLL */
949 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
951 /* Return the right error code */
952 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
953 STATUS_ENTRYPOINT_NOT_FOUND
;
957 /* The ordinal seems correct, get the AddressOfFunctions VA */
958 AddressOfFunctions
= (PULONG
)
959 ((ULONG_PTR
)ExportBase
+
960 (ULONG_PTR
)ExportEntry
->AddressOfFunctions
);
962 /* Write the function pointer*/
963 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
965 /* Make sure it's within the exports */
966 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportEntry
) &&
967 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportEntry
+ ExportSize
)))
969 /* Get the Import and Forwarder Names */
970 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
971 ForwarderName
.Buffer
= ImportName
;
972 ForwarderName
.Length
= (USHORT
)(strchr(ImportName
, '.') - ImportName
);
973 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
974 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
978 /* Make sure the conversion was OK */
979 if (NT_SUCCESS(Status
))
981 /* Load the forwarder, free the temp string */
982 Status
= LdrpLoadDll(FALSE
,
988 RtlFreeUnicodeString(&TempUString
);
991 /* If the load or conversion failed, use the failure path */
992 if (!NT_SUCCESS(Status
)) goto FailurePath
;
994 /* Now set up a name for the actual forwarder dll */
995 RtlInitAnsiString(&ForwarderName
,
996 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
998 /* Check if it's an ordinal forward */
999 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
1001 /* We don't have an actual function name */
1004 /* Convert the string into an ordinal */
1005 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
1009 /* If this fails, then error out */
1010 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1014 /* Import by name */
1015 ForwardName
= &ForwarderName
;
1018 /* Get the pointer */
1019 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1022 (PVOID
*)&Thunk
->u1
.Function
,
1024 /* If this fails, then error out */
1025 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1029 /* It's not within the exports, let's hope it's valid */
1030 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1033 /* If we got here, then it's success */
1034 Status
= STATUS_SUCCESS
;