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 Thunk
, OriginalThunk
, FirstThunk
;
50 PIMAGE_NT_HEADERS NtHeader
;
51 PIMAGE_SECTION_HEADER SectionHeader
;
55 /* Get export directory */
56 ExportDirectory
= RtlImageDirectoryEntryToData(ExportLdrEntry
->DllBase
,
58 IMAGE_DIRECTORY_ENTRY_EXPORT
,
61 /* Make sure it has one */
62 if (!ExportDirectory
) return STATUS_INVALID_IMAGE_FORMAT
;
65 Iat
= RtlImageDirectoryEntryToData(ImportLdrEntry
->DllBase
,
67 IMAGE_DIRECTORY_ENTRY_IAT
,
71 /* Check if we don't have one */
74 /* Get the NT Header and the first section */
75 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
76 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
78 /* Get the RVA of the import directory */
79 Rva
= NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
81 /* Make sure we got one */
84 /* Loop all the sections */
85 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
87 /* Check if we are inside this section */
88 if ((Rva
>= SectionHeader
->VirtualAddress
) &&
89 (Rva
< (SectionHeader
->VirtualAddress
+
90 SectionHeader
->SizeOfRawData
)))
92 /* We are, so set the IAT here */
93 Iat
= (PVOID
)((ULONG_PTR
)(ImportLdrEntry
->DllBase
) +
94 SectionHeader
->VirtualAddress
);
97 IatSize
= SectionHeader
->Misc
.VirtualSize
;
99 /* Deal with Watcom and other retarded compilers */
102 IatSize
= SectionHeader
->SizeOfRawData
;
105 /* Found it, get out */
109 /* No match, move to the next section */
114 /* If we still don't have an IAT, that's bad */
115 if (!Iat
) return STATUS_INVALID_IMAGE_FORMAT
;
117 /* Set the right size */
118 ImportSize
= IatSize
;
121 /* Unprotect the IAT */
122 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
127 if (!NT_SUCCESS(Status
)) return Status
;
129 /* Check if the Thunks are already valid */
132 /* We'll only do forwarders. Get the import name */
133 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+ IatEntry
->Name
);
135 /* Get the list of forwaders */
136 ForwarderChain
= IatEntry
->ForwarderChain
;
139 while (ForwarderChain
!= -1)
141 /* Get the cached thunk VA*/
142 OriginalThunk
= (PIMAGE_THUNK_DATA
)
143 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
144 IatEntry
->OriginalFirstThunk
+
145 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
147 /* Get the first thunk */
148 FirstThunk
= (PIMAGE_THUNK_DATA
)
149 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
150 IatEntry
->FirstThunk
+
151 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
153 /* Get the Forwarder from the thunk */
154 ForwarderChain
= (ULONG
)FirstThunk
->u1
.Ordinal
;
157 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
158 ImportLdrEntry
->DllBase
,
166 /* Move to the next thunk */
169 /* If we messed up, exit */
170 if (!NT_SUCCESS(Status
)) break;
173 else if (IatEntry
->FirstThunk
)
175 /* Full snapping. Get the First thunk */
176 FirstThunk
= (PIMAGE_THUNK_DATA
)
177 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
178 IatEntry
->FirstThunk
);
180 /* Get the NT Header */
181 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
183 /* Get the Original thunk VA, watch out for weird images */
184 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
185 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
187 /* Reuse it, this is a strange linked file */
188 OriginalThunk
= FirstThunk
;
192 /* Get the address from the field and convert to VA */
193 OriginalThunk
= (PIMAGE_THUNK_DATA
)
194 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
195 IatEntry
->OriginalFirstThunk
);
198 /* Get the Import name VA */
199 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
202 /* Loop while it's valid */
203 while (OriginalThunk
->u1
.AddressOfData
)
206 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
207 ImportLdrEntry
->DllBase
,
219 /* If we failed the snap, break out */
220 if (!NT_SUCCESS(Status
)) break;
224 /* Protect the IAT again */
225 NtProtectVirtualMemory(NtCurrentProcess(),
231 /* Also flush out the cache */
232 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
234 /* Return to Caller */
240 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
241 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
242 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
,
243 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
245 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
247 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
248 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
249 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
250 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
251 PPEB Peb
= NtCurrentPeb();
254 /* Get the name's VA */
255 BoundImportName
= (LPSTR
)(BoundEntry
+ BoundEntry
->OffsetModuleName
);
257 /* Show debug mesage */
260 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
263 /* Load the module for this entry */
264 Status
= LdrpLoadImportModule(DllPath
,
269 if (!NT_SUCCESS(Status
))
271 /* Show debug message */
274 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
275 &LdrEntry
->BaseDllName
,
282 /* Check if it wasn't already loaded */
285 /* Add it to our list */
286 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
287 &DllLdrEntry
->InInitializationOrderModuleList
);
290 /* Check if the Bound Entry is now invalid */
291 if ((BoundEntry
->TimeDateStamp
!= DllLdrEntry
->TimeDateStamp
) ||
292 (DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
294 /* Show debug message */
297 DPRINT1("LDR: %wZ has stale binding to %s\n",
298 &DllLdrEntry
->BaseDllName
,
302 /* Remember it's become stale */
307 /* Show debug message */
310 DPRINT1("LDR: %wZ has correct binding to %s\n",
311 &DllLdrEntry
->BaseDllName
,
315 /* Remember it's valid */
319 /* Get the forwarders */
320 ForwarderEntry
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
323 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
326 ForwarderName
= (LPSTR
)(FirstEntry
+ ForwarderEntry
->OffsetModuleName
);
328 /* Show debug message */
331 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
332 &LdrEntry
->BaseDllName
,
334 &DllLdrEntry
->BaseDllName
);
337 /* Load the module */
338 Status
= LdrpLoadImportModule(DllPath
,
343 if (NT_SUCCESS(Status
))
345 /* Loaded it, was it already loaded? */
348 /* Add it to our list */
349 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
350 &ForwarderLdrEntry
->InInitializationOrderModuleList
);
354 /* Check if the Bound Entry is now invalid */
355 if (!(NT_SUCCESS(Status
)) ||
356 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
357 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
359 /* Show debug message */
362 DPRINT1("LDR: %wZ has stale binding to %s\n",
363 &ForwarderLdrEntry
->BaseDllName
,
367 /* Remember it's become stale */
372 /* Show debug message */
375 DPRINT1("LDR: %wZ has correct binding to %s\n",
376 &ForwarderLdrEntry
->BaseDllName
,
380 /* Remember it's valid */
384 /* Move to the next one */
388 /* Set the next bound entry to the forwarder */
389 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
391 /* Check if the binding was stale */
394 /* It was, so find the IAT entry for it */
395 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
397 IMAGE_DIRECTORY_ENTRY_IMPORT
,
400 /* Make sure it has a name */
401 while (ImportEntry
->Name
)
404 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
407 if (!_stricmp(ImportName
, BoundImportName
)) break;
409 /* Move to next entry */
413 /* If we didn't find a name, fail */
414 if (!ImportEntry
->Name
)
416 /* Show debug message */
419 DPRINT1("LDR: LdrpWalkImportTable - failing with"
420 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
424 Status
= STATUS_OBJECT_NAME_INVALID
;
428 /* Show debug message */
431 DPRINT1("LDR: Stale Bind %s from %wZ\n",
433 &LdrEntry
->BaseDllName
);
436 /* Snap the IAT Entry*/
437 Status
= LdrpSnapIAT(DllLdrEntry
,
442 /* Make sure we didn't fail */
443 if (!NT_SUCCESS(Status
))
445 /* Show debug message */
448 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
449 &LdrEntry
->BaseDllName
,
460 Status
= STATUS_SUCCESS
;
463 /* Write where we are now and return */
464 *BoundEntry
= *FirstEntry
;
470 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
471 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
472 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
474 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
477 /* Make sure we have a name */
478 while (BoundEntry
->OffsetModuleName
)
480 /* Parse this descriptor */
481 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
485 if (!NT_SUCCESS(Status
)) return Status
;
489 return STATUS_SUCCESS
;
494 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
495 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
496 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
501 BOOLEAN AlreadyLoaded
= FALSE
, StaticEntriesValid
= FALSE
, SkipSnap
= TRUE
;
502 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
503 PIMAGE_THUNK_DATA FirstThunk
;
504 PPEB Peb
= NtCurrentPeb();
506 /* Get the import name's VA */
507 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
509 /* Get the first thunk */
510 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
511 ImportEntry
->FirstThunk
);
513 /* Make sure it's valid */
514 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
516 /* Show debug message */
519 DPRINT1("LDR: %s used by %wZ\n",
521 &LdrEntry
->BaseDllName
);
524 /* Load the module associated to it */
525 Status
= LdrpLoadImportModule(DllPath
,
530 if (!NT_SUCCESS(Status
)) return Status
;
532 /* Show debug message */
535 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
536 &LdrEntry
->BaseDllName
,
540 /* Check if the image was bound when compiled */
541 if (ImportEntry
->OriginalFirstThunk
)
543 /* It was, so check if the static IAT entries are still valid */
544 if ((ImportEntry
->TimeDateStamp
) &&
545 (ImportEntry
->TimeDateStamp
== DllLdrEntry
->TimeDateStamp
) &&
546 (!(DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)))
548 /* Show debug message */
551 DPRINT1("LDR: Snap bypass %s from %wZ\n",
553 &LdrEntry
->BaseDllName
);
557 * They are still valid, so we can skip snapping them.
558 * Additionally, if we have no forwarders, we are totally
561 if (ImportEntry
->ForwarderChain
== -1)
563 /* Totally skip LdrpSnapIAT */
568 /* Set this so LdrpSnapIAT will only do forwarders */
569 StaticEntriesValid
= TRUE
;
574 /* Check if it wasn't already loaded */
577 /* Add the DLL to our list */
578 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
579 &DllLdrEntry
->InInitializationOrderModuleList
);
582 /* Check if we should snap at all */
585 /* Now snap the IAT Entry */
586 Status
= LdrpSnapIAT(DllLdrEntry
,
590 if (!NT_SUCCESS(Status
)) return Status
;
594 return STATUS_SUCCESS
;
599 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
600 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
601 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
605 /* Check for Name and Thunk */
606 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
608 /* Parse this descriptor */
609 Status
= LdrpHandleOneOldFormatImportDescriptor(DllPath
,
612 if (!NT_SUCCESS(Status
)) return Status
;
614 /* Move to the next entry */
619 return STATUS_SUCCESS
;
623 LdrpNameToOrdinal(LPSTR ImportName
,
627 PUSHORT OrdinalTable
)
635 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
636 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
638 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
639 PPEB Peb
= NtCurrentPeb();
640 NTSTATUS Status
= STATUS_SUCCESS
;
641 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
642 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
643 ULONG BoundSize
, IatSize
;
644 DPRINT1("LdrpWalkImportDescriptor('%S' %x)\n", DllPath
, LdrEntry
);
645 /* Set up the Act Ctx */
646 ActCtx
.Size
= sizeof(ActCtx
);
647 ActCtx
.Frame
.Flags
= ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID
;
648 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
650 /* Check if we have a manifest prober routine */
651 if (LdrpManifestProberRoutine
)
653 DPRINT1("We don't support manifests yet, much less prober routines\n");
656 /* Check if we failed above */
657 if (!NT_SUCCESS(Status
)) return Status
;
659 /* Get the Active ActCtx */
660 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
661 if (!NT_SUCCESS(Status
)) return Status
;
663 /* Activate the ActCtx */
664 RtlActivateActivationContextUnsafeFast(&ActCtx
,
665 LdrEntry
->EntryPointActivationContext
);
667 /* Check if we were directed */
668 if (!(LdrEntry
->Flags
& LDRP_REDIRECTED
))
670 /* Get the Bound IAT */
671 BoundEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
673 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
677 /* Get the regular IAT, for fallback */
678 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
680 IMAGE_DIRECTORY_ENTRY_IMPORT
,
683 /* Check if we got at least one */
684 if (BoundEntry
|| ImportEntry
)
686 /* Do we have a Bound IAT */
689 /* Handle the descriptor */
690 Status
= LdrpHandleNewFormatImportDescriptors(DllPath
,
696 /* Handle the descriptor */
697 Status
= LdrpHandleOldFormatImportDescriptors(DllPath
,
702 /* Check the status of the handlers */
703 if (NT_SUCCESS(Status
))
705 /* Check for Per-DLL Heap Tagging */
706 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAG_BY_DLL
)
709 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
712 /* Check if Page Heap was enabled */
713 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
716 DPRINT1("We don't support Page Heaps yet!\n");
719 /* Check if Application Verifier was enabled */
720 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
723 DPRINT1("We don't support Application Verifier yet!\n");
726 /* Just to be safe */
727 Status
= STATUS_SUCCESS
;
731 /* Release the activation context */
732 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
740 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
743 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
744 OUT PBOOLEAN Existing
)
746 ANSI_STRING AnsiString
;
747 PUNICODE_STRING ImpDescName
;
749 PPEB Peb
= RtlGetCurrentPeb();
750 PTEB Teb
= NtCurrentTeb();
751 DPRINT1("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath
, ImportName
, DllBase
, DataTableEntry
, Existing
);
752 /* Convert import descriptor name to unicode string */
753 ImpDescName
= &Teb
->StaticUnicodeString
;
754 RtlInitAnsiString(&AnsiString
, ImportName
);
755 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
756 if (!NT_SUCCESS(Status
)) return Status
;
758 /* Check if it's loaded */
759 if (LdrpCheckForLoadedDll(DllPath
,
765 /* It's already existing in the list */
767 return STATUS_SUCCESS
;
770 /* We're loading it for the first time */
774 Status
= LdrpMapDll(DllPath
,
782 if (!NT_SUCCESS(Status
)) return Status
;
784 /* Walk its import descriptor table */
785 Status
= LdrpWalkImportDescriptor(DllPath
,
787 if (!NT_SUCCESS(Status
))
789 /* Add it to the in-init-order list in case of failure */
790 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
791 &(*DataTableEntry
)->InInitializationOrderModuleList
);
799 LdrpSnapThunk(IN PVOID ExportBase
,
801 IN PIMAGE_THUNK_DATA OriginalThunk
,
802 IN OUT PIMAGE_THUNK_DATA Thunk
,
803 IN PIMAGE_EXPORT_DIRECTORY ExportEntry
,
810 ULONG OriginalOrdinal
= 0;
811 PIMAGE_IMPORT_BY_NAME AddressOfData
;
813 PUSHORT OrdinalTable
;
814 LPSTR ImportName
= NULL
;
817 ULONG_PTR HardErrorParameters
[3];
818 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
819 ANSI_STRING TempString
;
822 PULONG AddressOfFunctions
;
823 UNICODE_STRING TempUString
;
824 ANSI_STRING ForwarderName
;
825 PANSI_STRING ForwardName
;
826 PVOID ForwarderHandle
;
827 ULONG ForwardOrdinal
;
829 /* Check if the snap is by ordinal */
830 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
832 /* Get the ordinal number, and its normalized version */
833 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
834 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportEntry
->Base
);
838 /* First get the data VA */
839 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
840 ((ULONG_PTR
)ImportBase
+
841 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
844 ImportName
= (LPSTR
)AddressOfData
->Name
;
846 /* Now get the VA of the Name and Ordinal Tables */
847 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
848 (ULONG_PTR
)ExportEntry
->AddressOfNames
);
849 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
850 (ULONG_PTR
)ExportEntry
->AddressOfNameOrdinals
);
853 Hint
= AddressOfData
->Hint
;
855 /* Try to get a match by using the hint */
856 if (((ULONG
)Hint
< ExportEntry
->NumberOfNames
) &&
857 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
859 /* We got a match, get the Ordinal from the hint */
860 Ordinal
= OrdinalTable
[Hint
];
864 /* Well bummer, hint didn't work, do it the long way */
865 Ordinal
= LdrpNameToOrdinal(ImportName
,
866 ExportEntry
->NumberOfNames
,
873 /* Check if the ordinal is invalid */
874 if ((ULONG
)Ordinal
>= ExportEntry
->NumberOfFunctions
)
877 /* Is this a static snap? */
880 /* These are critical errors. Setup a string for the DLL name */
881 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
882 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
884 /* Set it as the parameter */
885 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
888 /* Check if we have an ordinal */
891 /* Then set the ordinal as the 1st parameter */
892 HardErrorParameters
[0] = OriginalOrdinal
;
896 /* We don't, use the entrypoint. Set up a string for it */
897 RtlInitAnsiString(&TempString
, ImportName
);
898 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
902 /* Set it as the parameter */
903 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
907 /* Raise the error */
908 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
909 STATUS_ENTRYPOINT_NOT_FOUND
,
916 /* Increase the error count */
917 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
919 /* Free our string */
920 RtlFreeUnicodeString(&HardErrorDllName
);
923 /* Free our second string. Return entrypoint error */
924 RtlFreeUnicodeString(&HardErrorEntryPointName
);
925 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
928 /* Return ordinal error */
929 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
932 /* Set this as a bad DLL */
933 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
935 /* Return the right error code */
936 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
937 STATUS_ENTRYPOINT_NOT_FOUND
;
941 /* The ordinal seems correct, get the AddressOfFunctions VA */
942 AddressOfFunctions
= (PULONG
)
943 ((ULONG_PTR
)ExportBase
+
944 (ULONG_PTR
)ExportEntry
->AddressOfFunctions
);
946 /* Write the function pointer*/
947 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
949 /* Make sure it's within the exports */
950 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportEntry
) &&
951 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportEntry
+ ExportSize
)))
953 /* Get the Import and Forwarder Names */
954 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
955 ForwarderName
.Buffer
= ImportName
;
956 ForwarderName
.Length
= (USHORT
)(strchr(ImportName
, '.') - ImportName
);
957 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
958 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
962 /* Make sure the conversion was OK */
963 if (NT_SUCCESS(Status
))
965 /* Load the forwarder, free the temp string */
966 Status
= LdrpLoadDll(FALSE
,
972 RtlFreeUnicodeString(&TempUString
);
975 /* If the load or conversion failed, use the failure path */
976 if (!NT_SUCCESS(Status
)) goto FailurePath
;
978 /* Now set up a name for the actual forwarder dll */
979 RtlInitAnsiString(&ForwarderName
,
980 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
982 /* Check if it's an ordinal forward */
983 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
985 /* We don't have an actual function name */
988 /* Convert the string into an ordinal */
989 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
993 /* If this fails, then error out */
994 if (!NT_SUCCESS(Status
)) goto FailurePath
;
999 ForwardName
= &ForwarderName
;
1002 /* Get the pointer */
1003 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1006 (PVOID
*)&Thunk
->u1
.Function
,
1008 /* If this fails, then error out */
1009 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1013 /* It's not within the exports, let's hope it's valid */
1014 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1017 /* If we got here, then it's success */
1018 Status
= STATUS_SUCCESS
;