3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Provides routines for loading PE files.
5 * (Deprecated remark) To be merged with arch/i386/loader.c in future.
7 * COPYRIGHT: Copyright 1998-2003 Brian Palmer <brianp@sginet.com>
8 * Copyright 2006-2019 Aleksey Bragin <aleksey@reactos.org>
10 * NOTES: The source code in this file is based on the work of respective
11 * authors of PE loading code in ReactOS and Brian Palmer and
12 * Alex Ionescu's arch/i386/loader.c, and my research project
13 * (creating a native EFI loader for Windows).
15 * This article was very handy during development:
16 * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
19 /* INCLUDES ***************************************************************/
24 DBG_DEFAULT_CHANNEL(PELOADER
);
26 /* FUNCTIONS **************************************************************/
29 WinLdrpCompareDllName(IN PCH DllName
,
30 IN PUNICODE_STRING UnicodeName
);
33 WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead
,
36 IN PIMAGE_THUNK_DATA ThunkData
,
37 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
39 IN BOOLEAN ProcessForwards
,
40 IN PCSTR DirectoryPath
);
43 WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead
,
46 PLDR_DATA_TABLE_ENTRY
*DataTableEntry
);
49 WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead
,
52 IN PIMAGE_THUNK_DATA ThunkData
,
53 IN PCSTR DirectoryPath
);
56 /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
58 WinLdrCheckForLoadedDll(IN OUT PLIST_ENTRY ModuleListHead
,
60 OUT PLDR_DATA_TABLE_ENTRY
*LoadedEntry
)
62 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
63 LIST_ENTRY
*ModuleEntry
;
65 TRACE("WinLdrCheckForLoadedDll: DllName %s\n", DllName
);
67 /* Just go through each entry in the LoadOrderList and compare loaded module's
68 name with a given name */
69 ModuleEntry
= ModuleListHead
->Flink
;
70 while (ModuleEntry
!= ModuleListHead
)
72 /* Get pointer to the current DTE */
73 DataTableEntry
= CONTAINING_RECORD(ModuleEntry
,
77 TRACE("WinLdrCheckForLoadedDll: DTE %p, EP %p, base %p name '%.*ws'\n",
78 DataTableEntry
, DataTableEntry
->EntryPoint
, DataTableEntry
->DllBase
,
79 DataTableEntry
->BaseDllName
.Length
/ 2, VaToPa(DataTableEntry
->BaseDllName
.Buffer
));
82 if (WinLdrpCompareDllName(DllName
, &DataTableEntry
->BaseDllName
))
84 /* Yes, found it, report pointer to the loaded module's DTE
85 to the caller and increase load count for it */
86 *LoadedEntry
= DataTableEntry
;
87 DataTableEntry
->LoadCount
++;
88 TRACE("WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry
);
92 /* Go to the next entry */
93 ModuleEntry
= ModuleEntry
->Flink
;
101 WinLdrScanImportDescriptorTable(IN OUT PLIST_ENTRY ModuleListHead
,
102 IN PCCH DirectoryPath
,
103 IN PLDR_DATA_TABLE_ENTRY ScanDTE
)
105 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
106 PIMAGE_IMPORT_DESCRIPTOR ImportTable
;
107 ULONG ImportTableSize
;
111 /* Get a pointer to the import table of this image */
112 ImportTable
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(VaToPa(ScanDTE
->DllBase
),
113 TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &ImportTableSize
);
117 UNICODE_STRING BaseName
;
118 BaseName
.Buffer
= VaToPa(ScanDTE
->BaseDllName
.Buffer
);
119 BaseName
.MaximumLength
= ScanDTE
->BaseDllName
.MaximumLength
;
120 BaseName
.Length
= ScanDTE
->BaseDllName
.Length
;
121 TRACE("WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",
122 &BaseName
, ImportTable
);
126 /* If image doesn't have any import directory - just return success */
127 if (ImportTable
== NULL
)
130 /* Loop through all entries */
131 for (;(ImportTable
->Name
!= 0) && (ImportTable
->FirstThunk
!= 0);ImportTable
++)
133 /* Get pointer to the name */
134 ImportName
= (PCH
)VaToPa(RVA(ScanDTE
->DllBase
, ImportTable
->Name
));
135 TRACE("WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName
);
137 /* In case we get a reference to ourselves - just skip it */
138 if (WinLdrpCompareDllName(ImportName
, &ScanDTE
->BaseDllName
))
141 /* Load the DLL if it is not already loaded */
142 if (!WinLdrCheckForLoadedDll(ModuleListHead
, ImportName
, &DataTableEntry
))
144 Success
= WinLdrpLoadAndScanReferencedDll(ModuleListHead
,
150 ERR("WinLdrpLoadAndScanReferencedDll() failed\n");
155 /* Scan its import address table */
156 Success
= WinLdrpScanImportAddressTable(ModuleListHead
,
157 DataTableEntry
->DllBase
,
159 (PIMAGE_THUNK_DATA
)RVA(ScanDTE
->DllBase
, ImportTable
->FirstThunk
),
164 ERR("WinLdrpScanImportAddressTable() failed: ImportName = '%s', DirectoryPath = '%s'\n",
165 ImportName
, DirectoryPath
);
174 WinLdrAllocateDataTableEntry(IN OUT PLIST_ENTRY ModuleListHead
,
178 OUT PLDR_DATA_TABLE_ENTRY
*NewEntry
)
180 PVOID BaseVA
= PaToVa(BasePA
);
182 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
183 PIMAGE_NT_HEADERS NtHeaders
;
185 TRACE("WinLdrAllocateDataTableEntry(, '%s', '%s', %p)\n",
186 BaseDllName
, FullDllName
, BasePA
);
188 /* Allocate memory for a data table entry, zero-initialize it */
189 DataTableEntry
= (PLDR_DATA_TABLE_ENTRY
)FrLdrHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY
),
191 if (DataTableEntry
== NULL
)
193 RtlZeroMemory(DataTableEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
195 /* Get NT headers from the image */
196 NtHeaders
= RtlImageNtHeader(BasePA
);
198 /* Initialize corresponding fields of DTE based on NT headers value */
199 DataTableEntry
->DllBase
= BaseVA
;
200 DataTableEntry
->SizeOfImage
= NtHeaders
->OptionalHeader
.SizeOfImage
;
201 DataTableEntry
->EntryPoint
= RVA(BaseVA
, NtHeaders
->OptionalHeader
.AddressOfEntryPoint
);
202 DataTableEntry
->SectionPointer
= 0;
203 DataTableEntry
->CheckSum
= NtHeaders
->OptionalHeader
.CheckSum
;
205 /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
206 by simple conversion - copying each character */
207 Length
= (USHORT
)(strlen(BaseDllName
) * sizeof(WCHAR
));
208 Buffer
= (PWSTR
)FrLdrHeapAlloc(Length
, TAG_WLDR_NAME
);
211 FrLdrHeapFree(DataTableEntry
, TAG_WLDR_DTE
);
214 RtlZeroMemory(Buffer
, Length
);
216 DataTableEntry
->BaseDllName
.Length
= Length
;
217 DataTableEntry
->BaseDllName
.MaximumLength
= Length
;
218 DataTableEntry
->BaseDllName
.Buffer
= PaToVa(Buffer
);
219 while (*BaseDllName
!= 0)
221 *Buffer
++ = *BaseDllName
++;
224 /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
225 using the same method */
226 Length
= (USHORT
)(strlen(FullDllName
) * sizeof(WCHAR
));
227 Buffer
= (PWSTR
)FrLdrHeapAlloc(Length
, TAG_WLDR_NAME
);
230 FrLdrHeapFree(DataTableEntry
, TAG_WLDR_DTE
);
233 RtlZeroMemory(Buffer
, Length
);
235 DataTableEntry
->FullDllName
.Length
= Length
;
236 DataTableEntry
->FullDllName
.MaximumLength
= Length
;
237 DataTableEntry
->FullDllName
.Buffer
= PaToVa(Buffer
);
238 while (*FullDllName
!= 0)
240 *Buffer
++ = *FullDllName
++;
243 /* Initialize what's left - LoadCount which is 1, and set Flags so that
244 we know this entry is processed */
245 DataTableEntry
->Flags
= LDRP_ENTRY_PROCESSED
;
246 DataTableEntry
->LoadCount
= 1;
248 /* Insert this DTE to a list in the LPB */
249 InsertTailList(ModuleListHead
, &DataTableEntry
->InLoadOrderLinks
);
250 TRACE("Inserting DTE %p, name='%.*S' DllBase=%p \n", DataTableEntry
,
251 DataTableEntry
->BaseDllName
.Length
/ 2,
252 VaToPa(DataTableEntry
->BaseDllName
.Buffer
),
253 DataTableEntry
->DllBase
);
255 /* Save pointer to a newly allocated and initialized entry */
256 *NewEntry
= DataTableEntry
;
263 * WinLdrLoadImage loads the specified image from the file (it doesn't
264 * perform any additional operations on the filename, just directly
265 * calls the file I/O routines), and relocates it so that it's ready
266 * to be used when paging is enabled.
267 * Addressing mode: physical
270 WinLdrLoadImage(IN PCHAR FileName
,
271 TYPE_OF_MEMORY MemoryType
,
272 OUT PVOID
*ImageBasePA
)
276 PVOID VirtualBase
= NULL
;
277 UCHAR HeadersBuffer
[SECTOR_SIZE
* 2];
278 PIMAGE_NT_HEADERS NtHeaders
;
279 PIMAGE_SECTION_HEADER SectionHeader
;
280 ULONG VirtualSize
, SizeOfRawData
, NumberOfSections
;
282 LARGE_INTEGER Position
;
284 TRACE("WinLdrLoadImage(%s, %ld, *)\n", FileName
, MemoryType
);
286 /* Open the image file */
287 Status
= ArcOpen(FileName
, OpenReadOnly
, &FileId
);
288 if (Status
!= ESUCCESS
)
290 ERR("ArcOpen(FileName: \"%s\", OpenReadOnly: %u) failed. Status %u\n", FileName
, OpenReadOnly
, Status
);
294 /* Load the first 2 sectors of the image so we can read the PE header */
295 Status
= ArcRead(FileId
, HeadersBuffer
, SECTOR_SIZE
* 2, &BytesRead
);
296 if (Status
!= ESUCCESS
)
298 ERR("ArcRead(File: '%s') failed. Status: %u\n", FileName
, Status
);
299 UiMessageBox("Error reading from file.");
304 /* Now read the MZ header to get the offset to the PE Header */
305 NtHeaders
= RtlImageNtHeader(HeadersBuffer
);
308 ERR("No NT header found in \"%s\"\n", FileName
);
309 UiMessageBox("Error - no NT header found.");
314 /* Ensure this is executable image */
315 if (((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
) == 0))
317 ERR("Not an executable image \"%s\"\n", FileName
);
318 UiMessageBox("Not an executable image.");
323 /* Store number of sections to read and a pointer to the first section */
324 NumberOfSections
= NtHeaders
->FileHeader
.NumberOfSections
;
325 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
327 /* Try to allocate this memory, if fails - allocate somewhere else */
328 PhysicalBase
= MmAllocateMemoryAtAddress(NtHeaders
->OptionalHeader
.SizeOfImage
,
329 (PVOID
)((ULONG
)NtHeaders
->OptionalHeader
.ImageBase
& (KSEG0_BASE
- 1)),
332 if (PhysicalBase
== NULL
)
334 /* It's ok, we don't panic - let's allocate again at any other "low" place */
335 PhysicalBase
= MmAllocateMemoryWithType(NtHeaders
->OptionalHeader
.SizeOfImage
, MemoryType
);
337 if (PhysicalBase
== NULL
)
339 ERR("Failed to alloc %lu bytes for image %s\n", NtHeaders
->OptionalHeader
.SizeOfImage
, FileName
);
340 UiMessageBox("Failed to alloc pages for image.");
346 /* This is the real image base - in form of a virtual address */
347 VirtualBase
= PaToVa(PhysicalBase
);
349 TRACE("Base PA: 0x%X, VA: 0x%X\n", PhysicalBase
, VirtualBase
);
351 /* Set to 0 position and fully load the file image */
352 Position
.QuadPart
= 0;
353 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
354 if (Status
!= ESUCCESS
)
356 ERR("ArcSeek(File: '%s') failed. Status: 0x%lx\n", FileName
, Status
);
357 UiMessageBox("Error seeking the start of a file.");
362 Status
= ArcRead(FileId
, PhysicalBase
, NtHeaders
->OptionalHeader
.SizeOfHeaders
, &BytesRead
);
363 if (Status
!= ESUCCESS
)
365 ERR("ArcRead(File: '%s') failed. Status: %u\n", FileName
, Status
);
366 UiMessageBox("Error reading headers.");
371 /* Reload the NT Header */
372 NtHeaders
= RtlImageNtHeader(PhysicalBase
);
374 /* Load the first section */
375 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
377 /* Fill output parameters */
378 *ImageBasePA
= PhysicalBase
;
380 /* Walk through each section and read it (check/fix any possible
381 bad situations, if they arise) */
382 for (i
= 0; i
< NumberOfSections
; i
++)
384 VirtualSize
= SectionHeader
->Misc
.VirtualSize
;
385 SizeOfRawData
= SectionHeader
->SizeOfRawData
;
387 /* Handle a case when VirtualSize equals 0 */
388 if (VirtualSize
== 0)
389 VirtualSize
= SizeOfRawData
;
391 /* If PointerToRawData is 0, then force its size to be also 0 */
392 if (SectionHeader
->PointerToRawData
== 0)
398 /* Cut the loaded size to the VirtualSize extents */
399 if (SizeOfRawData
> VirtualSize
)
400 SizeOfRawData
= VirtualSize
;
403 /* Actually read the section (if its size is not 0) */
404 if (SizeOfRawData
!= 0)
406 /* Seek to the correct position */
407 Position
.LowPart
= SectionHeader
->PointerToRawData
;
408 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
410 TRACE("SH->VA: 0x%X\n", SectionHeader
->VirtualAddress
);
412 /* Read this section from the file, size = SizeOfRawData */
413 Status
= ArcRead(FileId
, (PUCHAR
)PhysicalBase
+ SectionHeader
->VirtualAddress
, SizeOfRawData
, &BytesRead
);
414 if (Status
!= ESUCCESS
)
416 ERR("WinLdrLoadImage(): Error reading section from file!\n");
421 /* Size of data is less than the virtual size - fill up the remainder with zeroes */
422 if (SizeOfRawData
< VirtualSize
)
424 TRACE("WinLdrLoadImage(): SORD %d < VS %d\n", SizeOfRawData
, VirtualSize
);
425 RtlZeroMemory((PVOID
)(SectionHeader
->VirtualAddress
+ (ULONG_PTR
)PhysicalBase
+ SizeOfRawData
), VirtualSize
- SizeOfRawData
);
431 /* We are done with the file - close it */
434 /* If loading failed - return right now */
435 if (Status
!= ESUCCESS
)
438 /* Relocate the image, if it needs it */
439 if (NtHeaders
->OptionalHeader
.ImageBase
!= (ULONG_PTR
)VirtualBase
)
441 WARN("Relocating %p -> %p\n", NtHeaders
->OptionalHeader
.ImageBase
,
443 return (BOOLEAN
)LdrRelocateImageWithBias(PhysicalBase
,
444 (ULONG_PTR
)VirtualBase
- (ULONG_PTR
)PhysicalBase
,
447 TRUE
, /* in case of conflict still return success */
451 TRACE("WinLdrLoadImage() done, PA = %p\n", *ImageBasePA
);
455 /* PRIVATE FUNCTIONS *******************************************************/
457 /* DllName - physical, UnicodeString->Buffer - virtual */
459 WinLdrpCompareDllName(IN PCH DllName
,
460 IN PUNICODE_STRING UnicodeName
)
465 /* First obvious check: for length of two names */
466 Length
= strlen(DllName
);
470 UNICODE_STRING UnicodeNamePA
;
471 UnicodeNamePA
.Length
= UnicodeName
->Length
;
472 UnicodeNamePA
.MaximumLength
= UnicodeName
->MaximumLength
;
473 UnicodeNamePA
.Buffer
= VaToPa(UnicodeName
->Buffer
);
474 TRACE("WinLdrpCompareDllName: %s and %wZ, Length = %d "
475 "UN->Length %d\n", DllName
, &UnicodeNamePA
, Length
, UnicodeName
->Length
);
479 if ((Length
* sizeof(WCHAR
)) > UnicodeName
->Length
)
482 /* Store pointer to unicode string's buffer */
483 Buffer
= VaToPa(UnicodeName
->Buffer
);
485 /* Loop character by character */
486 for (i
= 0; i
< Length
; i
++)
488 /* Compare two characters, uppercasing them */
489 if (toupper(*DllName
) != toupper((CHAR
)*Buffer
))
492 /* Move to the next character */
497 /* Check, if strings either fully match, or match till the "." (w/o extension) */
498 if ((UnicodeName
->Length
== Length
* sizeof(WCHAR
)) || (*Buffer
== L
'.'))
504 /* Strings don't match, return FALSE */
509 WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead
,
512 IN PIMAGE_THUNK_DATA ThunkData
,
513 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
515 IN BOOLEAN ProcessForwards
,
516 IN PCSTR DirectoryPath
)
519 PULONG NameTable
, FunctionTable
;
520 PUSHORT OrdinalTable
;
521 LONG High
, Low
, Middle
, Result
;
523 PIMAGE_IMPORT_BY_NAME ImportData
;
524 PCHAR ExportName
, ForwarderName
;
527 //TRACE("WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
528 // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
530 /* Check passed DllBase param */
533 WARN("DllBase == NULL!\n");
537 /* Convert all non-critical pointers to PA from VA */
538 ThunkData
= VaToPa(ThunkData
);
540 /* Is the reference by ordinal? */
541 if (IMAGE_SNAP_BY_ORDINAL(ThunkData
->u1
.Ordinal
) && !ProcessForwards
)
543 /* Yes, calculate the ordinal */
544 Ordinal
= (ULONG
)(IMAGE_ORDINAL(ThunkData
->u1
.Ordinal
) - (UINT32
)ExportDirectory
->Base
);
545 //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
549 /* It's reference by name, we have to look it up in the export directory */
550 if (!ProcessForwards
)
552 /* AddressOfData in thunk entry will become a virtual address (from relative) */
553 //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData);
554 ThunkData
->u1
.AddressOfData
=
555 (ULONG_PTR
)RVA(ImageBase
, ThunkData
->u1
.AddressOfData
);
556 //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData);
559 /* Get the import name */
560 ImportData
= VaToPa((PVOID
)ThunkData
->u1
.AddressOfData
);
562 /* Get pointers to Name and Ordinal tables (RVA -> VA) */
563 NameTable
= VaToPa(RVA(DllBase
, ExportDirectory
->AddressOfNames
));
564 OrdinalTable
= VaToPa(RVA(DllBase
, ExportDirectory
->AddressOfNameOrdinals
));
566 //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
567 // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals);
569 /* Get the hint, convert it to a physical pointer */
570 Hint
= ((PIMAGE_IMPORT_BY_NAME
)VaToPa((PVOID
)ThunkData
->u1
.AddressOfData
))->Hint
;
571 //TRACE("HintIndex %d\n", Hint);
573 /* Get the export name from the hint */
574 ExportName
= VaToPa(RVA(DllBase
, NameTable
[Hint
]));
576 /* If Hint is less than total number of entries in the export directory,
577 and import name == export name, then we can just get it from the OrdinalTable */
578 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
579 (strcmp(ExportName
, (PCHAR
)ImportData
->Name
) == 0))
581 Ordinal
= OrdinalTable
[Hint
];
582 //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
586 /* It's not the easy way, we have to lookup import name in the name table.
587 Let's use a binary search for this task. */
589 //TRACE("WinLdrpBindImportName() looking up the import name using binary search...\n");
591 /* Low boundary is set to 0, and high boundary to the maximum index */
593 High
= ExportDirectory
->NumberOfNames
- 1;
595 /* Perform a binary-search loop */
598 /* Divide by 2 by shifting to the right once */
599 Middle
= (Low
+ High
) / 2;
601 /* Get the name from the name table */
602 ExportName
= VaToPa(RVA(DllBase
, NameTable
[Middle
]));
604 /* Compare the names */
605 Result
= strcmp(ExportName
, (PCHAR
)ImportData
->Name
);
607 /*TRACE("Binary search: comparing Import '__', Export '%s'\n",*/
608 /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/
609 /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/
611 /*TRACE("TE->u1.AOD %p, fulladdr %p\n",
612 ThunkData->u1.AddressOfData,
613 ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/
616 /* Depending on result of strcmp, perform different actions */
619 /* Adjust top boundary */
624 /* Adjust bottom boundary */
634 /* If high boundary is less than low boundary, then no result found */
637 //Print(L"Error in binary search\n");
638 ERR("Did not find export '%s'!\n", (PCHAR
)ImportData
->Name
);
642 /* Everything alright, get the ordinal */
643 Ordinal
= OrdinalTable
[Middle
];
645 //TRACE("WinLdrpBindImportName() found Ordinal %d\n", Ordinal);
649 /* Check ordinal number for validity! */
650 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
652 ERR("Ordinal number is invalid!\n");
656 /* Get a pointer to the function table */
657 FunctionTable
= (PULONG
)VaToPa(RVA(DllBase
, ExportDirectory
->AddressOfFunctions
));
659 /* Save a pointer to the function */
660 ThunkData
->u1
.Function
= (ULONG_PTR
)RVA(DllBase
, FunctionTable
[Ordinal
]);
662 /* Is it a forwarder? (function pointer is within the export directory) */
663 ForwarderName
= (PCHAR
)VaToPa((PVOID
)ThunkData
->u1
.Function
);
664 if (((ULONG_PTR
)ForwarderName
> (ULONG_PTR
)ExportDirectory
) &&
665 ((ULONG_PTR
)ForwarderName
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
667 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
668 CHAR ForwardDllName
[255];
669 PIMAGE_EXPORT_DIRECTORY RefExportDirectory
;
671 TRACE("WinLdrpBindImportName(): ForwarderName %s\n", ForwarderName
);
673 /* Save the name of the forward dll */
674 RtlCopyMemory(ForwardDllName
, ForwarderName
, sizeof(ForwardDllName
));
676 /* Strip out the symbol name */
677 *strrchr(ForwardDllName
,'.') = '\0';
679 /* Check if the target image is already loaded */
680 if (!WinLdrCheckForLoadedDll(ModuleListHead
, ForwardDllName
, &DataTableEntry
))
682 /* Check if the forward dll name has an extension */
683 if (strchr(ForwardDllName
, '.') == NULL
)
685 /* Name does not have an extension, append '.dll' */
686 strcat(ForwardDllName
, ".dll");
689 /* Now let's try to load it! */
690 Success
= WinLdrpLoadAndScanReferencedDll(ModuleListHead
,
696 ERR("WinLdrpLoadAndScanReferencedDll() failed to load forwarder dll.\n");
701 /* Get pointer to the export directory of loaded DLL */
702 RefExportDirectory
= (PIMAGE_EXPORT_DIRECTORY
)
703 RtlImageDirectoryEntryToData(VaToPa(DataTableEntry
->DllBase
),
705 IMAGE_DIRECTORY_ENTRY_EXPORT
,
708 /* Fail if it's NULL */
709 if (RefExportDirectory
)
712 IMAGE_THUNK_DATA RefThunkData
;
713 PIMAGE_IMPORT_BY_NAME ImportByName
;
716 /* Get pointer to the import name */
717 ImportName
= strrchr(ForwarderName
, '.') + 1;
719 /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
720 ImportByName
= (PIMAGE_IMPORT_BY_NAME
)Buffer
;
722 /* Fill the name with the import name */
723 RtlCopyMemory(ImportByName
->Name
, ImportName
, strlen(ImportName
)+1);
726 ImportByName
->Hint
= 0;
728 /* And finally point ThunkData's AddressOfData to that structure */
729 RefThunkData
.u1
.AddressOfData
= (ULONG_PTR
)ImportByName
;
731 /* And recursively call ourselves */
732 Success
= WinLdrpBindImportName(ModuleListHead
,
733 DataTableEntry
->DllBase
,
741 /* Fill out the ThunkData with data from RefThunkData */
742 ThunkData
->u1
= RefThunkData
.u1
;
744 /* Return what we got from the recursive call */
749 /* Fail if ExportDirectory is NULL */
759 WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead
,
762 PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
764 CHAR FullDllName
[256];
768 /* Prepare the full path to the file to be loaded */
769 strcpy(FullDllName
, DirectoryPath
);
770 strcat(FullDllName
, ImportName
);
772 TRACE("Loading referenced DLL: %s\n", FullDllName
);
773 //Print(L"Loading referenced DLL: %s\n", FullDllName);
776 Success
= WinLdrLoadImage(FullDllName
, LoaderBootDriver
, &BasePA
);
779 ERR("WinLdrLoadImage() failed\n");
783 /* Allocate DTE for newly loaded DLL */
784 Success
= WinLdrAllocateDataTableEntry(ModuleListHead
,
791 ERR("WinLdrAllocateDataTableEntry() failed\n");
795 /* Scan its dependencies too */
796 TRACE("WinLdrScanImportDescriptorTable() calling ourselves for %S\n",
797 VaToPa((*DataTableEntry
)->BaseDllName
.Buffer
));
798 Success
= WinLdrScanImportDescriptorTable(ModuleListHead
, DirectoryPath
, *DataTableEntry
);
801 ERR("WinLdrScanImportDescriptorTable() failed\n");
809 WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead
,
812 IN PIMAGE_THUNK_DATA ThunkData
,
813 IN PCSTR DirectoryPath
)
815 PIMAGE_EXPORT_DIRECTORY ExportDirectory
= NULL
;
819 TRACE("WinLdrpScanImportAddressTable(): DllBase 0x%X, "
820 "ImageBase 0x%X, ThunkData 0x%X\n", DllBase
, ImageBase
, ThunkData
);
822 /* Obtain the export table from the DLL's base */
825 ERR("Error, DllBase == NULL!\n");
831 (PIMAGE_EXPORT_DIRECTORY
)RtlImageDirectoryEntryToData(VaToPa(DllBase
),
833 IMAGE_DIRECTORY_ENTRY_EXPORT
,
837 TRACE("WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory
);
839 /* If pointer to Export Directory is */
840 if (ExportDirectory
== NULL
)
842 ERR("DllBase=%p(%p)\n", DllBase
, VaToPa(DllBase
));
846 /* Go through each entry in the thunk table and bind it */
847 while (((PIMAGE_THUNK_DATA
)VaToPa(ThunkData
))->u1
.AddressOfData
!= 0)
850 Success
= WinLdrpBindImportName(ModuleListHead
,
859 /* Move to the next entry */
862 /* Return error if binding was unsuccessful */