From ac79d6ae4b9a1c02259e91b68ab3bd29be82ef4c Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 4 Feb 2008 10:45:55 +0000 Subject: [PATCH] - Make Mm allocation strategy low->high by default. - Clean up Mm APIs which are not needed anymore. - Get rid of the LOADER_HIGH_ZONE definition, now the real LoaderPagesSpanned value is calculated and used. As a result, minimum memory requirement (which was >= LOADER_HIGH_ZONE) is gone, and a maximum amount of memory which could be allocated is also gone (previously, not more that the LOADER_HIGH_ZONE). - IMPORTANT: The FAT filesystem caching is disabled by default now due strange problems in 3rd boot stage, after switching the cache to use heap routines. Cache can't use non-heap routines anymore, since the memory will overlap the contigious modules memory space which ReactOS needs. - More cleanup and more usage of the heap routines for temporary buffers. - Fix a bug in MmAllocateMemoryWithType, where result of MmFindAvailablePages was checked against -1 in error case, when in reality it's 0 (spotted by Alex). NB: 0 page is marked as a reserved in x86 arch, so it's never going to be returned as an available. svn path=/trunk/; revision=32113 --- .../boot/freeldr/freeldr/arch/i386/loader.c | 4 +- .../boot/freeldr/freeldr/cache/blocklist.c | 6 +- reactos/boot/freeldr/freeldr/cache/cache.c | 2 +- reactos/boot/freeldr/freeldr/fs/fat.c | 2 +- reactos/boot/freeldr/freeldr/include/mm.h | 7 - reactos/boot/freeldr/freeldr/mm/meminit.c | 3 +- reactos/boot/freeldr/freeldr/mm/mm.c | 23 +- .../boot/freeldr/freeldr/windows/peloader.c | 1662 ++++++++--------- reactos/boot/freeldr/freeldr/windows/winldr.c | 19 +- .../boot/freeldr/freeldr/windows/wlmemory.c | 21 +- 10 files changed, 874 insertions(+), 875 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/arch/i386/loader.c b/reactos/boot/freeldr/freeldr/arch/i386/loader.c index 4bd7d07ccd7..0700f51d8cb 100644 --- a/reactos/boot/freeldr/freeldr/arch/i386/loader.c +++ b/reactos/boot/freeldr/freeldr/arch/i386/loader.c @@ -582,7 +582,7 @@ FrLdrMapImage(IN FILE *Image, FsSetFilePointer(Image, 0); /* Allocate a temporary buffer for the read */ - ReadBuffer = MmAllocateMemory(ImageSize); + ReadBuffer = MmHeapAlloc(ImageSize); /* Load the file image */ FsReadFile(Image, ImageSize, NULL, ReadBuffer); @@ -591,7 +591,7 @@ FrLdrMapImage(IN FILE *Image, ImageSize = FrLdrReMapImage(ReadBuffer, LoadBase); /* Free the temporary buffer */ - MmFreeMemory(ReadBuffer); + MmHeapFree(ReadBuffer); /* Calculate Difference between Real Base and Compiled Base*/ Status = LdrRelocateImageWithBias(LoadBase, diff --git a/reactos/boot/freeldr/freeldr/cache/blocklist.c b/reactos/boot/freeldr/freeldr/cache/blocklist.c index 1bc4b1fdc8e..8a74a32c953 100644 --- a/reactos/boot/freeldr/freeldr/cache/blocklist.c +++ b/reactos/boot/freeldr/freeldr/cache/blocklist.c @@ -108,7 +108,7 @@ PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNu // allocate room for the block data RtlZeroMemory(CacheBlock, sizeof(CACHE_BLOCK)); CacheBlock->BlockNumber = BlockNumber; - CacheBlock->BlockData = MmAllocateMemory(CacheDrive->BlockSize * CacheDrive->BytesPerSector); + CacheBlock->BlockData = MmHeapAlloc(CacheDrive->BlockSize * CacheDrive->BytesPerSector); if (CacheBlock->BlockData ==NULL) { MmHeapFree(CacheBlock); @@ -118,7 +118,7 @@ PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNu // Now try to read in the block if (!MachDiskReadLogicalSectors(CacheDrive->DriveNumber, (BlockNumber * CacheDrive->BlockSize), CacheDrive->BlockSize, (PVOID)DISKREADBUFFER)) { - MmFreeMemory(CacheBlock->BlockData); + MmHeapFree(CacheBlock->BlockData); MmHeapFree(CacheBlock); return NULL; } @@ -161,7 +161,7 @@ BOOLEAN CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive) RemoveEntryList(&CacheBlockToFree->ListEntry); // Free the block memory and the block structure - MmFreeMemory(CacheBlockToFree->BlockData); + MmHeapFree(CacheBlockToFree->BlockData); MmHeapFree(CacheBlockToFree); // Update the cache data diff --git a/reactos/boot/freeldr/freeldr/cache/cache.c b/reactos/boot/freeldr/freeldr/cache/cache.c index af8b909eac6..5d1bc26254f 100644 --- a/reactos/boot/freeldr/freeldr/cache/cache.c +++ b/reactos/boot/freeldr/freeldr/cache/cache.c @@ -70,7 +70,7 @@ BOOLEAN CacheInitializeDrive(ULONG DriveNumber) CACHE_BLOCK, ListEntry); - MmFreeMemory(NextCacheBlock->BlockData); + MmHeapFree(NextCacheBlock->BlockData); MmHeapFree(NextCacheBlock); } } diff --git a/reactos/boot/freeldr/freeldr/fs/fat.c b/reactos/boot/freeldr/freeldr/fs/fat.c index f76b73ac8fa..6d8fcd5da3d 100644 --- a/reactos/boot/freeldr/freeldr/fs/fat.c +++ b/reactos/boot/freeldr/freeldr/fs/fat.c @@ -22,7 +22,7 @@ #define NDEBUG #include -BOOLEAN gCacheEnabled = TRUE; +BOOLEAN gCacheEnabled = FALSE; ULONG BytesPerSector; /* Number of bytes per sector */ ULONG SectorsPerCluster; /* Number of sectors per cluster */ diff --git a/reactos/boot/freeldr/freeldr/include/mm.h b/reactos/boot/freeldr/freeldr/include/mm.h index c942b1efc76..7199c0597e8 100644 --- a/reactos/boot/freeldr/freeldr/include/mm.h +++ b/reactos/boot/freeldr/freeldr/include/mm.h @@ -47,10 +47,6 @@ typedef struct ( ((a) >> MM_PAGE_SHIFT) + ((a) & MM_PAGE_MASK ? 1 : 0) ) #endif // defined __i386__ or _PPC_ or _MIPS_ -// -// This is the zone which is used by the OS loader -// -#define LOADER_HIGH_ZONE ((24*1024*1024) >> MM_PAGE_SHIFT) // 24Mb // HEAP and STACK size #define HEAP_PAGES 0x400 @@ -105,9 +101,6 @@ VOID MmInitializeHeap(PVOID PageLookupTable); PVOID MmAllocateMemory(ULONG MemorySize); PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType); VOID MmFreeMemory(PVOID MemoryPointer); -VOID MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd); -//PVOID MmAllocateLowMemory(ULONG MemorySize); -//VOID MmFreeLowMemory(PVOID MemoryPointer); PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType); PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType); diff --git a/reactos/boot/freeldr/freeldr/mm/meminit.c b/reactos/boot/freeldr/freeldr/mm/meminit.c index f2a784c9faf..e6b8f004261 100644 --- a/reactos/boot/freeldr/freeldr/mm/meminit.c +++ b/reactos/boot/freeldr/freeldr/mm/meminit.c @@ -393,8 +393,7 @@ ULONG MmFindAvailablePages(PVOID PageLookupTable, ULONG TotalPageCount, ULONG Pa if (FromEnd) { /* Allocate "high" (from end) pages */ - for (Index=/*LastFreePageHint-1*/LOADER_HIGH_ZONE-1; Index>0; Index--) - //for (Index=LastFreePageHint-1; Index>0; Index--) + for (Index=LastFreePageHint-1; Index>0; Index--) { if (RealPageLookupTable[Index].PageAllocated != LoaderFree) { diff --git a/reactos/boot/freeldr/freeldr/mm/mm.c b/reactos/boot/freeldr/freeldr/mm/mm.c index fdc57190832..3400a66b6d9 100644 --- a/reactos/boot/freeldr/freeldr/mm/mm.c +++ b/reactos/boot/freeldr/freeldr/mm/mm.c @@ -25,12 +25,7 @@ VOID DumpMemoryAllocMap(VOID); VOID MemAllocTest(VOID); #endif // DBG -BOOLEAN AllocateFromEnd = TRUE; - -VOID MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd) -{ - AllocateFromEnd = PolicyAllocatePagesFromEnd; -} +ULONG LoaderPagesSpanned = 0; PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) { @@ -60,9 +55,9 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) return NULL; } - FirstFreePageFromEnd = MmFindAvailablePages(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, AllocateFromEnd); + FirstFreePageFromEnd = MmFindAvailablePages(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, FALSE); - if (FirstFreePageFromEnd == (ULONG)-1) + if (FirstFreePageFromEnd == 0) { DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize)); UiMessageBoxCritical("Memory allocation failed: out of memory."); @@ -79,6 +74,10 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer)); #endif // DBG + // Update LoaderPagesSpanned count + if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned) + LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT); + // Now return the pointer return MemPointer; } @@ -175,6 +174,10 @@ PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_ DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer)); #endif // DBG + // Update LoaderPagesSpanned count + if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned) + LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT); + // Now return the pointer return MemPointer; } @@ -228,6 +231,10 @@ PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer)); #endif // DBG + // Update LoaderPagesSpanned count + if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned) + LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT); + // Now return the pointer return MemPointer; } diff --git a/reactos/boot/freeldr/freeldr/windows/peloader.c b/reactos/boot/freeldr/freeldr/windows/peloader.c index fdbb21d3c91..a3792388669 100644 --- a/reactos/boot/freeldr/freeldr/windows/peloader.c +++ b/reactos/boot/freeldr/freeldr/windows/peloader.c @@ -1,832 +1,830 @@ -/* - * 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 (aleksey@reactos.org) - * 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 -#include - - -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); - - { - UNICODE_STRING BaseName; - BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer); - BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength; - BaseName.Length = ScanDTE->BaseDllName.Length; - DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n", - &BaseName, 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 != 0);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)MmHeapAlloc(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)MmHeapAlloc(Length); - if (Buffer == NULL) - { - MmHeapFree(DataTableEntry); - 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)MmHeapAlloc(Length); - if (Buffer == NULL) - { - MmHeapFree(DataTableEntry); - 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 = - (ULONG)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((PVOID)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((PVOID)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((PVOID)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 = (ULONG)RVA(DllBase, FunctionTable[Ordinal]); - - /* Is it a forwarder? (function pointer isn't within the export directory) */ - if (((ULONG)VaToPa((PVOID)ThunkData->u1.Function) > (ULONG)ExportDirectory) && - ((ULONG)VaToPa((PVOID)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((PVOID)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((PVOID)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 = (ULONG)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 != 0) - { - /* 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; -} +/* + * 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 (aleksey@reactos.org) + * 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 +#include + + +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); + + { + UNICODE_STRING BaseName; + BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer); + BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength; + BaseName.Length = ScanDTE->BaseDllName.Length; + DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n", + &BaseName, 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 != 0);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)MmHeapAlloc(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)MmHeapAlloc(Length); + if (Buffer == NULL) + { + MmHeapFree(DataTableEntry); + 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)MmHeapAlloc(Length); + if (Buffer == NULL) + { + MmHeapFree(DataTableEntry); + 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 */ + PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType); + + 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 = + (ULONG)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((PVOID)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((PVOID)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((PVOID)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 = (ULONG)RVA(DllBase, FunctionTable[Ordinal]); + + /* Is it a forwarder? (function pointer isn't within the export directory) */ + if (((ULONG)VaToPa((PVOID)ThunkData->u1.Function) > (ULONG)ExportDirectory) && + ((ULONG)VaToPa((PVOID)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((PVOID)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((PVOID)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 = (ULONG)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 != 0) + { + /* 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; +} diff --git a/reactos/boot/freeldr/freeldr/windows/winldr.c b/reactos/boot/freeldr/freeldr/windows/winldr.c index ad2b9ceb979..881302e0621 100644 --- a/reactos/boot/freeldr/freeldr/windows/winldr.c +++ b/reactos/boot/freeldr/freeldr/windows/winldr.c @@ -30,6 +30,7 @@ extern ARC_DISK_SIGNATURE reactos_arc_disk_info[]; extern char reactos_arc_strings[32][256]; extern BOOLEAN UseRealHeap; +extern ULONG LoaderPagesSpanned; BOOLEAN WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock, @@ -186,12 +187,11 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, } RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION)); - /* Save size and version information */ + /* Fill LPB extension */ Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION); Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8; Extension->MinorVersion = VersionToBoot & 0xFF; - Extension->LoaderPagesSpanned = LOADER_HIGH_ZONE; - + Extension->Profile.Status = 2; LoaderBlock->Extension = PaToVa(Extension); } @@ -208,8 +208,8 @@ void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock, ULONG_PTR Tss = 0; ULONG BlockSize, NumPages; - LoaderBlock->u.I386.CommonDataArea = NULL;//CommonDataArea; - //LoaderBlock->u.I386.MachineType = MachineType; //FIXME: MachineType? + LoaderBlock->u.I386.CommonDataArea = NULL; //CommonDataArea; + LoaderBlock->u.I386.MachineType = 0; // ntldr sets this to 0 /* Allocate 2 pages for PCR */ Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage); @@ -483,12 +483,12 @@ LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion) Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath); DbgPrint((DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status)); - /* Initialize Phase 1 - no drivers loading anymore */ - WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion); - /* Alloc PCR, TSS, do magic things with the GDT/IDT */ WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage); + /* Initialize Phase 1 - no drivers loading anymore */ + WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion); + /* Save entry-point pointer and Loader block VAs */ KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint; LoaderBlockVA = PaToVa(LoaderBlock); @@ -506,6 +506,9 @@ LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion) /* Turn on paging mode of CPU*/ WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt); + /* Save final value of LoaderPagesSpanned */ + LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned; + DbgPrint((DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", KiSystemStartup, LoaderBlockVA)); diff --git a/reactos/boot/freeldr/freeldr/windows/wlmemory.c b/reactos/boot/freeldr/freeldr/windows/wlmemory.c index 08c208d2dbc..6ae0d1dbca6 100644 --- a/reactos/boot/freeldr/freeldr/windows/wlmemory.c +++ b/reactos/boot/freeldr/freeldr/windows/wlmemory.c @@ -14,6 +14,7 @@ #include extern ULONG TotalNLSSize; +extern ULONG LoaderPagesSpanned; // This is needed because headers define wrong one for ReactOS #undef KIP0PCRADDRESS @@ -131,14 +132,14 @@ MempAllocatePageTables() // PDE, HAL mapping page table, physical mapping, kernel mapping TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE; - // Physical PTEs = FirmwareTemporary - PhysicalPageTablesBuffer = MmAllocateMemoryWithType( - NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary); - // PDE+HAL+KernelPTEs == MemoryData Buffer = MmAllocateMemoryWithType( TotalSize - NumPageTables*MM_PAGE_SIZE, LoaderMemoryData); + // Physical PTEs = FirmwareTemporary + PhysicalPageTablesBuffer = MmAllocateMemoryWithType( + NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary); + if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) != PhysicalPageTablesBuffer) { @@ -290,23 +291,22 @@ MempDisablePages() if (Mad[i].MemoryType == LoaderFirmwarePermanent || Mad[i].MemoryType == LoaderSpecialMemory || Mad[i].MemoryType == LoaderFree || - (Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LOADER_HIGH_ZONE) || + (Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) || Mad[i].MemoryType == LoaderOsloaderStack || Mad[i].MemoryType == LoaderLoadedProgram) { - // // But, the first megabyte of memory always stays! // And, to tell the truth, we don't care about what's higher - // than LOADER_HIGH_ZONE + // than LoaderPagesSpanned if (Mad[i].MemoryType == LoaderFirmwarePermanent || Mad[i].MemoryType == LoaderSpecialMemory) { if (StartPage < 0x100) StartPage = 0x100; - if (EndPage > LOADER_HIGH_ZONE) - EndPage = LOADER_HIGH_ZONE; + if (EndPage > LoaderPagesSpanned) + EndPage = LoaderPagesSpanned; } for (Page = StartPage; Page < EndPage; Page++) @@ -330,7 +330,6 @@ MempDisablePages() } } - VOID MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, ULONG BasePage, @@ -361,7 +360,7 @@ MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, // Check if it's more than the allowed for OS loader // if yes - don't map the pages, just add as FirmwareTemporary // - if (BasePage + PageCount > LOADER_HIGH_ZONE) + if (BasePage + PageCount > LoaderPagesSpanned) { if (Mad[MadCount].MemoryType != LoaderSpecialMemory && Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&