- Silence TCPIP.
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
index c20a857..8866fda 100644 (file)
-/* $Id: loader.c,v 1.136 2003/10/12 17:05:45 hbirr Exp $
- * 
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ldr/loader.c
  * PURPOSE:         Loaders for PE executables
+ *
  * PROGRAMMERS:     Jean Michault
  *                  Rex Jolliff (rex@lvcablemodem.com)
  *                  Jason Filby (jasonfilby@yahoo.com)
  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
- * UPDATE HISTORY:
- *   DW   22/05/98   Created
- *   RJJ  10/12/98   Completed image loader function and added hooks for MZ/PE
- *   RJJ  10/12/98   Built driver loader function and added hooks for PE/COFF
- *   RJJ  10/12/98   Rolled in David's code to load COFF drivers
- *   JM   14/12/98   Built initial PE user module loader
- *   RJJ  06/03/99   Moved user PE loader into NTDLL
- *   JF   26/01/2000 Recoded some parts to retrieve export details correctly
- *   DW   27/06/2000 Removed redundant header files
- *   CSH  11/04/2001 Added automatic loading of module symbols if they exist
- *   KJK  02/04/2003 Nebbet-ized a couple of type names
  */
 
 
 /* INCLUDES *****************************************************************/
 
-#include <limits.h>
-#include <ddk/ntddk.h>
-#include <roscfg.h>
-#include <internal/module.h>
-#include <internal/ntoskrnl.h>
-#include <internal/kd.h>
-#include <internal/io.h>
-#include <internal/mm.h>
-#include <internal/ps.h>
-#include <internal/ldr.h>
-#include <internal/pool.h>
-#include <internal/kd.h>
-#include <ntos/minmax.h>
+#include <ntoskrnl.h>
 
 #ifdef HALDBG
 #include <internal/ntosdbg.h>
 #else
+#ifdef __GNUC__
 #define ps(args...)
+#else
+#define ps
+#endif /* __GNUC__ */
+#endif
+
+#if 0
+#undef ps
+#define ps(args...) DPRINT1(args)
 #endif
 
 #define NDEBUG
 #include <internal/debug.h>
 
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, LdrInit1)
+#pragma alloc_text(INIT, LdrInitModuleManagement)
+#pragma alloc_text(INIT, LdrSafePEProcessModule)
+#endif
+
 /* GLOBALS *******************************************************************/
 
 LIST_ENTRY ModuleListHead;
 KSPIN_LOCK ModuleListLock;
+LDR_DATA_TABLE_ENTRY NtoskrnlModuleObject;
+LDR_DATA_TABLE_ENTRY HalModuleObject;
 
-LIST_ENTRY ModuleTextListHead;
-STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
-STATIC MODULE_TEXT_SECTION LdrHalTextSection;
 ULONG_PTR LdrHalBase;
 
-#define TAG_DRIVER_MEM  TAG('D', 'R', 'V', 'M')
-
 /* FORWARD DECLARATIONS ******************************************************/
 
 NTSTATUS
-LdrProcessModule(PVOID ModuleLoadBase,
-                PUNICODE_STRING ModuleName,
-                PMODULE_OBJECT *ModuleObject);
-
-PVOID
-LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
-                   char *Name,
-                   unsigned short Hint);
+LdrProcessModule (
+    PVOID ModuleLoadBase,
+    PUNICODE_STRING ModuleName,
+    PLDR_DATA_TABLE_ENTRY *ModuleObject );
 
 static VOID
-LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
-                       PUNICODE_STRING FullName);
+LdrpBuildModuleBaseName (
+    PUNICODE_STRING BaseName,
+    PUNICODE_STRING FullName );
 
 static LONG
-LdrpCompareModuleNames(IN PUNICODE_STRING String1,
-                      IN PUNICODE_STRING String2);
+LdrpCompareModuleNames (
+    IN PUNICODE_STRING String1,
+    IN PUNICODE_STRING String2 );
 
 
 /*  PE Driver load support  */
-static NTSTATUS LdrPEProcessModule(PVOID ModuleLoadBase,
-                                   PUNICODE_STRING FileName,
-                                   PMODULE_OBJECT *ModuleObject);
-static PVOID
-LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
-                     PCHAR Name,
-                     USHORT Hint);
+static NTSTATUS
+LdrPEProcessModule (
+    PVOID ModuleLoadBase,
+    PUNICODE_STRING FileName,
+    PLDR_DATA_TABLE_ENTRY *ModuleObject );
 
 static PVOID
-LdrSafePEGetExportAddress(PVOID ImportModuleBase,
-                         PCHAR Name,
-                         USHORT Hint);
+LdrPEGetExportByName (
+    PVOID BaseAddress,
+    PUCHAR SymbolName,
+    WORD Hint );
 
 static PVOID
-LdrPEFixupForward(PCHAR ForwardName);
+LdrPEFixupForward ( PCHAR ForwardName );
 
+static NTSTATUS
+LdrPEPerformRelocations (
+    PVOID DriverBase,
+    ULONG DriverSize );
+
+static NTSTATUS
+LdrPEFixupImports ( PLDR_DATA_TABLE_ENTRY Module );
 
 /* FUNCTIONS *****************************************************************/
 
 VOID
-LdrInitDebug(PLOADER_MODULE Module, PWCH Name)
+NTAPI
+LdrInitDebug ( PLOADER_MODULE Module, PWCH Name )
 {
-  PLIST_ENTRY current_entry;
-  MODULE_TEXT_SECTION* current;
-
-  current_entry = ModuleTextListHead.Flink;
-  while (current_entry != &ModuleTextListHead)
-    {
-      current = 
-       CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
-      if (wcscmp(current->Name, Name) == 0)
-       {
-         break;
-       }
-      current_entry = current_entry->Flink;
-    }
-
-  if (current_entry == &ModuleTextListHead)
-    {
-      return;
-    }
 }
 
-VOID INIT_FUNCTION
-LdrInit1(VOID)
+VOID
+INIT_FUNCTION
+NTAPI
+LdrInit1 ( VOID )
 {
-  PIMAGE_DOS_HEADER DosHeader;
-  PIMAGE_FILE_HEADER FileHeader;
-  PIMAGE_OPTIONAL_HEADER OptionalHeader;
-  PIMAGE_SECTION_HEADER SectionList;
-
-  InitializeListHead(&ModuleTextListHead);
-
-  /* Setup ntoskrnl.exe text section */
-  DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
-  FileHeader =
-    (PIMAGE_FILE_HEADER) ((DWORD)KERNEL_BASE + 
-                         DosHeader->e_lfanew + sizeof(ULONG));
-  OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
-    ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
-  SectionList = (PIMAGE_SECTION_HEADER)
-    ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
-  NtoskrnlTextSection.Base = KERNEL_BASE;
-  NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
-    SectionList[0].VirtualAddress;
-  NtoskrnlTextSection.Name = KERNEL_MODULE_NAME;
-  NtoskrnlTextSection.OptionalHeader = OptionalHeader;
-  InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
-
-  /* Setup hal.dll text section */
-  DosHeader = (PIMAGE_DOS_HEADER)LdrHalBase;
-  FileHeader =
-    (PIMAGE_FILE_HEADER) ((DWORD)LdrHalBase + 
-                         DosHeader->e_lfanew + sizeof(ULONG));
-  OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
-    ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
-  SectionList = (PIMAGE_SECTION_HEADER)
-    ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
-  LdrHalTextSection.Base = LdrHalBase;
-  LdrHalTextSection.Length = SectionList[0].Misc.VirtualSize +
-    SectionList[0].VirtualAddress;
-  LdrHalTextSection.Name = HAL_MODULE_NAME;
-  LdrHalTextSection.OptionalHeader = OptionalHeader;
-  InsertTailList(&ModuleTextListHead, &LdrHalTextSection.ListEntry);
-
-  /* Hook for KDB on initialization of the loader. */
-  KDB_LOADERINIT_HOOK(&NtoskrnlTextSection, &LdrHalTextSection);
+    /* Hook for KDB on initialization of the loader. */
+    KDB_LOADERINIT_HOOK(&NtoskrnlModuleObject, &HalModuleObject);
 }
 
-
-VOID INIT_FUNCTION
-LdrInitModuleManagement(VOID)
+VOID
+INIT_FUNCTION
+NTAPI
+LdrInitModuleManagement ( VOID )
 {
-  PIMAGE_DOS_HEADER DosHeader;
-  PMODULE_OBJECT ModuleObject;
-
-  /* Initialize the module list and spinlock */
-  InitializeListHead(&ModuleListHead);
-  KeInitializeSpinLock(&ModuleListLock);
-
-  /* Create module object for NTOSKRNL */
-  ModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
-  assert(ModuleObject != NULL);
-  RtlZeroMemory(ModuleObject, sizeof(MODULE_OBJECT));
-
-  /* Initialize ModuleObject data */
-  ModuleObject->Base = (PVOID) KERNEL_BASE;
-  ModuleObject->Flags = MODULE_FLAG_PE;
-  RtlCreateUnicodeString(&ModuleObject->FullName,
-                        KERNEL_MODULE_NAME);
-  LdrpBuildModuleBaseName(&ModuleObject->BaseName,
-                         &ModuleObject->FullName);
-
-  DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
-  ModuleObject->Image.PE.FileHeader =
-    (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
-    DosHeader->e_lfanew + sizeof(ULONG));
-  ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
-    ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
-  ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
-    ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
-  ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
-    ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
-  DPRINT("ModuleObject:%08x  entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
-  ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
-  ModuleObject->TextSection = &NtoskrnlTextSection;
-
-  InsertTailList(&ModuleListHead,
-                &ModuleObject->ListEntry);
-
-  /* Create module object for HAL */
-  ModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
-  assert(ModuleObject != NULL);
-  RtlZeroMemory(ModuleObject, sizeof(MODULE_OBJECT));
-
-  /* Initialize ModuleObject data */
-  ModuleObject->Base = (PVOID) LdrHalBase;
-  ModuleObject->Flags = MODULE_FLAG_PE;
-
-  RtlCreateUnicodeString(&ModuleObject->FullName,
-                        HAL_MODULE_NAME);
-  LdrpBuildModuleBaseName(&ModuleObject->BaseName,
-                         &ModuleObject->FullName);
-
-  DosHeader = (PIMAGE_DOS_HEADER) LdrHalBase;
-  ModuleObject->Image.PE.FileHeader =
-    (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
-    DosHeader->e_lfanew + sizeof(ULONG));
-  ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
-    ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
-  ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
-    ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
-  ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
-    ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
-  DPRINT("ModuleObject:%08x  entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
-  ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
-  ModuleObject->TextSection = &LdrHalTextSection;
-
-  InsertTailList(&ModuleListHead,
-                &ModuleObject->ListEntry);
+    PIMAGE_NT_HEADERS NtHeader;
+
+    /* Initialize the module list and spinlock */
+    InitializeListHead(&ModuleListHead);
+    KeInitializeSpinLock(&ModuleListLock);
+
+    /* Initialize ModuleObject for NTOSKRNL */
+    RtlZeroMemory(&NtoskrnlModuleObject, sizeof(LDR_DATA_TABLE_ENTRY));
+    NtoskrnlModuleObject.DllBase = (PVOID) KERNEL_BASE;
+    RtlInitUnicodeString(&NtoskrnlModuleObject.FullDllName, KERNEL_MODULE_NAME);
+    LdrpBuildModuleBaseName(&NtoskrnlModuleObject.BaseDllName, &NtoskrnlModuleObject.FullDllName);
+
+    NtHeader = RtlImageNtHeader((PVOID)KERNEL_BASE);
+    NtoskrnlModuleObject.EntryPoint = (PVOID) ((ULONG_PTR) NtoskrnlModuleObject.DllBase + NtHeader->OptionalHeader.AddressOfEntryPoint);
+    DPRINT("ModuleObject:%08x  entrypoint at %x\n", &NtoskrnlModuleObject, NtoskrnlModuleObject.EntryPoint);
+    NtoskrnlModuleObject.SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
+
+    InsertTailList(&ModuleListHead, &NtoskrnlModuleObject.InLoadOrderModuleList);
+
+    /* Initialize ModuleObject for HAL */
+    RtlZeroMemory(&HalModuleObject, sizeof(LDR_DATA_TABLE_ENTRY));
+    HalModuleObject.DllBase = (PVOID) LdrHalBase;
+
+    RtlInitUnicodeString(&HalModuleObject.FullDllName, HAL_MODULE_NAME);
+    LdrpBuildModuleBaseName(&HalModuleObject.BaseDllName, &HalModuleObject.FullDllName);
+
+    NtHeader = RtlImageNtHeader((PVOID)LdrHalBase);
+    HalModuleObject.EntryPoint = (PVOID) ((ULONG_PTR) HalModuleObject.DllBase + NtHeader->OptionalHeader.AddressOfEntryPoint);
+    DPRINT("ModuleObject:%08x  entrypoint at %x\n", &HalModuleObject, HalModuleObject.EntryPoint);
+    HalModuleObject.SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
+
+    InsertTailList(&ModuleListHead, &HalModuleObject.InLoadOrderModuleList);
 }
 
 NTSTATUS
-LdrpLoadImage(PUNICODE_STRING DriverName,
-             PVOID *ModuleBase,
-             PVOID *SectionPointer,
-             PVOID *EntryPoint,
-             PVOID *ExportSectionPointer)
+NTAPI
+LdrpLoadImage (
+    PUNICODE_STRING DriverName,
+    PVOID *ModuleBase,
+    PVOID *SectionPointer,
+    PVOID *EntryPoint,
+    PVOID *ExportSectionPointer )
 {
-  PMODULE_OBJECT ModuleObject;
-  NTSTATUS Status;
+    PLDR_DATA_TABLE_ENTRY ModuleObject;
+    NTSTATUS Status;
 
-  ModuleObject = LdrGetModuleObject(DriverName);
-  if (ModuleObject == NULL)
+    ModuleObject = LdrGetModuleObject(DriverName);
+    if (ModuleObject == NULL)
     {
-      Status = LdrLoadModule(DriverName, &ModuleObject);
-      if (!NT_SUCCESS(Status))
-       {
-         return(Status);
-       }
+        Status = LdrLoadModule(DriverName, &ModuleObject);
+        if (!NT_SUCCESS(Status))
+        {
+            return(Status);
+        }
     }
 
-  if (ModuleBase)
-    *ModuleBase = ModuleObject->Base;
+    if (ModuleBase)
+        *ModuleBase = ModuleObject->DllBase;
 
-//  if (SectionPointer)
-//    *SectionPointer = ModuleObject->
+    if (SectionPointer)
+        *SectionPointer = ModuleObject;
 
-  if (EntryPoint)
-    *EntryPoint = ModuleObject->EntryPoint;
+    if (EntryPoint)
+        *EntryPoint = ModuleObject->EntryPoint;
 
-//  if (ExportSectionPointer)
-//    *ExportSectionPointer = ModuleObject->
+    //if (ExportSectionPointer)
+    //    *ExportSectionPointer = ModuleObject->
 
-  return(STATUS_SUCCESS);
+    return(STATUS_SUCCESS);
 }
 
 
 NTSTATUS
-LdrpUnloadImage(PVOID ModuleBase)
+NTAPI
+LdrpUnloadImage ( PVOID ModuleBase )
 {
-  return(STATUS_NOT_IMPLEMENTED);
+    return(STATUS_NOT_IMPLEMENTED);
 }
 
 
 NTSTATUS
-LdrpLoadAndCallImage(PUNICODE_STRING ModuleName)
+NTAPI
+LdrpLoadAndCallImage ( PUNICODE_STRING ModuleName )
 {
-  PDRIVER_INITIALIZE DriverEntry;
-  PMODULE_OBJECT ModuleObject;
-  NTSTATUS Status;
+    PDRIVER_INITIALIZE DriverEntry;
+    PLDR_DATA_TABLE_ENTRY ModuleObject;
+    DRIVER_OBJECT DriverObject;
+    NTSTATUS Status;
 
-  ModuleObject = LdrGetModuleObject(ModuleName);
-  if (ModuleObject != NULL)
+    ModuleObject = LdrGetModuleObject(ModuleName);
+    if (ModuleObject != NULL)
     {
-      return(STATUS_IMAGE_ALREADY_LOADED);
+        return(STATUS_IMAGE_ALREADY_LOADED);
     }
 
-  Status = LdrLoadModule(ModuleName, &ModuleObject);
-  if (!NT_SUCCESS(Status))
+    Status = LdrLoadModule(ModuleName, &ModuleObject);
+    if (!NT_SUCCESS(Status))
     {
-      return(Status);
+        return(Status);
     }
 
-  DriverEntry = (PDRIVER_INITIALIZE)ModuleObject->EntryPoint;
+    DriverEntry = (PDRIVER_INITIALIZE)ModuleObject->EntryPoint;
+
+    RtlZeroMemory(&DriverObject, sizeof(DriverObject));
+//    DriverObject.DriverStart = ModuleObject->DllBase;
 
-  Status = DriverEntry(NULL, NULL);
-  if (!NT_SUCCESS(Status))
+    Status = DriverEntry(&DriverObject, NULL);
+    if (!NT_SUCCESS(Status))
     {
-      LdrUnloadModule(ModuleObject);
+        LdrUnloadModule(ModuleObject);
     }
 
-  return(Status);
+    return(Status);
 }
 
 
 NTSTATUS
-LdrLoadModule(PUNICODE_STRING Filename,
-             PMODULE_OBJECT *ModuleObject)
+NTAPI
+LdrLoadModule(
+    PUNICODE_STRING Filename,
+    PLDR_DATA_TABLE_ENTRY *ModuleObject )
 {
-  PVOID ModuleLoadBase;
-  NTSTATUS Status;
-  HANDLE FileHandle;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  PMODULE_OBJECT Module;
-  FILE_STANDARD_INFORMATION FileStdInfo;
-  IO_STATUS_BLOCK IoStatusBlock;
-
-  *ModuleObject = NULL;
-
-  DPRINT("Loading Module %wZ...\n", Filename);
-
-  /*  Open the Module  */
-  InitializeObjectAttributes(&ObjectAttributes,
-                             Filename,
-                             0,
-                             NULL,
-                             NULL);
-  CHECKPOINT;
-  Status = NtOpenFile(&FileHandle,
-                      FILE_ALL_ACCESS,
-                      &ObjectAttributes,
-                      &IoStatusBlock,
-                      0,
-                      FILE_SYNCHRONOUS_IO_NONALERT);
-  CHECKPOINT;
-  if (!NT_SUCCESS(Status))
+    PVOID ModuleLoadBase;
+    NTSTATUS Status;
+    HANDLE FileHandle;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    PLDR_DATA_TABLE_ENTRY Module;
+    FILE_STANDARD_INFORMATION FileStdInfo;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    *ModuleObject = NULL;
+
+    DPRINT("Loading Module %wZ...\n", Filename);
+
+    /*  Open the Module  */
+    InitializeObjectAttributes(&ObjectAttributes,
+        Filename,
+        OBJ_CASE_INSENSITIVE,
+        NULL,
+        NULL);
+    CHECKPOINT;
+    Status = ZwOpenFile(&FileHandle,
+        GENERIC_READ,
+        &ObjectAttributes,
+        &IoStatusBlock,
+        FILE_SHARE_READ,
+        FILE_SYNCHRONOUS_IO_NONALERT);
+    CHECKPOINT;
+    if (!NT_SUCCESS(Status))
     {
-      CPRINT("Could not open module file: %wZ\n", Filename);
-      return(Status);
+        CPRINT("Could not open module file: %wZ (Status 0x%08lx)\n", Filename, Status);
+        return(Status);
     }
-  CHECKPOINT;
-
-  /*  Get the size of the file  */
-  Status = NtQueryInformationFile(FileHandle,
-                                  &IoStatusBlock,
-                                  &FileStdInfo,
-                                  sizeof(FileStdInfo),
-                                  FileStandardInformation);
-  if (!NT_SUCCESS(Status))
+    CHECKPOINT;
+
+    /*  Get the size of the file  */
+    Status = ZwQueryInformationFile(FileHandle,
+        &IoStatusBlock,
+        &FileStdInfo,
+        sizeof(FileStdInfo),
+        FileStandardInformation);
+    if (!NT_SUCCESS(Status))
     {
-      CPRINT("Could not get file size\n");
-      NtClose(FileHandle);
-      return(Status);
+        CPRINT("Could not get file size\n");
+        NtClose(FileHandle);
+        return(Status);
     }
-  CHECKPOINT;
+    CHECKPOINT;
 
-  /*  Allocate nonpageable memory for driver  */
-  ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
-                                        FileStdInfo.EndOfFile.u.LowPart,
-                                        TAG_DRIVER_MEM);
-  if (ModuleLoadBase == NULL)
+    /*  Allocate nonpageable memory for driver  */
+    ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
+        FileStdInfo.EndOfFile.u.LowPart,
+        TAG_DRIVER_MEM);
+    if (ModuleLoadBase == NULL)
     {
-      CPRINT("Could not allocate memory for module");
-      NtClose(FileHandle);
-      return(STATUS_INSUFFICIENT_RESOURCES);
+        CPRINT("Could not allocate memory for module");
+        NtClose(FileHandle);
+        return(STATUS_INSUFFICIENT_RESOURCES);
     }
-  CHECKPOINT;
-
-  /*  Load driver into memory chunk  */
-  Status = NtReadFile(FileHandle,
-                      0, 0, 0,
-                      &IoStatusBlock,
-                      ModuleLoadBase,
-                      FileStdInfo.EndOfFile.u.LowPart,
-                      0, 0);
-  if (!NT_SUCCESS(Status))
+    CHECKPOINT;
+
+    /*  Load driver into memory chunk  */
+    Status = ZwReadFile(FileHandle,
+        0, 0, 0,
+        &IoStatusBlock,
+        ModuleLoadBase,
+        FileStdInfo.EndOfFile.u.LowPart,
+        0, 0);
+    if (!NT_SUCCESS(Status))
     {
-      CPRINT("Could not read module file into memory");
-      ExFreePool(ModuleLoadBase);
-      NtClose(FileHandle);
-      return(Status);
+        CPRINT("Could not read module file into memory");
+        ExFreePool(ModuleLoadBase);
+        NtClose(FileHandle);
+        return(Status);
     }
-  CHECKPOINT;
+    CHECKPOINT;
 
-  NtClose(FileHandle);
+    ZwClose(FileHandle);
 
-  Status = LdrProcessModule(ModuleLoadBase,
-                            Filename,
-                            &Module);
-  if (!NT_SUCCESS(Status))
+    Status = LdrProcessModule(ModuleLoadBase,
+        Filename,
+        &Module);
+    if (!NT_SUCCESS(Status))
     {
-      CPRINT("Could not process module");
-      ExFreePool(ModuleLoadBase);
-      return(Status);
+        CPRINT("Could not process module\n");
+        ExFreePool(ModuleLoadBase);
+        return(Status);
     }
 
-  /*  Cleanup  */
-  ExFreePool(ModuleLoadBase);
+    /*  Cleanup  */
+    ExFreePool(ModuleLoadBase);
 
-  *ModuleObject = Module;
+    *ModuleObject = Module;
 
-  /* Hook for KDB on loading a driver. */
-  KDB_LOADDRIVER_HOOK(Filename, Module);
+    /* Hook for KDB on loading a driver. */
+    KDB_LOADDRIVER_HOOK(Filename, Module);
 
-  return(STATUS_SUCCESS);
+    return(STATUS_SUCCESS);
 }
 
 
 NTSTATUS
-LdrUnloadModule(PMODULE_OBJECT ModuleObject)
+NTAPI
+LdrUnloadModule ( PLDR_DATA_TABLE_ENTRY ModuleObject )
 {
-  KIRQL Irql;
+    KIRQL Irql;
 
-  /* Remove the module from the module list */
-  KeAcquireSpinLock(&ModuleListLock,&Irql);
-  RemoveEntryList(&ModuleObject->ListEntry);
-  KeReleaseSpinLock(&ModuleListLock, Irql);
+    /* Remove the module from the module list */
+    KeAcquireSpinLock(&ModuleListLock,&Irql);
+    RemoveEntryList(&ModuleObject->InLoadOrderModuleList);
+    KeReleaseSpinLock(&ModuleListLock, Irql);
 
-  /* Hook for KDB on unloading a driver. */
-  KDB_UNLOADDRIVER_HOOK(ModuleObject);
-
-  /* Free text section */
-  if (ModuleObject->TextSection != NULL)
-    {
-      ExFreePool(ModuleObject->TextSection->Name);
-      RemoveEntryList(&ModuleObject->TextSection->ListEntry);
-      ExFreePool(ModuleObject->TextSection);
-      ModuleObject->TextSection = NULL;
-    }
+    /* Hook for KDB on unloading a driver. */
+    KDB_UNLOADDRIVER_HOOK(ModuleObject);
 
-  /* Free module section */
-//  MmFreeSection(ModuleObject->Base);
+    /* Free module section */
+    //  MmFreeSection(ModuleObject->DllBase);
 
-  ExFreePool(ModuleObject);
+    ExFreePool(ModuleObject->FullDllName.Buffer);
+    ExFreePool(ModuleObject);
 
-  return(STATUS_SUCCESS);
-}
-
-
-NTSTATUS INIT_FUNCTION
-LdrInitializeBootStartDriver(PVOID ModuleLoadBase,
-                            PCHAR FileName,
-                            ULONG ModuleLength)
-{
-  PMODULE_OBJECT ModuleObject;
-  UNICODE_STRING ModuleName;
-  PDEVICE_NODE DeviceNode;
-  NTSTATUS Status;
-
-  WCHAR Buffer[MAX_PATH];
-  ULONG Length;
-  LPWSTR Start;
-  LPWSTR Ext;
-  PCHAR FileExt;
-  CHAR TextBuffer [256];
-  ULONG x, y, cx, cy;
-
-  HalQueryDisplayParameters(&x, &y, &cx, &cy);
-  RtlFillMemory(TextBuffer, x, ' ');
-  TextBuffer[x] = '\0';
-  HalSetDisplayParameters(0, y-1);
-  HalDisplayString(TextBuffer);
-
-  sprintf(TextBuffer, "Initializing %s...\n", FileName);
-  HalSetDisplayParameters(0, y-1);
-  HalDisplayString(TextBuffer);
-  HalSetDisplayParameters(cx, cy);
-
-  /*  Split the filename into base name and extension  */
-  FileExt = strrchr(FileName, '.');
-  if (FileExt != NULL)
-    Length = FileExt - FileName;
-  else
-    Length = strlen(FileName);
-
-  if ((FileExt != NULL) && (strcmp(FileExt, ".sym") == 0))
-    {
-      KDB_SYMBOLFILE_HOOK(ModuleLoadBase, FileName, Length);
-      return(STATUS_SUCCESS);
-    }
-  else if ((FileExt != NULL) && !(strcmp(FileExt, ".sys") == 0))
-    {
-      CPRINT("Ignoring non-driver file %s\n", FileName);
-      return STATUS_SUCCESS;
-    }
-
-  /* Use IopRootDeviceNode for now */
-  Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
-  if (!NT_SUCCESS(Status))
-    {
-      CPRINT("Driver load failed, status (%x)\n", Status);
-      return(Status);
-    }
-
-  RtlCreateUnicodeStringFromAsciiz(&ModuleName,
-                                  FileName);
-  Status = LdrProcessModule(ModuleLoadBase,
-                           &ModuleName,
-                           &ModuleObject);
-  RtlFreeUnicodeString(&ModuleName);
-  if (ModuleObject == NULL)
-    {
-      IopFreeDeviceNode(DeviceNode);
-      CPRINT("Driver load failed, status (%x)\n", Status);
-      return(STATUS_UNSUCCESSFUL);
-    }
-
-
-  /* Get the service name from the module name */
-  Start = wcsrchr(ModuleObject->BaseName.Buffer, L'\\');
-  if (Start == NULL)
-    Start = ModuleObject->BaseName.Buffer;
-  else
-    Start++;
-
-  Ext = wcsrchr(ModuleObject->BaseName.Buffer, L'.');
-  if (Ext != NULL)
-    Length = Ext - Start;
-  else
-    Length = wcslen(Start);
-
-  wcsncpy(Buffer, Start, Length);
-  Buffer[Length] = 0;
-  RtlCreateUnicodeString(&DeviceNode->ServiceName, Buffer);
-
-  Status = IopInitializeDriver(ModuleObject->EntryPoint,
-                              DeviceNode, FALSE,
-                              ModuleObject->Base,
-                              ModuleObject->Length,
-                              TRUE);
-  if (!NT_SUCCESS(Status))
-    {
-      IopFreeDeviceNode(DeviceNode);
-      CPRINT("Driver load failed, status (%x)\n", Status);
-    }
-
-  return(Status);
+    return(STATUS_SUCCESS);
 }
 
 
 NTSTATUS
-LdrProcessModule(PVOID ModuleLoadBase,
-                PUNICODE_STRING ModuleName,
-                PMODULE_OBJECT *ModuleObject)
+LdrProcessModule(
+    PVOID ModuleLoadBase,
+    PUNICODE_STRING ModuleName,
+    PLDR_DATA_TABLE_ENTRY *ModuleObject )
 {
-  PIMAGE_DOS_HEADER PEDosHeader;
+    PIMAGE_DOS_HEADER PEDosHeader;
 
-  /*  If MZ header exists  */
-  PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
-  if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
+    /*  If MZ header exists  */
+    PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
+    if (PEDosHeader->e_magic == IMAGE_DOS_SIGNATURE && PEDosHeader->e_lfanew != 0L)
     {
-      return LdrPEProcessModule(ModuleLoadBase,
-                               ModuleName,
-                               ModuleObject);
+        return LdrPEProcessModule(ModuleLoadBase,
+            ModuleName,
+            ModuleObject);
     }
 
-  CPRINT("Module wasn't PE\n");
-  return STATUS_UNSUCCESSFUL;
-}
-
-
-PVOID
-LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
-                    char *Name,
-                    unsigned short Hint)
-{
-  if (ModuleObject->Flags & MODULE_FLAG_PE)
-    {
-      return LdrPEGetExportAddress(ModuleObject, Name, Hint);
-    }
-  else
-    {
-      return 0;
-    }
+    CPRINT("Module wasn't PE\n");
+    return STATUS_UNSUCCESSFUL;
 }
 
-
 NTSTATUS
-LdrpQueryModuleInformation(PVOID Buffer,
-                          ULONG Size,
-                          PULONG ReqSize)
+NTAPI
+LdrpQueryModuleInformation (
+    PVOID Buffer,
+    ULONG Size,
+    PULONG ReqSize )
 {
-  PLIST_ENTRY current_entry;
-  PMODULE_OBJECT current;
-  ULONG ModuleCount = 0;
-  PSYSTEM_MODULE_INFORMATION Smi;
-  ANSI_STRING AnsiName;
-  PCHAR p;
-  KIRQL Irql;
-
-  KeAcquireSpinLock(&ModuleListLock,&Irql);
-
-  /* calculate required size */
-  current_entry = ModuleListHead.Flink;
-  while (current_entry != (&ModuleListHead))
+    PLIST_ENTRY current_entry;
+    PLDR_DATA_TABLE_ENTRY current;
+    ULONG ModuleCount = 0;
+    PSYSTEM_MODULE_INFORMATION Smi;
+    ANSI_STRING AnsiName;
+    PCHAR p;
+    KIRQL Irql;
+
+    KeAcquireSpinLock(&ModuleListLock,&Irql);
+
+    /* calculate required size */
+    current_entry = ModuleListHead.Flink;
+    while (current_entry != (&ModuleListHead))
     {
-      ModuleCount++;
-      current_entry = current_entry->Flink;
+        ModuleCount++;
+        current_entry = current_entry->Flink;
     }
 
-  *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
-    (ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION_ENTRY);
+    *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
+        (ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION_ENTRY);
 
-  if (Size < *ReqSize)
+    if (Size < *ReqSize)
     {
-      KeReleaseSpinLock(&ModuleListLock, Irql);
-      return(STATUS_INFO_LENGTH_MISMATCH);
+        KeReleaseSpinLock(&ModuleListLock, Irql);
+        return(STATUS_INFO_LENGTH_MISMATCH);
     }
 
-  /* fill the buffer */
-  memset(Buffer, '=', Size);
+    /* fill the buffer */
+    memset(Buffer, '=', Size);
 
-  Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
-  Smi->Count = ModuleCount;
+    Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
+    Smi->Count = ModuleCount;
 
-  ModuleCount = 0;
-  current_entry = ModuleListHead.Flink;
-  while (current_entry != (&ModuleListHead))
+    ModuleCount = 0;
+    current_entry = ModuleListHead.Flink;
+    while (current_entry != (&ModuleListHead))
     {
-      current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
-
-      Smi->Module[ModuleCount].Unknown1 = 0;           /* Always 0 */
-      Smi->Module[ModuleCount].Unknown2 = 0;           /* Always 0 */
-      Smi->Module[ModuleCount].Base = current->Base;
-      Smi->Module[ModuleCount].Size = current->Length;
-      Smi->Module[ModuleCount].Flags = 0;              /* Flags ??? (GN) */
-      Smi->Module[ModuleCount].Index = ModuleCount;
-      Smi->Module[ModuleCount].NameLength = 0;
-      Smi->Module[ModuleCount].LoadCount = 0; /* FIXME */
-
-      AnsiName.Length = 0;
-      AnsiName.MaximumLength = 256;
-      AnsiName.Buffer = Smi->Module[ModuleCount].ImageName;
-      RtlUnicodeStringToAnsiString(&AnsiName,
-                                  &current->FullName,
-                                  FALSE);
-
-      p = strrchr(AnsiName.Buffer, '\\');
-      if (p == NULL)
-       {
-         Smi->Module[ModuleCount].PathLength = 0;
-       }
-      else
-       {
-         p++;
-         Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
-       }
-
-      ModuleCount++;
-      current_entry = current_entry->Flink;
+        current = CONTAINING_RECORD(current_entry,LDR_DATA_TABLE_ENTRY,InLoadOrderModuleList);
+
+        Smi->Module[ModuleCount].Unknown1 = 0;                /* Always 0 */
+        Smi->Module[ModuleCount].Unknown2 = 0;                /* Always 0 */
+        Smi->Module[ModuleCount].Base = current->DllBase;
+        Smi->Module[ModuleCount].Size = current->SizeOfImage;
+        Smi->Module[ModuleCount].Flags = 0;                /* Flags ??? (GN) */
+        Smi->Module[ModuleCount].Index = (USHORT)ModuleCount;
+        Smi->Module[ModuleCount].NameLength = 0;
+        Smi->Module[ModuleCount].LoadCount = 0; /* FIXME */
+
+        AnsiName.Length = 0;
+        AnsiName.MaximumLength = 256;
+        AnsiName.Buffer = Smi->Module[ModuleCount].ImageName;
+        RtlUnicodeStringToAnsiString(&AnsiName,
+            &current->FullDllName,
+            FALSE);
+
+        p = strrchr(AnsiName.Buffer, '\\');
+        if (p == NULL)
+        {
+            Smi->Module[ModuleCount].PathLength = 0;
+        }
+        else
+        {
+            p++;
+            Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
+        }
+
+        ModuleCount++;
+        current_entry = current_entry->Flink;
     }
 
-  KeReleaseSpinLock(&ModuleListLock, Irql);
+    KeReleaseSpinLock(&ModuleListLock, Irql);
 
-  return(STATUS_SUCCESS);
+    return(STATUS_SUCCESS);
 }
 
 
 static VOID
-LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
-                       PUNICODE_STRING FullName)
+LdrpBuildModuleBaseName (
+    PUNICODE_STRING BaseName,
+    PUNICODE_STRING FullName )
 {
-   UNICODE_STRING Name;
-   PWCHAR p;
-   PWCHAR q;
+    PWCHAR p;
 
-   DPRINT("LdrpBuildModuleBaseName()\n");
-   DPRINT("FullName %wZ\n", FullName);
+    DPRINT("LdrpBuildModuleBaseName()\n");
+    DPRINT("FullName %wZ\n", FullName);
 
-   p = wcsrchr(FullName->Buffer, L'\\');
-   if (p == NULL)
-     {
-       p = FullName->Buffer;
-     }
-   else
-     {
-       p++;
-     }
-
-   DPRINT("p %S\n", p);
-
-   RtlCreateUnicodeString(&Name, p);
-
-   q = wcschr(Name.Buffer, L'.');
-   if (q != NULL)
-     {
-       *q = (WCHAR)0;
-     }
+    p = wcsrchr(FullName->Buffer, L'\\');
+    if (p == NULL)
+    {
+        p = FullName->Buffer;
+    }
+    else
+    {
+        p++;
+    }
 
-   DPRINT("p %S\n", p);
+    DPRINT("p %S\n", p);
 
-   RtlCreateUnicodeString(BaseName, Name.Buffer);
-   RtlFreeUnicodeString(&Name);
+    RtlInitUnicodeString(BaseName, p);
 }
 
 
 static LONG
-LdrpCompareModuleNames(IN PUNICODE_STRING String1,
-                      IN PUNICODE_STRING String2)
+LdrpCompareModuleNames (
+    IN PUNICODE_STRING String1,
+    IN PUNICODE_STRING String2 )
 {
-  ULONG len1, len2, i;
-  PWCHAR s1, s2, p;
-  WCHAR  c1, c2;
+    ULONG len1, len2, i;
+    PWCHAR s1, s2, p;
+    WCHAR  c1, c2;
 
-  if (String1 && String2)
+    if (String1 && String2)
     {
-      /* Search String1 for last path component */
-      len1 = String1->Length / sizeof(WCHAR);
-      s1 = String1->Buffer;
-      for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
-       {
-         if (*p == L'\\')
-           {
-             if (i == String1->Length - sizeof(WCHAR))
-               {
-                 s1 = NULL;
-                 len1 = 0;
-               }
-             else
-               {
-                 s1 = p + 1;
-                 len1 = (String1->Length - i) / sizeof(WCHAR);
-               }
-           }
-       }
-
-      /* Search String2 for last path component */
-      len2 = String2->Length / sizeof(WCHAR);
-      s2 = String2->Buffer;
-      for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
-       {
-         if (*p == L'\\')
-           {
-             if (i == String2->Length - sizeof(WCHAR))
-               {
-                 s2 = NULL;
-                 len2 = 0;
-               }
-             else
-               {
-                 s2 = p + 1;
-                 len2 = (String2->Length - i) / sizeof(WCHAR);
-               }
-           }
-       }
-
-      /* Compare last path components */
-      if (s1 && s2)
-       {
-         while (1)
-           {
-             c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
-             c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
-             if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
-               return(0);
-             if (!c1 || !c2 || c1 != c2)
-               return(c1 - c2);
-           }
-       }
+        /* Search String1 for last path component */
+        len1 = String1->Length / sizeof(WCHAR);
+        s1 = String1->Buffer;
+        for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
+        {
+            if (*p == L'\\')
+            {
+                if (i == String1->Length - sizeof(WCHAR))
+                {
+                    s1 = NULL;
+                    len1 = 0;
+                }
+                else
+                {
+                    s1 = p + 1;
+                    len1 = (String1->Length - i) / sizeof(WCHAR);
+                }
+            }
+        }
+
+        /* Search String2 for last path component */
+        len2 = String2->Length / sizeof(WCHAR);
+        s2 = String2->Buffer;
+        for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
+        {
+            if (*p == L'\\')
+            {
+                if (i == String2->Length - sizeof(WCHAR))
+                {
+                    s2 = NULL;
+                    len2 = 0;
+                }
+                else
+                {
+                    s2 = p + 1;
+                    len2 = (String2->Length - i) / sizeof(WCHAR);
+                }
+            }
+        }
+
+        /* Compare last path components */
+        if (s1 && s2)
+        {
+            while (1)
+            {
+                c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
+                c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
+                if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
+                    return(0);
+                if (!c1 || !c2 || c1 != c2)
+                    return(c1 - c2);
+            }
+        }
     }
 
-  return(0);
+    return(0);
 }
 
-
-PMODULE_OBJECT
-LdrGetModuleObject(PUNICODE_STRING ModuleName)
+PLDR_DATA_TABLE_ENTRY
+NTAPI
+LdrGetModuleObject ( PUNICODE_STRING ModuleName )
 {
-  PMODULE_OBJECT Module;
-  PLIST_ENTRY Entry;
-  KIRQL Irql;
+    PLDR_DATA_TABLE_ENTRY Module;
+    PLIST_ENTRY Entry;
+    KIRQL Irql;
 
-  DPRINT("LdrpGetModuleObject(%wZ) called\n", ModuleName);
+    DPRINT("LdrGetModuleObject(%wZ) called\n", ModuleName);
 
-  KeAcquireSpinLock(&ModuleListLock,&Irql);
+    KeAcquireSpinLock(&ModuleListLock,&Irql);
 
-  Entry = ModuleListHead.Flink;
-  while (Entry != &ModuleListHead)
+    Entry = ModuleListHead.Flink;
+    while (Entry != &ModuleListHead)
     {
-      Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
+        Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
 
-      DPRINT("Comparing %wZ and %wZ\n",
-            &Module->BaseName,
-            ModuleName);
+        DPRINT("Comparing %wZ and %wZ\n",
+            &Module->BaseDllName,
+            ModuleName);
 
-      if (!LdrpCompareModuleNames(&Module->BaseName, ModuleName))
-       {
-         DPRINT("Module %wZ\n", &Module->BaseName);
-         KeReleaseSpinLock(&ModuleListLock, Irql);
-         return(Module);
-       }
+        if (!LdrpCompareModuleNames(&Module->BaseDllName, ModuleName))
+        {
+            DPRINT("Module %wZ\n", &Module->BaseDllName);
+            KeReleaseSpinLock(&ModuleListLock, Irql);
+            return(Module);
+        }
 
-      Entry = Entry->Flink;
+        Entry = Entry->Flink;
     }
 
-  KeReleaseSpinLock(&ModuleListLock, Irql);
+    KeReleaseSpinLock(&ModuleListLock, Irql);
 
-  DPRINT("Could not find module '%wZ'\n", ModuleName);
+    DPRINT("Could not find module '%wZ'\n", ModuleName);
 
-  return(NULL);
+    return(NULL);
 }
 
 
 /*  ----------------------------------------------  PE Module support */
 
-static BOOL
-PageNeedsWriteAccess(PVOID PageStart,
-                     PVOID DriverBase,
-                     PIMAGE_FILE_HEADER PEFileHeader,
-                     PIMAGE_SECTION_HEADER PESectionHeaders)
+static ULONG
+LdrLookupPageProtection (
+    PVOID PageStart,
+    PVOID DriverBase,
+    PIMAGE_FILE_HEADER PEFileHeader,
+    PIMAGE_SECTION_HEADER PESectionHeaders )
 {
-  BOOL NeedsWriteAccess;
-  unsigned Idx;
-  ULONG Characteristics;
-  ULONG Length;
-  PVOID BaseAddress;
-
-  NeedsWriteAccess = FALSE;
-  /* Set the protections for the various parts of the driver */
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections && ! NeedsWriteAccess; Idx++)
+    BOOLEAN Write = FALSE;
+    BOOLEAN Execute = FALSE;
+    ULONG Characteristics;
+    ULONG Idx;
+    ULONG Length;
+    PVOID BaseAddress;
+
+    for (Idx = 0; Idx < PEFileHeader->NumberOfSections && (!Write || !Execute); Idx++)
+    {
+        Characteristics = PESectionHeaders[Idx].Characteristics;
+        if (!(Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+        {
+            Length = max(PESectionHeaders[Idx].Misc.VirtualSize, PESectionHeaders[Idx].SizeOfRawData);
+            BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
+            if (BaseAddress < (PVOID)((ULONG_PTR)PageStart + PAGE_SIZE) &&
+                PageStart < (PVOID)((ULONG_PTR)BaseAddress + Length))
+            {
+                if (Characteristics & IMAGE_SCN_CNT_CODE)
+                {
+                    Execute = TRUE;
+                }
+                if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
+                {
+                    Write = TRUE;
+                }
+            }
+        }
+    }
+    if (Write && Execute)
     {
-      Characteristics = PESectionHeaders[Idx].Characteristics;
-      if (!(Characteristics & IMAGE_SECTION_CHAR_CODE) ||
-         (Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
-          Characteristics & IMAGE_SECTION_CHAR_DATA ||
-          Characteristics & IMAGE_SECTION_CHAR_BSS))
-       {
-         Length = 
-             max(PESectionHeaders[Idx].Misc.VirtualSize,
-                 PESectionHeaders[Idx].SizeOfRawData);
-         BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
-         NeedsWriteAccess = BaseAddress < PageStart + PAGE_SIZE &&
-                            PageStart < (PVOID)((PCHAR) BaseAddress + Length);
-       }
+        return PAGE_EXECUTE_READWRITE;
+    }
+    else if (Execute)
+    {
+        return PAGE_EXECUTE_READ;
+    }
+    else if (Write)
+    {
+        return PAGE_READWRITE;
+    }
+    else
+    {
+        return PAGE_READONLY;
     }
-
-  return(NeedsWriteAccess);
 }
 
 static NTSTATUS
-LdrPEProcessModule(PVOID ModuleLoadBase,
-                  PUNICODE_STRING FileName,
-                  PMODULE_OBJECT *ModuleObject)
+LdrPEProcessModule(
+    PVOID ModuleLoadBase,
+    PUNICODE_STRING FileName,
+    PLDR_DATA_TABLE_ENTRY *ModuleObject )
 {
-  unsigned int DriverSize, Idx;
-  ULONG RelocDelta, NumRelocs;
-  DWORD CurrentSize, TotalRelocs;
-  PVOID DriverBase;
-  PULONG PEMagic;
-  PIMAGE_DOS_HEADER PEDosHeader;
-  PIMAGE_FILE_HEADER PEFileHeader;
-  PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
-  PIMAGE_SECTION_HEADER PESectionHeaders;
-  PRELOCATION_DIRECTORY RelocDir;
-  PRELOCATION_ENTRY RelocEntry;
-  PMODULE_OBJECT  LibraryModuleObject;
-  PMODULE_OBJECT CreatedModuleObject;
-  PVOID *ImportAddressList;
-  PULONG FunctionNameList;
-  PCHAR pName;
-  WORD Hint;
-  UNICODE_STRING ModuleName;
-  UNICODE_STRING NameString;
-  WCHAR  NameBuffer[60];
-  MODULE_TEXT_SECTION* ModuleTextSection;
-  NTSTATUS Status;
-  KIRQL Irql;
-
-  DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
-
-  /*  Get header pointers  */
-  PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
-  PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew);
-  PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew + sizeof(ULONG));
-  PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
-  PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
-    sizeof(IMAGE_OPTIONAL_HEADER));
-  CHECKPOINT;
-
-  /*  Check file magic numbers  */
-  if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
+    unsigned int DriverSize, Idx;
+    DWORD CurrentSize;
+    PVOID DriverBase;
+    PIMAGE_DOS_HEADER PEDosHeader;
+    PIMAGE_NT_HEADERS PENtHeaders;
+    PIMAGE_SECTION_HEADER PESectionHeaders;
+    PLDR_DATA_TABLE_ENTRY CreatedModuleObject;
+    NTSTATUS Status;
+    KIRQL Irql;
+
+    DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
+
+    /*  Get header pointers  */
+    PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
+    PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
+    PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
+    CHECKPOINT;
+
+    /*  Check file magic numbers  */
+    if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
     {
-      CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
-      return STATUS_UNSUCCESSFUL;
+        CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
+        return STATUS_UNSUCCESSFUL;
     }
-  if (PEDosHeader->e_lfanew == 0)
+    if (PEDosHeader->e_lfanew == 0)
     {
-      CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
-      return STATUS_UNSUCCESSFUL;
+        CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
+        return STATUS_UNSUCCESSFUL;
     }
-  if (*PEMagic != IMAGE_PE_MAGIC)
+    if (PENtHeaders->Signature != IMAGE_NT_SIGNATURE)
     {
-      CPRINT("Incorrect PE magic: %08x\n", *PEMagic);
-      return STATUS_UNSUCCESSFUL;
+        CPRINT("Incorrect PE magic: %08x\n", PENtHeaders->Signature);
+        return STATUS_UNSUCCESSFUL;
     }
-  if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
+    if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
     {
-      CPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
-      return STATUS_UNSUCCESSFUL;
+        CPRINT("Incorrect Architechture: %04x\n", PENtHeaders->FileHeader.Machine);
+        return STATUS_UNSUCCESSFUL;
     }
-  CHECKPOINT;
+    CHECKPOINT;
 
-  /* FIXME: if image is fixed-address load, then fail  */
+    /* FIXME: if image is fixed-address load, then fail  */
 
-  /* FIXME: check/verify OS version number  */
+    /* FIXME: check/verify OS version number  */
 
-  DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
-         PEOptionalHeader->Magic,
-         PEOptionalHeader->MajorLinkerVersion,
-         PEOptionalHeader->MinorLinkerVersion);
-  DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
-  CHECKPOINT;
+    DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
+        PENtHeaders->OptionalHeader.Magic,
+        PENtHeaders->OptionalHeader.MajorLinkerVersion,
+        PENtHeaders->OptionalHeader.MinorLinkerVersion);
+    DPRINT("Entry Point:%08lx\n", PENtHeaders->OptionalHeader.AddressOfEntryPoint);
 
-  /*  Determine the size of the module  */
-  DriverSize = PEOptionalHeader->SizeOfImage;
-  DPRINT("DriverSize %x\n",DriverSize);
+    /*  Determine the size of the module  */
+    DriverSize = 0;
+    for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
+    {
+        if (!(PESectionHeaders[Idx].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+        {
+            CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
+            DriverSize = max(DriverSize, CurrentSize);
+        }
+    }
+    DriverSize = ROUND_UP(DriverSize, PENtHeaders->OptionalHeader.SectionAlignment);
+    DPRINT("DriverSize %x, SizeOfImage %x\n",DriverSize, PENtHeaders->OptionalHeader.SizeOfImage);
 
-  /*  Allocate a virtual section for the module  */
-  DriverBase = MmAllocateSection(DriverSize);
-  if (DriverBase == 0)
+    /*  Allocate a virtual section for the module  */
+    DriverBase = NULL;
+    DriverBase = MmAllocateSection(DriverSize, DriverBase);
+    if (DriverBase == 0)
     {
-      CPRINT("Failed to allocate a virtual section for driver\n");
-      return STATUS_UNSUCCESSFUL;
+        CPRINT("Failed to allocate a virtual section for driver\n");
+        return STATUS_UNSUCCESSFUL;
     }
-  DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase);
-  CHECKPOINT;
-  /*  Copy headers over */
-  memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
-   CurrentSize = 0;
-  /*  Copy image sections into virtual section  */
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
+    DPRINT("DriverBase for %wZ: %x\n", FileName, DriverBase);
+
+    /*  Copy headers over */
+    memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
+
+    /*  Copy image sections into virtual section  */
+    for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
     {
-      //  Copy current section into current offset of virtual section
-      if (PESectionHeaders[Idx].Characteristics & 
-          (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
+        CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
+        /* Copy current section into current offset of virtual section */
+        if (CurrentSize <= DriverSize &&
+            PESectionHeaders[Idx].SizeOfRawData)
         {
-          DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
-                 PESectionHeaders[Idx].VirtualAddress + DriverBase);
-           memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
-                  (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
-                  PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
-                  ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
+            DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
+                PESectionHeaders[Idx].VirtualAddress + (ULONG_PTR)DriverBase);
+            memcpy((PVOID)((ULONG_PTR)DriverBase + PESectionHeaders[Idx].VirtualAddress),
+                (PVOID)((ULONG_PTR)ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
+                PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
+                ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
         }
-      else
-        {
-          DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
-                 PESectionHeaders[Idx].VirtualAddress + DriverBase);
-          memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
-                 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
+    }
 
-        }
-      CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
-                              PEOptionalHeader->SectionAlignment);
+    /*  Perform relocation fixups  */
+    Status = LdrPEPerformRelocations(DriverBase, DriverSize);
+    if (!NT_SUCCESS(Status))
+    {
+        //   MmFreeSection(DriverBase);
+        return Status;
+    }
 
+    /* Create the module */
+    CreatedModuleObject = ExAllocatePoolWithTag (
+        NonPagedPool, sizeof(LDR_DATA_TABLE_ENTRY), TAG_MODULE_OBJECT );
+    if (CreatedModuleObject == NULL)
+    {
+        //   MmFreeSection(DriverBase);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(CreatedModuleObject, sizeof(LDR_DATA_TABLE_ENTRY));
 
-//      CurrentBase = (PVOID)((DWORD)CurrentBase + 
-  //      ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
-    //             PEOptionalHeader->SectionAlignment));
+    /*  Initialize ModuleObject data  */
+    CreatedModuleObject->DllBase = DriverBase;
+
+    CreatedModuleObject->FullDllName.Length = 0;
+    CreatedModuleObject->FullDllName.MaximumLength = FileName->Length + sizeof(UNICODE_NULL);
+    CreatedModuleObject->FullDllName.Buffer =
+        ExAllocatePoolWithTag(PagedPool, CreatedModuleObject->FullDllName.MaximumLength, TAG_LDR_WSTR);
+    if (CreatedModuleObject->FullDllName.Buffer == NULL)
+    {
+        ExFreePool(CreatedModuleObject);
+        //   MmFreeSection(DriverBase);
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-  /*  Perform relocation fixups  */
-  RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
-  RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
-    IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
-  DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
-         DriverBase,
-         PEOptionalHeader->ImageBase,
-         RelocDelta);   
-  DPRINT("RelocDir %x\n",RelocDir);
-#if 1
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
+    RtlCopyUnicodeString(&CreatedModuleObject->FullDllName, FileName);
+    CreatedModuleObject->FullDllName.Buffer[FileName->Length / sizeof(WCHAR)] = 0;
+    LdrpBuildModuleBaseName(&CreatedModuleObject->BaseDllName,
+        &CreatedModuleObject->FullDllName);
+
+    CreatedModuleObject->EntryPoint =
+        (PVOID)((ULONG_PTR)DriverBase +
+        PENtHeaders->OptionalHeader.AddressOfEntryPoint);
+    CreatedModuleObject->SizeOfImage = DriverSize;
+    DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
+
+    /*  Perform import fixups  */
+    Status = LdrPEFixupImports(CreatedModuleObject);
+    if (!NT_SUCCESS(Status))
     {
-       if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
-        {
-           DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
-                  PESectionHeaders[Idx].Name,
-                  PESectionHeaders[Idx].PointerToRawData);
-           RelocDir = PESectionHeaders[Idx].PointerToRawData +
-             ModuleLoadBase;
-            CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
-           break;
-        }
+        //   MmFreeSection(DriverBase);
+        ExFreePool(CreatedModuleObject->FullDllName.Buffer);
+        ExFreePool(CreatedModuleObject);
+        return Status;
     }
-#else
-   RelocDir = RelocDir + (ULONG)DriverBase;
-   CurrentSize = PEOptionalHeader->DataDirectory
-                 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
-#endif
-  DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
-  TotalRelocs = 0;
-  while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
+
+    MmSetPageProtect(NULL, DriverBase, PAGE_READONLY);
+    /* Set the protections for the various parts of the driver */
+    for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
     {
-      NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
-        sizeof(WORD);
-/*      DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
-             RelocDir, 
-             RelocDir->VirtualAddress,
-             NumRelocs);*/
-      RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir + 
-        sizeof(RELOCATION_DIRECTORY));
-      for (Idx = 0; Idx < NumRelocs; Idx++)
+        ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
+        ULONG Length;
+        PVOID BaseAddress;
+        PVOID PageAddress;
+        ULONG Protect;
+        Length = PESectionHeaders[Idx].Misc.VirtualSize;
+        BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
+        PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
+
+        Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
+#if 1
+        /*
+        * FIXME:
+        *   This driver modifies a string in the first page of the text section while initialising.
+        */
+        if (0 == _wcsicmp(L"fireport.sys", FileName->Buffer))
         {
-          ULONG Offset;
-          ULONG Type;
-          PDWORD RelocItem;
-          
-          Offset = RelocEntry[Idx].TypeOffset & 0xfff;
-          Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
-          RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress + 
-                               Offset);
-/*        DPRINT("  reloc at %08lx %x %s old:%08lx new:%08lx\n", 
-                 RelocItem,
-                 Type,
-                 Type ? "HIGHLOW" : "ABS",
-                 *RelocItem,
-                 (*RelocItem) + RelocDelta); */
-          if (Type == 3)
-            {
-              (*RelocItem) += RelocDelta;
-            }
-          else if (Type != 0)
-            {
-              CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
-              return STATUS_UNSUCCESSFUL;
-            }
+            Protect = PAGE_EXECUTE_READWRITE;
         }
-      TotalRelocs += RelocDir->SizeOfBlock;
-      RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir + 
-        RelocDir->SizeOfBlock);
-//      DPRINT("TotalRelocs: %08lx  CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
-    }
-   
-  DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
-         PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
-         .VirtualAddress);
-  /*  Perform import fixups  */
-  if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
-    {
-      PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
-
-      /*  Process each import module  */
-      ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
-        ((DWORD)DriverBase + PEOptionalHeader->
-          DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
-      DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
-      while (ImportModuleDirectory->dwRVAModuleName)
+#endif
+        if (PageAddress < RVA(DriverBase, DriverSize))
         {
-          /*  Check to make sure that import lib is kernel  */
-          pName = (PCHAR) DriverBase + 
-            ImportModuleDirectory->dwRVAModuleName;
-
-          RtlCreateUnicodeStringFromAsciiz(&ModuleName, pName);
-          DPRINT("Import module: %wZ\n", &ModuleName);
-
-          LibraryModuleObject = LdrGetModuleObject(&ModuleName);
-          if (LibraryModuleObject == NULL)
-            {
-              DPRINT("Module '%wZ' not loaded yet\n", &ModuleName);
-              wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
-              wcscat(NameBuffer, ModuleName.Buffer);
-              RtlInitUnicodeString(&NameString, NameBuffer);
-              Status = LdrLoadModule(&NameString, &LibraryModuleObject);
-              if (!NT_SUCCESS(Status))
-                {
-                  wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
-                  wcscat(NameBuffer, ModuleName.Buffer);
-                  RtlInitUnicodeString(&NameString, NameBuffer);
-                  Status = LdrLoadModule(&NameString, &LibraryModuleObject);
-                  if (!NT_SUCCESS(Status))
-                    {
-                      DPRINT1("Unknown import module: %wZ (Status %lx)\n", &ModuleName, Status);
-                      return(Status);
-                    }
-                }
-            }
-          /*  Get the import address list  */
-          ImportAddressList = (PVOID *) ((DWORD)DriverBase + 
-            ImportModuleDirectory->dwRVAFunctionAddressList);
+            MmSetPageProtect(NULL, PageAddress, Protect);
+        }
 
-          /*  Get the list of functions to import  */
-          if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
+        if (Characteristics & IMAGE_SCN_CNT_CODE)
+        {
+            if (Characteristics & IMAGE_SCN_MEM_WRITE)
             {
-              FunctionNameList = (PULONG) ((DWORD)DriverBase + 
-                ImportModuleDirectory->dwRVAFunctionNameList);
+                Protect = PAGE_EXECUTE_READWRITE;
             }
-          else
+            else
             {
-              FunctionNameList = (PULONG) ((DWORD)DriverBase + 
-                ImportModuleDirectory->dwRVAFunctionAddressList);
+                Protect = PAGE_EXECUTE_READ;
             }
-          /*  Walk through function list and fixup addresses  */
-          while (*FunctionNameList != 0L)
+        }
+        else if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
+        {
+            Protect = PAGE_READWRITE;
+        }
+        else
+        {
+            Protect = PAGE_READONLY;
+        }
+        PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
+        while ((ULONG_PTR)PageAddress + PAGE_SIZE < (ULONG_PTR)BaseAddress + Length)
+        {
+            if (PageAddress < RVA(DriverBase, DriverSize))
             {
-              if ((*FunctionNameList) & 0x80000000) // hint
-                {
-                  pName = NULL;
-
-
-                  Hint = (*FunctionNameList) & 0xffff;
-                }
-              else // hint-name
-                {
-                  pName = (PCHAR)((DWORD)DriverBase + 
-                                  *FunctionNameList + 2);
-                  Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
-                }
-              DPRINT("  Hint:%04x  Name:%s\n", Hint, pName);
-
-              /*  Fixup the current import symbol  */
-              if (LibraryModuleObject != NULL)
-                {
-                  *ImportAddressList = LdrGetExportAddress(LibraryModuleObject, 
-                                                           pName, 
-                                                           Hint);
-                }
-              else
-                {
-                  CPRINT("Unresolved kernel symbol: %s\n", pName);
-                  return STATUS_UNSUCCESSFUL;
-                }
-              ImportAddressList++;
-              FunctionNameList++;
+                MmSetPageProtect(NULL, PageAddress, Protect);
             }
-
-          RtlFreeUnicodeString(&ModuleName);
-
-          ImportModuleDirectory++;
+            PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
+        }
+        if (PageAddress < (PVOID)((ULONG_PTR)BaseAddress + Length) &&
+            PageAddress < RVA(DriverBase, DriverSize))
+        {
+            Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
+            MmSetPageProtect(NULL, PageAddress, Protect);
         }
     }
 
-  /* Set the protections for the various parts of the driver */
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
-    {
-      ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
-      ULONG Length;
-      PVOID BaseAddress;
-      PVOID PageAddress;
-      if (Characteristics & IMAGE_SECTION_CHAR_CODE &&
-         !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
-           Characteristics & IMAGE_SECTION_CHAR_DATA ||
-           Characteristics & IMAGE_SECTION_CHAR_BSS))
-       {
-         Length = 
-             max(PESectionHeaders[Idx].Misc.VirtualSize,
-                 PESectionHeaders[Idx].SizeOfRawData);
-         BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
-         PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
-         if (! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
-           {
-             MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
-           }
-         PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
-         while ((PVOID)((PCHAR) PageAddress + PAGE_SIZE) <
-                (PVOID)((PCHAR) BaseAddress + Length))
-           {
-             MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
-             PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
-           }
-         if (PageAddress < (PVOID)((PCHAR) BaseAddress + Length) &&
-             ! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
-           {
-             MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
-           }
-       }
-    }
+    /* Insert module */
+    KeAcquireSpinLock(&ModuleListLock, &Irql);
+    InsertTailList(&ModuleListHead,
+        &CreatedModuleObject->InLoadOrderModuleList);
+    KeReleaseSpinLock(&ModuleListLock, Irql);
 
-  /* Create the module */
-  CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
-  if (CreatedModuleObject == NULL)
-    {
-      return(STATUS_INSUFFICIENT_RESOURCES);
-    }
+    *ModuleObject = CreatedModuleObject;
 
-  RtlZeroMemory(CreatedModuleObject, sizeof(MODULE_OBJECT));
-
-   /*  Initialize ModuleObject data  */
-  CreatedModuleObject->Base = DriverBase;
-  CreatedModuleObject->Flags = MODULE_FLAG_PE;
-  
-  RtlCreateUnicodeString(&CreatedModuleObject->FullName,
-                        FileName->Buffer);
-  LdrpBuildModuleBaseName(&CreatedModuleObject->BaseName,
-                         &CreatedModuleObject->FullName);
-  
-  CreatedModuleObject->EntryPoint = 
-    (PVOID)((DWORD)DriverBase + 
-           PEOptionalHeader->AddressOfEntryPoint);
-  CreatedModuleObject->Length = DriverSize;
-  DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
-  
-  CreatedModuleObject->Image.PE.FileHeader =
-    (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
-
-  DPRINT("FileHeader at %x\n", CreatedModuleObject->Image.PE.FileHeader);
-  CreatedModuleObject->Image.PE.OptionalHeader = 
-    (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
-    sizeof(IMAGE_FILE_HEADER));
-  DPRINT("OptionalHeader at %x\n", CreatedModuleObject->Image.PE.OptionalHeader);
-  CreatedModuleObject->Image.PE.SectionList = 
-    (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
-    sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
-  DPRINT("SectionList at %x\n", CreatedModuleObject->Image.PE.SectionList);
-
-  /* Insert module */
-  KeAcquireSpinLock(&ModuleListLock, &Irql);
-  InsertTailList(&ModuleListHead,
-                &CreatedModuleObject->ListEntry);
-  KeReleaseSpinLock(&ModuleListLock, Irql);
-
-
-  ModuleTextSection = ExAllocatePool(NonPagedPool, 
-                                    sizeof(MODULE_TEXT_SECTION));
-  assert(ModuleTextSection);
-  RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
-  ModuleTextSection->Base = (ULONG)DriverBase;
-  ModuleTextSection->Length = DriverSize;
-  ModuleTextSection->Name = ExAllocatePool(NonPagedPool, 
-       (wcslen(CreatedModuleObject->BaseName.Buffer) + 1) * sizeof(WCHAR));
-  wcscpy(ModuleTextSection->Name, CreatedModuleObject->BaseName.Buffer);
-  ModuleTextSection->OptionalHeader = 
-    CreatedModuleObject->Image.PE.OptionalHeader;
-  InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
-
-  CreatedModuleObject->TextSection = ModuleTextSection;
-
-  *ModuleObject = CreatedModuleObject;
-
-  DPRINT("Loading Module %wZ...\n", FileName);
-
-  if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
-    {
-      DPRINT("Module %wZ loaded at 0x%.08x.\n",
-             FileName, CreatedModuleObject->Base);
-    }
+    DPRINT("Loading Module %wZ...\n", FileName);
+
+    DPRINT("Module %wZ loaded at 0x%.08x.\n",
+            FileName, CreatedModuleObject->DllBase);
 
-  return STATUS_SUCCESS;
+    return STATUS_SUCCESS;
 }
 
 
 PVOID
-LdrSafePEProcessModule(PVOID ModuleLoadBase,
-                      PVOID DriverBase,
-                      PVOID ImportModuleBase,
-                      PULONG DriverSize)
+INIT_FUNCTION
+NTAPI
+LdrSafePEProcessModule (
+    PVOID ModuleLoadBase,
+    PVOID DriverBase,
+    PVOID ImportModuleBase,
+    PULONG DriverSize)
 {
-  unsigned int Idx;
-  ULONG RelocDelta, NumRelocs;
-  ULONG CurrentSize, TotalRelocs;
-  PULONG PEMagic;
-  PIMAGE_DOS_HEADER PEDosHeader;
-  PIMAGE_FILE_HEADER PEFileHeader;
-  PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
-  PIMAGE_SECTION_HEADER PESectionHeaders;
-  PRELOCATION_DIRECTORY RelocDir;
-  PRELOCATION_ENTRY RelocEntry;
-  PVOID *ImportAddressList;
-  PULONG FunctionNameList;
-  PCHAR pName;
-  USHORT Hint;
-
-  ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
-
-  /*  Get header pointers  */
-  PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
-  PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew);
-  PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew + sizeof(ULONG));
-  PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
-  PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
-    PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
-    sizeof(IMAGE_OPTIONAL_HEADER));
-  CHECKPOINT;
-
-  /*  Check file magic numbers  */
-  if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
+    unsigned int Idx;
+    ULONG CurrentSize;
+    PIMAGE_DOS_HEADER PEDosHeader;
+    PIMAGE_NT_HEADERS PENtHeaders;
+    PIMAGE_SECTION_HEADER PESectionHeaders;
+    NTSTATUS Status;
+
+    ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
+
+    /*  Get header pointers  */
+    PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
+    PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
+    PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
+    CHECKPOINT;
+
+    /*  Check file magic numbers  */
+    if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
     {
-      return 0;
+        return NULL;
     }
-  if (PEDosHeader->e_lfanew == 0)
+    if (PEDosHeader->e_lfanew == 0)
     {
-      return 0;
+        return NULL;
     }
-  if (*PEMagic != IMAGE_PE_MAGIC)
+    if (PENtHeaders->Signature != IMAGE_NT_SIGNATURE)
     {
-      return 0;
+        return NULL;
     }
-  if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
+    if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
     {
-      return 0;
+        return NULL;
     }
 
-  ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
-         PEOptionalHeader->Magic,
-         PEOptionalHeader->MajorLinkerVersion,
-         PEOptionalHeader->MinorLinkerVersion);
-  ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
+    ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
+        PENtHeaders->OptionalHeader.Magic,
+        PENtHeaders->OptionalHeader.MajorLinkerVersion,
+        PENtHeaders->OptionalHeader.MinorLinkerVersion);
+    ps("Entry Point:%08lx\n", PENtHeaders->OptionalHeader.AddressOfEntryPoint);
 
-  /*  Determine the size of the module  */
-  *DriverSize = PEOptionalHeader->SizeOfImage;
-  ps("DriverSize %x\n",*DriverSize);
+    /*  Determine the size of the module  */
+    *DriverSize = PENtHeaders->OptionalHeader.SizeOfImage;
+    ps("DriverSize %x\n",*DriverSize);
 
-  /*  Copy headers over */
-  if (DriverBase != ModuleLoadBase)
+    /*  Copy headers over */
+    if (DriverBase != ModuleLoadBase)
     {
-      memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
+        memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
     }
 
-  ps("Hdr: 0x%X\n", (ULONG)PEOptionalHeader);
-  ps("Hdr->SizeOfHeaders: 0x%X\n", (ULONG)PEOptionalHeader->SizeOfHeaders);
-  ps("FileHdr->NumberOfSections: 0x%X\n", (ULONG)PEFileHeader->NumberOfSections);
+    ps("Hdr: 0x%X\n", PENtHeaders);
+    ps("Hdr->SizeOfHeaders: 0x%X\n", PENtHeaders->OptionalHeader.SizeOfHeaders);
+    ps("FileHdr->NumberOfSections: 0x%X\n", PENtHeaders->FileHeader.NumberOfSections);
 
-  /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
-     address as it is mapped */
-  if (DriverBase != ModuleLoadBase)
+    /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
+    address as it is mapped */
+    if (DriverBase != ModuleLoadBase)
     {
-      CurrentSize = 0;
+        CurrentSize = 0;
 
-  /*  Copy image sections into virtual section  */
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
-    {
-      //  Copy current section into current offset of virtual section
-      if (PESectionHeaders[Idx].Characteristics & 
-          (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
-       {
-         //ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
-         //PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
-         memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
-                (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
-                PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ?
-                  PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
-       }
-      else
-       {
-         ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
-            PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
-         memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
-                '\0',
-                PESectionHeaders[Idx].Misc.VirtualSize);
-       }
-      CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
-                              PEOptionalHeader->SectionAlignment);
+        /*  Copy image sections into virtual section  */
+        for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
+        {
+            PIMAGE_SECTION_HEADER Section = &PESectionHeaders[Idx];
+            //  Copy current section into current offset of virtual section
+            if (Section->SizeOfRawData)
+            {
+                //            ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
+                //                PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
+                memcpy(Section->VirtualAddress   + (char*)DriverBase,
+                    Section->PointerToRawData + (char*)ModuleLoadBase,
+                    Section->Misc.VirtualSize > Section->SizeOfRawData ? Section->SizeOfRawData : Section->Misc.VirtualSize);
+            }
+            if (Section->SizeOfRawData < Section->Misc.VirtualSize)
+            {
+                memset(Section->VirtualAddress + Section->SizeOfRawData + (char*)DriverBase,
+                    0,
+                    Section->Misc.VirtualSize - Section->SizeOfRawData);
+            }
+            CurrentSize += ROUND_UP(Section->Misc.VirtualSize,
+                PENtHeaders->OptionalHeader.SectionAlignment);
+        }
+
+        /*  Perform relocation fixups  */
+        Status = LdrPEPerformRelocations(DriverBase, *DriverSize);
+        if (!NT_SUCCESS(Status))
+        {
+            return NULL;
+        }
     }
 
-  /*  Perform relocation fixups  */
-  RelocDelta = (ULONG) DriverBase - PEOptionalHeader->ImageBase;
-  RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
-    IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
-  ps("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
-         DriverBase,
-         PEOptionalHeader->ImageBase,
-         RelocDelta);   
-  ps("RelocDir %x\n",RelocDir);
-
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
+    /*  Perform import fixups  */
+    Status = LdrPEFixupImports(DriverBase == ModuleLoadBase ? &NtoskrnlModuleObject : &HalModuleObject);
+    if (!NT_SUCCESS(Status))
     {
-      if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
-       {
-         DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
-                PESectionHeaders[Idx].Name,
-                PESectionHeaders[Idx].PointerToRawData);
-         RelocDir = PESectionHeaders[Idx].PointerToRawData + ModuleLoadBase;
-         CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
-         break;
-       }
+        return NULL;
     }
 
-  ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
-
-  TotalRelocs = 0;
-  while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
+    /*  Set the page protection for the virtual sections */
+    MmSetPageProtect(NULL, DriverBase, PAGE_READONLY);
+    for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
     {
-      NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
-        sizeof(USHORT);
-      RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir + 
-        sizeof(RELOCATION_DIRECTORY));
-      for (Idx = 0; Idx < NumRelocs; Idx++)
+        ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
+        ULONG Length;
+        PVOID BaseAddress;
+        PVOID PageAddress;
+        ULONG Protect;
+        Length = PESectionHeaders[Idx].Misc.VirtualSize;
+        BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
+        PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
+
+        if (Characteristics & IMAGE_SCN_MEM_EXECUTE)
+        {
+            if (Characteristics & IMAGE_SCN_MEM_WRITE)
+            {
+                Protect = PAGE_EXECUTE_READWRITE;
+            }
+            else
+            {
+                Protect = PAGE_EXECUTE_READ;
+            }
+        }
+        else if (Characteristics & IMAGE_SCN_MEM_WRITE)
+        {
+            Protect = PAGE_READWRITE;
+        }
+        else
+        {
+            Protect = PAGE_READONLY;
+        }
+        while ((ULONG_PTR)PageAddress < (ULONG_PTR)BaseAddress + Length)
+        {
+            MmSetPageProtect(NULL, PageAddress, Protect);
+            PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
+        }
+        if (DriverBase == ModuleLoadBase &&
+            Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
         {
-         ULONG Offset;
-         ULONG Type;
-         PULONG RelocItem;
-
-         Offset = RelocEntry[Idx].TypeOffset & 0xfff;
-         Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
-         RelocItem = (PULONG)(DriverBase + RelocDir->VirtualAddress + Offset);
-         if (Type == 3)
-           {
-             (*RelocItem) += RelocDelta;
-           }
-         else if (Type != 0)
-           {
-             CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
-             return(0);
-           }
-       }
-      TotalRelocs += RelocDir->SizeOfBlock;
-      RelocDir = (PRELOCATION_DIRECTORY)((ULONG)RelocDir + 
-        RelocDir->SizeOfBlock);
+            /* For ntoskrnl, we must stop after the bss section */
+            break;
+        }
+
     }
 
-    ps("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
-         PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
-         .VirtualAddress);
-  }
+    return DriverBase;
+}
+
+static PVOID
+LdrPEFixupForward ( PCHAR ForwardName )
+{
+    CHAR NameBuffer[128];
+    UNICODE_STRING ModuleName;
+    PCHAR p;
+    PLDR_DATA_TABLE_ENTRY ModuleObject;
+
+    DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
 
-  /*  Perform import fixups  */
-  if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
+    strcpy(NameBuffer, ForwardName);
+    p = strchr(NameBuffer, '.');
+    if (p == NULL)
     {
-      PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
-
-      /*  Process each import module  */
-      ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
-        ((ULONG)DriverBase + PEOptionalHeader->
-          DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
-
-      ps("Processeing import directory at %p\n", ImportModuleDirectory);
-
-      /*  Check to make sure that import lib is kernel  */
-      pName = (PCHAR)DriverBase + ImportModuleDirectory->dwRVAModuleName;
-
-      ps("Import module: %s\n", pName);
-
-      /*  Get the import address list  */
-      ImportAddressList = (PVOID *)((ULONG)DriverBase + 
-       ImportModuleDirectory->dwRVAFunctionAddressList);
-
-      ps("  ImportModuleDirectory->dwRVAFunctionAddressList: 0x%X\n",
-        ImportModuleDirectory->dwRVAFunctionAddressList);
-      ps("  ImportAddressList: 0x%X\n", ImportAddressList);
-
-      /*  Get the list of functions to import  */
-      if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
-       {
-         ps("Using function name list.\n");
-
-         FunctionNameList = (PULONG)((ULONG)DriverBase + 
-           ImportModuleDirectory->dwRVAFunctionNameList);
-       }
-      else
-       {
-         ps("Using function address list.\n");
-
-         FunctionNameList = (PULONG)((ULONG)DriverBase + 
-           ImportModuleDirectory->dwRVAFunctionAddressList);
-       }
-
-      /* Walk through function list and fixup addresses */
-      while (*FunctionNameList != 0L)
-       {
-         if ((*FunctionNameList) & 0x80000000)
-           {
-              /* Hint */
-             pName = NULL;
-             Hint = (*FunctionNameList) & 0xffff;
-           }
-         else
-           {
-             /* Hint name */
-             pName = (PCHAR)((ULONG)DriverBase + *FunctionNameList + 2);
-             Hint = *(PWORD)((ULONG)DriverBase + *FunctionNameList);
-           }
-         //ps("  Hint:%04x  Name:%s(0x%X)(%x)\n", Hint, pName, pName, ImportAddressList);
-
-         *ImportAddressList = LdrSafePEGetExportAddress(ImportModuleBase,
-                                                        pName,
-                                                        Hint);
-
-         ImportAddressList++;
-         FunctionNameList++;
-       }
+        return NULL;
     }
 
-  ps("Finished importing.\n");
+    *p = 0;
 
-  return(0);
-}
+    DPRINT("Driver: %s  Function: %s\n", NameBuffer, p+1);
 
+    RtlCreateUnicodeStringFromAsciiz(&ModuleName,
+        NameBuffer);
+    ModuleObject = LdrGetModuleObject(&ModuleName);
+    RtlFreeUnicodeString(&ModuleName);
 
-static PVOID
-LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
-                     PCHAR Name,
-                     USHORT Hint)
+    DPRINT("ModuleObject: %p\n", ModuleObject);
+
+    if (ModuleObject == NULL)
+    {
+        CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
+        return NULL;
+    }
+    return LdrPEGetExportByName(ModuleObject->DllBase, (PUCHAR)(p+1), 0xffff);
+}
+
+static NTSTATUS
+LdrPEPerformRelocations (
+    PVOID DriverBase,
+    ULONG DriverSize)
 {
-  PIMAGE_EXPORT_DIRECTORY ExportDir;
-  ULONG ExportDirSize;
-  USHORT Idx;
-  PVOID  ExportAddress;
-  PWORD  OrdinalList;
-  PDWORD FunctionList, NameList;
-
-   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-     RtlImageDirectoryEntryToData(ModuleObject->Base,
-                                 TRUE,
-                                 IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                 &ExportDirSize);
-   DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
-   if (ExportDir == NULL)
-     {
-       return NULL;
-     }
-
-   FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
-   NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
-   OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
-
-  ExportAddress = 0;
-
-  if (Name != NULL)
+    PIMAGE_NT_HEADERS NtHeaders;
+    PIMAGE_DATA_DIRECTORY RelocationDDir;
+    PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
+    ULONG Count, i;
+    PVOID Address, MaxAddress;
+    PUSHORT TypeOffset;
+    ULONG_PTR Delta;
+    SHORT Offset;
+    USHORT Type;
+    PUSHORT ShortPtr;
+    PULONG LongPtr;
+
+    NtHeaders = RtlImageNtHeader(DriverBase);
+
+    if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+    if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    Delta = (ULONG_PTR)DriverBase - NtHeaders->OptionalHeader.ImageBase;
+    RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)DriverBase + RelocationDDir->VirtualAddress);
+    RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
+    MaxAddress = RVA(DriverBase, DriverSize);
+
+    while (RelocationDir < RelocationEnd &&
+        RelocationDir->SizeOfBlock > 0)
     {
-      for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
+        Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
+        Address = RVA(DriverBase, RelocationDir->VirtualAddress);
+        TypeOffset = (PUSHORT)(RelocationDir + 1);
+
+        for (i = 0; i < Count; i++)
         {
-#if 0
-          DPRINT("  Name:%s  NameList[%d]:%s\n", 
-                 Name, 
-                 Idx, 
-                 (DWORD) ModuleObject->Base + NameList[Idx]);
+            Offset = *TypeOffset & 0xFFF;
+            Type = *TypeOffset >> 12;
+            ShortPtr = (PUSHORT)(RVA(Address, Offset));
 
-#endif
-          if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
+            /* Don't relocate after the end of the loaded driver */
+            if ((PVOID)ShortPtr >= MaxAddress)
+            {
+                break;
+            }
+
+            /*
+            * Don't relocate within the relocation section itself.
+            * GCC/LD generates sometimes relocation records for the relocation section.
+            * This is a bug in GCC/LD.
+            */
+            if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
+                (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
             {
-              ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
-                FunctionList[OrdinalList[Idx]]);
-                 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
-                     ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
-                   {
-                      DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
-                      ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
-                      DPRINT("ExportAddress: %p\n", ExportAddress);
-                   }
-
-              break;
+                switch (Type)
+                {
+                case IMAGE_REL_BASED_ABSOLUTE:
+                    break;
+
+                case IMAGE_REL_BASED_HIGH:
+                    *ShortPtr += HIWORD(Delta);
+                    break;
+
+                case IMAGE_REL_BASED_LOW:
+                    *ShortPtr += LOWORD(Delta);
+                    break;
+
+                case IMAGE_REL_BASED_HIGHLOW:
+                    LongPtr = (PULONG)ShortPtr;
+                    *LongPtr += Delta;
+                    break;
+
+                case IMAGE_REL_BASED_HIGHADJ:
+                case IMAGE_REL_BASED_MIPS_JMPADDR:
+                default:
+                    DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
+                    DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, *TypeOffset);
+                    return STATUS_UNSUCCESSFUL;
+                }
             }
+            TypeOffset++;
         }
+        RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
     }
-  else  /*  use hint  */
+
+    return STATUS_SUCCESS;
+}
+#ifndef PATH_MAX
+#define PATH_MAX 260
+#endif
+
+static NTSTATUS
+LdrPEGetOrLoadModule (
+    PLDR_DATA_TABLE_ENTRY Module,
+    PCHAR ImportedName,
+    PLDR_DATA_TABLE_ENTRY* ImportedModule)
+{
+    UNICODE_STRING DriverName;
+    UNICODE_STRING NameString;
+    WCHAR  NameBuffer[PATH_MAX];
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (0 == _stricmp(ImportedName, "ntoskrnl") ||
+        0 == _stricmp(ImportedName, "ntoskrnl.exe"))
     {
-      ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
-        FunctionList[Hint - ExportDir->Base]);
+        *ImportedModule = &NtoskrnlModuleObject;
+        return STATUS_SUCCESS;
     }
 
-  if (ExportAddress == NULL)
+    if (0 == _stricmp(ImportedName, "hal") ||
+        0 == _stricmp(ImportedName, "hal.dll"))
     {
-      DbgPrint("Export not found for %d:%s\n",
-            Hint,
-            Name != NULL ? Name : "(Ordinal)");
-      KEBUGCHECK(0);
+        *ImportedModule = &HalModuleObject;
+        return STATUS_SUCCESS;
     }
 
-  return(ExportAddress);
-}
+    RtlCreateUnicodeStringFromAsciiz (&DriverName, ImportedName);
+    DPRINT("Import module: %wZ\n", &DriverName);
 
+    *ImportedModule = LdrGetModuleObject(&DriverName);
+    if (*ImportedModule == NULL)
+    {
+        PWCHAR PathEnd;
+        ULONG PathLength;
 
-static PVOID
-LdrSafePEGetExportAddress(PVOID ImportModuleBase,
-                         PCHAR Name,
-                         USHORT Hint)
-{
-  USHORT Idx;
-  PVOID  ExportAddress;
-  PWORD  OrdinalList;
-  PDWORD FunctionList, NameList;
-  PIMAGE_EXPORT_DIRECTORY  ExportDir;
-  ULONG ExportDirSize;
+        PathEnd = wcsrchr(Module->FullDllName.Buffer, L'\\');
+        if (NULL != PathEnd)
+        {
+            PathLength = (PathEnd - Module->FullDllName.Buffer + 1) * sizeof(WCHAR);
+            RtlCopyMemory(NameBuffer, Module->FullDllName.Buffer, PathLength);
+            RtlCopyMemory(NameBuffer + (PathLength / sizeof(WCHAR)), DriverName.Buffer, DriverName.Length);
+            NameString.Buffer = NameBuffer;
+            NameString.MaximumLength = NameString.Length = PathLength + DriverName.Length;
 
-  static BOOLEAN EP = FALSE;
+            /* NULL-terminate */
+            NameString.MaximumLength++;
+            NameBuffer[NameString.Length / sizeof(WCHAR)] = 0;
 
-  ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-    RtlImageDirectoryEntryToData(ImportModuleBase,
-         TRUE,
-               IMAGE_DIRECTORY_ENTRY_EXPORT,
-               &ExportDirSize);
+            Status = LdrLoadModule(&NameString, ImportedModule);
+        }
+        else
+        {
+            DPRINT("Module '%wZ' not loaded yet\n", &DriverName);
+            wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
+            wcsncat(NameBuffer, DriverName.Buffer, DriverName.Length / sizeof(WCHAR));
+            RtlInitUnicodeString(&NameString, NameBuffer);
+            Status = LdrLoadModule(&NameString, ImportedModule);
+        }
+        if (!NT_SUCCESS(Status))
+        {
+            wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
+            wcsncat(NameBuffer, DriverName.Buffer, DriverName.Length / sizeof(WCHAR));
+            RtlInitUnicodeString(&NameString, NameBuffer);
+            Status = LdrLoadModule(&NameString, ImportedModule);
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT1("Unknown import module: %wZ (Status %lx)\n", &DriverName, Status);
+            }
+        }
+    }
+    RtlFreeUnicodeString(&DriverName);
+    return Status;
+}
 
-  if (!EP) {
-    EP = TRUE;
-    ps("ExportDir %x\n", ExportDir);
-  }
+static PVOID
+LdrPEGetExportByName (
+    PVOID BaseAddress,
+    PUCHAR SymbolName,
+    WORD Hint )
+{
+    PIMAGE_EXPORT_DIRECTORY ExportDir;
+    PDWORD * ExFunctions;
+    PDWORD * ExNames;
+    USHORT * ExOrdinals;
+    PVOID ExName;
+    ULONG Ordinal;
+    PVOID Function;
+    LONG minn, maxn, mid, res;
+    ULONG ExportDirSize;
+
+    DPRINT("LdrPEGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
+
+    ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(BaseAddress,
+        TRUE,
+        IMAGE_DIRECTORY_ENTRY_EXPORT,
+        &ExportDirSize);
+    if (ExportDir == NULL)
+    {
+        DPRINT1("LdrPEGetExportByName(): no export directory!\n");
+        return NULL;
+    }
 
-  FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ImportModuleBase);
-  NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
-  OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ImportModuleBase);
 
-  ExportAddress = 0;
+    /* The symbol names may be missing entirely */
+    if (ExportDir->AddressOfNames == 0)
+    {
+        DPRINT("LdrPEGetExportByName(): symbol names missing entirely\n");
+        return NULL;
+    }
 
-  if (Name != NULL)
+    /*
+    * Get header pointers
+    */
+    ExNames = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfNames);
+    ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
+    ExFunctions = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
+
+    /*
+    * Check the hint first
+    */
+    if (Hint < ExportDir->NumberOfNames)
     {
-      for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
+        ExName = RVA(BaseAddress, ExNames[Hint]);
+        if (strcmp(ExName, (PCHAR)SymbolName) == 0)
         {
-          if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
-                       {
-              ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
-                FunctionList[OrdinalList[Idx]]);
-              break;
+            Ordinal = ExOrdinals[Hint];
+            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+            if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
+                (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
+            {
+                DPRINT("Forward: %s\n", (PCHAR)Function);
+                Function = LdrPEFixupForward((PCHAR)Function);
+                if (Function == NULL)
+                {
+                    DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
+                }
+                return Function;
+            }
+            if (Function != NULL)
+            {
+                return Function;
             }
         }
     }
-  else  /*  use hint  */
+
+    /*
+    * Binary search
+    */
+    minn = 0;
+    maxn = ExportDir->NumberOfNames - 1;
+    while (minn <= maxn)
     {
-      ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
+        mid = (minn + maxn) / 2;
 
-        FunctionList[Hint - ExportDir->Base]);
+        ExName = RVA(BaseAddress, ExNames[mid]);
+        res = strcmp(ExName, (PCHAR)SymbolName);
+        if (res == 0)
+        {
+            Ordinal = ExOrdinals[mid];
+            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+            if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
+                (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
+            {
+                DPRINT("Forward: %s\n", (PCHAR)Function);
+                Function = LdrPEFixupForward((PCHAR)Function);
+                if (Function == NULL)
+                {
+                    DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
+                }
+                return Function;
+            }
+            if (Function != NULL)
+            {
+                return Function;
+            }
+        }
+        else if (res > 0)
+        {
+            maxn = mid - 1;
+        }
+        else
+        {
+            minn = mid + 1;
+        }
     }
 
-  if (ExportAddress == 0)
+    ExName = RVA(BaseAddress, ExNames[mid]);
+    DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
+    return (PVOID)NULL;
+}
+
+static PVOID
+LdrPEGetExportByOrdinal (
+    PVOID BaseAddress,
+    ULONG Ordinal )
+{
+    PIMAGE_EXPORT_DIRECTORY ExportDir;
+    ULONG ExportDirSize;
+    PDWORD * ExFunctions;
+    PVOID Function;
+
+    ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData (
+        BaseAddress,
+        TRUE,
+        IMAGE_DIRECTORY_ENTRY_EXPORT,
+        &ExportDirSize);
+
+    ExFunctions = (PDWORD *)RVA(BaseAddress,
+        ExportDir->AddressOfFunctions);
+    DPRINT("LdrPEGetExportByOrdinal(Ordinal %d) = %x\n",
+        Ordinal,
+        RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base]));
+
+    Function = 0 != ExFunctions[Ordinal - ExportDir->Base]
+        ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
+        : NULL;
+
+    if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
+        ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize))
     {
-      ps("Export not found for %d:%s\n",
-        Hint,
-        Name != NULL ? Name : "(Ordinal)");
-      KEBUGCHECK(0);
+        DPRINT("Forward: %s\n", (PCHAR)Function);
+        Function = LdrPEFixupForward((PCHAR)Function);
     }
-  return ExportAddress;
-}
 
+    return Function;
+}
 
-static PVOID
-LdrPEFixupForward(PCHAR ForwardName)
+static NTSTATUS
+LdrPEProcessImportDirectoryEntry(
+    PVOID DriverBase,
+    PLDR_DATA_TABLE_ENTRY ImportedModule,
+    PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory )
 {
-   CHAR NameBuffer[128];
-   UNICODE_STRING ModuleName;
-   PCHAR p;
-   PMODULE_OBJECT ModuleObject;
+    PVOID* ImportAddressList;
+    PULONG FunctionNameList;
+    ULONG Ordinal;
+
+    if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
 
-   DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
+    /* Get the import address list. */
+    ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
 
-   strcpy(NameBuffer, ForwardName);
-   p = strchr(NameBuffer, '.');
-   if (p == NULL)
-     {
-       return NULL;
-     }
+    /* Get the list of functions to import. */
+    if (ImportModuleDirectory->OriginalFirstThunk != 0)
+    {
+        FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
+    }
+    else
+    {
+        FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
+    }
 
-   *p = 0;
+    /* Walk through function list and fixup addresses. */
+    while (*FunctionNameList != 0L)
+    {
+        if ((*FunctionNameList) & 0x80000000)
+        {
+            Ordinal = (*FunctionNameList) & 0x7fffffff;
+            *ImportAddressList = LdrPEGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
+            if ((*ImportAddressList) == NULL)
+            {
+                DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
+                return STATUS_UNSUCCESSFUL;
+            }
+        }
+        else
+        {
+            IMAGE_IMPORT_BY_NAME *pe_name;
+            pe_name = RVA(DriverBase, *FunctionNameList);
+            *ImportAddressList = LdrPEGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
+            if ((*ImportAddressList) == NULL)
+            {
+                DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
+                return STATUS_UNSUCCESSFUL;
+            }
+        }
+        ImportAddressList++;
+        FunctionNameList++;
+    }
+    return STATUS_SUCCESS;
+}
 
-   DPRINT("Driver: %s  Function: %s\n", NameBuffer, p+1);
+static NTSTATUS
+LdrPEFixupImports ( PLDR_DATA_TABLE_ENTRY Module )
+{
+    PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+    PCHAR ImportedName;
+    PLDR_DATA_TABLE_ENTRY ImportedModule;
+    NTSTATUS Status;
+    ULONG Size;
+
+    /*  Process each import module  */
+    ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+        RtlImageDirectoryEntryToData(Module->DllBase,
+        TRUE,
+        IMAGE_DIRECTORY_ENTRY_IMPORT,
+        &Size);
+    DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
+    while (ImportModuleDirectory->Name)
+    {
+        if (Module->SizeOfImage <= ImportModuleDirectory->Name)
+        {
+            DPRINT1("Invalid import directory in %wZ\n", &Module->FullDllName);
+            return STATUS_SECTION_NOT_IMAGE;
+        }
 
-   RtlCreateUnicodeStringFromAsciiz(&ModuleName,
-                                   NameBuffer);
-   ModuleObject = LdrGetModuleObject(&ModuleName);
-   RtlFreeUnicodeString(&ModuleName);
+        /*  Check to make sure that import lib is kernel  */
+        ImportedName = (PCHAR) Module->DllBase + ImportModuleDirectory->Name;
 
-   DPRINT("ModuleObject: %p\n", ModuleObject);
+        Status = LdrPEGetOrLoadModule(Module, ImportedName, &ImportedModule);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
 
-   if (ModuleObject == NULL)
-     {
-       CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
-       return NULL;
-     }
+        Status = LdrPEProcessImportDirectoryEntry(Module->DllBase, ImportedModule, ImportModuleDirectory);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
 
-  return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
+        ImportModuleDirectory++;
+    }
+    return STATUS_SUCCESS;
 }
 
 /* EOF */