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 *******************************************************************/
17 PVOID LdrpManifestProberRoutine
;
20 /* FUNCTIONS *****************************************************************/
24 AVrfPageHeapDllNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
26 /* Check if page heap dll notification is turned on */
27 if (!(RtlpDphGlobalFlags
&& DPH_FLAG_DLL_NOTIFY
))
30 /* We don't support this flag currently */
36 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry
,
37 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry
,
38 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry
,
39 IN BOOLEAN EntriesValid
)
43 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
44 PIMAGE_NT_HEADERS NtHeader
;
45 PIMAGE_SECTION_HEADER SectionHeader
;
46 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
48 ULONG ForwarderChain
, i
, Rva
, OldProtect
, IatSize
, ExportSize
;
50 DPRINT("LdrpSnapIAT(%wZ %wZ %p %d)\n", &ExportLdrEntry
->BaseDllName
, &ImportLdrEntry
->BaseDllName
, IatEntry
, EntriesValid
);
52 /* Get export directory */
53 ExportDirectory
= RtlImageDirectoryEntryToData(ExportLdrEntry
->DllBase
,
55 IMAGE_DIRECTORY_ENTRY_EXPORT
,
58 /* Make sure it has one */
62 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
63 &ExportLdrEntry
->BaseDllName
);
64 return STATUS_INVALID_IMAGE_FORMAT
;
68 Iat
= RtlImageDirectoryEntryToData(ImportLdrEntry
->DllBase
,
70 IMAGE_DIRECTORY_ENTRY_IAT
,
74 /* Check if we don't have one */
77 /* Get the NT Header and the first section */
78 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
79 if (!NtHeader
) return STATUS_INVALID_IMAGE_FORMAT
;
80 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
82 /* Get the RVA of the import directory */
83 Rva
= NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
85 /* Make sure we got one */
88 /* Loop all the sections */
89 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
91 /* Check if we are inside this section */
92 if ((Rva
>= SectionHeader
->VirtualAddress
) &&
93 (Rva
< (SectionHeader
->VirtualAddress
+
94 SectionHeader
->SizeOfRawData
)))
96 /* We are, so set the IAT here */
97 Iat
= (PVOID
)((ULONG_PTR
)(ImportLdrEntry
->DllBase
) +
98 SectionHeader
->VirtualAddress
);
101 IatSize
= SectionHeader
->Misc
.VirtualSize
;
103 /* Deal with Watcom and other retarded compilers */
104 if (!IatSize
) IatSize
= SectionHeader
->SizeOfRawData
;
106 /* Found it, get out */
110 /* No match, move to the next section */
115 /* If we still don't have an IAT, that's bad */
119 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
120 &ImportLdrEntry
->BaseDllName
,
121 ImportLdrEntry
->DllBase
);
122 return STATUS_INVALID_IMAGE_FORMAT
;
125 /* Set the right size */
126 ImportSize
= IatSize
;
129 /* Unprotect the IAT */
130 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
135 if (!NT_SUCCESS(Status
))
138 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
139 &ImportLdrEntry
->BaseDllName
,
144 /* Check if the Thunks are already valid */
147 /* We'll only do forwarders. Get the import name */
148 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+ IatEntry
->Name
);
150 /* Get the list of forwaders */
151 ForwarderChain
= IatEntry
->ForwarderChain
;
154 while (ForwarderChain
!= -1)
156 /* Get the cached thunk VA*/
157 OriginalThunk
= (PIMAGE_THUNK_DATA
)
158 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
159 IatEntry
->OriginalFirstThunk
+
160 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
162 /* Get the first thunk */
163 FirstThunk
= (PIMAGE_THUNK_DATA
)
164 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
165 IatEntry
->FirstThunk
+
166 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
168 /* Get the Forwarder from the thunk */
169 ForwarderChain
= (ULONG
)FirstThunk
->u1
.Ordinal
;
174 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
175 ImportLdrEntry
->DllBase
,
183 /* Move to the next thunk */
185 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
187 /* Fail with the SEH error */
188 Status
= _SEH2_GetExceptionCode();
191 /* If we messed up, exit */
192 if (!NT_SUCCESS(Status
)) break;
195 else if (IatEntry
->FirstThunk
)
197 /* Full snapping. Get the First thunk */
198 FirstThunk
= (PIMAGE_THUNK_DATA
)
199 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
200 IatEntry
->FirstThunk
);
202 /* Get the NT Header */
203 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
205 /* Get the Original thunk VA, watch out for weird images */
206 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
207 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
209 /* Refuse it, this is a strange linked file */
210 OriginalThunk
= FirstThunk
;
214 /* Get the address from the field and convert to VA */
215 OriginalThunk
= (PIMAGE_THUNK_DATA
)
216 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
217 IatEntry
->OriginalFirstThunk
);
220 /* Get the Import name VA */
221 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
224 /* Loop while it's valid */
225 while (OriginalThunk
->u1
.AddressOfData
)
230 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
231 ImportLdrEntry
->DllBase
,
242 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
244 /* Fail with the SEH error */
245 Status
= _SEH2_GetExceptionCode();
248 /* If we failed the snap, break out */
249 if (!NT_SUCCESS(Status
)) break;
253 /* Protect the IAT again */
254 NtProtectVirtualMemory(NtCurrentProcess(),
260 /* Also flush out the cache */
261 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
263 /* Return to Caller */
269 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
270 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
271 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR
*BoundEntryPtr
,
272 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
274 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
276 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
277 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
278 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
279 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
280 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
281 PPEB Peb
= NtCurrentPeb();
284 /* Get the pointer to the bound entry */
285 BoundEntry
= *BoundEntryPtr
;
287 /* Get the name's VA */
288 BoundImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
290 /* Show debug mesage */
293 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
296 /* Load the module for this entry */
297 Status
= LdrpLoadImportModule(DllPath
,
302 if (!NT_SUCCESS(Status
))
304 /* Show debug message */
307 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
308 &LdrEntry
->BaseDllName
,
315 /* Check if it wasn't already loaded */
318 /* Add it to our list */
319 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
320 &DllLdrEntry
->InInitializationOrderModuleList
);
323 /* Check if the Bound Entry is now invalid */
324 if ((BoundEntry
->TimeDateStamp
!= DllLdrEntry
->TimeDateStamp
) ||
325 (DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
327 /* Show debug message */
330 DPRINT1("LDR: %wZ has stale binding to %s\n",
331 &LdrEntry
->BaseDllName
,
335 /* Remember it's become stale */
340 /* Show debug message */
343 DPRINT1("LDR: %wZ has correct binding to %s\n",
344 &LdrEntry
->BaseDllName
,
348 /* Remember it's valid */
352 /* Get the forwarders */
353 ForwarderEntry
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
356 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
359 ForwarderName
= (LPSTR
)FirstEntry
+ ForwarderEntry
->OffsetModuleName
;
361 /* Show debug message */
364 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
365 &LdrEntry
->BaseDllName
,
367 &DllLdrEntry
->BaseDllName
);
370 /* Load the module */
371 Status
= LdrpLoadImportModule(DllPath
,
376 if (NT_SUCCESS(Status
))
378 /* Loaded it, was it already loaded? */
381 /* Add it to our list */
382 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
383 &ForwarderLdrEntry
->InInitializationOrderModuleList
);
387 /* Check if the Bound Entry is now invalid */
388 if (!(NT_SUCCESS(Status
)) ||
389 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
390 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
392 /* Show debug message */
395 DPRINT1("LDR: %wZ has stale binding to %s\n",
396 &LdrEntry
->BaseDllName
,
400 /* Remember it's become stale */
405 /* Show debug message */
408 DPRINT1("LDR: %wZ has correct binding to %s\n",
409 &LdrEntry
->BaseDllName
,
413 /* Remember it's valid */
417 /* Move to the next one */
421 /* Set the next bound entry to the forwarder */
422 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
424 /* Check if the binding was stale */
427 /* It was, so find the IAT entry for it */
429 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
431 IMAGE_DIRECTORY_ENTRY_IMPORT
,
434 /* Make sure it has a name */
435 while (ImportEntry
->Name
)
438 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
441 if (!_stricmp(ImportName
, BoundImportName
)) break;
443 /* Move to next entry */
447 /* If we didn't find a name, fail */
448 if (!ImportEntry
->Name
)
450 /* Show debug message */
453 DPRINT1("LDR: LdrpWalkImportTable - failing with"
454 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
458 Status
= STATUS_OBJECT_NAME_INVALID
;
462 /* Show debug message */
465 DPRINT1("LDR: Stale Bind %s from %wZ\n",
467 &LdrEntry
->BaseDllName
);
470 /* Snap the IAT Entry*/
471 Status
= LdrpSnapIAT(DllLdrEntry
,
476 /* Make sure we didn't fail */
477 if (!NT_SUCCESS(Status
))
479 /* Show debug message */
482 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
483 &LdrEntry
->BaseDllName
,
494 Status
= STATUS_SUCCESS
;
497 /* Write where we are now and return */
498 *BoundEntryPtr
= FirstEntry
;
504 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
505 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
506 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
508 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
511 /* Make sure we have a name */
512 while (BoundEntry
->OffsetModuleName
)
514 /* Parse this descriptor */
515 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
519 if (!NT_SUCCESS(Status
)) return Status
;
523 return STATUS_SUCCESS
;
528 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
529 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
530 IN PIMAGE_IMPORT_DESCRIPTOR
*ImportEntry
)
534 BOOLEAN AlreadyLoaded
= FALSE
;
535 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
536 PIMAGE_THUNK_DATA FirstThunk
;
537 PPEB Peb
= NtCurrentPeb();
539 /* Get the import name's VA */
540 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ (*ImportEntry
)->Name
);
542 /* Get the first thunk */
543 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
544 (*ImportEntry
)->FirstThunk
);
546 /* Make sure it's valid */
547 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
549 /* Show debug message */
552 DPRINT1("LDR: %s used by %wZ\n",
554 &LdrEntry
->BaseDllName
);
557 /* Load the module associated to it */
558 Status
= LdrpLoadImportModule(DllPath
,
563 if (!NT_SUCCESS(Status
))
568 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
569 "on import %s with status %x\n",
578 /* Show debug message */
581 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
582 &LdrEntry
->BaseDllName
,
586 /* Check if it wasn't already loaded */
590 /* Add the DLL to our list */
591 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
592 &DllLdrEntry
->InInitializationOrderModuleList
);
595 /* Now snap the IAT Entry */
596 Status
= LdrpSnapIAT(DllLdrEntry
, LdrEntry
, *ImportEntry
, FALSE
);
597 if (!NT_SUCCESS(Status
))
602 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
614 return STATUS_SUCCESS
;
619 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
620 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
621 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
625 /* Check for Name and Thunk */
626 while ((ImportEntry
->Name
) && (ImportEntry
->FirstThunk
))
628 /* Parse this descriptor */
629 Status
= LdrpHandleOneOldFormatImportDescriptor(DllPath
,
632 if (!NT_SUCCESS(Status
)) return Status
;
636 return STATUS_SUCCESS
;
641 LdrpNameToOrdinal(IN LPSTR ImportName
,
642 IN ULONG NumberOfNames
,
645 IN PUSHORT OrdinalTable
)
647 LONG Start
, End
, Next
, CmpResult
;
649 /* Use classical binary search to find the ordinal */
651 End
= NumberOfNames
- 1;
654 /* Next will be exactly between Start and End */
655 Next
= (Start
+ End
) >> 1;
657 /* Compare this name with the one we need to find */
658 CmpResult
= strcmp(ImportName
, (PCHAR
)((ULONG_PTR
)ExportBase
+ NameTable
[Next
]));
660 /* We found our entry if result is 0 */
661 if (!CmpResult
) break;
663 /* We didn't find, update our range then */
668 else if (CmpResult
> 0)
674 /* If end is before start, then the search failed */
675 if (End
< Start
) return -1;
677 /* Return found name */
678 return OrdinalTable
[Next
];
683 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
684 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
686 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
687 PPEB Peb
= NtCurrentPeb();
688 NTSTATUS Status
= STATUS_SUCCESS
;
689 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
690 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
691 ULONG BoundSize
, IatSize
;
692 DPRINT("LdrpWalkImportDescriptor('%S' %x)\n", DllPath
, LdrEntry
);
694 /* Set up the Act Ctx */
695 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
696 ActCtx
.Size
= sizeof(ActCtx
);
697 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
699 /* Check if we have a manifest prober routine */
700 if (LdrpManifestProberRoutine
)
702 DPRINT1("We don't support manifests yet, much less prober routines\n");
705 /* Check if we failed above */
706 if (!NT_SUCCESS(Status
)) return Status
;
708 /* Get the Active ActCtx */
709 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
710 if (!NT_SUCCESS(Status
))
713 DbgPrintEx(51, // DPFLTR_SXS_ID
714 DPFLTR_WARNING_LEVEL
,
715 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
721 /* Activate the ActCtx */
722 RtlActivateActivationContextUnsafeFast(&ActCtx
,
723 LdrEntry
->EntryPointActivationContext
);
725 /* Check if we were redirected */
726 if (!(LdrEntry
->Flags
& LDRP_REDIRECTED
))
728 /* Get the Bound IAT */
729 BoundEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
731 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
735 /* Get the regular IAT, for fallback */
736 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
738 IMAGE_DIRECTORY_ENTRY_IMPORT
,
741 /* Check if we got at least one */
742 if ((BoundEntry
) || (ImportEntry
))
744 /* Do we have a Bound IAT */
747 /* Handle the descriptor */
748 Status
= LdrpHandleNewFormatImportDescriptors(DllPath
,
754 /* Handle the descriptor */
755 Status
= LdrpHandleOldFormatImportDescriptors(DllPath
,
760 /* Check the status of the handlers */
761 if (NT_SUCCESS(Status
))
763 /* Check for Per-DLL Heap Tagging */
764 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAG_BY_DLL
)
767 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
770 /* Check if Page Heap was enabled */
771 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
773 /* Initialize target DLL */
774 AVrfPageHeapDllNotification(LdrEntry
);
777 /* Check if Application Verifier was enabled */
778 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
781 DPRINT1("We don't support Application Verifier yet!\n");
784 /* Just to be safe */
785 Status
= STATUS_SUCCESS
;
789 /* Release the activation context */
790 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
796 /* FIXME: This function is missing SxS support and has wrong prototype */
799 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
802 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
803 OUT PBOOLEAN Existing
)
805 ANSI_STRING AnsiString
;
806 PUNICODE_STRING ImpDescName
;
808 PPEB Peb
= RtlGetCurrentPeb();
809 PTEB Teb
= NtCurrentTeb();
811 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath
, ImportName
, DllBase
, DataTableEntry
, Existing
);
813 /* Convert import descriptor name to unicode string */
814 ImpDescName
= &Teb
->StaticUnicodeString
;
815 RtlInitAnsiString(&AnsiString
, ImportName
);
816 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
817 if (!NT_SUCCESS(Status
)) return Status
;
819 /* Check if it's loaded */
820 if (LdrpCheckForLoadedDll(DllPath
,
826 /* It's already existing in the list */
828 return STATUS_SUCCESS
;
831 /* We're loading it for the first time */
835 Status
= LdrpMapDll(DllPath
,
843 if (!NT_SUCCESS(Status
)) return Status
;
845 /* Walk its import descriptor table */
846 Status
= LdrpWalkImportDescriptor(DllPath
,
848 if (!NT_SUCCESS(Status
))
850 /* Add it to the in-init-order list in case of failure */
851 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
852 &(*DataTableEntry
)->InInitializationOrderModuleList
);
860 LdrpSnapThunk(IN PVOID ExportBase
,
862 IN PIMAGE_THUNK_DATA OriginalThunk
,
863 IN OUT PIMAGE_THUNK_DATA Thunk
,
864 IN PIMAGE_EXPORT_DIRECTORY ExportEntry
,
871 ULONG OriginalOrdinal
= 0;
872 PIMAGE_IMPORT_BY_NAME AddressOfData
;
874 PUSHORT OrdinalTable
;
875 LPSTR ImportName
= NULL
;
878 ULONG_PTR HardErrorParameters
[3];
879 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
880 ANSI_STRING TempString
;
883 PULONG AddressOfFunctions
;
884 UNICODE_STRING TempUString
;
885 ANSI_STRING ForwarderName
;
886 PANSI_STRING ForwardName
;
887 PVOID ForwarderHandle
;
888 ULONG ForwardOrdinal
;
890 /* Check if the snap is by ordinal */
891 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
893 /* Get the ordinal number, and its normalized version */
894 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
895 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportEntry
->Base
);
899 /* First get the data VA */
900 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
901 ((ULONG_PTR
)ImportBase
+
902 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
905 ImportName
= (LPSTR
)AddressOfData
->Name
;
907 /* Now get the VA of the Name and Ordinal Tables */
908 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
909 (ULONG_PTR
)ExportEntry
->AddressOfNames
);
910 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
911 (ULONG_PTR
)ExportEntry
->AddressOfNameOrdinals
);
914 Hint
= AddressOfData
->Hint
;
916 /* Try to get a match by using the hint */
917 if (((ULONG
)Hint
< ExportEntry
->NumberOfNames
) &&
918 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
920 /* We got a match, get the Ordinal from the hint */
921 Ordinal
= OrdinalTable
[Hint
];
925 /* Well bummer, hint didn't work, do it the long way */
926 Ordinal
= LdrpNameToOrdinal(ImportName
,
927 ExportEntry
->NumberOfNames
,
934 /* Check if the ordinal is invalid */
935 if ((ULONG
)Ordinal
>= ExportEntry
->NumberOfFunctions
)
938 /* Is this a static snap? */
941 /* Inform the debug log */
943 DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
945 DPRINT1("Failed to snap %s\n", ImportName
);
947 /* These are critical errors. Setup a string for the DLL name */
948 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
949 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
951 /* Set it as the parameter */
952 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
955 /* Check if we have an ordinal */
958 /* Then set the ordinal as the 1st parameter */
959 HardErrorParameters
[0] = OriginalOrdinal
;
963 /* We don't, use the entrypoint. Set up a string for it */
964 RtlInitAnsiString(&TempString
, ImportName
);
965 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
969 /* Set it as the parameter */
970 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
974 /* Raise the error */
975 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
976 STATUS_ENTRYPOINT_NOT_FOUND
,
983 /* Increase the error count */
984 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
986 /* Free our string */
987 RtlFreeUnicodeString(&HardErrorDllName
);
990 /* Free our second string. Return entrypoint error */
991 RtlFreeUnicodeString(&HardErrorEntryPointName
);
992 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
995 /* Return ordinal error */
996 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
1000 /* Inform the debug log */
1002 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
1004 DPRINT("Non-fatal: Failed to snap %s\n", ImportName
);
1007 /* Set this as a bad DLL */
1008 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
1010 /* Return the right error code */
1011 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1012 STATUS_ENTRYPOINT_NOT_FOUND
;
1016 /* The ordinal seems correct, get the AddressOfFunctions VA */
1017 AddressOfFunctions
= (PULONG
)
1018 ((ULONG_PTR
)ExportBase
+
1019 (ULONG_PTR
)ExportEntry
->AddressOfFunctions
);
1021 /* Write the function pointer*/
1022 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
1024 /* Make sure it's within the exports */
1025 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportEntry
) &&
1026 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportEntry
+ ExportSize
)))
1028 /* Get the Import and Forwarder Names */
1029 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
1030 ForwarderName
.Buffer
= ImportName
;
1031 ForwarderName
.Length
= (USHORT
)(strchr(ImportName
, '.') - ImportName
);
1032 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
1033 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
1037 /* Make sure the conversion was OK */
1038 if (NT_SUCCESS(Status
))
1040 /* Load the forwarder, free the temp string */
1041 Status
= LdrpLoadDll(FALSE
,
1047 RtlFreeUnicodeString(&TempUString
);
1050 /* If the load or conversion failed, use the failure path */
1051 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1053 /* Now set up a name for the actual forwarder dll */
1054 RtlInitAnsiString(&ForwarderName
,
1055 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
1057 /* Check if it's an ordinal forward */
1058 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
1060 /* We don't have an actual function name */
1063 /* Convert the string into an ordinal */
1064 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
1068 /* If this fails, then error out */
1069 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1073 /* Import by name */
1074 ForwardName
= &ForwarderName
;
1077 /* Get the pointer */
1078 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1081 (PVOID
*)&Thunk
->u1
.Function
,
1083 /* If this fails, then error out */
1084 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1088 /* It's not within the exports, let's hope it's valid */
1089 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1092 /* If we got here, then it's success */
1093 Status
= STATUS_SUCCESS
;