3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: freeldr/winldr/peloader.c
5 * PURPOSE: Provides routines for loading PE files. To be merged with
6 * arch/i386/loader.c in future
7 * This article was very handy during development:
8 * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
9 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
10 * 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)
16 /* INCLUDES ***************************************************************/
22 WinLdrpCompareDllName(IN PCH DllName
,
23 IN PUNICODE_STRING UnicodeName
);
26 WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
29 IN PIMAGE_THUNK_DATA ThunkData
,
30 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
32 IN BOOLEAN ProcessForwards
);
35 WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock
,
38 PLDR_DATA_TABLE_ENTRY
*DataTableEntry
);
41 WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
44 IN PIMAGE_THUNK_DATA ThunkData
);
48 /* FUNCTIONS **************************************************************/
50 /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
52 WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
54 OUT PLDR_DATA_TABLE_ENTRY
*LoadedEntry
)
56 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
57 LIST_ENTRY
*ModuleEntry
;
59 DPRINTM(DPRINT_PELOADER
, "WinLdrCheckForLoadedDll: DllName %X, LoadedEntry: %X\n",
60 DllName
, LoadedEntry
);
62 /* Just go through each entry in the LoadOrderList and compare loaded module's
63 name with a given name */
64 ModuleEntry
= WinLdrBlock
->LoadOrderListHead
.Flink
;
65 while (ModuleEntry
!= &WinLdrBlock
->LoadOrderListHead
)
67 /* Get pointer to the current DTE */
68 DataTableEntry
= CONTAINING_RECORD(ModuleEntry
,
72 DPRINTM(DPRINT_PELOADER
, "WinLdrCheckForLoadedDll: DTE %p, EP %p\n",
73 DataTableEntry
, DataTableEntry
->EntryPoint
);
76 if (WinLdrpCompareDllName(DllName
, &DataTableEntry
->BaseDllName
))
78 /* Yes, found it, report pointer to the loaded module's DTE
79 to the caller and increase load count for it */
80 *LoadedEntry
= DataTableEntry
;
81 DataTableEntry
->LoadCount
++;
82 DPRINTM(DPRINT_PELOADER
, "WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry
);
86 /* Go to the next entry */
87 ModuleEntry
= ModuleEntry
->Flink
;
95 WinLdrScanImportDescriptorTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
96 IN PCCH DirectoryPath
,
97 IN PLDR_DATA_TABLE_ENTRY ScanDTE
)
99 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
100 PIMAGE_IMPORT_DESCRIPTOR ImportTable
;
101 ULONG ImportTableSize
;
105 /* Get a pointer to the import table of this image */
106 ImportTable
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(VaToPa(ScanDTE
->DllBase
),
107 TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &ImportTableSize
);
110 UNICODE_STRING BaseName
;
111 BaseName
.Buffer
= VaToPa(ScanDTE
->BaseDllName
.Buffer
);
112 BaseName
.MaximumLength
= ScanDTE
->BaseDllName
.MaximumLength
;
113 BaseName
.Length
= ScanDTE
->BaseDllName
.Length
;
114 DPRINTM(DPRINT_PELOADER
, "WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",
115 &BaseName
, ImportTable
);
118 /* If image doesn't have any import directory - just return success */
119 if (ImportTable
== NULL
)
122 /* Loop through all entries */
123 for (;(ImportTable
->Name
!= 0) && (ImportTable
->FirstThunk
!= 0);ImportTable
++)
125 /* Get pointer to the name */
126 ImportName
= (PCH
)VaToPa(RVA(ScanDTE
->DllBase
, ImportTable
->Name
));
127 DPRINTM(DPRINT_PELOADER
, "WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName
);
129 /* In case we get a reference to ourselves - just skip it */
130 if (WinLdrpCompareDllName(ImportName
, &ScanDTE
->BaseDllName
))
133 /* Load the DLL if it is not already loaded */
134 if (!WinLdrCheckForLoadedDll(WinLdrBlock
, ImportName
, &DataTableEntry
))
136 Status
= WinLdrpLoadAndScanReferencedDll(WinLdrBlock
,
143 DPRINTM(DPRINT_PELOADER
, "WinLdrpLoadAndScanReferencedDll() failed\n");
148 /* Scan its import address table */
149 Status
= WinLdrpScanImportAddressTable(
151 DataTableEntry
->DllBase
,
153 (PIMAGE_THUNK_DATA
)RVA(ScanDTE
->DllBase
, ImportTable
->FirstThunk
));
157 DPRINTM(DPRINT_PELOADER
, "WinLdrpScanImportAddressTable() failed\n");
166 WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
170 OUT PLDR_DATA_TABLE_ENTRY
*NewEntry
)
172 PVOID BaseVA
= PaToVa(BasePA
);
174 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
175 PIMAGE_NT_HEADERS NtHeaders
;
178 /* Allocate memory for a data table entry, zero-initialize it */
179 DataTableEntry
= (PLDR_DATA_TABLE_ENTRY
)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY
));
180 if (DataTableEntry
== NULL
)
182 RtlZeroMemory(DataTableEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
184 /* Get NT headers from the image */
185 NtHeaders
= RtlImageNtHeader(BasePA
);
187 /* Initialize corresponding fields of DTE based on NT headers value */
188 DataTableEntry
->DllBase
= BaseVA
;
189 DataTableEntry
->SizeOfImage
= NtHeaders
->OptionalHeader
.SizeOfImage
;
190 DataTableEntry
->EntryPoint
= RVA(BaseVA
, NtHeaders
->OptionalHeader
.AddressOfEntryPoint
);
191 DataTableEntry
->SectionPointer
= 0;
192 DataTableEntry
->CheckSum
= NtHeaders
->OptionalHeader
.CheckSum
;
194 /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
195 by simple conversion - copying each character */
196 Length
= (USHORT
)(strlen(BaseDllName
) * sizeof(WCHAR
));
197 Buffer
= (PWSTR
)MmHeapAlloc(Length
);
200 MmHeapFree(DataTableEntry
);
203 RtlZeroMemory(Buffer
, Length
);
205 DataTableEntry
->BaseDllName
.Length
= Length
;
206 DataTableEntry
->BaseDllName
.MaximumLength
= Length
;
207 DataTableEntry
->BaseDllName
.Buffer
= PaToVa(Buffer
);
208 while (*BaseDllName
!= 0)
210 *Buffer
++ = *BaseDllName
++;
213 /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
214 using the same method */
215 Length
= (USHORT
)(strlen(FullDllName
) * sizeof(WCHAR
));
216 Buffer
= (PWSTR
)MmHeapAlloc(Length
);
219 MmHeapFree(DataTableEntry
);
222 RtlZeroMemory(Buffer
, Length
);
224 DataTableEntry
->FullDllName
.Length
= Length
;
225 DataTableEntry
->FullDllName
.MaximumLength
= Length
;
226 DataTableEntry
->FullDllName
.Buffer
= PaToVa(Buffer
);
227 while (*FullDllName
!= 0)
229 *Buffer
++ = *FullDllName
++;
232 /* Initialize what's left - LoadCount which is 1, and set Flags so that
233 we know this entry is processed */
234 DataTableEntry
->Flags
= LDRP_ENTRY_PROCESSED
;
235 DataTableEntry
->LoadCount
= 1;
237 /* Insert this DTE to a list in the LPB */
238 InsertTailList(&WinLdrBlock
->LoadOrderListHead
, &DataTableEntry
->InLoadOrderLinks
);
240 /* Save pointer to a newly allocated and initialized entry */
241 *NewEntry
= DataTableEntry
;
247 /* WinLdrLoadImage loads the specified image from the file (it doesn't
248 perform any additional operations on the filename, just directly
249 calls the file I/O routines), and relocates it so that it's ready
250 to be used when paging is enabled.
251 Addressing mode: physical
254 WinLdrLoadImage(IN PCHAR FileName
,
255 TYPE_OF_MEMORY MemoryType
,
256 OUT PVOID
*ImageBasePA
)
260 PVOID VirtualBase
= NULL
;
261 UCHAR HeadersBuffer
[SECTOR_SIZE
* 2];
262 PIMAGE_NT_HEADERS NtHeaders
;
263 PIMAGE_SECTION_HEADER SectionHeader
;
264 ULONG VirtualSize
, SizeOfRawData
, NumberOfSections
;
266 LARGE_INTEGER Position
;
269 CHAR ProgressString
[256];
271 /* Inform user we are loading files */
272 sprintf(ProgressString
, "Loading %s...", strchr(FileName
, '\\') + 1);
274 UiDrawProgressBarCenter(1, 100, ProgressString
);
276 /* Open the image file */
277 Status
= ArcOpen(FileName
, OpenReadOnly
, &FileId
);
278 if (Status
!= ESUCCESS
)
280 UiMessageBox("Can not open the file");
284 /* Load the first 2 sectors of the image so we can read the PE header */
285 Status
= ArcRead(FileId
, HeadersBuffer
, SECTOR_SIZE
* 2, &BytesRead
);
286 if (Status
!= ESUCCESS
)
288 UiMessageBox("Error reading from file");
293 /* Now read the MZ header to get the offset to the PE Header */
294 NtHeaders
= RtlImageNtHeader(HeadersBuffer
);
298 //Print(L"Error - no NT header found in %s\n", FileName);
299 UiMessageBox("Error - no NT header found");
304 /* Ensure this is executable image */
305 if (((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
) == 0))
307 //Print(L"Not an executable image %s\n", FileName);
308 UiMessageBox("Not an executable image");
313 /* Store number of sections to read and a pointer to the first section */
314 NumberOfSections
= NtHeaders
->FileHeader
.NumberOfSections
;
315 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
317 /* Try to allocate this memory, if fails - allocate somewhere else */
318 PhysicalBase
= MmAllocateMemoryAtAddress(NtHeaders
->OptionalHeader
.SizeOfImage
,
319 (PVOID
)((ULONG
)NtHeaders
->OptionalHeader
.ImageBase
& (KSEG0_BASE
- 1)),
322 if (PhysicalBase
== NULL
)
324 /* It's ok, we don't panic - let's allocate again at any other "low" place */
325 PhysicalBase
= MmAllocateMemoryWithType(NtHeaders
->OptionalHeader
.SizeOfImage
, MemoryType
);
327 if (PhysicalBase
== NULL
)
329 //Print(L"Failed to alloc pages for image %s\n", FileName);
330 UiMessageBox("Failed to alloc pages for image");
336 /* This is the real image base - in form of a virtual address */
337 VirtualBase
= PaToVa(PhysicalBase
);
339 DPRINTM(DPRINT_PELOADER
, "Base PA: 0x%X, VA: 0x%X\n", PhysicalBase
, VirtualBase
);
341 /* Set to 0 position and fully load the file image */
342 Position
.HighPart
= Position
.LowPart
= 0;
343 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
344 if (Status
!= ESUCCESS
)
346 UiMessageBox("Error seeking to start of file");
351 Status
= ArcRead(FileId
, PhysicalBase
, NtHeaders
->OptionalHeader
.SizeOfHeaders
, &BytesRead
);
353 if (Status
!= ESUCCESS
)
355 //Print(L"Error reading headers %s\n", FileName);
356 UiMessageBox("Error reading headers");
361 /* Reload the NT Header */
362 NtHeaders
= RtlImageNtHeader(PhysicalBase
);
364 /* Load the first section */
365 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
367 /* Fill output parameters */
368 *ImageBasePA
= PhysicalBase
;
370 /* Walk through each section and read it (check/fix any possible
371 bad situations, if they arise) */
372 for (i
= 0; i
< NumberOfSections
; i
++)
374 VirtualSize
= SectionHeader
->Misc
.VirtualSize
;
375 SizeOfRawData
= SectionHeader
->SizeOfRawData
;
377 /* Handle a case when VirtualSize equals 0 */
378 if (VirtualSize
== 0)
379 VirtualSize
= SizeOfRawData
;
381 /* If PointerToRawData is 0, then force its size to be also 0 */
382 if (SectionHeader
->PointerToRawData
== 0)
388 /* Cut the loaded size to the VirtualSize extents */
389 if (SizeOfRawData
> VirtualSize
)
390 SizeOfRawData
= VirtualSize
;
393 /* Actually read the section (if its size is not 0) */
394 if (SizeOfRawData
!= 0)
396 /* Seek to the correct position */
397 Position
.LowPart
= SectionHeader
->PointerToRawData
;
398 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
400 DPRINTM(DPRINT_PELOADER
, "SH->VA: 0x%X\n", SectionHeader
->VirtualAddress
);
402 /* Read this section from the file, size = SizeOfRawData */
403 Status
= ArcRead(FileId
, (PUCHAR
)PhysicalBase
+ SectionHeader
->VirtualAddress
, SizeOfRawData
, &BytesRead
);
405 if (Status
!= ESUCCESS
)
407 DPRINTM(DPRINT_PELOADER
, "WinLdrLoadImage(): Error reading section from file!\n");
412 /* Size of data is less than the virtual size - fill up the remainder with zeroes */
413 if (SizeOfRawData
< VirtualSize
)
415 DPRINTM(DPRINT_PELOADER
, "WinLdrLoadImage(): SORD %d < VS %d\n", SizeOfRawData
, VirtualSize
);
416 RtlZeroMemory((PVOID
)(SectionHeader
->VirtualAddress
+ (ULONG_PTR
)PhysicalBase
+ SizeOfRawData
), VirtualSize
- SizeOfRawData
);
422 /* We are done with the file - close it */
425 /* If loading failed - return right now */
426 if (Status
!= ESUCCESS
)
430 /* Relocate the image, if it needs it */
431 if (NtHeaders
->OptionalHeader
.ImageBase
!= (ULONG_PTR
)VirtualBase
)
433 DPRINTM(DPRINT_PELOADER
, "Relocating %p -> %p\n",
434 NtHeaders
->OptionalHeader
.ImageBase
, VirtualBase
);
435 return (BOOLEAN
)LdrRelocateImageWithBias(PhysicalBase
,
436 (ULONG_PTR
)VirtualBase
- (ULONG_PTR
)PhysicalBase
,
439 TRUE
, /* in case of conflict still return success */
446 /* PRIVATE FUNCTIONS *******************************************************/
448 /* DllName - physical, UnicodeString->Buffer - virtual */
450 WinLdrpCompareDllName(IN PCH DllName
,
451 IN PUNICODE_STRING UnicodeName
)
454 UNICODE_STRING UnicodeNamePA
;
457 /* First obvious check: for length of two names */
458 Length
= strlen(DllName
);
460 UnicodeNamePA
.Length
= UnicodeName
->Length
;
461 UnicodeNamePA
.MaximumLength
= UnicodeName
->MaximumLength
;
462 UnicodeNamePA
.Buffer
= VaToPa(UnicodeName
->Buffer
);
463 DPRINTM(DPRINT_PELOADER
, "WinLdrpCompareDllName: %s and %wZ, Length = %d "
464 "UN->Length %d\n", DllName
, &UnicodeNamePA
, Length
, UnicodeName
->Length
);
466 if ((Length
* sizeof(WCHAR
)) > UnicodeName
->Length
)
469 /* Store pointer to unicode string's buffer */
470 Buffer
= VaToPa(UnicodeName
->Buffer
);
472 /* Loop character by character */
473 for (i
= 0; i
< Length
; i
++)
475 /* Compare two characters, uppercasing them */
476 if (toupper(*DllName
) != toupper((CHAR
)*Buffer
))
479 /* Move to the next character */
484 /* Check, if strings either fully match, or match till the "." (w/o extension) */
485 if ((UnicodeName
->Length
== Length
* sizeof(WCHAR
)) || (*Buffer
== L
'.'))
491 /* Strings don't match, return FALSE */
496 WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
499 IN PIMAGE_THUNK_DATA ThunkData
,
500 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
502 IN BOOLEAN ProcessForwards
)
505 PULONG NameTable
, FunctionTable
;
506 PUSHORT OrdinalTable
;
507 LONG High
, Low
, Middle
, Result
;
510 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
511 // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
513 /* Check passed DllBase param */
516 DPRINTM(DPRINT_PELOADER
, "WARNING: DllBase == NULL!\n");
520 /* Convert all non-critical pointers to PA from VA */
521 ThunkData
= VaToPa(ThunkData
);
523 /* Is the reference by ordinal? */
524 if (IMAGE_SNAP_BY_ORDINAL(ThunkData
->u1
.Ordinal
) && !ProcessForwards
)
526 /* Yes, calculate the ordinal */
527 Ordinal
= (ULONG
)(IMAGE_ORDINAL(ThunkData
->u1
.Ordinal
) - (UINT32
)ExportDirectory
->Base
);
528 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
532 /* It's reference by name, we have to look it up in the export directory */
533 if (!ProcessForwards
)
535 /* AddressOfData in thunk entry will become a virtual address (from relative) */
536 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData);
537 ThunkData
->u1
.AddressOfData
=
538 (ULONG_PTR
)RVA(ImageBase
, ThunkData
->u1
.AddressOfData
);
539 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData);
542 /* Get pointers to Name and Ordinal tables (RVA -> VA) */
543 NameTable
= (PULONG
)VaToPa(RVA(DllBase
, ExportDirectory
->AddressOfNames
));
544 OrdinalTable
= (PUSHORT
)VaToPa(RVA(DllBase
, ExportDirectory
->AddressOfNameOrdinals
));
546 //DPRINTM(DPRINT_PELOADER, "NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
547 // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals);
549 /* Get the hint, convert it to a physical pointer */
550 Hint
= ((PIMAGE_IMPORT_BY_NAME
)VaToPa((PVOID
)ThunkData
->u1
.AddressOfData
))->Hint
;
551 //DPRINTM(DPRINT_PELOADER, "HintIndex %d\n", Hint);
553 /* If Hint is less than total number of entries in the export directory,
554 and import name == export name, then we can just get it from the OrdinalTable */
556 (Hint
< ExportDirectory
->NumberOfNames
) &&
558 strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME
)VaToPa((PVOID
)ThunkData
->u1
.AddressOfData
))->Name
[0]),
559 (PCHAR
)VaToPa( RVA(DllBase
, NameTable
[Hint
])) ) == 0
563 Ordinal
= OrdinalTable
[Hint
];
564 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
568 /* It's not the easy way, we have to lookup import name in the name table.
569 Let's use a binary search for this task. */
571 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName() looking up the import name using binary search...\n");
573 /* Low boundary is set to 0, and high boundary to the maximum index */
575 High
= ExportDirectory
->NumberOfNames
- 1;
577 /* Perform a binary-search loop */
580 /* Divide by 2 by shifting to the right once */
581 Middle
= (Low
+ High
) >> 1;
583 /* Compare the names */
584 Result
= strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME
)VaToPa((PVOID
)ThunkData
->u1
.AddressOfData
))->Name
[0]),
585 (PCHAR
)VaToPa(RVA(DllBase
, NameTable
[Middle
])));
587 /*DPRINTM(DPRINT_PELOADER, "Binary search: comparing Import '__', Export '%s'\n",*/
588 /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/
589 /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/
591 /*DPRINTM(DPRINT_PELOADER, "TE->u1.AOD %p, fulladdr %p\n",
592 ThunkData->u1.AddressOfData,
593 ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/
596 /* Depending on result of strcmp, perform different actions */
599 /* Adjust top boundary */
604 /* Adjust bottom boundary */
614 /* If high boundary is less than low boundary, then no result found */
617 //Print(L"Error in binary search\n");
618 DPRINTM(DPRINT_PELOADER
, "Error in binary search!\n");
622 /* Everything allright, get the ordinal */
623 Ordinal
= OrdinalTable
[Middle
];
625 //DPRINTM(DPRINT_PELOADER, "WinLdrpBindImportName() found Ordinal %d\n", Ordinal);
629 /* Check ordinal number for validity! */
630 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
632 DPRINTM(DPRINT_PELOADER
, "Ordinal number is invalid!\n");
636 /* Get a pointer to the function table */
637 FunctionTable
= (PULONG
)VaToPa(RVA(DllBase
, ExportDirectory
->AddressOfFunctions
));
639 /* Save a pointer to the function */
640 ThunkData
->u1
.Function
= (ULONG_PTR
)RVA(DllBase
, FunctionTable
[Ordinal
]);
642 /* Is it a forwarder? (function pointer isn't within the export directory) */
643 if (((ULONG_PTR
)VaToPa((PVOID
)ThunkData
->u1
.Function
) > (ULONG_PTR
)ExportDirectory
) &&
644 ((ULONG_PTR
)VaToPa((PVOID
)ThunkData
->u1
.Function
) < ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
646 PLDR_DATA_TABLE_ENTRY DataTableEntry
;
647 CHAR ForwardDllName
[255];
648 PIMAGE_EXPORT_DIRECTORY RefExportDirectory
;
651 /* Save the name of the forward dll */
652 RtlCopyMemory(ForwardDllName
, (PCHAR
)VaToPa((PVOID
)ThunkData
->u1
.Function
), sizeof(ForwardDllName
));
654 /* Strip out its extension */
655 *strchr(ForwardDllName
,'.') = '\0';
657 DPRINTM(DPRINT_PELOADER
, "WinLdrpBindImportName(): ForwardDllName %s\n", ForwardDllName
);
658 if (!WinLdrCheckForLoadedDll(WinLdrBlock
, ForwardDllName
, &DataTableEntry
))
660 /* We can't continue if DLL couldn't be loaded, so bomb out with an error */
661 //Print(L"Error loading DLL!\n");
662 DPRINTM(DPRINT_PELOADER
, "Error loading DLL!\n");
666 /* Get pointer to the export directory of loaded DLL */
667 RefExportDirectory
= (PIMAGE_EXPORT_DIRECTORY
)
668 RtlImageDirectoryEntryToData(VaToPa(DataTableEntry
->DllBase
),
670 IMAGE_DIRECTORY_ENTRY_EXPORT
,
673 /* Fail if it's NULL */
674 if (RefExportDirectory
)
677 IMAGE_THUNK_DATA RefThunkData
;
678 PIMAGE_IMPORT_BY_NAME ImportByName
;
682 /* Get pointer to the import name */
683 ImportName
= strchr((PCHAR
)VaToPa((PVOID
)ThunkData
->u1
.Function
), '.') + 1;
685 /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
686 ImportByName
= (PIMAGE_IMPORT_BY_NAME
)Buffer
;
688 /* Fill the name with the import name */
689 RtlCopyMemory(ImportByName
->Name
, ImportName
, strlen(ImportName
)+1);
692 ImportByName
->Hint
= 0;
694 /* And finally point ThunkData's AddressOfData to that structure */
695 RefThunkData
.u1
.AddressOfData
= (ULONG_PTR
)ImportByName
;
697 /* And recursively call ourselves */
698 Status
= WinLdrpBindImportName(
700 DataTableEntry
->DllBase
,
707 /* Fill out the ThunkData with data from RefThunkData */
708 ThunkData
->u1
= RefThunkData
.u1
;
710 /* Return what we got from the recursive call */
715 /* Fail if ExportDirectory is NULL */
725 WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock
,
728 PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
730 CHAR FullDllName
[256];
734 /* Prepare the full path to the file to be loaded */
735 strcpy(FullDllName
, DirectoryPath
);
736 strcat(FullDllName
, ImportName
);
738 DPRINTM(DPRINT_PELOADER
, "Loading referenced DLL: %s\n", FullDllName
);
739 //Print(L"Loading referenced DLL: %s\n", FullDllName);
742 Status
= WinLdrLoadImage(FullDllName
, LoaderHalCode
, &BasePA
);
746 DPRINTM(DPRINT_PELOADER
, "WinLdrLoadImage() failed\n");
750 /* Allocate DTE for newly loaded DLL */
751 Status
= WinLdrAllocateDataTableEntry(WinLdrBlock
,
759 DPRINTM(DPRINT_PELOADER
,
760 "WinLdrAllocateDataTableEntry() failed with Status=0x%X\n", Status
);
764 /* Scan its dependencies too */
765 DPRINTM(DPRINT_PELOADER
,
766 "WinLdrScanImportDescriptorTable() calling ourselves for %S\n",
767 VaToPa((*DataTableEntry
)->BaseDllName
.Buffer
));
768 Status
= WinLdrScanImportDescriptorTable(WinLdrBlock
, DirectoryPath
, *DataTableEntry
);
772 DPRINTM(DPRINT_PELOADER
,
773 "WinLdrScanImportDescriptorTable() failed with Status=0x%X\n", Status
);
781 WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock
,
784 IN PIMAGE_THUNK_DATA ThunkData
)
786 PIMAGE_EXPORT_DIRECTORY ExportDirectory
= NULL
;
790 DPRINTM(DPRINT_PELOADER
, "WinLdrpScanImportAddressTable(): DllBase 0x%X, "
791 "ImageBase 0x%X, ThunkData 0x%X\n", DllBase
, ImageBase
, ThunkData
);
793 /* Obtain the export table from the DLL's base */
796 //Print(L"Error, DllBase == NULL!\n");
802 (PIMAGE_EXPORT_DIRECTORY
)RtlImageDirectoryEntryToData(VaToPa(DllBase
),
804 IMAGE_DIRECTORY_ENTRY_EXPORT
,
808 DPRINTM(DPRINT_PELOADER
, "WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory
);
810 /* If pointer to Export Directory is */
811 if (ExportDirectory
== NULL
)
814 /* Go through each entry in the thunk table and bind it */
815 while (((PIMAGE_THUNK_DATA
)VaToPa(ThunkData
))->u1
.AddressOfData
!= 0)
818 Status
= WinLdrpBindImportName(
827 /* Move to the next entry */
830 /* Return error if binding was unsuccessful */