reactos/reactos/ntoskrnl/ldr/loader.c
Filip Navara 014d8e9588 - Rewritten some driver loading functions to get higher control of the driver loading and initialization process (Fixes bug #263).
- Added support for lower level filter drivers.

svn path=/trunk/; revision=8891
2004-03-27 19:41:32 +00:00

1580 lines
47 KiB
C

/* $Id: loader.c,v 1.141 2004/03/27 19:41:32 navaraf Exp $
*
* 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>
#ifdef HALDBG
#include <internal/ntosdbg.h>
#else
#ifdef __GNUC__
#define ps(args...)
#else
#define ps
#endif /* __GNUC__ */
#endif
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
LIST_ENTRY ModuleListHead;
KSPIN_LOCK ModuleListLock;
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);
static VOID
LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
PUNICODE_STRING FullName);
static LONG
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 PVOID
LdrSafePEGetExportAddress(PVOID ImportModuleBase,
PCHAR Name,
USHORT Hint);
static PVOID
LdrPEFixupForward(PCHAR ForwardName);
/* FUNCTIONS *****************************************************************/
VOID
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)
{
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER SectionList;
InitializeListHead(&ModuleTextListHead);
/* Setup ntoskrnl.exe text section */
/*
* This isn't the base of the text segment, but the start of the
* full image (in memory)
* Also, the Length field isn't set to the length of the segment,
* but is more like the offset, from the image base, to the end
* of the segment.
*/
NtHeader = RtlImageNtHeader((PVOID)KERNEL_BASE);
SectionList = IMAGE_FIRST_SECTION(NtHeader);
NtoskrnlTextSection.Base = KERNEL_BASE;
NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
SectionList[0].VirtualAddress;
NtoskrnlTextSection.Name = KERNEL_MODULE_NAME;
NtoskrnlTextSection.OptionalHeader = OPTHDROFFSET(KERNEL_BASE);
InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
/* Setup hal.dll text section */
/* Same comment as above applies */
NtHeader = RtlImageNtHeader((PVOID)LdrHalBase);
SectionList = IMAGE_FIRST_SECTION(NtHeader);
LdrHalTextSection.Base = LdrHalBase;
LdrHalTextSection.Length = SectionList[0].Misc.VirtualSize +
SectionList[0].VirtualAddress;
LdrHalTextSection.Name = HAL_MODULE_NAME;
LdrHalTextSection.OptionalHeader = OPTHDROFFSET(LdrHalBase);
InsertTailList(&ModuleTextListHead, &LdrHalTextSection.ListEntry);
/* Hook for KDB on initialization of the loader. */
KDB_LOADERINIT_HOOK(&NtoskrnlTextSection, &LdrHalTextSection);
}
VOID INIT_FUNCTION
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);
}
NTSTATUS
LdrpLoadImage(PUNICODE_STRING DriverName,
PVOID *ModuleBase,
PVOID *SectionPointer,
PVOID *EntryPoint,
PVOID *ExportSectionPointer)
{
PMODULE_OBJECT ModuleObject;
NTSTATUS Status;
ModuleObject = LdrGetModuleObject(DriverName);
if (ModuleObject == NULL)
{
Status = LdrLoadModule(DriverName, &ModuleObject);
if (!NT_SUCCESS(Status))
{
return(Status);
}
}
if (ModuleBase)
*ModuleBase = ModuleObject->Base;
// if (SectionPointer)
// *SectionPointer = ModuleObject->
if (EntryPoint)
*EntryPoint = ModuleObject->EntryPoint;
// if (ExportSectionPointer)
// *ExportSectionPointer = ModuleObject->
return(STATUS_SUCCESS);
}
NTSTATUS
LdrpUnloadImage(PVOID ModuleBase)
{
return(STATUS_NOT_IMPLEMENTED);
}
NTSTATUS
LdrpLoadAndCallImage(PUNICODE_STRING ModuleName)
{
PDRIVER_INITIALIZE DriverEntry;
PMODULE_OBJECT ModuleObject;
NTSTATUS Status;
ModuleObject = LdrGetModuleObject(ModuleName);
if (ModuleObject != NULL)
{
return(STATUS_IMAGE_ALREADY_LOADED);
}
Status = LdrLoadModule(ModuleName, &ModuleObject);
if (!NT_SUCCESS(Status))
{
return(Status);
}
DriverEntry = (PDRIVER_INITIALIZE)ModuleObject->EntryPoint;
Status = DriverEntry(NULL, NULL);
if (!NT_SUCCESS(Status))
{
LdrUnloadModule(ModuleObject);
}
return(Status);
}
NTSTATUS
LdrLoadModule(PUNICODE_STRING Filename,
PMODULE_OBJECT *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))
{
CPRINT("Could not open module file: %wZ\n", Filename);
return(Status);
}
CHECKPOINT;
/* Get the size of the file */
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileStdInfo,
sizeof(FileStdInfo),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
CPRINT("Could not get file size\n");
NtClose(FileHandle);
return(Status);
}
CHECKPOINT;
/* 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);
}
CHECKPOINT;
/* Load driver into memory chunk */
Status = NtReadFile(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);
}
CHECKPOINT;
NtClose(FileHandle);
Status = LdrProcessModule(ModuleLoadBase,
Filename,
&Module);
if (!NT_SUCCESS(Status))
{
CPRINT("Could not process module\n");
ExFreePool(ModuleLoadBase);
return(Status);
}
/* Cleanup */
ExFreePool(ModuleLoadBase);
*ModuleObject = Module;
/* Hook for KDB on loading a driver. */
KDB_LOADDRIVER_HOOK(Filename, Module);
return(STATUS_SUCCESS);
}
NTSTATUS
LdrUnloadModule(PMODULE_OBJECT ModuleObject)
{
KIRQL Irql;
/* Remove the module from the module list */
KeAcquireSpinLock(&ModuleListLock,&Irql);
RemoveEntryList(&ModuleObject->ListEntry);
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;
}
/* Free module section */
// MmFreeSection(ModuleObject->Base);
ExFreePool(ModuleObject);
return(STATUS_SUCCESS);
}
NTSTATUS
LdrProcessModule(PVOID ModuleLoadBase,
PUNICODE_STRING ModuleName,
PMODULE_OBJECT *ModuleObject)
{
PIMAGE_DOS_HEADER PEDosHeader;
/* If MZ header exists */
PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
{
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;
}
}
NTSTATUS
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))
{
ModuleCount++;
current_entry = current_entry->Flink;
}
*ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
(ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION_ENTRY);
if (Size < *ReqSize)
{
KeReleaseSpinLock(&ModuleListLock, Irql);
return(STATUS_INFO_LENGTH_MISMATCH);
}
/* fill the buffer */
memset(Buffer, '=', Size);
Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
Smi->Count = ModuleCount;
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 = (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->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;
}
KeReleaseSpinLock(&ModuleListLock, Irql);
return(STATUS_SUCCESS);
}
static VOID
LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
PUNICODE_STRING FullName)
{
PWCHAR p;
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(BaseName, p);
}
static LONG
LdrpCompareModuleNames(IN PUNICODE_STRING String1,
IN PUNICODE_STRING String2)
{
ULONG len1, len2, i;
PWCHAR s1, s2, p;
WCHAR c1, c2;
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);
}
}
}
return(0);
}
PMODULE_OBJECT
LdrGetModuleObject(PUNICODE_STRING ModuleName)
{
PMODULE_OBJECT Module;
PLIST_ENTRY Entry;
KIRQL Irql;
DPRINT("LdrpGetModuleObject(%wZ) called\n", ModuleName);
KeAcquireSpinLock(&ModuleListLock,&Irql);
Entry = ModuleListHead.Flink;
while (Entry != &ModuleListHead)
{
Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
DPRINT("Comparing %wZ and %wZ\n",
&Module->BaseName,
ModuleName);
if (!LdrpCompareModuleNames(&Module->BaseName, ModuleName))
{
DPRINT("Module %wZ\n", &Module->BaseName);
KeReleaseSpinLock(&ModuleListLock, Irql);
return(Module);
}
Entry = Entry->Flink;
}
KeReleaseSpinLock(&ModuleListLock, Irql);
DPRINT("Could not find module '%wZ'\n", ModuleName);
return(NULL);
}
/* ---------------------------------------------- PE Module support */
static BOOL
PageNeedsWriteAccess(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++)
{
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 + (char*)DriverBase;
NeedsWriteAccess = (char*)BaseAddress < (char*)PageStart + PAGE_SIZE &&
PageStart < (PVOID)((PCHAR) BaseAddress + Length);
}
}
return(NeedsWriteAccess);
}
static NTSTATUS
LdrPEProcessModule(PVOID ModuleLoadBase,
PUNICODE_STRING FileName,
PMODULE_OBJECT *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[PATH_MAX];
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)
{
CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
return STATUS_UNSUCCESSFUL;
}
if (PEDosHeader->e_lfanew == 0)
{
CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
return STATUS_UNSUCCESSFUL;
}
if (*PEMagic != IMAGE_PE_MAGIC)
{
CPRINT("Incorrect PE magic: %08x\n", *PEMagic);
return STATUS_UNSUCCESSFUL;
}
if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
{
CPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
return STATUS_UNSUCCESSFUL;
}
CHECKPOINT;
/* FIXME: if image is fixed-address load, then fail */
/* 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;
/* Determine the size of the module */
DriverSize = PEOptionalHeader->SizeOfImage;
DPRINT("DriverSize %x\n",DriverSize);
/* Allocate a virtual section for the module */
DriverBase = MmAllocateSection(DriverSize);
if (DriverBase == 0)
{
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++)
{
// Copy current section into current offset of virtual section
if (PESectionHeaders[Idx].Characteristics &
(IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
{
DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase);
memcpy(PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase,
(PVOID)((char*)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 + (char*)DriverBase);
memset(PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase,
'\0', PESectionHeaders[Idx].Misc.VirtualSize);
}
CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
PEOptionalHeader->SectionAlignment);
// CurrentBase = (PVOID)((DWORD)CurrentBase +
// ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
// PEOptionalHeader->SectionAlignment));
}
/* 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++)
{
if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
{
DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
PESectionHeaders[Idx].Name,
PESectionHeaders[Idx].PointerToRawData);
RelocDir = (PRELOCATION_DIRECTORY)(PESectionHeaders[Idx].PointerToRawData +
(char*)ModuleLoadBase);
CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
break;
}
}
#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)
{
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 Offset;
ULONG Type;
PDWORD RelocItem;
Offset = RelocEntry[Idx].TypeOffset & 0xfff;
Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
RelocItem = (PDWORD)((char*)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;
}
}
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)
{
/* 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)
{
PWCHAR PathEnd;
ULONG PathLength;
PathEnd = wcsrchr(FileName->Buffer, L'\\');
if (PathEnd != NULL)
{
PathLength = (PathEnd - FileName->Buffer + 1) * sizeof(WCHAR);
RtlCopyMemory(
NameBuffer,
FileName->Buffer,
PathLength);
RtlCopyMemory(
NameBuffer + (PathLength / sizeof(WCHAR)),
ModuleName.Buffer,
ModuleName.Length);
NameString.Buffer = NameBuffer;
NameString.MaximumLength =
NameString.Length = PathLength + ModuleName.Length;
Status = LdrLoadModule(&NameString, &LibraryModuleObject);
}
else
{
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);
/* Get the list of functions to import */
if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
{
FunctionNameList = (PULONG) ((DWORD)DriverBase +
ImportModuleDirectory->dwRVAFunctionNameList);
}
else
{
FunctionNameList = (PULONG) ((DWORD)DriverBase +
ImportModuleDirectory->dwRVAFunctionAddressList);
}
/* Walk through function list and fixup addresses */
while (*FunctionNameList != 0L)
{
if ((*FunctionNameList) & 0x80000000) // hint
{
pName = NULL;
Hint = (WORD)((*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);
if (*ImportAddressList == NULL)
{
return STATUS_PROCEDURE_NOT_FOUND;
}
}
else
{
CPRINT("Unresolved kernel symbol: %s\n", pName);
return STATUS_PROCEDURE_NOT_FOUND;
}
ImportAddressList++;
FunctionNameList++;
}
RtlFreeUnicodeString(&ModuleName);
ImportModuleDirectory++;
}
}
/* 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 + (char*)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);
}
}
}
/* Create the module */
CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
if (CreatedModuleObject == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
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);
}
return STATUS_SUCCESS;
}
PVOID
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)
{
return 0;
}
if (PEDosHeader->e_lfanew == 0)
{
return 0;
}
if (*PEMagic != IMAGE_PE_MAGIC)
{
return 0;
}
if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
{
return 0;
}
ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
PEOptionalHeader->Magic,
PEOptionalHeader->MajorLinkerVersion,
PEOptionalHeader->MinorLinkerVersion);
ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
/* Determine the size of the module */
*DriverSize = PEOptionalHeader->SizeOfImage;
ps("DriverSize %x\n",*DriverSize);
/* Copy headers over */
if (DriverBase != ModuleLoadBase)
{
memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->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);
/* 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;
/* Copy image sections into virtual section */
for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
{
PIMAGE_SECTION_HEADER Section = &PESectionHeaders[Idx];
// Copy current section into current offset of virtual section
// if (PESectionHeaders[Idx].Characteristics &
// (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
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->SizeOfRawData);
}
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,
PEOptionalHeader->SectionAlignment);
}
/* 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++)
{
if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
{
DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
PESectionHeaders[Idx].Name,
PESectionHeaders[Idx].PointerToRawData);
RelocDir = (PRELOCATION_DIRECTORY)(PESectionHeaders[Idx].PointerToRawData + (char*)ModuleLoadBase);
CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
break;
}
}
ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
TotalRelocs = 0;
while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
{
NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
sizeof(USHORT);
RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir +
sizeof(RELOCATION_DIRECTORY));
for (Idx = 0; Idx < NumRelocs; Idx++)
{
ULONG Offset;
ULONG Type;
PULONG RelocItem;
Offset = RelocEntry[Idx].TypeOffset & 0xfff;
Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
RelocItem = (PULONG)((char*)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);
}
ps("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)
((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 = (USHORT)((*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++;
}
}
ps("Finished importing.\n");
return(0);
}
static PVOID
LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
PCHAR Name,
USHORT Hint)
{
PIMAGE_EXPORT_DIRECTORY ExportDir;
ULONG ExportDirSize;
USHORT Idx;
PVOID ExportAddress;
PWORD OrdinalList;
PDWORD FunctionList, NameList;
PCHAR ModuleBase = (PCHAR)ModuleObject->Base;
ExportDir = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(ModuleBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportDirSize);
DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
if (ExportDir == NULL)
{
return NULL;
}
FunctionList = (PDWORD)((char*)ModuleBase + (DWORD)ExportDir->AddressOfFunctions);
NameList = (PDWORD)((char*)ModuleBase + (DWORD)ExportDir->AddressOfNames);
OrdinalList = (PWORD) ((char*)ModuleBase + (DWORD)ExportDir->AddressOfNameOrdinals);
ExportAddress = 0;
if (Name != NULL)
{
for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
{
#if 0
DPRINT(" Name:%s NameList[%d]:%s\n",
Name,
Idx,
(DWORD) ModuleBase + NameList[Idx]);
#endif
if (!strcmp(Name, ModuleBase + NameList[Idx]))
{
ExportAddress = (PVOID) ((DWORD)ModuleBase +
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;
}
}
}
else /* use hint */
{
ExportAddress = (PVOID) ((DWORD)ModuleBase +
FunctionList[Hint - ExportDir->Base]);
}
if (ExportAddress == NULL)
{
DbgPrint("Export not found for %d:%s\n",
Hint,
Name != NULL ? Name : "(Ordinal)");
}
return(ExportAddress);
}
static PVOID
LdrSafePEGetExportAddress(PVOID ImportModuleBase,
PCHAR Name,
USHORT Hint)
{
USHORT Idx;
PVOID ExportAddress;
PWORD OrdinalList;
PDWORD FunctionList, NameList;
PIMAGE_EXPORT_DIRECTORY ExportDir;
ULONG ExportDirSize;
static BOOLEAN EP = FALSE;
ExportDir = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(ImportModuleBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportDirSize);
if (!EP) {
EP = TRUE;
ps("ExportDir %x\n", ExportDir);
}
FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + (char*)ImportModuleBase);
NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + (char*)ImportModuleBase);
OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + (char*)ImportModuleBase);
ExportAddress = 0;
if (Name != NULL)
{
for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
{
if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
{
ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
FunctionList[OrdinalList[Idx]]);
break;
}
}
}
else /* use hint */
{
ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
FunctionList[Hint - ExportDir->Base]);
}
if (ExportAddress == 0)
{
ps("Export not found for %d:%s\n",
Hint,
Name != NULL ? Name : "(Ordinal)");
KEBUGCHECK(0);
}
return ExportAddress;
}
static PVOID
LdrPEFixupForward(PCHAR ForwardName)
{
CHAR NameBuffer[128];
UNICODE_STRING ModuleName;
PCHAR p;
PMODULE_OBJECT ModuleObject;
DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
strcpy(NameBuffer, ForwardName);
p = strchr(NameBuffer, '.');
if (p == NULL)
{
return NULL;
}
*p = 0;
DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
RtlCreateUnicodeStringFromAsciiz(&ModuleName,
NameBuffer);
ModuleObject = LdrGetModuleObject(&ModuleName);
RtlFreeUnicodeString(&ModuleName);
DPRINT("ModuleObject: %p\n", ModuleObject);
if (ModuleObject == NULL)
{
CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
return NULL;
}
return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
}
/* EOF */