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 *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine
;
21 /* FUNCTIONS *****************************************************************/
25 AVrfPageHeapDllNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
27 /* Check if page heap dll notification is turned on */
28 if (!(RtlpDphGlobalFlags
& DPH_FLAG_DLL_NOTIFY
))
31 /* We don't support this flag currently */
37 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry
,
38 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry
,
39 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry
,
40 IN BOOLEAN EntriesValid
)
44 PIMAGE_THUNK_DATA OriginalThunk
, FirstThunk
;
45 PIMAGE_NT_HEADERS NtHeader
;
46 PIMAGE_SECTION_HEADER SectionHeader
;
47 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
49 ULONG ForwarderChain
, i
, Rva
, OldProtect
, IatSize
, ExportSize
;
51 DPRINT("LdrpSnapIAT(%wZ %wZ %p %u)\n", &ExportLdrEntry
->BaseDllName
, &ImportLdrEntry
->BaseDllName
, IatEntry
, EntriesValid
);
53 /* Get export directory */
54 ExportDirectory
= RtlImageDirectoryEntryToData(ExportLdrEntry
->DllBase
,
56 IMAGE_DIRECTORY_ENTRY_EXPORT
,
59 /* Make sure it has one */
63 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
64 &ExportLdrEntry
->BaseDllName
);
65 return STATUS_INVALID_IMAGE_FORMAT
;
69 Iat
= RtlImageDirectoryEntryToData(ImportLdrEntry
->DllBase
,
71 IMAGE_DIRECTORY_ENTRY_IAT
,
75 /* Check if we don't have one */
78 /* Get the NT Header and the first section */
79 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
80 if (!NtHeader
) return STATUS_INVALID_IMAGE_FORMAT
;
81 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
83 /* Get the RVA of the import directory */
84 Rva
= NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
86 /* Make sure we got one */
89 /* Loop all the sections */
90 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
92 /* Check if we are inside this section */
93 if ((Rva
>= SectionHeader
->VirtualAddress
) &&
94 (Rva
< (SectionHeader
->VirtualAddress
+
95 SectionHeader
->SizeOfRawData
)))
97 /* We are, so set the IAT here */
98 Iat
= (PVOID
)((ULONG_PTR
)(ImportLdrEntry
->DllBase
) +
99 SectionHeader
->VirtualAddress
);
102 IatSize
= SectionHeader
->Misc
.VirtualSize
;
104 /* Deal with Watcom and other retarded compilers */
105 if (!IatSize
) 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 */
120 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
121 &ImportLdrEntry
->BaseDllName
,
122 ImportLdrEntry
->DllBase
);
123 return STATUS_INVALID_IMAGE_FORMAT
;
126 /* Set the right size */
127 ImportSize
= IatSize
;
130 /* Unprotect the IAT */
131 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
136 if (!NT_SUCCESS(Status
))
139 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
140 &ImportLdrEntry
->BaseDllName
,
145 /* Check if the Thunks are already valid */
148 /* We'll only do forwarders. Get the import name */
149 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+ IatEntry
->Name
);
151 /* Get the list of forwarders */
152 ForwarderChain
= IatEntry
->ForwarderChain
;
155 while (ForwarderChain
!= -1)
157 /* Get the cached thunk VA*/
158 OriginalThunk
= (PIMAGE_THUNK_DATA
)
159 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
160 IatEntry
->OriginalFirstThunk
+
161 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
163 /* Get the first thunk */
164 FirstThunk
= (PIMAGE_THUNK_DATA
)
165 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
166 IatEntry
->FirstThunk
+
167 (ForwarderChain
* sizeof(IMAGE_THUNK_DATA
)));
169 /* Get the Forwarder from the thunk */
170 ForwarderChain
= (ULONG
)FirstThunk
->u1
.Ordinal
;
175 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
176 ImportLdrEntry
->DllBase
,
184 /* Move to the next thunk */
186 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
188 /* Fail with the SEH error */
189 Status
= _SEH2_GetExceptionCode();
192 /* If we messed up, exit */
193 if (!NT_SUCCESS(Status
)) break;
196 else if (IatEntry
->FirstThunk
)
198 /* Full snapping. Get the First thunk */
199 FirstThunk
= (PIMAGE_THUNK_DATA
)
200 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
201 IatEntry
->FirstThunk
);
203 /* Get the NT Header */
204 NtHeader
= RtlImageNtHeader(ImportLdrEntry
->DllBase
);
206 /* Get the Original thunk VA, watch out for weird images */
207 if ((IatEntry
->Characteristics
< NtHeader
->OptionalHeader
.SizeOfHeaders
) ||
208 (IatEntry
->Characteristics
>= NtHeader
->OptionalHeader
.SizeOfImage
))
210 /* Refuse it, this is a strange linked file */
211 OriginalThunk
= FirstThunk
;
215 /* Get the address from the field and convert to VA */
216 OriginalThunk
= (PIMAGE_THUNK_DATA
)
217 ((ULONG_PTR
)ImportLdrEntry
->DllBase
+
218 IatEntry
->OriginalFirstThunk
);
221 /* Get the Import name VA */
222 ImportName
= (LPSTR
)((ULONG_PTR
)ImportLdrEntry
->DllBase
+
225 /* Loop while it's valid */
226 while (OriginalThunk
->u1
.AddressOfData
)
231 Status
= LdrpSnapThunk(ExportLdrEntry
->DllBase
,
232 ImportLdrEntry
->DllBase
,
243 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
245 /* Fail with the SEH error */
246 Status
= _SEH2_GetExceptionCode();
249 /* If we failed the snap, break out */
250 if (!NT_SUCCESS(Status
)) break;
254 /* Protect the IAT again */
255 NtProtectVirtualMemory(NtCurrentProcess(),
261 /* Also flush out the cache */
262 NtFlushInstructionCache(NtCurrentProcess(), Iat
, IatSize
);
264 /* Return to Caller */
270 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
271 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
272 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR
*BoundEntryPtr
,
273 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
)
275 LPSTR ImportName
= NULL
, BoundImportName
, ForwarderName
;
277 BOOLEAN AlreadyLoaded
= FALSE
, Stale
;
278 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
279 PLDR_DATA_TABLE_ENTRY DllLdrEntry
, ForwarderLdrEntry
;
280 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry
;
281 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
282 PPEB Peb
= NtCurrentPeb();
285 /* Get the pointer to the bound entry */
286 BoundEntry
= *BoundEntryPtr
;
288 /* Get the name's VA */
289 BoundImportName
= (LPSTR
)FirstEntry
+ BoundEntry
->OffsetModuleName
;
291 /* Show debug message */
294 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry
->BaseDllName
, BoundImportName
);
297 /* Load the module for this entry */
298 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
->InInitializationOrderLinks
);
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
,
375 if (NT_SUCCESS(Status
))
377 /* Loaded it, was it already loaded? */
380 /* Add it to our list */
381 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
382 &ForwarderLdrEntry
->InInitializationOrderLinks
);
386 /* Check if the Bound Entry is now invalid */
387 if (!(NT_SUCCESS(Status
)) ||
388 (ForwarderEntry
->TimeDateStamp
!= ForwarderLdrEntry
->TimeDateStamp
) ||
389 (ForwarderLdrEntry
->Flags
& LDRP_IMAGE_NOT_AT_BASE
))
391 /* Show debug message */
394 DPRINT1("LDR: %wZ has stale binding to %s\n",
395 &LdrEntry
->BaseDllName
,
399 /* Remember it's become stale */
404 /* Show debug message */
407 DPRINT1("LDR: %wZ has correct binding to %s\n",
408 &LdrEntry
->BaseDllName
,
412 /* Remember it's valid */
416 /* Move to the next one */
420 /* Set the next bound entry to the forwarder */
421 FirstEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)ForwarderEntry
;
423 /* Check if the binding was stale */
426 /* It was, so find the IAT entry for it */
428 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
430 IMAGE_DIRECTORY_ENTRY_IMPORT
,
433 /* Make sure it has a name */
434 while (ImportEntry
->Name
)
437 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
440 if (!_stricmp(ImportName
, BoundImportName
)) break;
442 /* Move to next entry */
446 /* If we didn't find a name, fail */
447 if (!ImportEntry
->Name
)
449 /* Show debug message */
452 DPRINT1("LDR: LdrpWalkImportTable - failing with"
453 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
457 Status
= STATUS_OBJECT_NAME_INVALID
;
461 /* Show debug message */
464 DPRINT1("LDR: Stale Bind %s from %wZ\n",
466 &LdrEntry
->BaseDllName
);
469 /* Snap the IAT Entry*/
470 Status
= LdrpSnapIAT(DllLdrEntry
,
475 /* Make sure we didn't fail */
476 if (!NT_SUCCESS(Status
))
478 /* Show debug message */
481 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
482 &LdrEntry
->BaseDllName
,
493 Status
= STATUS_SUCCESS
;
496 /* Write where we are now and return */
497 *BoundEntryPtr
= FirstEntry
;
503 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL
,
504 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
505 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
)
507 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry
= BoundEntry
;
510 /* Make sure we have a name */
511 while (BoundEntry
->OffsetModuleName
)
513 /* Parse this descriptor */
514 Status
= LdrpHandleOneNewFormatImportDescriptor(DllPath
,
518 if (!NT_SUCCESS(Status
)) return Status
;
522 return STATUS_SUCCESS
;
527 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
528 IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
529 IN PIMAGE_IMPORT_DESCRIPTOR
*ImportEntry
)
533 BOOLEAN AlreadyLoaded
= FALSE
;
534 PLDR_DATA_TABLE_ENTRY DllLdrEntry
;
535 PIMAGE_THUNK_DATA FirstThunk
;
536 PPEB Peb
= NtCurrentPeb();
538 /* Get the import name's VA */
539 ImportName
= (LPSTR
)((ULONG_PTR
)LdrEntry
->DllBase
+ (*ImportEntry
)->Name
);
541 /* Get the first thunk */
542 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+
543 (*ImportEntry
)->FirstThunk
);
545 /* Make sure it's valid */
546 if (!FirstThunk
->u1
.Function
) goto SkipEntry
;
548 /* Show debug message */
551 DPRINT1("LDR: %s used by %wZ\n",
553 &LdrEntry
->BaseDllName
);
556 /* Load the module associated to it */
557 Status
= LdrpLoadImportModule(DllPath
,
561 if (!NT_SUCCESS(Status
))
566 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
567 "on import %s with status %x\n",
576 /* Show debug message */
579 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
580 &LdrEntry
->BaseDllName
,
584 /* Check if it wasn't already loaded */
588 /* Add the DLL to our list */
589 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
590 &DllLdrEntry
->InInitializationOrderLinks
);
593 /* Now snap the IAT Entry */
594 Status
= LdrpSnapIAT(DllLdrEntry
, LdrEntry
, *ImportEntry
, FALSE
);
595 if (!NT_SUCCESS(Status
))
600 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
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
;
634 return STATUS_SUCCESS
;
639 LdrpNameToOrdinal(IN LPSTR ImportName
,
640 IN ULONG NumberOfNames
,
643 IN PUSHORT OrdinalTable
)
645 LONG Start
, End
, Next
, CmpResult
;
647 /* Use classical binary search to find the ordinal */
649 End
= NumberOfNames
- 1;
652 /* Next will be exactly between Start and End */
653 Next
= (Start
+ End
) >> 1;
655 /* Compare this name with the one we need to find */
656 CmpResult
= strcmp(ImportName
, (PCHAR
)((ULONG_PTR
)ExportBase
+ NameTable
[Next
]));
658 /* We found our entry if result is 0 */
659 if (!CmpResult
) break;
661 /* We didn't find, update our range then */
666 else if (CmpResult
> 0)
672 /* If end is before start, then the search failed */
673 if (End
< Start
) return -1;
675 /* Return found name */
676 return OrdinalTable
[Next
];
681 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL
,
682 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
684 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
685 PPEB Peb
= NtCurrentPeb();
686 NTSTATUS Status
= STATUS_SUCCESS
, Status2
;
687 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
= NULL
;
688 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
689 ULONG BoundSize
, IatSize
;
691 DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry
->BaseDllName
, LdrEntry
, DllPath
);
693 /* Set up the Act Ctx */
694 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
695 ActCtx
.Size
= sizeof(ActCtx
);
696 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
698 /* Check if we have a manifest prober routine */
699 if (LdrpManifestProberRoutine
)
701 /* Probe the DLL for its manifest. Some details are omitted */
702 Status2
= LdrpManifestProberRoutine(LdrEntry
->DllBase
, LdrEntry
->FullDllName
.Buffer
, &LdrEntry
->EntryPointActivationContext
);
704 if (!NT_SUCCESS(Status2
) &&
705 Status2
!= STATUS_NO_SUCH_FILE
&&
706 Status2
!= STATUS_RESOURCE_DATA_NOT_FOUND
&&
707 Status2
!= STATUS_RESOURCE_TYPE_NOT_FOUND
&&
708 Status2
!= STATUS_RESOURCE_NAME_NOT_FOUND
&&
709 Status2
!= STATUS_RESOURCE_LANG_NOT_FOUND
)
711 /* Some serious issue */
712 //Status = Status2; // FIXME: Ignore that error for now
713 DbgPrintEx(DPFLTR_SXS_ID
,
714 DPFLTR_WARNING_LEVEL
,
715 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its "
716 "manifest, ntstatus = 0x%08lx\n",
717 &LdrEntry
->FullDllName
, Status
);
721 /* Check if we failed above */
722 if (!NT_SUCCESS(Status
)) return Status
;
724 /* Get the Active ActCtx */
725 if (!LdrEntry
->EntryPointActivationContext
)
727 Status
= RtlGetActiveActivationContext(&LdrEntry
->EntryPointActivationContext
);
729 if (!NT_SUCCESS(Status
))
732 DbgPrintEx(DPFLTR_SXS_ID
,
733 DPFLTR_WARNING_LEVEL
,
734 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
741 /* Activate the ActCtx */
742 RtlActivateActivationContextUnsafeFast(&ActCtx
,
743 LdrEntry
->EntryPointActivationContext
);
745 /* Check if we were redirected */
746 if (!(LdrEntry
->Flags
& LDRP_REDIRECTED
))
748 /* Get the Bound IAT */
749 BoundEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
751 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
755 /* Get the regular IAT, for fallback */
756 ImportEntry
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
758 IMAGE_DIRECTORY_ENTRY_IMPORT
,
761 /* Check if we got at least one */
762 if ((BoundEntry
) || (ImportEntry
))
764 /* Do we have a Bound IAT */
767 /* Handle the descriptor */
768 Status
= LdrpHandleNewFormatImportDescriptors(DllPath
,
774 /* Handle the descriptor */
775 Status
= LdrpHandleOldFormatImportDescriptors(DllPath
,
780 /* Check the status of the handlers */
781 if (NT_SUCCESS(Status
))
783 /* Check for Per-DLL Heap Tagging */
784 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAG_BY_DLL
)
787 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
790 /* Check if Page Heap was enabled */
791 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
793 /* Initialize target DLL */
794 AVrfPageHeapDllNotification(LdrEntry
);
797 /* Check if Application Verifier was enabled */
798 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
801 DPRINT1("We don't support Application Verifier yet!\n");
804 /* Just to be safe */
805 Status
= STATUS_SUCCESS
;
809 /* Release the activation context */
810 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
812 DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry
->BaseDllName
, LdrEntry
);
818 /* FIXME: This function is missing SxS support */
821 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL
,
823 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
,
824 OUT PBOOLEAN Existing
)
826 ANSI_STRING AnsiString
;
827 PUNICODE_STRING ImpDescName
;
829 BOOLEAN GotExtension
;
832 PPEB Peb
= RtlGetCurrentPeb();
833 PTEB Teb
= NtCurrentTeb();
835 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p)\n", DllPath
, ImportName
, DataTableEntry
, Existing
);
837 /* Convert import descriptor name to unicode string */
838 ImpDescName
= &Teb
->StaticUnicodeString
;
839 RtlInitAnsiString(&AnsiString
, ImportName
);
840 Status
= RtlAnsiStringToUnicodeString(ImpDescName
, &AnsiString
, FALSE
);
841 if (!NT_SUCCESS(Status
)) return Status
;
843 /* Find the extension, if present */
844 p
= ImpDescName
->Buffer
+ ImpDescName
->Length
/ sizeof(WCHAR
) - 1;
845 GotExtension
= FALSE
;
846 while (p
>= ImpDescName
->Buffer
)
860 /* If no extension was found, add the default extension */
863 /* Check that we have space to add one */
864 if ((ImpDescName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
)) >=
865 sizeof(Teb
->StaticUnicodeBuffer
))
867 /* No space to add the extension */
868 DbgPrintEx(DPFLTR_LDR_ID
,
870 "LDR: %s - Dll name missing extension; with extension "
871 "added the name is too long\n"
872 " ImpDescName: (@ %p) \"%wZ\"\n"
873 " ImpDescName->Length: %u\n",
877 ImpDescName
->Length
);
878 return STATUS_NAME_TOO_LONG
;
881 /* Add it. Needs to be null terminated, thus the length check above */
882 (VOID
)RtlAppendUnicodeStringToString(ImpDescName
,
883 &LdrApiDefaultExtension
);
886 /* Check if it's loaded */
887 if (LdrpCheckForLoadedDll(DllPath
,
893 /* It's already existing in the list */
895 return STATUS_SUCCESS
;
898 /* We're loading it for the first time */
904 ACTCTX_SECTION_KEYED_DATA data
;
907 //DPRINT1("find_actctx_dll for %S\n", fullname);
908 //RtlInitUnicodeString(&nameW, libname);
909 data
.cbSize
= sizeof(data
);
910 status
= RtlFindActivationContextSectionString(
911 FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
912 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
915 //if (status != STATUS_SUCCESS) return status;
916 DPRINT1("Status: 0x%08X\n", status
);
918 if (NT_SUCCESS(status
))
920 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*info
;
921 SIZE_T needed
, size
= 1024;
925 if (!(info
= RtlAllocateHeap(RtlGetProcessHeap(), 0, size
)))
927 status
= STATUS_NO_MEMORY
;
930 status
= RtlQueryInformationActivationContext(0, data
.hActCtx
, &data
.ulAssemblyRosterIndex
,
931 AssemblyDetailedInformationInActivationContext
,
932 info
, size
, &needed
);
933 if (status
== STATUS_SUCCESS
) break;
934 if (status
!= STATUS_BUFFER_TOO_SMALL
) goto done
;
935 RtlFreeHeap(RtlGetProcessHeap(), 0, info
);
939 DPRINT("manifestpath === %S\n", info
->lpAssemblyManifestPath
);
940 DPRINT("DirectoryName === %S\n", info
->lpAssemblyDirectoryName
);
947 Status
= LdrpMapDll(DllPath
,
955 if (!NT_SUCCESS(Status
)) return Status
;
957 /* Walk its import descriptor table */
958 Status
= LdrpWalkImportDescriptor(DllPath
,
960 if (!NT_SUCCESS(Status
))
962 /* Add it to the in-init-order list in case of failure */
963 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
964 &(*DataTableEntry
)->InInitializationOrderLinks
);
972 LdrpSnapThunk(IN PVOID ExportBase
,
974 IN PIMAGE_THUNK_DATA OriginalThunk
,
975 IN OUT PIMAGE_THUNK_DATA Thunk
,
976 IN PIMAGE_EXPORT_DIRECTORY ExportEntry
,
983 ULONG OriginalOrdinal
= 0;
984 PIMAGE_IMPORT_BY_NAME AddressOfData
;
986 PUSHORT OrdinalTable
;
987 LPSTR ImportName
= NULL
;
990 ULONG_PTR HardErrorParameters
[3];
991 UNICODE_STRING HardErrorDllName
, HardErrorEntryPointName
;
992 ANSI_STRING TempString
;
995 PULONG AddressOfFunctions
;
996 UNICODE_STRING TempUString
;
997 ANSI_STRING ForwarderName
;
998 PANSI_STRING ForwardName
;
999 PVOID ForwarderHandle
;
1000 ULONG ForwardOrdinal
;
1002 /* Check if the snap is by ordinal */
1003 if ((IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(OriginalThunk
->u1
.Ordinal
)))
1005 /* Get the ordinal number, and its normalized version */
1006 OriginalOrdinal
= IMAGE_ORDINAL(OriginalThunk
->u1
.Ordinal
);
1007 Ordinal
= (USHORT
)(OriginalOrdinal
- ExportEntry
->Base
);
1011 /* First get the data VA */
1012 AddressOfData
= (PIMAGE_IMPORT_BY_NAME
)
1013 ((ULONG_PTR
)ImportBase
+
1014 ((ULONG_PTR
)OriginalThunk
->u1
.AddressOfData
& 0xffffffff));
1017 ImportName
= (LPSTR
)AddressOfData
->Name
;
1019 /* Now get the VA of the Name and Ordinal Tables */
1020 NameTable
= (PULONG
)((ULONG_PTR
)ExportBase
+
1021 (ULONG_PTR
)ExportEntry
->AddressOfNames
);
1022 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)ExportBase
+
1023 (ULONG_PTR
)ExportEntry
->AddressOfNameOrdinals
);
1026 Hint
= AddressOfData
->Hint
;
1028 /* Try to get a match by using the hint */
1029 if (((ULONG
)Hint
< ExportEntry
->NumberOfNames
) &&
1030 (!strcmp(ImportName
, ((LPSTR
)((ULONG_PTR
)ExportBase
+ NameTable
[Hint
])))))
1032 /* We got a match, get the Ordinal from the hint */
1033 Ordinal
= OrdinalTable
[Hint
];
1037 /* Well bummer, hint didn't work, do it the long way */
1038 Ordinal
= LdrpNameToOrdinal(ImportName
,
1039 ExportEntry
->NumberOfNames
,
1046 /* Check if the ordinal is invalid */
1047 if ((ULONG
)Ordinal
>= ExportEntry
->NumberOfFunctions
)
1050 /* Is this a static snap? */
1053 /* Inform the debug log */
1055 DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
1057 DPRINT1("Failed to snap %s\n", ImportName
);
1059 /* These are critical errors. Setup a string for the DLL name */
1060 RtlInitAnsiString(&TempString
, DllName
? DllName
: "Unknown");
1061 RtlAnsiStringToUnicodeString(&HardErrorDllName
, &TempString
, TRUE
);
1063 /* Set it as the parameter */
1064 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllName
;
1067 /* Check if we have an ordinal */
1070 /* Then set the ordinal as the 1st parameter */
1071 HardErrorParameters
[0] = OriginalOrdinal
;
1075 /* We don't, use the entrypoint. Set up a string for it */
1076 RtlInitAnsiString(&TempString
, ImportName
);
1077 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName
,
1081 /* Set it as the parameter */
1082 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorEntryPointName
;
1086 /* Raise the error */
1087 NtRaiseHardError(IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1088 STATUS_ENTRYPOINT_NOT_FOUND
,
1091 HardErrorParameters
,
1095 /* Increase the error count */
1096 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1098 /* Free our string */
1099 RtlFreeUnicodeString(&HardErrorDllName
);
1102 /* Free our second string. Return entrypoint error */
1103 RtlFreeUnicodeString(&HardErrorEntryPointName
);
1104 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND
);
1107 /* Return ordinal error */
1108 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND
);
1112 /* Inform the debug log */
1114 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal
);
1116 DPRINT("Non-fatal: Failed to snap %s\n", ImportName
);
1119 /* Set this as a bad DLL */
1120 Thunk
->u1
.Function
= (ULONG_PTR
)0xffbadd11;
1122 /* Return the right error code */
1123 Status
= IsOrdinal
? STATUS_ORDINAL_NOT_FOUND
:
1124 STATUS_ENTRYPOINT_NOT_FOUND
;
1128 /* The ordinal seems correct, get the AddressOfFunctions VA */
1129 AddressOfFunctions
= (PULONG
)
1130 ((ULONG_PTR
)ExportBase
+
1131 (ULONG_PTR
)ExportEntry
->AddressOfFunctions
);
1133 /* Write the function pointer*/
1134 Thunk
->u1
.Function
= (ULONG_PTR
)ExportBase
+ AddressOfFunctions
[Ordinal
];
1136 /* Make sure it's within the exports */
1137 if ((Thunk
->u1
.Function
> (ULONG_PTR
)ExportEntry
) &&
1138 (Thunk
->u1
.Function
< ((ULONG_PTR
)ExportEntry
+ ExportSize
)))
1140 /* Get the Import and Forwarder Names */
1141 ImportName
= (LPSTR
)Thunk
->u1
.Function
;
1142 ForwarderName
.Buffer
= ImportName
;
1143 ForwarderName
.Length
= (USHORT
)(strchr(ImportName
, '.') - ImportName
);
1144 ForwarderName
.MaximumLength
= ForwarderName
.Length
;
1145 Status
= RtlAnsiStringToUnicodeString(&TempUString
,
1149 /* Make sure the conversion was OK */
1150 if (NT_SUCCESS(Status
))
1152 /* Load the forwarder, free the temp string */
1153 Status
= LdrpLoadDll(FALSE
,
1159 RtlFreeUnicodeString(&TempUString
);
1162 /* If the load or conversion failed, use the failure path */
1163 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1165 /* Now set up a name for the actual forwarder dll */
1166 RtlInitAnsiString(&ForwarderName
,
1167 ImportName
+ ForwarderName
.Length
+ sizeof(CHAR
));
1169 /* Check if it's an ordinal forward */
1170 if ((ForwarderName
.Length
> 1) && (*ForwarderName
.Buffer
== '#'))
1172 /* We don't have an actual function name */
1175 /* Convert the string into an ordinal */
1176 Status
= RtlCharToInteger(ForwarderName
.Buffer
+ sizeof(CHAR
),
1180 /* If this fails, then error out */
1181 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1185 /* Import by name */
1186 ForwardName
= &ForwarderName
;
1189 /* Get the pointer */
1190 Status
= LdrpGetProcedureAddress(ForwarderHandle
,
1193 (PVOID
*)&Thunk
->u1
.Function
,
1195 /* If this fails, then error out */
1196 if (!NT_SUCCESS(Status
)) goto FailurePath
;
1200 /* It's not within the exports, let's hope it's valid */
1201 if (!AddressOfFunctions
[Ordinal
]) goto FailurePath
;
1204 /* If we got here, then it's success */
1205 Status
= STATUS_SUCCESS
;