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 ULONG LdrpFatalHardErrorCount
;
18 PVOID LdrpManifestProberRoutine
;
21 /* FUNCTIONS *****************************************************************/
25 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry
,
26 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry
,
27 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry
,
28 IN BOOLEAN EntriesValid
)
32 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
33 PIMAGE_NT_HEADERS NtHeader
;
34 PIMAGE_SECTION_HEADER SectionHeader
;
35 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
37 ULONG ForwarderChain
, i
, Rva
, OldProtect
, IatSize
, ExportSize
;
39 DPRINT("LdrpSnapIAT(%wZ %wZ %p %d)\n", &ExportLdrEntry
->BaseDllName
, &ImportLdrEntry
->BaseDllName
, IatEntry
, EntriesValid
);
41 /* Get export directory */
42 ExportDirectory
= RtlImageDirectoryEntryToData(ExportLdrEntry
->DllBase
,
44 IMAGE_DIRECTORY_ENTRY_EXPORT
,
47 /* Make sure it has one */
51 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
52 &ExportLdrEntry
->BaseDllName
);
53 return STATUS_INVALID_IMAGE_FORMAT
;
57 Iat
= RtlImageDirectoryEntryToData(ImportLdrEntry
->DllBase
,
59 IMAGE_DIRECTORY_ENTRY_IAT
,
63 /* Check if we don't have one */
66 /* Get the NT Header and the first section */
67 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
68 if (!NtHeader
) return STATUS_INVALID_IMAGE_FORMAT
;
69 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
71 /* Get the RVA of the import directory */
72 Rva
= NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
74 /* Make sure we got one */
77 /* Loop all the sections */
78 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
80 /* Check if we are inside this section */
81 if ((Rva
>= SectionHeader
->VirtualAddress
) &&
82 (Rva
< (SectionHeader
->VirtualAddress
+
83 SectionHeader
->SizeOfRawData
)))
85 /* We are, so set the IAT here */
86 Iat
= (PVOID
)((ULONG_PTR
)(ImportLdrEntry
->DllBase
) +
87 SectionHeader
->VirtualAddress
);
90 IatSize
= SectionHeader
->Misc
.VirtualSize
;
92 /* Deal with Watcom and other retarded compilers */
93 if (!IatSize
) IatSize
= SectionHeader
->SizeOfRawData
;
95 /* Found it, get out */
99 /* No match, move to the next section */
104 /* If we still don't have an IAT, that's bad */
108 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
109 &ImportLdrEntry
->BaseDllName
,
110 ImportLdrEntry
->DllBase
);
111 return STATUS_INVALID_IMAGE_FORMAT
;
114 /* Set the right size */
115 ImportSize
= IatSize
;
118 /* Unprotect the IAT */
119 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
124 if (!NT_SUCCESS(Status
))
127 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
128 &ImportLdrEntry
->BaseDllName
,
133 /* Check if the Thunks are already valid */
136 /* We'll only do forwarders. Get the import name */
137 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+ IatEntry
->Name
);
139 /* Get the list of forwaders */
140 ForwarderChain
= IatEntry
->ForwarderChain
;
143 while (ForwarderChain
!= -1)
145 /* Get the cached thunk VA*/
146 OriginalThunk
= (PIMAGE_THUNK_DATA
)
147 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
148 IatEntry
->OriginalFirstThunk
+
149 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
151 /* Get the first thunk */
152 FirstThunk
= (PIMAGE_THUNK_DATA
)
153 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
154 IatEntry
->FirstThunk
+
155 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
157 /* Get the Forwarder from the thunk */
158 ForwarderChain
= (ULONG
)FirstThunk
->u1
.Ordinal
;
163 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
164 ImportLdrEntry
->DllBase
,
172 /* Move to the next thunk */
174 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
176 /* Fail with the SEH error */
177 Status
= _SEH2_GetExceptionCode();
180 /* If we messed up, exit */
181 if (!NT_SUCCESS(Status
)) break;
184 else if (IatEntry
->FirstThunk
)
186 /* Full snapping. Get the First thunk */
187 FirstThunk
= (PIMAGE_THUNK_DATA
)
188 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
189 IatEntry
->FirstThunk
);
191 /* Get the NT Header */
192 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
194 /* Get the Original thunk VA, watch out for weird images */
195 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
196 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
198 /* Refuse it, this is a strange linked file */
199 OriginalThunk
= FirstThunk
;
203 /* Get the address from the field and convert to VA */
204 OriginalThunk
= (PIMAGE_THUNK_DATA
)
205 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
206 IatEntry
->OriginalFirstThunk
);
209 /* Get the Import name VA */
210 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
213 /* Loop while it's valid */
214 while (OriginalThunk
->u1
.AddressOfData
)
219 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
220 ImportLdrEntry
->DllBase
,
231 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
233 /* Fail with the SEH error */
234 Status
= _SEH2_GetExceptionCode();
237 /* If we failed the snap, break out */
238 if (!NT_SUCCESS(Status
)) break;
242 /* Protect the IAT again */
243 NtProtectVirtualMemory(NtCurrentProcess(),
249 /* Also flush out the cache */
250 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
252 /* Return to Caller */
258 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
259 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
260 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR
*BoundEntryPtr
,
261 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
263 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
265 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
266 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
267 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
268 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
269 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
270 PPEB Peb
= NtCurrentPeb();
273 /* Get the pointer to the bound entry */
274 BoundEntry
= *BoundEntryPtr
;
276 /* Get the name's VA */
277 BoundImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
279 /* Show debug mesage */
282 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
285 /* Load the module for this entry */
286 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
->InInitializationOrderModuleList
);
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
,
365 if (NT_SUCCESS(Status
))
367 /* Loaded it, was it already loaded? */
370 /* Add it to our list */
371 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
372 &ForwarderLdrEntry
->InInitializationOrderModuleList
);
376 /* Check if the Bound Entry is now invalid */
377 if (!(NT_SUCCESS(Status
)) ||
378 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
379 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
381 /* Show debug message */
384 DPRINT1("LDR: %wZ has stale binding to %s\n",
385 &LdrEntry
->BaseDllName
,
389 /* Remember it's become stale */
394 /* Show debug message */
397 DPRINT1("LDR: %wZ has correct binding to %s\n",
398 &LdrEntry
->BaseDllName
,
402 /* Remember it's valid */
406 /* Move to the next one */
410 /* Set the next bound entry to the forwarder */
411 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
413 /* Check if the binding was stale */
416 /* It was, so find the IAT entry for it */
418 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
420 IMAGE_DIRECTORY_ENTRY_IMPORT
,
423 /* Make sure it has a name */
424 while (ImportEntry
->Name
)
427 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
430 if (!_stricmp(ImportName
, BoundImportName
)) break;
432 /* Move to next entry */
436 /* If we didn't find a name, fail */
437 if (!ImportEntry
->Name
)
439 /* Show debug message */
442 DPRINT1("LDR: LdrpWalkImportTable - failing with"
443 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
447 Status
= STATUS_OBJECT_NAME_INVALID
;
451 /* Show debug message */
454 DPRINT1("LDR: Stale Bind %s from %wZ\n",
456 &LdrEntry
->BaseDllName
);
459 /* Snap the IAT Entry*/
460 Status
= LdrpSnapIAT(DllLdrEntry
,
465 /* Make sure we didn't fail */
466 if (!NT_SUCCESS(Status
))
468 /* Show debug message */
471 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
472 &LdrEntry
->BaseDllName
,
483 Status
= STATUS_SUCCESS
;
486 /* Write where we are now and return */
487 *BoundEntryPtr
= FirstEntry
;
493 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
494 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
495 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
497 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
500 /* Make sure we have a name */
501 while (BoundEntry
->OffsetModuleName
)
503 /* Parse this descriptor */
504 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
508 if (!NT_SUCCESS(Status
)) return Status
;
512 return STATUS_SUCCESS
;
517 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
518 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
519 IN PIMAGE_IMPORT_DESCRIPTOR
*ImportEntry
)
523 BOOLEAN AlreadyLoaded
= FALSE
;
524 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
525 PIMAGE_THUNK_DATA FirstThunk
;
526 PPEB Peb
= NtCurrentPeb();
528 /* Get the import name's VA */
529 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ (*ImportEntry
)->Name
);
531 /* Get the first thunk */
532 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
533 (*ImportEntry
)->FirstThunk
);
535 /* Make sure it's valid */
536 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
538 /* Show debug message */
541 DPRINT1("LDR: %s used by %wZ\n",
543 &LdrEntry
->BaseDllName
);
546 /* Load the module associated to it */
547 Status
= LdrpLoadImportModule(DllPath
,
552 if (!NT_SUCCESS(Status
))
557 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
558 "on import %s with status %x\n",
567 /* Show debug message */
570 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
571 &LdrEntry
->BaseDllName
,
575 /* Check if it wasn't already loaded */
579 /* Add the DLL to our list */
580 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
581 &DllLdrEntry
->InInitializationOrderModuleList
);
584 /* Now snap the IAT Entry */
585 Status
= LdrpSnapIAT(DllLdrEntry
, LdrEntry
, *ImportEntry
, FALSE
);
586 if (!NT_SUCCESS(Status
))
591 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
603 return STATUS_SUCCESS
;
608 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
609 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
610 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
614 /* Check for Name and Thunk */
615 while ((ImportEntry
->Name
) && (ImportEntry
->FirstThunk
))
617 /* Parse this descriptor */
618 Status
= LdrpHandleOneOldFormatImportDescriptor(DllPath
,
621 if (!NT_SUCCESS(Status
)) return Status
;
625 return STATUS_SUCCESS
;
630 LdrpNameToOrdinal(IN LPSTR ImportName
,
631 IN ULONG NumberOfNames
,
634 IN PUSHORT OrdinalTable
)
636 LONG Start
, End
, Next
, CmpResult
;
638 /* Use classical binary search to find the ordinal */
640 End
= NumberOfNames
- 1;
643 /* Next will be exactly between Start and End */
644 Next
= (Start
+ End
) >> 1;
646 /* Compare this name with the one we need to find */
647 CmpResult
= strcmp(ImportName
, (PCHAR
)((ULONG_PTR
)ExportBase
+ NameTable
[Next
]));
649 /* We found our entry if result is 0 */
650 if (!CmpResult
) break;
652 /* We didn't find, update our range then */
657 else if (CmpResult
> 0)
663 /* If end is before start, then the search failed */
664 if (End
< Start
) return -1;
666 /* Return found name */
667 return OrdinalTable
[Next
];
672 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
673 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
675 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
676 PPEB Peb
= NtCurrentPeb();
677 NTSTATUS Status
= STATUS_SUCCESS
;
678 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
679 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
680 ULONG BoundSize
, IatSize
;
681 DPRINT("LdrpWalkImportDescriptor('%S' %x)\n", DllPath
, LdrEntry
);
683 /* Set up the Act Ctx */
684 ActCtx
.Size
= sizeof(ActCtx
);
685 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
686 RtlZeroMemory(&ActCtx
.Frame
, sizeof(ActCtx
));
688 /* Check if we have a manifest prober routine */
689 if (LdrpManifestProberRoutine
)
691 DPRINT1("We don't support manifests yet, much less prober routines\n");
694 /* Check if we failed above */
695 if (!NT_SUCCESS(Status
)) return Status
;
697 /* Get the Active ActCtx */
698 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
699 if (!NT_SUCCESS(Status
))
702 DbgPrintEx(51, // DPFLTR_SXS_ID
703 DPFLTR_WARNING_LEVEL
,
704 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
710 /* Activate the ActCtx */
711 RtlActivateActivationContextUnsafeFast(&ActCtx
,
712 LdrEntry
->EntryPointActivationContext
);
714 /* Check if we were redirected */
715 if (!(LdrEntry
->Flags
& LDRP_REDIRECTED
))
717 /* Get the Bound IAT */
718 BoundEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
720 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
724 /* Get the regular IAT, for fallback */
725 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
727 IMAGE_DIRECTORY_ENTRY_IMPORT
,
730 /* Check if we got at least one */
731 if ((BoundEntry
) || (ImportEntry
))
733 /* Do we have a Bound IAT */
736 /* Handle the descriptor */
737 Status
= LdrpHandleNewFormatImportDescriptors(DllPath
,
743 /* Handle the descriptor */
744 Status
= LdrpHandleOldFormatImportDescriptors(DllPath
,
749 /* Check the status of the handlers */
750 if (NT_SUCCESS(Status
))
752 /* Check for Per-DLL Heap Tagging */
753 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAG_BY_DLL
)
756 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
759 /* Check if Page Heap was enabled */
760 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
763 DPRINT1("We don't support Page Heaps yet!\n");
766 /* Check if Application Verifier was enabled */
767 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
770 DPRINT1("We don't support Application Verifier yet!\n");
773 /* Just to be safe */
774 Status
= STATUS_SUCCESS
;
778 /* Release the activation context */
779 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
785 /* FIXME: This function is missing SxS support and has wrong prototype */
788 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
791 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
792 OUT PBOOLEAN Existing
)
794 ANSI_STRING AnsiString
;
795 PUNICODE_STRING ImpDescName
;
797 PPEB Peb
= RtlGetCurrentPeb();
798 PTEB Teb
= NtCurrentTeb();
800 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath
, ImportName
, DllBase
, DataTableEntry
, Existing
);
802 /* Convert import descriptor name to unicode string */
803 ImpDescName
= &Teb
->StaticUnicodeString
;
804 RtlInitAnsiString(&AnsiString
, ImportName
);
805 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
806 if (!NT_SUCCESS(Status
)) return Status
;
808 /* Check if it's loaded */
809 if (LdrpCheckForLoadedDll(DllPath
,
815 /* It's already existing in the list */
817 return STATUS_SUCCESS
;
820 /* We're loading it for the first time */
824 Status
= LdrpMapDll(DllPath
,
832 if (!NT_SUCCESS(Status
)) return Status
;
834 /* Walk its import descriptor table */
835 Status
= LdrpWalkImportDescriptor(DllPath
,
837 if (!NT_SUCCESS(Status
))
839 /* Add it to the in-init-order list in case of failure */
840 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
841 &(*DataTableEntry
)->InInitializationOrderModuleList
);
849 LdrpSnapThunk(IN PVOID ExportBase
,
851 IN PIMAGE_THUNK_DATA OriginalThunk
,
852 IN OUT PIMAGE_THUNK_DATA Thunk
,
853 IN PIMAGE_EXPORT_DIRECTORY ExportEntry
,
860 ULONG OriginalOrdinal
= 0;
861 PIMAGE_IMPORT_BY_NAME AddressOfData
;
863 PUSHORT OrdinalTable
;
864 LPSTR ImportName
= NULL
;
867 ULONG_PTR HardErrorParameters
[3];
868 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
869 ANSI_STRING TempString
;
872 PULONG AddressOfFunctions
;
873 UNICODE_STRING TempUString
;
874 ANSI_STRING ForwarderName
;
875 PANSI_STRING ForwardName
;
876 PVOID ForwarderHandle
;
877 ULONG ForwardOrdinal
;
879 /* Check if the snap is by ordinal */
880 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
882 /* Get the ordinal number, and its normalized version */
883 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
884 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportEntry
->Base
);
888 /* First get the data VA */
889 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
890 ((ULONG_PTR
)ImportBase
+
891 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
894 ImportName
= (LPSTR
)AddressOfData
->Name
;
896 /* Now get the VA of the Name and Ordinal Tables */
897 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
898 (ULONG_PTR
)ExportEntry
->AddressOfNames
);
899 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
900 (ULONG_PTR
)ExportEntry
->AddressOfNameOrdinals
);
903 Hint
= AddressOfData
->Hint
;
905 /* Try to get a match by using the hint */
906 if (((ULONG
)Hint
< ExportEntry
->NumberOfNames
) &&
907 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
909 /* We got a match, get the Ordinal from the hint */
910 Ordinal
= OrdinalTable
[Hint
];
914 /* Well bummer, hint didn't work, do it the long way */
915 Ordinal
= LdrpNameToOrdinal(ImportName
,
916 ExportEntry
->NumberOfNames
,
923 /* Check if the ordinal is invalid */
924 if ((ULONG
)Ordinal
>= ExportEntry
->NumberOfFunctions
)
927 /* Is this a static snap? */
930 /* Inform the debug log */
932 DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
934 DPRINT1("Failed to snap %s\n", ImportName
);
936 /* These are critical errors. Setup a string for the DLL name */
937 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
938 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
940 /* Set it as the parameter */
941 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
944 /* Check if we have an ordinal */
947 /* Then set the ordinal as the 1st parameter */
948 HardErrorParameters
[0] = OriginalOrdinal
;
952 /* We don't, use the entrypoint. Set up a string for it */
953 RtlInitAnsiString(&TempString
, ImportName
);
954 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
958 /* Set it as the parameter */
959 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
963 /* Raise the error */
964 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
965 STATUS_ENTRYPOINT_NOT_FOUND
,
972 /* Increase the error count */
973 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
975 /* Free our string */
976 RtlFreeUnicodeString(&HardErrorDllName
);
979 /* Free our second string. Return entrypoint error */
980 RtlFreeUnicodeString(&HardErrorEntryPointName
);
981 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
984 /* Return ordinal error */
985 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
989 /* Inform the debug log */
991 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
993 DPRINT("Non-fatal: Failed to snap %s\n", ImportName
);
996 /* Set this as a bad DLL */
997 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
999 /* Return the right error code */
1000 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1001 STATUS_ENTRYPOINT_NOT_FOUND
;
1005 /* The ordinal seems correct, get the AddressOfFunctions VA */
1006 AddressOfFunctions
= (PULONG
)
1007 ((ULONG_PTR
)ExportBase
+
1008 (ULONG_PTR
)ExportEntry
->AddressOfFunctions
);
1010 /* Write the function pointer*/
1011 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
1013 /* Make sure it's within the exports */
1014 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportEntry
) &&
1015 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportEntry
+ ExportSize
)))
1017 /* Get the Import and Forwarder Names */
1018 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
1019 ForwarderName
.Buffer
= ImportName
;
1020 ForwarderName
.Length
= (USHORT
)(strchr(ImportName
, '.') - ImportName
);
1021 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
1022 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
1026 /* Make sure the conversion was OK */
1027 if (NT_SUCCESS(Status
))
1029 /* Load the forwarder, free the temp string */
1030 Status
= LdrpLoadDll(FALSE
,
1036 RtlFreeUnicodeString(&TempUString
);
1039 /* If the load or conversion failed, use the failure path */
1040 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1042 /* Now set up a name for the actual forwarder dll */
1043 RtlInitAnsiString(&ForwarderName
,
1044 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
1046 /* Check if it's an ordinal forward */
1047 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
1049 /* We don't have an actual function name */
1052 /* Convert the string into an ordinal */
1053 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
1057 /* If this fails, then error out */
1058 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1062 /* Import by name */
1063 ForwardName
= &ForwarderName
;
1066 /* Get the pointer */
1067 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1070 (PVOID
*)&Thunk
->u1
.Function
,
1072 /* If this fails, then error out */
1073 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1077 /* It's not within the exports, let's hope it's valid */
1078 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1081 /* If we got here, then it's success */
1082 Status
= STATUS_SUCCESS
;