Files
reactos/windows/peloader.c
T
Aleksey Bragin e1cf9b2cdb - Unlock lower 1Mb for use by memory manager, and properly mark all "unusable" places (except one place which is marked as strange).
- Get rid of in-memory hardware registry, hwdetect functions which has not been converted yet to use configuration lists are #if0ed or not used for now. Reduces memory requirements a little.

svn path=/branches/winldr/; revision=25191
2006-12-19 16:44:14 +00:00

823 lines
25 KiB
C

/*
* PROJECT: FreeLoader
* LICENSE: GPL - See COPYING in the top level directory
* FILE: freeldr/winldr/peloader.c
* PURPOSE: Provides routines for loading PE files. To be merged with
* arch/i386/loader.c in future
* This article was very handy during development:
* http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
* PROGRAMMERS: Aleksey Bragin ([email protected])
* The source code in this file is based on the work of respective
* authors of PE loading code in ReactOS and Brian Palmer and
* Alex Ionescu's arch/i386/loader.c, and my research project
* (creating a native EFI loader for Windows)
*/
/* INCLUDES ***************************************************************/
#include <freeldr.h>
//#define NDEBUG
#include <debug.h>
BOOLEAN
WinLdrpCompareDllName(IN PCH DllName,
IN PUNICODE_STRING UnicodeName);
BOOLEAN
WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PVOID DllBase,
IN PVOID ImageBase,
IN PIMAGE_THUNK_DATA ThunkData,
IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
IN ULONG ExportSize,
IN BOOLEAN ProcessForwards);
BOOLEAN
WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock,
PCCH DirectoryPath,
PCH ImportName,
PLDR_DATA_TABLE_ENTRY *DataTableEntry);
BOOLEAN
WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PVOID DllBase,
IN PVOID ImageBase,
IN PIMAGE_THUNK_DATA ThunkData);
/* FUNCTIONS **************************************************************/
/* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
BOOLEAN
WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PCH DllName,
OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
{
PLDR_DATA_TABLE_ENTRY DataTableEntry;
LIST_ENTRY *ModuleEntry;
DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: DllName %X, LoadedEntry: %X\n",
DllName, LoadedEntry));
/* Just go through each entry in the LoadOrderList and compare loaded module's
name with a given name */
ModuleEntry = WinLdrBlock->LoadOrderListHead.Flink;
while (ModuleEntry != &WinLdrBlock->LoadOrderListHead)
{
/* Get pointer to the current DTE */
DataTableEntry = CONTAINING_RECORD(ModuleEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: DTE %p, EP %p\n",
DataTableEntry, DataTableEntry->EntryPoint));
/* Compare names */
if (WinLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName))
{
/* Yes, found it, report pointer to the loaded module's DTE
to the caller and increase load count for it */
*LoadedEntry = DataTableEntry;
DataTableEntry->LoadCount++;
DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry));
return TRUE;
}
/* Go to the next entry */
ModuleEntry = ModuleEntry->Flink;
}
/* Nothing found */
return FALSE;
}
BOOLEAN
WinLdrScanImportDescriptorTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PCCH DirectoryPath,
IN PLDR_DATA_TABLE_ENTRY ScanDTE)
{
PLDR_DATA_TABLE_ENTRY DataTableEntry;
PIMAGE_IMPORT_DESCRIPTOR ImportTable;
ULONG ImportTableSize;
PCH ImportName;
BOOLEAN Status;
/* Get a pointer to the import table of this image */
ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase),
TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): %S ImportTable = 0x%X\n",
VaToPa(ScanDTE->BaseDllName.Buffer),ImportTable));
/* If image doesn't have any import directory - just return success */
if (ImportTable == NULL)
return TRUE;
/* Loop through all entries */
for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != NULL);ImportTable++)
{
/* Get pointer to the name */
ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));
DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName));
/* In case we get a reference to ourselves - just skip it */
if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName))
continue;
/* Load the DLL if it is not already loaded */
if (!WinLdrCheckForLoadedDll(WinLdrBlock, ImportName, &DataTableEntry))
{
Status = WinLdrpLoadAndScanReferencedDll(WinLdrBlock,
DirectoryPath,
ImportName,
&DataTableEntry);
if (!Status)
{
DbgPrint((DPRINT_WINDOWS, "WinLdrpLoadAndScanReferencedDll() failed\n"));
return Status;
}
}
/* Scan its import address table */
Status = WinLdrpScanImportAddressTable(
WinLdrBlock,
DataTableEntry->DllBase,
ScanDTE->DllBase,
(PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk));
if (!Status)
{
DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable() failed\n"));
return Status;
}
}
return TRUE;
}
BOOLEAN
WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PCCH BaseDllName,
IN PCCH FullDllName,
IN PVOID BasePA,
OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
{
PVOID BaseVA = PaToVa(BasePA);
PWSTR Buffer;
PLDR_DATA_TABLE_ENTRY DataTableEntry;
PIMAGE_NT_HEADERS NtHeaders;
USHORT Length;
/* Allocate memory for a data table entry, zero-initialize it */
DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmAllocateMemory(sizeof(LDR_DATA_TABLE_ENTRY));
if (DataTableEntry == NULL)
return FALSE;
RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));
/* Get NT headers from the image */
NtHeaders = RtlImageNtHeader(BasePA);
/* Initialize corresponding fields of DTE based on NT headers value */
DataTableEntry->DllBase = BaseVA;
DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint);
DataTableEntry->SectionPointer = 0;
DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
/* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
by simple conversion - copying each character */
Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
Buffer = (PWSTR)MmAllocateMemory(Length);
if (Buffer == NULL)
return FALSE;
RtlZeroMemory(Buffer, Length);
DataTableEntry->BaseDllName.Length = Length;
DataTableEntry->BaseDllName.MaximumLength = Length;
DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);
while (*BaseDllName != 0)
{
*Buffer++ = *BaseDllName++;
}
/* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
using the same method */
Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
Buffer = (PWSTR)MmAllocateMemory(Length);
if (Buffer == NULL)
return FALSE;
RtlZeroMemory(Buffer, Length);
DataTableEntry->FullDllName.Length = Length;
DataTableEntry->FullDllName.MaximumLength = Length;
DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);
while (*FullDllName != 0)
{
*Buffer++ = *FullDllName++;
}
/* Initialize what's left - LoadCount which is 1, and set Flags so that
we know this entry is processed */
DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
DataTableEntry->LoadCount = 1;
/* Insert this DTE to a list in the LPB */
InsertTailList(&WinLdrBlock->LoadOrderListHead, &DataTableEntry->InLoadOrderLinks);
/* Save pointer to a newly allocated and initialized entry */
*NewEntry = DataTableEntry;
/* Return success */
return TRUE;
}
/* WinLdrLoadImage loads the specified image from the file (it doesn't
perform any additional operations on the filename, just directly
calls the file I/O routines), and relocates it so that it's ready
to be used when paging is enabled.
Addressing mode: physical
*/
BOOLEAN
WinLdrLoadImage(IN PCHAR FileName,
TYPE_OF_MEMORY MemoryType,
OUT PVOID *ImageBasePA)
{
PFILE FileHandle;
PVOID PhysicalBase;
PVOID VirtualBase = NULL;
UCHAR HeadersBuffer[SECTOR_SIZE * 2];
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_SECTION_HEADER SectionHeader;
ULONG VirtualSize, SizeOfRawData, NumberOfSections;
BOOLEAN Status;
ULONG i, BytesRead;
CHAR ProgressString[256];
/* Inform user we are loading files */
sprintf(ProgressString, "Loading %s...", FileName);
UiDrawProgressBarCenter(1, 100, ProgressString);
/* Open the image file */
FileHandle = FsOpenFile(FileName);
if (FileHandle == NULL)
{
//Print(L"Can not open the file %s\n",FileName);
UiMessageBox("Can not open the file");
return FALSE;
}
/* Load the first 2 sectors of the image so we can read the PE header */
Status = FsReadFile(FileHandle, SECTOR_SIZE * 2, NULL, HeadersBuffer);
if (!Status)
{
//Print(L"Error reading from file %s\n", FileName);
UiMessageBox("Error reading from file");
FsCloseFile(FileHandle);
return FALSE;
}
/* Now read the MZ header to get the offset to the PE Header */
NtHeaders = RtlImageNtHeader(HeadersBuffer);
if (!NtHeaders)
{
//Print(L"Error - no NT header found in %s\n", FileName);
UiMessageBox("Error - no NT header found");
FsCloseFile(FileHandle);
return FALSE;
}
/* Ensure this is executable image */
if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))
{
//Print(L"Not an executable image %s\n", FileName);
UiMessageBox("Not an executable image");
FsCloseFile(FileHandle);
return FALSE;
}
/* Store number of sections to read and a pointer to the first section */
NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
/* Try to allocate this memory, if fails - allocate somewhere else */
PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,
(PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),
MemoryType);
if (PhysicalBase == NULL)
{
/* It's ok, we don't panic - let's allocate again at any other "low" place */
//MmChangeAllocationPolicy(FALSE);
PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);
//MmChangeAllocationPolicy(TRUE);
if (PhysicalBase == NULL)
{
//Print(L"Failed to alloc pages for image %s\n", FileName);
UiMessageBox("Failed to alloc pages for image");
FsCloseFile(FileHandle);
return FALSE;
}
}
/* This is the real image base - in form of a virtual address */
VirtualBase = PaToVa(PhysicalBase);
DbgPrint((DPRINT_WINDOWS, "Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase));
/* Set to 0 position and fully load the file image */
FsSetFilePointer(FileHandle, 0);
Status = FsReadFile(FileHandle, NtHeaders->OptionalHeader.SizeOfHeaders, NULL, PhysicalBase);
if (!Status)
{
//Print(L"Error reading headers %s\n", FileName);
UiMessageBox("Error reading headers");
FsCloseFile(FileHandle);
return FALSE;
}
/* Reload the NT Header */
NtHeaders = RtlImageNtHeader(PhysicalBase);
/* Load the first section */
SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
/* Fill output parameters */
*ImageBasePA = PhysicalBase;
/* Walk through each section and read it (check/fix any possible
bad situations, if they arise) */
for (i = 0; i < NumberOfSections; i++)
{
VirtualSize = SectionHeader->Misc.VirtualSize;
SizeOfRawData = SectionHeader->SizeOfRawData;
/* Handle a case when VirtualSize equals 0 */
if (VirtualSize == 0)
VirtualSize = SizeOfRawData;
/* If PointerToRawData is 0, then force its size to be also 0 */
if (SectionHeader->PointerToRawData == 0)
{
SizeOfRawData = 0;
}
else
{
/* Cut the loaded size to the VirtualSize extents */
if (SizeOfRawData > VirtualSize)
SizeOfRawData = VirtualSize;
}
/* Actually read the section (if its size is not 0) */
if (SizeOfRawData != 0)
{
/* Seek to the correct position */
FsSetFilePointer(FileHandle, SectionHeader->PointerToRawData);
DbgPrint((DPRINT_WINDOWS, "SH->VA: 0x%X\n", SectionHeader->VirtualAddress));
/* Read this section from the file, size = SizeOfRawData */
Status = FsReadFile(FileHandle, SizeOfRawData, &BytesRead, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress);
if (!Status && (BytesRead == 0))
{
DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage(): Error reading section from file!\n"));
break;
}
}
/* Size of data is less than the virtual size - fill up the remainder with zeroes */
if (SizeOfRawData < VirtualSize)
{
DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage(): SORD %d < VS %d", SizeOfRawData, VirtualSize));
RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);
}
SectionHeader++;
}
/* We are done with the file - close it */
FsCloseFile(FileHandle);
/* If loading failed - return right now */
if (!Status)
return FALSE;
/* Relocate the image, if it needs it */
if (NtHeaders->OptionalHeader.ImageBase != (ULONG)VirtualBase)
{
DbgPrint((DPRINT_WINDOWS, "Relocating %p -> %p\n",
NtHeaders->OptionalHeader.ImageBase, VirtualBase));
Status = (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,
(ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase,
"FreeLdr",
TRUE,
TRUE, /* in case of conflict still return success */
FALSE);
}
return Status;
}
/* PRIVATE FUNCTIONS *******************************************************/
/* DllName - physical, UnicodeString->Buffer - virtual */
BOOLEAN
WinLdrpCompareDllName(IN PCH DllName,
IN PUNICODE_STRING UnicodeName)
{
PWSTR Buffer;
UNICODE_STRING UnicodeNamePA;
ULONG i, Length;
/* First obvious check: for length of two names */
Length = strlen(DllName);
UnicodeNamePA.Length = UnicodeName->Length;
UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength;
UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer);
DbgPrint((DPRINT_WINDOWS, "WinLdrpCompareDllName: %s and %wZ, Length = %d "
"UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length));
if ((Length * sizeof(WCHAR)) > UnicodeName->Length)
return FALSE;
/* Store pointer to unicode string's buffer */
Buffer = VaToPa(UnicodeName->Buffer);
/* Loop character by character */
for (i = 0; i < Length; i++)
{
/* Compare two characters, uppercasing them */
if (toupper(*DllName) != toupper((CHAR)*Buffer))
return FALSE;
/* Move to the next character */
DllName++;
Buffer++;
}
/* Check, if strings either fully match, or match till the "." (w/o extension) */
if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.'))
{
/* Yes they do */
return TRUE;
}
/* Strings don't match, return FALSE */
return FALSE;
}
BOOLEAN
WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PVOID DllBase,
IN PVOID ImageBase,
IN PIMAGE_THUNK_DATA ThunkData,
IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
IN ULONG ExportSize,
IN BOOLEAN ProcessForwards)
{
ULONG Ordinal;
PULONG NameTable, FunctionTable;
PUSHORT OrdinalTable;
LONG High, Low, Middle, Result;
ULONG Hint;
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
// DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards));
/* Check passed DllBase param */
if(DllBase == NULL)
{
DbgPrint((DPRINT_WINDOWS, "WARNING: DllBase == NULL!\n"));
return FALSE;
}
/* Convert all non-critical pointers to PA from VA */
ThunkData = VaToPa(ThunkData);
/* Is the reference by ordinal? */
if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)
{
/* Yes, calculate the ordinal */
Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal));
}
else
{
/* It's reference by name, we have to look it up in the export directory */
if (!ProcessForwards)
{
/* AddressOfData in thunk entry will become a virtual address (from relative) */
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData));
ThunkData->u1.AddressOfData =
(PIMAGE_IMPORT_BY_NAME)RVA(ImageBase, ThunkData->u1.AddressOfData);
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData));
}
/* Get pointers to Name and Ordinal tables (RVA -> VA) */
NameTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));
OrdinalTable = (PUSHORT)VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals));
//DbgPrint((DPRINT_WINDOWS, "NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
// NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals));
/* Get the hint, convert it to a physical pointer */
Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Hint;
//DbgPrint((DPRINT_WINDOWS, "HintIndex %d\n", Hint));
/* If Hint is less than total number of entries in the export directory,
and import name == export name, then we can just get it from the OrdinalTable */
if (
(Hint < ExportDirectory->NumberOfNames) &&
(
strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),
(PCHAR)VaToPa( RVA(DllBase, NameTable[Hint])) ) == 0
)
)
{
Ordinal = OrdinalTable[Hint];
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal));
}
else
{
/* It's not the easy way, we have to lookup import name in the name table.
Let's use a binary search for this task. */
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName() looking up the import name using binary search...\n"));
/* Low boundary is set to 0, and high boundary to the maximum index */
Low = 0;
High = ExportDirectory->NumberOfNames - 1;
/* Perform a binary-search loop */
while (High >= Low)
{
/* Divide by 2 by shifting to the right once */
Middle = (Low + High) >> 1;
/* Compare the names */
Result = strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),
(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));
DbgPrint((DPRINT_WINDOWS, "Binary search: comparing Import '__', Export '%s'\n",
/*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/
(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle]))));
DbgPrint((DPRINT_WINDOWS, "TE->u1.AOD %p, fulladdr %p\n",
ThunkData->u1.AddressOfData,
((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name ));
/* Depending on result of strcmp, perform different actions */
if (Result < 0)
{
/* Adjust top boundary */
High = Middle - 1;
}
else if (Result > 0)
{
/* Adjust bottom boundary */
Low = Middle + 1;
}
else
{
/* Yay, found it! */
break;
}
}
/* If high boundary is less than low boundary, then no result found */
if (High < Low)
{
//Print(L"Error in binary search\n");
DbgPrint((DPRINT_WINDOWS, "Error in binary search!\n"));
return FALSE;
}
/* Everything allright, get the ordinal */
Ordinal = OrdinalTable[Middle];
//DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName() found Ordinal %d\n", Ordinal));
}
}
/* Check ordinal number for validity! */
if (Ordinal >= ExportDirectory->NumberOfFunctions)
{
DbgPrint((DPRINT_WINDOWS, "Ordinal number is invalid!\n"));
return FALSE;
}
/* Get a pointer to the function table */
FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions));
/* Save a pointer to the function */
ThunkData->u1.Function = (PULONG)RVA(DllBase, FunctionTable[Ordinal]);
/* Is it a forwarder? (function pointer isn't within the export directory) */
if (((ULONG)VaToPa(ThunkData->u1.Function) > (ULONG)ExportDirectory) &&
((ULONG)VaToPa(ThunkData->u1.Function) < ((ULONG)ExportDirectory + ExportSize)))
{
PLDR_DATA_TABLE_ENTRY DataTableEntry;
CHAR ForwardDllName[255];
PIMAGE_EXPORT_DIRECTORY RefExportDirectory;
ULONG RefExportSize;
/* Save the name of the forward dll */
RtlCopyMemory(ForwardDllName, (PCHAR)VaToPa(ThunkData->u1.Function), sizeof(ForwardDllName));
/* Strip out its extension */
*strchr(ForwardDllName,'.') = '\0';
DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ForwardDllName %s\n", ForwardDllName));
if (!WinLdrCheckForLoadedDll(WinLdrBlock, ForwardDllName, &DataTableEntry))
{
/* We can't continue if DLL couldn't be loaded, so bomb out with an error */
//Print(L"Error loading DLL!\n");
DbgPrint((DPRINT_WINDOWS, "Error loading DLL!\n"));
return FALSE;
}
/* Get pointer to the export directory of loaded DLL */
RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase),
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&RefExportSize);
/* Fail if it's NULL */
if (RefExportDirectory)
{
UCHAR Buffer[128];
IMAGE_THUNK_DATA RefThunkData;
PIMAGE_IMPORT_BY_NAME ImportByName;
PCHAR ImportName;
BOOLEAN Status;
/* Get pointer to the import name */
ImportName = strchr((PCHAR)VaToPa(ThunkData->u1.Function), '.') + 1;
/* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer;
/* Fill the name with the import name */
RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1);
/* Set Hint to 0 */
ImportByName->Hint = 0;
/* And finally point ThunkData's AddressOfData to that structure */
RefThunkData.u1.AddressOfData = ImportByName;
/* And recursively call ourselves */
Status = WinLdrpBindImportName(
WinLdrBlock,
DataTableEntry->DllBase,
ImageBase,
&RefThunkData,
RefExportDirectory,
RefExportSize,
TRUE);
/* Fill out the ThunkData with data from RefThunkData */
ThunkData->u1 = RefThunkData.u1;
/* Return what we got from the recursive call */
return Status;
}
else
{
/* Fail if ExportDirectory is NULL */
return FALSE;
}
}
/* Success! */
return TRUE;
}
BOOLEAN
WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock,
PCCH DirectoryPath,
PCH ImportName,
PLDR_DATA_TABLE_ENTRY *DataTableEntry)
{
CHAR FullDllName[256];
BOOLEAN Status;
PVOID BasePA;
/* Prepare the full path to the file to be loaded */
strcpy(FullDllName, DirectoryPath);
strcat(FullDllName, ImportName);
DbgPrint((DPRINT_WINDOWS, "Loading referenced DLL: %s\n", FullDllName));
//Print(L"Loading referenced DLL: %s\n", FullDllName);
/* Load the image */
Status = WinLdrLoadImage(FullDllName, LoaderHalCode, &BasePA);
if (!Status)
{
DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage() failed\n"));
return Status;
}
/* Allocate DTE for newly loaded DLL */
Status = WinLdrAllocateDataTableEntry(WinLdrBlock,
ImportName,
FullDllName,
BasePA,
DataTableEntry);
if (!Status)
{
DbgPrint((DPRINT_WINDOWS,
"WinLdrAllocateDataTableEntry() failed with Status=0x%X\n", Status));
return Status;
}
/* Scan its dependencies too */
DbgPrint((DPRINT_WINDOWS,
"WinLdrScanImportDescriptorTable() calling ourselves for %S\n",
VaToPa((*DataTableEntry)->BaseDllName.Buffer)));
Status = WinLdrScanImportDescriptorTable(WinLdrBlock, DirectoryPath, *DataTableEntry);
if (!Status)
{
DbgPrint((DPRINT_WINDOWS,
"WinLdrScanImportDescriptorTable() failed with Status=0x%X\n", Status));
return Status;
}
return TRUE;
}
BOOLEAN
WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
IN PVOID DllBase,
IN PVOID ImageBase,
IN PIMAGE_THUNK_DATA ThunkData)
{
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
BOOLEAN Status;
ULONG ExportSize;
DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable(): DllBase 0x%X, "
"ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData));
/* Obtain the export table from the DLL's base */
if (DllBase == NULL)
{
//Print(L"Error, DllBase == NULL!\n");
return FALSE;
}
else
{
ExportDirectory =
(PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(VaToPa(DllBase),
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize);
}
DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory));
/* If pointer to Export Directory is */
if (ExportDirectory == NULL)
return FALSE;
/* Go through each entry in the thunk table and bind it */
while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != NULL)
{
/* Bind it */
Status = WinLdrpBindImportName(
WinLdrBlock,
DllBase,
ImageBase,
ThunkData,
ExportDirectory,
ExportSize,
FALSE);
/* Move to the next entry */
ThunkData++;
/* Return error if binding was unsuccessful */
if (!Status)
return Status;
}
/* Return success */
return TRUE;
}