set most of trunk svn property eol-style:native
[reactos.git] / reactos / boot / freeldr / freeldr / windows / peloader.c
index 1f1e75f..2aeb30f 100644 (file)
-/*\r
- * PROJECT:         WinLoader\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            freeldr/winldr/peloader.c\r
- * PURPOSE:         Provides routines for loading PE files. To be merged with\r
- *                  arch/i386/loader.c in future\r
- *                  This article was very handy during development:\r
- *                  http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/\r
- * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)\r
- *                  The source code in this file is based on the work of respective\r
- *                  authors of PE loading code in ReactOS and Brian Palmer and\r
- *                  Alex Ionescu's arch/i386/loader.c, and my research project\r
- *                  (creating a native EFI loader for Windows)\r
- */\r
-\r
-/* INCLUDES ***************************************************************/\r
-#include <freeldr.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* FUNCTIONS **************************************************************/\r
-\r
-BOOLEAN\r
-WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
-                        IN PCH DllName,\r
-                        OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)\r
-{\r
-       return FALSE;\r
-}\r
-\r
-\r
-BOOLEAN\r
-WinLdrScanImportDescriptorTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
-                                IN PCCH DirectoryPath,\r
-                                IN PLDR_DATA_TABLE_ENTRY ScanDTE)\r
-{\r
-       return FALSE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
-                             IN PCCH BaseDllName,\r
-                             IN PCCH FullDllName,\r
-                             IN PVOID BasePA,\r
-                             OUT PLDR_DATA_TABLE_ENTRY *NewEntry)\r
-{\r
-       PVOID BaseVA = PaToVa(BasePA);\r
-       PWSTR Buffer;\r
-       PLDR_DATA_TABLE_ENTRY DataTableEntry;\r
-       PIMAGE_NT_HEADERS NtHeaders;\r
-       USHORT Length;\r
-\r
-       /* Allocate memory for a data table entry, zero-initialize it */\r
-       DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmAllocateMemory(sizeof(LDR_DATA_TABLE_ENTRY));\r
-       if (DataTableEntry == NULL)\r
-               return FALSE;\r
-       RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));\r
-\r
-       /* Get NT headers from the image */\r
-       NtHeaders = RtlImageNtHeader(BasePA);\r
-\r
-       /* Initialize corresponding fields of DTE based on NT headers value */\r
-       DataTableEntry->DllBase = BaseVA;\r
-       DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;\r
-       DataTableEntry->EntryPoint = (PVOID)((ULONG)BaseVA +\r
-               NtHeaders->OptionalHeader.AddressOfEntryPoint);\r
-       DataTableEntry->SectionPointer = 0;\r
-       DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;\r
-\r
-       /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName\r
-          by simple conversion - copying each character */\r
-       Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));\r
-       Buffer = (PWSTR)MmAllocateMemory(Length);\r
-       if (Buffer == NULL)\r
-               return FALSE;\r
-       RtlZeroMemory(Buffer, Length);\r
-\r
-       DataTableEntry->BaseDllName.Length = Length;\r
-       DataTableEntry->BaseDllName.MaximumLength = Length;\r
-       DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);\r
-       while (*BaseDllName != 0)\r
-       {\r
-               *Buffer++ = *BaseDllName++;\r
-       }\r
-\r
-       /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName\r
-          using the same method */\r
-       Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));\r
-       Buffer = (PWSTR)MmAllocateMemory(Length);\r
-       if (Buffer == NULL)\r
-               return FALSE;\r
-       RtlZeroMemory(Buffer, Length);\r
-\r
-       DataTableEntry->FullDllName.Length = Length;\r
-       DataTableEntry->FullDllName.MaximumLength = Length;\r
-       DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);\r
-       while (*FullDllName != 0)\r
-       {\r
-               *Buffer++ = *FullDllName++;\r
-       }\r
-\r
-       /* Initialize what's left - LoadCount which is 1, and set Flags so that\r
-          we know this entry is processed */\r
-       DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;\r
-       DataTableEntry->LoadCount = 1;\r
-\r
-       /* Insert this DTE to a list in the LPB */\r
-       InsertTailList(&WinLdrBlock->LoadOrderListHead, &DataTableEntry->InLoadOrderLinks);\r
-\r
-       /* Save pointer to a newly allocated and initialized entry */\r
-       *NewEntry = DataTableEntry;\r
-\r
-       /* Return success */\r
-       return TRUE;\r
-}\r
-\r
-/* WinLdrLoadImage loads the specified image from the file (it doesn't\r
-   perform any additional operations on the filename, just directly\r
-   calls the file I/O routines), and relocates it so that it's ready\r
-   to be used when paging is enabled.\r
-   Addressing mode: physical\r
- */\r
-BOOLEAN\r
-WinLdrLoadImage(IN PCHAR FileName,\r
-                OUT PVOID *ImageBasePA)\r
-{\r
-       PFILE FileHandle;\r
-       PVOID PhysicalBase;\r
-       PVOID VirtualBase = NULL;\r
-       UCHAR HeadersBuffer[SECTOR_SIZE * 2];\r
-       PIMAGE_NT_HEADERS NtHeaders;\r
-       PIMAGE_SECTION_HEADER SectionHeader;\r
-       ULONG VirtualSize, SizeOfRawData, NumberOfSections;\r
-       BOOLEAN Status;\r
-       ULONG i, BytesRead;\r
-\r
-       //Print(L"Loading %s...  ", FileName);\r
-\r
-       /* Open the image file */\r
-       FileHandle = FsOpenFile(FileName);\r
-\r
-       if (FileHandle == NULL)\r
-       {\r
-               //Print(L"Can not open the file %s\n",FileName);\r
-               UiMessageBox("Can not open the file");\r
-               return FALSE;\r
-       }\r
-\r
-       /* Load the first 2 sectors of the image so we can read the PE header */\r
-       Status = FsReadFile(FileHandle, SECTOR_SIZE * 2, NULL, HeadersBuffer);\r
-       if (!Status)\r
-       {\r
-               //Print(L"Error reading from file %s\n", FileName);\r
-               UiMessageBox("Error reading from file");\r
-               FsCloseFile(FileHandle);\r
-               return FALSE;\r
-       }\r
-\r
-       /* Now read the MZ header to get the offset to the PE Header */\r
-       NtHeaders = RtlImageNtHeader(HeadersBuffer);\r
-\r
-       if (!NtHeaders)\r
-       {\r
-               //Print(L"Error - no NT header found in %s\n", FileName);\r
-               UiMessageBox("Error - no NT header found");\r
-               FsCloseFile(FileHandle);\r
-               return FALSE;\r
-       }\r
-\r
-       /* Ensure this is executable image */\r
-       if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))\r
-       {\r
-               //Print(L"Not an executable image %s\n", FileName);\r
-               UiMessageBox("Not an executable image");\r
-               FsCloseFile(FileHandle);\r
-               return FALSE;\r
-       }\r
-\r
-       /* Store number of sections to read and a pointer to the first section */\r
-       NumberOfSections = NtHeaders->FileHeader.NumberOfSections;\r
-       SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);\r
-\r
-       /* Try to allocate this memory, if fails - allocate somewhere else */\r
-       PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,\r
-                                              (PVOID)NtHeaders->OptionalHeader.ImageBase);\r
-\r
-       if (PhysicalBase == NULL)\r
-       {\r
-               /* It's ok, we don't panic - let's allocate again at any other "low" place */\r
-               MmChangeAllocationPolicy(FALSE);\r
-               PhysicalBase = MmAllocateMemory(NtHeaders->OptionalHeader.SizeOfImage);\r
-               MmChangeAllocationPolicy(TRUE);\r
-\r
-               if (PhysicalBase == NULL)\r
-               {\r
-                       //Print(L"Failed to alloc pages for image %s\n", FileName);\r
-                       UiMessageBox("Failed to alloc pages for image");\r
-                       FsCloseFile(FileHandle);\r
-                       return FALSE;\r
-               }\r
-       }\r
-\r
-       /* This is the real image base - in form of a virtual address */\r
-       VirtualBase = PaToVa(PhysicalBase);\r
-\r
-       DbgPrint((DPRINT_WINDOWS, "Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase));\r
-\r
-       /* Set to 0 position and fully load the file image */\r
-       FsSetFilePointer(FileHandle, 0);\r
-\r
-       Status = FsReadFile(FileHandle, NtHeaders->OptionalHeader.SizeOfHeaders, NULL, PhysicalBase);\r
-\r
-       if (!Status)\r
-       {\r
-               //Print(L"Error reading headers %s\n", FileName);\r
-               UiMessageBox("Error reading headers");\r
-               FsCloseFile(FileHandle);\r
-               return FALSE;\r
-       }\r
-\r
-       /* Reload the NT Header */\r
-       NtHeaders = RtlImageNtHeader(PhysicalBase);\r
-\r
-       /* Load the first section */\r
-       SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);\r
-\r
-       /* Fill output parameters */\r
-       *ImageBasePA = PhysicalBase;\r
-\r
-       /* Walk through each section and read it (check/fix any possible\r
-          bad situations, if they arise) */\r
-       for (i = 0; i < NumberOfSections; i++)\r
-       {\r
-               VirtualSize = SectionHeader->Misc.VirtualSize;\r
-               SizeOfRawData = SectionHeader->SizeOfRawData;\r
-\r
-               /* Handle a case when VirtualSize equals 0 */\r
-               if (VirtualSize == 0)\r
-                       VirtualSize = SizeOfRawData;\r
-\r
-               /* If PointerToRawData is 0, then force its size to be also 0 */\r
-               if (SectionHeader->PointerToRawData == 0)\r
-               {\r
-                       SizeOfRawData = 0;\r
-               }\r
-               else\r
-               {\r
-                       /* Cut the loaded size to the VirtualSize extents */\r
-                       if (SizeOfRawData > VirtualSize)\r
-                               SizeOfRawData = VirtualSize;\r
-               }\r
-\r
-               /* Actually read the section (if its size is not 0) */\r
-               if (SizeOfRawData != 0)\r
-               {\r
-                       /* Seek to the correct position */\r
-                       FsSetFilePointer(FileHandle, SectionHeader->PointerToRawData);\r
-\r
-                       DbgPrint((DPRINT_WINDOWS, "SH->VA: 0x%X\n", SectionHeader->VirtualAddress));\r
-\r
-                       /* Read this section from the file, size = SizeOfRawData */\r
-                       Status = FsReadFile(FileHandle, SizeOfRawData, &BytesRead, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress);\r
-\r
-                       if (!Status && (BytesRead == 0))\r
-                               break;\r
-               }\r
-\r
-               /* Size of data is less than the virtual size - fill up the remainder with zeroes */\r
-               if (SizeOfRawData < VirtualSize)\r
-                       RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);\r
-\r
-               SectionHeader++;\r
-       }\r
-\r
-       /* We are done with the file - close it */\r
-       FsCloseFile(FileHandle);\r
-\r
-       /* If loading failed - return right now */\r
-       if (!Status)\r
-               return FALSE;\r
-\r
-\r
-       /* Relocate the image, if it needs it */\r
-       if (NtHeaders->OptionalHeader.ImageBase != (ULONG)VirtualBase)\r
-       {\r
-               DbgPrint((DPRINT_WINDOWS, "Relocating %p -> %p\n",\r
-                       NtHeaders->OptionalHeader.ImageBase, VirtualBase));\r
-               Status = (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,\r
-                       0,\r
-                       "FLx86",\r
-                       TRUE,\r
-                       3,\r
-                       FALSE);\r
-       }\r
-\r
-       return Status;\r
-}\r
-\r
-/* PRIVATE FUNCTIONS *******************************************************/\r
+/*
+ * PROJECT:         WinLoader
+ * 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 <freeldr.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS **************************************************************/
+
+BOOLEAN
+WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+                        IN PCH DllName,
+                        OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
+{
+       return FALSE;
+}
+
+
+BOOLEAN
+WinLdrScanImportDescriptorTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+                                IN PCCH DirectoryPath,
+                                IN PLDR_DATA_TABLE_ENTRY ScanDTE)
+{
+       return FALSE;
+}
+
+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 = (PVOID)((ULONG)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,
+                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;
+
+       //Print(L"Loading %s...  ", FileName);
+
+       /* 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)NtHeaders->OptionalHeader.ImageBase);
+
+       if (PhysicalBase == NULL)
+       {
+               /* It's ok, we don't panic - let's allocate again at any other "low" place */
+               MmChangeAllocationPolicy(FALSE);
+               PhysicalBase = MmAllocateMemory(NtHeaders->OptionalHeader.SizeOfImage);
+               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))
+                               break;
+               }
+
+               /* Size of data is less than the virtual size - fill up the remainder with zeroes */
+               if (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,
+                       0,
+                       "FLx86",
+                       TRUE,
+                       3,
+                       FALSE);
+       }
+
+       return Status;
+}
+
+/* PRIVATE FUNCTIONS *******************************************************/