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 */
103 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
;
159 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
160 ImportLdrEntry
->DllBase
,
168 /* Move to the next thunk */
170 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
172 /* Fail with the SEH error */
173 Status
= _SEH2_GetExceptionCode();
176 /* If we messed up, exit */
177 if (!NT_SUCCESS(Status
)) break;
180 else if (IatEntry
->FirstThunk
)
182 /* Full snapping. Get the First thunk */
183 FirstThunk
= (PIMAGE_THUNK_DATA
)
184 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
185 IatEntry
->FirstThunk
);
187 /* Get the NT Header */
188 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
190 /* Get the Original thunk VA, watch out for weird images */
191 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
192 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
194 /* Refuse it, this is a strange linked file */
195 OriginalThunk
= FirstThunk
;
199 /* Get the address from the field and convert to VA */
200 OriginalThunk
= (PIMAGE_THUNK_DATA
)
201 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
202 IatEntry
->OriginalFirstThunk
);
205 /* Get the Import name VA */
206 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
209 /* Loop while it's valid */
210 while (OriginalThunk
->u1
.AddressOfData
)
215 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
216 ImportLdrEntry
->DllBase
,
227 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
229 /* Fail with the SEH error */
230 Status
= _SEH2_GetExceptionCode();
233 /* If we failed the snap, break out */
234 if (!NT_SUCCESS(Status
)) break;
238 /* Protect the IAT again */
239 NtProtectVirtualMemory(NtCurrentProcess(),
245 /* Also flush out the cache */
246 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
248 /* Return to Caller */
254 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
255 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
256 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR
*BoundEntryPtr
,
257 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
259 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
261 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
262 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
263 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
264 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
265 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
266 PPEB Peb
= NtCurrentPeb();
269 /* Get the pointer to the bound entry */
270 BoundEntry
= *BoundEntryPtr
;
272 /* Get the name's VA */
273 BoundImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
275 /* Show debug mesage */
278 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
281 /* Load the module for this entry */
282 Status
= LdrpLoadImportModule(DllPath
,
287 if (!NT_SUCCESS(Status
))
289 /* Show debug message */
292 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
293 &LdrEntry
->BaseDllName
,
300 /* Check if it wasn't already loaded */
303 /* Add it to our list */
304 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
305 &DllLdrEntry
->InInitializationOrderModuleList
);
308 /* Check if the Bound Entry is now invalid */
309 if ((BoundEntry
->TimeDateStamp
!= DllLdrEntry
->TimeDateStamp
) ||
310 (DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
312 /* Show debug message */
315 DPRINT1("LDR: %wZ has stale binding to %s\n",
316 &LdrEntry
->BaseDllName
,
320 /* Remember it's become stale */
325 /* Show debug message */
328 DPRINT1("LDR: %wZ has correct binding to %s\n",
329 &LdrEntry
->BaseDllName
,
333 /* Remember it's valid */
337 /* Get the forwarders */
338 ForwarderEntry
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
341 for (i
= 0; i
< BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
344 ForwarderName
= (LPSTR
)FirstEntry
+ ForwarderEntry
->OffsetModuleName
;
346 /* Show debug message */
349 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
350 &LdrEntry
->BaseDllName
,
352 &DllLdrEntry
->BaseDllName
);
355 /* Load the module */
356 Status
= LdrpLoadImportModule(DllPath
,
361 if (NT_SUCCESS(Status
))
363 /* Loaded it, was it already loaded? */
366 /* Add it to our list */
367 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
368 &ForwarderLdrEntry
->InInitializationOrderModuleList
);
372 /* Check if the Bound Entry is now invalid */
373 if (!(NT_SUCCESS(Status
)) ||
374 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
375 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
377 /* Show debug message */
380 DPRINT1("LDR: %wZ has stale binding to %s\n",
381 &LdrEntry
->BaseDllName
,
385 /* Remember it's become stale */
390 /* Show debug message */
393 DPRINT1("LDR: %wZ has correct binding to %s\n",
394 &LdrEntry
->BaseDllName
,
398 /* Remember it's valid */
402 /* Move to the next one */
406 /* Set the next bound entry to the forwarder */
407 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
409 /* Check if the binding was stale */
412 /* It was, so find the IAT entry for it */
413 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
415 IMAGE_DIRECTORY_ENTRY_IMPORT
,
418 /* Make sure it has a name */
419 while (ImportEntry
->Name
)
422 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
425 if (!_stricmp(ImportName
, BoundImportName
)) break;
427 /* Move to next entry */
431 /* If we didn't find a name, fail */
432 if (!ImportEntry
->Name
)
434 /* Show debug message */
437 DPRINT1("LDR: LdrpWalkImportTable - failing with"
438 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
442 Status
= STATUS_OBJECT_NAME_INVALID
;
446 /* Show debug message */
449 DPRINT1("LDR: Stale Bind %s from %wZ\n",
451 &LdrEntry
->BaseDllName
);
454 /* Snap the IAT Entry*/
455 Status
= LdrpSnapIAT(DllLdrEntry
,
460 /* Make sure we didn't fail */
461 if (!NT_SUCCESS(Status
))
463 /* Show debug message */
466 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
467 &LdrEntry
->BaseDllName
,
478 Status
= STATUS_SUCCESS
;
481 /* Write where we are now and return */
482 *BoundEntryPtr
= FirstEntry
;
488 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
489 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
490 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
492 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
495 /* Make sure we have a name */
496 while (BoundEntry
->OffsetModuleName
)
498 /* Parse this descriptor */
499 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
503 if (!NT_SUCCESS(Status
)) return Status
;
507 return STATUS_SUCCESS
;
512 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
513 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
514 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
519 BOOLEAN AlreadyLoaded
= FALSE
, StaticEntriesValid
= FALSE
, SkipSnap
= FALSE
;
520 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
521 PIMAGE_THUNK_DATA FirstThunk
;
522 PPEB Peb
= NtCurrentPeb();
524 /* Get the import name's VA */
525 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
527 /* Get the first thunk */
528 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
529 ImportEntry
->FirstThunk
);
531 /* Make sure it's valid */
532 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
534 /* Show debug message */
537 DPRINT1("LDR: %s used by %wZ\n",
539 &LdrEntry
->BaseDllName
);
542 /* Load the module associated to it */
543 Status
= LdrpLoadImportModule(DllPath
,
548 if (!NT_SUCCESS(Status
)) return Status
;
550 /* Show debug message */
553 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
554 &LdrEntry
->BaseDllName
,
558 /* Check if the image was bound when compiled */
559 if (ImportEntry
->OriginalFirstThunk
)
561 /* It was, so check if the static IAT entries are still valid */
562 if ((ImportEntry
->TimeDateStamp
) &&
563 (ImportEntry
->TimeDateStamp
== DllLdrEntry
->TimeDateStamp
) &&
564 (!(DllLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)))
566 /* Show debug message */
569 DPRINT1("LDR: Snap bypass %s from %wZ\n",
571 &LdrEntry
->BaseDllName
);
575 * They are still valid, so we can skip snapping them.
576 * Additionally, if we have no forwarders, we are totally
579 if (ImportEntry
->ForwarderChain
== -1)
581 /* Totally skip LdrpSnapIAT */
586 /* Set this so LdrpSnapIAT will only do forwarders */
587 StaticEntriesValid
= TRUE
;
592 /* Check if it wasn't already loaded */
595 /* Add the DLL to our list */
596 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
597 &DllLdrEntry
->InInitializationOrderModuleList
);
600 /* Check if we should snap at all */
603 /* Now snap the IAT Entry */
604 Status
= LdrpSnapIAT(DllLdrEntry
,
608 if (!NT_SUCCESS(Status
)) return Status
;
612 return STATUS_SUCCESS
;
617 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
618 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
619 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry
)
623 /* Check for Name and Thunk */
624 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
626 /* Parse this descriptor */
627 Status
= LdrpHandleOneOldFormatImportDescriptor(DllPath
,
630 if (!NT_SUCCESS(Status
)) return Status
;
632 /* Move to the next entry */
637 return STATUS_SUCCESS
;
641 LdrpNameToOrdinal(LPSTR ImportName
,
645 PUSHORT OrdinalTable
)
647 ULONG Start
, End
, Next
;
650 /* Use classical binary search to find the ordinal */
652 End
= NumberOfNames
- 1;
655 /* Next will be exactly between Start and End */
656 Next
= (Start
+ End
) >> 1;
658 /* Compare this name with the one we need to find */
659 CmpResult
= strcmp(ImportName
, (PCHAR
)((ULONG_PTR
)ExportBase
+ NameTable
[Next
]));
661 /* We found our entry if result is 0 */
662 if (!CmpResult
) break;
664 /* We didn't find, update our range then */
667 else if (CmpResult
> 0)
671 /* If end is before start, then the search failed */
672 if (End
< Start
) return -1;
674 /* Return found name */
675 return OrdinalTable
[Next
];
680 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
681 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
683 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
684 PPEB Peb
= NtCurrentPeb();
685 NTSTATUS Status
= STATUS_SUCCESS
;
686 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
687 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
688 ULONG BoundSize
, IatSize
;
690 DPRINT("LdrpWalkImportDescriptor('%S' %x)\n", DllPath
, LdrEntry
);
692 /* Set up the Act Ctx */
693 ActCtx
.Size
= sizeof(ActCtx
);
695 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
697 /* Check if we have a manifest prober routine */
698 if (LdrpManifestProberRoutine
)
700 DPRINT1("We don't support manifests yet, much less prober routines\n");
703 /* Check if we failed above */
704 if (!NT_SUCCESS(Status
)) return Status
;
706 /* Get the Active ActCtx */
707 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
708 if (!NT_SUCCESS(Status
)) return Status
;
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
);
787 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
790 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
791 OUT PBOOLEAN Existing
)
793 ANSI_STRING AnsiString
;
794 PUNICODE_STRING ImpDescName
;
796 PPEB Peb
= RtlGetCurrentPeb();
797 PTEB Teb
= NtCurrentTeb();
799 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath
, ImportName
, DllBase
, DataTableEntry
, Existing
);
801 /* Convert import descriptor name to unicode string */
802 ImpDescName
= &Teb
->StaticUnicodeString
;
803 RtlInitAnsiString(&AnsiString
, ImportName
);
804 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
805 if (!NT_SUCCESS(Status
)) return Status
;
807 /* Check if it's loaded */
808 if (LdrpCheckForLoadedDll(DllPath
,
814 /* It's already existing in the list */
816 return STATUS_SUCCESS
;
819 /* We're loading it for the first time */
823 Status
= LdrpMapDll(DllPath
,
831 if (!NT_SUCCESS(Status
)) return Status
;
833 /* Walk its import descriptor table */
834 Status
= LdrpWalkImportDescriptor(DllPath
,
836 if (!NT_SUCCESS(Status
))
838 /* Add it to the in-init-order list in case of failure */
839 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
840 &(*DataTableEntry
)->InInitializationOrderModuleList
);
848 LdrpSnapThunk(IN PVOID ExportBase
,
850 IN PIMAGE_THUNK_DATA OriginalThunk
,
851 IN OUT PIMAGE_THUNK_DATA Thunk
,
852 IN PIMAGE_EXPORT_DIRECTORY ExportEntry
,
859 ULONG OriginalOrdinal
= 0;
860 PIMAGE_IMPORT_BY_NAME AddressOfData
;
862 PUSHORT OrdinalTable
;
863 LPSTR ImportName
= NULL
;
866 ULONG_PTR HardErrorParameters
[3];
867 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
868 ANSI_STRING TempString
;
871 PULONG AddressOfFunctions
;
872 UNICODE_STRING TempUString
;
873 ANSI_STRING ForwarderName
;
874 PANSI_STRING ForwardName
;
875 PVOID ForwarderHandle
;
876 ULONG ForwardOrdinal
;
878 /* Check if the snap is by ordinal */
879 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
881 /* Get the ordinal number, and its normalized version */
882 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
883 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportEntry
->Base
);
887 /* First get the data VA */
888 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
889 ((ULONG_PTR
)ImportBase
+
890 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
893 ImportName
= (LPSTR
)AddressOfData
->Name
;
895 /* Now get the VA of the Name and Ordinal Tables */
896 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
897 (ULONG_PTR
)ExportEntry
->AddressOfNames
);
898 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
899 (ULONG_PTR
)ExportEntry
->AddressOfNameOrdinals
);
902 Hint
= AddressOfData
->Hint
;
904 /* Try to get a match by using the hint */
905 if (((ULONG
)Hint
< ExportEntry
->NumberOfNames
) &&
906 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
908 /* We got a match, get the Ordinal from the hint */
909 Ordinal
= OrdinalTable
[Hint
];
913 /* Well bummer, hint didn't work, do it the long way */
914 Ordinal
= LdrpNameToOrdinal(ImportName
,
915 ExportEntry
->NumberOfNames
,
922 /* Check if the ordinal is invalid */
923 if ((ULONG
)Ordinal
>= ExportEntry
->NumberOfFunctions
)
926 /* Is this a static snap? */
929 /* Inform the debug log */
931 DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
933 DPRINT1("Failed to snap %s\n", ImportName
);
935 /* These are critical errors. Setup a string for the DLL name */
936 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
937 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
939 /* Set it as the parameter */
940 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
943 /* Check if we have an ordinal */
946 /* Then set the ordinal as the 1st parameter */
947 HardErrorParameters
[0] = OriginalOrdinal
;
951 /* We don't, use the entrypoint. Set up a string for it */
952 RtlInitAnsiString(&TempString
, ImportName
);
953 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
957 /* Set it as the parameter */
958 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
962 /* Raise the error */
963 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
964 STATUS_ENTRYPOINT_NOT_FOUND
,
971 /* Increase the error count */
972 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
974 /* Free our string */
975 RtlFreeUnicodeString(&HardErrorDllName
);
978 /* Free our second string. Return entrypoint error */
979 RtlFreeUnicodeString(&HardErrorEntryPointName
);
980 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
983 /* Return ordinal error */
984 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
988 /* Inform the debug log */
990 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
992 DPRINT("Non-fatal: Failed to snap %s\n", ImportName
);
995 /* Set this as a bad DLL */
996 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
998 /* Return the right error code */
999 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1000 STATUS_ENTRYPOINT_NOT_FOUND
;
1004 /* The ordinal seems correct, get the AddressOfFunctions VA */
1005 AddressOfFunctions
= (PULONG
)
1006 ((ULONG_PTR
)ExportBase
+
1007 (ULONG_PTR
)ExportEntry
->AddressOfFunctions
);
1009 /* Write the function pointer*/
1010 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
1012 /* Make sure it's within the exports */
1013 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportEntry
) &&
1014 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportEntry
+ ExportSize
)))
1016 /* Get the Import and Forwarder Names */
1017 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
1018 ForwarderName
.Buffer
= ImportName
;
1019 ForwarderName
.Length
= (USHORT
)(strchr(ImportName
, '.') - ImportName
);
1020 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
1021 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
1025 /* Make sure the conversion was OK */
1026 if (NT_SUCCESS(Status
))
1028 /* Load the forwarder, free the temp string */
1029 Status
= LdrpLoadDll(FALSE
,
1035 RtlFreeUnicodeString(&TempUString
);
1038 /* If the load or conversion failed, use the failure path */
1039 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1041 /* Now set up a name for the actual forwarder dll */
1042 RtlInitAnsiString(&ForwarderName
,
1043 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
1045 /* Check if it's an ordinal forward */
1046 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
1048 /* We don't have an actual function name */
1051 /* Convert the string into an ordinal */
1052 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
1056 /* If this fails, then error out */
1057 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1061 /* Import by name */
1062 ForwardName
= &ForwarderName
;
1065 /* Get the pointer */
1066 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1069 (PVOID
*)&Thunk
->u1
.Function
,
1071 /* If this fails, then error out */
1072 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1076 /* It's not within the exports, let's hope it's valid */
1077 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1080 /* If we got here, then it's success */
1081 Status
= STATUS_SUCCESS
;