reactos/reactos/ntoskrnl/ldr/loader.c
Eric Kohl c4d4559cce Moved io/drvlck.c to mm.
Minimize access to the module object via the object manager.
Use module list for internal module management.
Protect module list with a spinlock.

svn path=/trunk/; revision=3031
2002-06-10 08:50:55 +00:00

2163 lines
59 KiB
C

/* $Id: loader.c,v 1.106 2002/06/10 08:50:29 ekohl 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
*/
/* 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>
#ifdef HALDBG
#include <internal/ntosdbg.h>
#else
#define ps(args...)
#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')
#define TAG_SYM_BUF TAG('S', 'Y', 'M', 'B')
/* 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;
}
current->SymbolsBase = (PVOID)Module->ModStart;
current->SymbolsLength = Module->ModEnd - Module->ModStart;
}
VOID
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.SymbolsBase = NULL;
NtoskrnlTextSection.SymbolsLength = 0;
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.SymbolsBase = NULL;
LdrHalTextSection.SymbolsLength = 0;
InsertTailList(&ModuleTextListHead, &LdrHalTextSection.ListEntry);
}
VOID
LdrInitModuleManagement(VOID)
{
PIMAGE_DOS_HEADER DosHeader;
PMODULE_OBJECT ModuleObject;
#if 0
HANDLE ModuleHandle;
NTSTATUS Status;
WCHAR NameBuffer[60];
UNICODE_STRING ModuleName;
OBJECT_ATTRIBUTES ObjectAttributes;
#endif
/* Initialize the module list and spinlock */
InitializeListHead(&ModuleListHead);
KeInitializeSpinLock(&ModuleListLock);
/* Create module object for NTOSKRNL */
#if 0
wcscpy(NameBuffer, DRIVER_ROOT_NAME);
wcscat(NameBuffer, KERNEL_MODULE_NAME);
RtlInitUnicodeString (&ModuleName, NameBuffer);
DPRINT("Kernel's Module name is: %wZ\n", &ModuleName);
/* Initialize ObjectAttributes for ModuleObject */
InitializeObjectAttributes(&ObjectAttributes,
&ModuleName,
0,
NULL,
NULL);
/* Create module object */
ModuleHandle = 0;
Status = ObCreateObject(&ModuleHandle,
STANDARD_RIGHTS_REQUIRED,
&ObjectAttributes,
IoDriverObjectType,
(PVOID*)&ModuleObject);
assert(NT_SUCCESS(Status));
#endif
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 */
#if 0
wcscpy(NameBuffer, DRIVER_ROOT_NAME);
wcscat(NameBuffer, HAL_MODULE_NAME);
RtlInitUnicodeString (&ModuleName, NameBuffer);
DPRINT("HAL's Module name is: %wZ\n", &ModuleName);
/* Initialize ObjectAttributes for ModuleObject */
InitializeObjectAttributes(&ObjectAttributes,
&ModuleName,
0,
NULL,
NULL);
/* Create module object */
ModuleHandle = 0;
Status = ObCreateObject(&ModuleHandle,
STANDARD_RIGHTS_REQUIRED,
&ObjectAttributes,
IoDriverObjectType,
(PVOID*)&ModuleObject);
assert(NT_SUCCESS(Status));
#endif
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);
}
/*
* load the auto config drivers.
*/
static VOID
LdrLoadAutoConfigDriver(LPWSTR RelativeDriverName)
{
WCHAR TmpFileName [MAX_PATH];
CHAR Buffer [256];
UNICODE_STRING DriverName;
ULONG x, y, cx, cy;
HalQueryDisplayParameters(&x, &y, &cx, &cy);
RtlFillMemory(Buffer, x, ' ');
Buffer[x] = '\0';
HalSetDisplayParameters(0, y-1);
HalDisplayString(Buffer);
sprintf(Buffer, "Loading %S...\n",RelativeDriverName);
HalSetDisplayParameters(0, y-1);
HalDisplayString(Buffer);
HalSetDisplayParameters(cx, cy);
//CPRINT("Loading %S\n",RelativeDriverName);
wcscpy(TmpFileName, L"\\SystemRoot\\system32\\drivers\\");
wcscat(TmpFileName, RelativeDriverName);
RtlInitUnicodeString (&DriverName, TmpFileName);
NtLoadDriver(&DriverName);
}
#ifdef KDBG
BOOLEAN LdrpReadLine(PCHAR Line,
ULONG LineSize,
PVOID *Buffer,
PULONG Size)
{
CHAR ch;
PCHAR Block;
ULONG Count;
if (*Size == 0)
return FALSE;
ch = ' ';
Count = 0;
Block = *Buffer;
while ((*Size > 0) && (Count < LineSize) && ((ch = *Block) != (CHAR)13))
{
*Line = ch;
Line++;
Block++;
Count++;
*Size -= 1;
}
*Line = (CHAR)0;
if (ch == (CHAR)13)
{
Block++;
*Size -= 1;
}
if ((*Size > 0) && (*Block == (CHAR)10))
{
Block++;
*Size -= 1;
}
*Buffer = Block;
return TRUE;
}
ULONG HexL(PCHAR Buffer)
{
CHAR ch;
UINT i, j;
ULONG Value;
j = 32;
i = 0;
Value = 0;
while ((j > 0) && ((ch = Buffer[i]) != ' '))
{
j -= 4;
if ((ch >= '0') && (ch <= '9'))
Value |= ((ch - '0') << j);
if ((ch >= 'A') && (ch <= 'F'))
Value |= ((10 + (ch - 'A')) << j);
else
if ((ch >= 'a') && (ch <= 'f'))
Value |= ((10 + (ch - 'a')) << j);
i++;
}
return Value;
}
PSYMBOL LdrpParseLine(PCHAR Line,
PULONG TextBase,
PBOOLEAN TextBaseValid,
PULONG Alignment)
/*
Line format: [ADDRESS] <TYPE> <NAME>
TYPE:
U = ?
A = Image information
t = Symbol in text segment
T = Symbol in text segment
d = Symbol in data segment
D = Symbol in data segment
b = Symbol in BSS segment
B = Symbol in BSS segment
? = Unknown segment or symbol in unknown segment
*/
{
ANSI_STRING AnsiString;
CHAR Buffer[128];
PSYMBOL Symbol;
ULONG Address;
PCHAR Str;
CHAR Type;
if ((Line[0] == (CHAR)0) || (Line[0] == ' '))
return NULL;
Address = HexL(Line);
Line = strchr(Line, ' ');
if (Line == NULL)
return NULL;
Line++;
Type = *Line;
Line = strchr(Line, ' ');
if (Line == NULL)
return NULL;
Line++;
Str = strchr(Line, ' ');
if (Str == NULL)
strcpy((char*)&Buffer, Line);
else
strncpy((char*)&Buffer, Line, Str - Line);
if ((Type == 'A') && (strcmp((char*)&Buffer, "__section_alignment__")) == 0)
{
*Alignment = Address;
return NULL;
}
/* We only want symbols in the .text segment */
if ((Type != 't') && (Type != 'T'))
return NULL;
/* Discard other symbols we can't use */
if ((Buffer[0] != '_') || ((Buffer[0] == '_') && (Buffer[1] == '_')))
return NULL;
Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL));
if (!Symbol)
return NULL;
Symbol->Next = NULL;
Symbol->RelativeAddress = Address;
RtlInitAnsiString(&AnsiString, (PCSZ)&Buffer);
RtlAnsiStringToUnicodeString(&Symbol->Name, &AnsiString, TRUE);
if (!(*TextBaseValid))
{
*TextBase = Address - *Alignment;
*TextBaseValid = TRUE;
}
return Symbol;
}
VOID LdrpLoadModuleSymbolsFromBuffer(
PMODULE_OBJECT ModuleObject,
PVOID Buffer,
ULONG Length)
/*
Symbols must be sorted by address, e.g.
"nm --numeric-sort module.sys > module.sym"
*/
{
PSYMBOL Symbol, CurrentSymbol = NULL;
BOOLEAN TextBaseValid;
BOOLEAN Valid;
ULONG TextBase = 0;
ULONG Alignment = 0;
CHAR Line[256];
ULONG Tmp;
assert(ModuleObject);
if (ModuleObject->TextSection == NULL)
{
ModuleObject->TextSection = &NtoskrnlTextSection;
}
if (ModuleObject->TextSection->Symbols.SymbolCount > 0)
{
CPRINT("Symbols are already loaded for %wZ\n", &ModuleObject->BaseName);
return;
}
ModuleObject->TextSection->Symbols.SymbolCount = 0;
ModuleObject->TextSection->Symbols.Symbols = NULL;
TextBaseValid = FALSE;
Valid = FALSE;
while (LdrpReadLine((PCHAR)&Line, 256, &Buffer, &Length))
{
Symbol = LdrpParseLine((PCHAR)&Line, &Tmp, &Valid, &Alignment);
if ((Valid) && (!TextBaseValid))
{
TextBase = Tmp;
TextBaseValid = TRUE;
}
if (Symbol != NULL)
{
Symbol->RelativeAddress -= TextBase;
if (ModuleObject->TextSection->Symbols.Symbols == NULL)
ModuleObject->TextSection->Symbols.Symbols = Symbol;
else
CurrentSymbol->Next = Symbol;
CurrentSymbol = Symbol;
ModuleObject->TextSection->Symbols.SymbolCount++;
}
}
}
VOID LdrpLoadUserModuleSymbolsFromBuffer(
PLDR_MODULE ModuleObject,
PVOID Buffer,
ULONG Length)
/*
Symbols must be sorted by address, e.g.
"nm --numeric-sort module.dll > module.sym"
*/
{
PSYMBOL Symbol, CurrentSymbol = NULL;
BOOLEAN TextBaseValid;
BOOLEAN Valid;
ULONG TextBase = 0;
ULONG Alignment = 0;
CHAR Line[256];
ULONG Tmp;
if (ModuleObject->Symbols.SymbolCount > 0)
{
DPRINT("Symbols are already loaded for %wZ\n", &ModuleObject->BaseDllName);
return;
}
ModuleObject->Symbols.SymbolCount = 0;
ModuleObject->Symbols.Symbols = NULL;
TextBaseValid = FALSE;
Valid = FALSE;
while (LdrpReadLine((PCHAR)&Line, 256, &Buffer, &Length))
{
Symbol = LdrpParseLine((PCHAR)&Line, &Tmp, &Valid, &Alignment);
if ((Valid) && (!TextBaseValid))
{
TextBase = Tmp;
TextBaseValid = TRUE;
}
if (Symbol != NULL)
{
Symbol->RelativeAddress -= TextBase;
if (ModuleObject->Symbols.Symbols == NULL)
ModuleObject->Symbols.Symbols = Symbol;
else
CurrentSymbol->Next = Symbol;
CurrentSymbol = Symbol;
ModuleObject->Symbols.SymbolCount++;
}
}
}
VOID
LdrpLoadModuleSymbols(PMODULE_OBJECT ModuleObject)
{
FILE_STANDARD_INFORMATION FileStdInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR TmpFileName[MAX_PATH];
UNICODE_STRING Filename;
LPWSTR Start, Ext;
HANDLE FileHandle;
PVOID FileBuffer;
NTSTATUS Status;
ULONG Length;
IO_STATUS_BLOCK IoStatusBlock;
ModuleObject->TextSection->Symbols.SymbolCount = 0;
ModuleObject->TextSection->Symbols.Symbols = NULL;
/* Get the path to the symbol store */
wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\");
/* Get the symbol filename 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);
wcsncat(TmpFileName, Start, Length);
wcscat(TmpFileName, L".sym");
RtlInitUnicodeString(&Filename, TmpFileName);
/* Open the file */
InitializeObjectAttributes(&ObjectAttributes,
&Filename,
0,
NULL,
NULL);
Status = ZwOpenFile(&FileHandle,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
0,
0);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not open symbol file: %wZ\n", &Filename);
return;
}
CPRINT("Loading symbols from %wZ...\n", &Filename);
/* Get the size of the file */
Status = ZwQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileStdInfo,
sizeof(FileStdInfo),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not get file size\n");
return;
}
/* Allocate nonpageable memory for symbol file */
FileBuffer = ExAllocatePool(NonPagedPool,
FileStdInfo.EndOfFile.u.LowPart);
if (FileBuffer == NULL)
{
DPRINT("Could not allocate memory for symbol file\n");
return;
}
/* Load file into memory chunk */
Status = ZwReadFile(FileHandle,
0, 0, 0,
&IoStatusBlock,
FileBuffer,
FileStdInfo.EndOfFile.u.LowPart,
0, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not read symbol file into memory\n");
ExFreePool(FileBuffer);
return;
}
ZwClose(FileHandle);
LdrpLoadModuleSymbolsFromBuffer(ModuleObject,
FileBuffer,
FileStdInfo.EndOfFile.u.LowPart);
ExFreePool(FileBuffer);
}
VOID LdrLoadUserModuleSymbols(PLDR_MODULE ModuleObject)
{
FILE_STANDARD_INFORMATION FileStdInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR TmpFileName[MAX_PATH];
UNICODE_STRING Filename;
LPWSTR Start, Ext;
HANDLE FileHandle;
PVOID FileBuffer;
NTSTATUS Status;
ULONG Length;
IO_STATUS_BLOCK IoStatusBlock;
ModuleObject->Symbols.SymbolCount = 0;
ModuleObject->Symbols.Symbols = NULL;
/* Get the path to the symbol store */
wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\");
/* Get the symbol filename from the module name */
Start = wcsrchr(ModuleObject->BaseDllName.Buffer, L'\\');
if (Start == NULL)
Start = ModuleObject->BaseDllName.Buffer;
else
Start++;
Ext = wcsrchr(ModuleObject->BaseDllName.Buffer, L'.');
if (Ext != NULL)
Length = Ext - Start;
else
Length = wcslen(Start);
wcsncat(TmpFileName, Start, Length);
wcscat(TmpFileName, L".sym");
RtlInitUnicodeString(&Filename, TmpFileName);
/* Open the file */
InitializeObjectAttributes(&ObjectAttributes,
&Filename,
0,
NULL,
NULL);
Status = ZwOpenFile(&FileHandle,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
0,
0);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not open symbol file: %wZ\n", &Filename);
return;
}
CPRINT("Loading symbols from %wZ...\n", &Filename);
/* Get the size of the file */
Status = ZwQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileStdInfo,
sizeof(FileStdInfo),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not get file size\n");
return;
}
/* Allocate nonpageable memory for symbol file */
FileBuffer = ExAllocatePool(NonPagedPool,
FileStdInfo.EndOfFile.u.LowPart);
if (FileBuffer == NULL)
{
DPRINT("Could not allocate memory for symbol file\n");
return;
}
/* Load file into memory chunk */
Status = ZwReadFile(FileHandle,
0, 0, 0,
&IoStatusBlock,
FileBuffer,
FileStdInfo.EndOfFile.u.LowPart,
0, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not read symbol file into memory\n");
ExFreePool(FileBuffer);
return;
}
ZwClose(FileHandle);
LdrpLoadUserModuleSymbolsFromBuffer(ModuleObject,
FileBuffer,
FileStdInfo.EndOfFile.u.LowPart);
ExFreePool(FileBuffer);
}
#endif /* KDBG */
VOID LdrLoadAutoConfigDrivers (VOID)
{
#ifdef KDBG
NTSTATUS Status;
UNICODE_STRING ModuleName;
PMODULE_OBJECT ModuleObject;
/* Load symbols for ntoskrnl.exe and hal.dll because \SystemRoot
is created after their module entries */
RtlInitUnicodeString(&ModuleName, KERNEL_MODULE_NAME);
Status = LdrFindModuleObject(&ModuleName, &ModuleObject);
if (NT_SUCCESS(Status))
{
LdrpLoadModuleSymbols(ModuleObject);
}
RtlInitUnicodeString(&ModuleName, HAL_MODULE_NAME);
Status = LdrFindModuleObject(&ModuleName, &ModuleObject);
if (NT_SUCCESS(Status))
{
LdrpLoadModuleSymbols(ModuleObject);
}
#endif /* KDBG */
/*
* PCI bus driver
*/
//LdrLoadAutoConfigDriver( L"pci.sys" );
/*
* Keyboard driver
*/
LdrLoadAutoConfigDriver( L"keyboard.sys" );
if ((KdDebuggerEnabled) && (KdDebugState & KD_DEBUG_PICE))
{
/*
* Private ICE debugger
*/
LdrLoadAutoConfigDriver( L"pice.sys" );
}
/*
* Raw console driver
*/
LdrLoadAutoConfigDriver( L"blue.sys" );
/*
*
*/
LdrLoadAutoConfigDriver(L"vidport.sys");
#if 0
/*
* Minix filesystem driver
*/
LdrLoadAutoConfigDriver(L"minixfs.sys");
/*
* Mailslot filesystem driver
*/
LdrLoadAutoConfigDriver(L"msfs.sys");
#endif
/*
* Named pipe filesystem driver
*/
LdrLoadAutoConfigDriver(L"npfs.sys");
/*
* Mouse drivers
*/
// LdrLoadAutoConfigDriver(L"l8042prt.sys");
LdrLoadAutoConfigDriver(L"psaux.sys");
LdrLoadAutoConfigDriver(L"mouclass.sys");
/*
* Networking
*/
#if 1
/*
* NDIS library
*/
LdrLoadAutoConfigDriver(L"ndis.sys");
#endif
}
NTSTATUS
LdrLoadGdiDriver(PUNICODE_STRING DriverName,
PVOID *ImageAddress,
PVOID *SectionPointer,
PVOID *EntryPoint,
PVOID *ExportSectionPointer)
{
PMODULE_OBJECT ModuleObject;
NTSTATUS Status;
Status = LdrLoadModule(DriverName, &ModuleObject);
if (!NT_SUCCESS(Status))
{
return(Status);
}
if (ImageAddress)
*ImageAddress = ModuleObject->Base;
// if (SectionPointer)
// *SectionPointer = ModuleObject->
if (EntryPoint)
*EntryPoint = ModuleObject->EntryPoint;
// if (ExportSectionPointer)
// *ExportSectionPointer = ModuleObject->
return(STATUS_SUCCESS);
}
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;
/* Check for module already loaded */
Module = LdrGetModuleObject(Filename);
if (Module != NULL)
{
*ModuleObject = Module;
return(STATUS_SUCCESS);
}
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,
0);
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");
ExFreePool(ModuleLoadBase);
return(Status);
}
/* Cleanup */
ExFreePool(ModuleLoadBase);
#ifdef KDBG
/* Load symbols for module if available */
LdrpLoadModuleSymbols(Module);
#endif /* KDBG */
*ModuleObject = Module;
return(STATUS_SUCCESS);
}
NTSTATUS
LdrInitializeBootStartDriver(PVOID ModuleLoadBase,
PCHAR FileName,
ULONG ModuleLength)
{
PMODULE_OBJECT ModuleObject;
UNICODE_STRING ModuleName;
PDEVICE_NODE DeviceNode;
NTSTATUS Status;
CHAR Buffer [256];
ULONG x, y, cx, cy;
#ifdef KDBG
CHAR TmpBaseName[MAX_PATH];
CHAR TmpFileName[MAX_PATH];
ANSI_STRING AnsiString;
ULONG Length;
PCHAR Ext;
#endif
HalQueryDisplayParameters(&x, &y, &cx, &cy);
RtlFillMemory(Buffer, x, ' ');
Buffer[x] = '\0';
HalSetDisplayParameters(0, y-1);
HalDisplayString(Buffer);
sprintf(Buffer, "Initializing %s...\n", FileName);
HalSetDisplayParameters(0, y-1);
HalDisplayString(Buffer);
HalSetDisplayParameters(cx, cy);
#ifdef KDBG
/* Split the filename into base name and extension */
Ext = strrchr(FileName, '.');
if (Ext != NULL)
Length = Ext - FileName;
else
Length = strlen(FileName);
if ((Ext != NULL) && (strcmp(Ext, ".sym") == 0))
{
DPRINT("Module %s is a symbol file\n", FileName);
strncpy(TmpBaseName, FileName, Length);
TmpBaseName[Length] = '\0';
DPRINT("base: %s (Length %d)\n", TmpBaseName, Length);
strcpy(TmpFileName, TmpBaseName);
strcat(TmpFileName, ".sys");
RtlInitAnsiString(&AnsiString, TmpFileName);
DPRINT("dasdsad: %s\n", TmpFileName);
RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE);
Status = LdrFindModuleObject(&ModuleName, &ModuleObject);
RtlFreeUnicodeString(&ModuleName);
if (!NT_SUCCESS(Status))
{
strcpy(TmpFileName, TmpBaseName);
strcat(TmpFileName, ".exe");
RtlInitAnsiString(&AnsiString, TmpFileName);
RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE);
Status = LdrFindModuleObject(&ModuleName, &ModuleObject);
RtlFreeUnicodeString(&ModuleName);
}
if (NT_SUCCESS(Status))
{
LdrpLoadModuleSymbolsFromBuffer(ModuleObject,
ModuleLoadBase,
ModuleLength);
}
return(STATUS_SUCCESS);
}
else
{
DPRINT("Module %s is executable\n", FileName);
}
#endif /* KDBG */
/* 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);
}
Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode);
if (!NT_SUCCESS(Status))
{
IopFreeDeviceNode(DeviceNode);
CPRINT("Driver load failed, status (%x)\n", Status);
}
return(Status);
}
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_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].Unknown2 = 0; /* Always 0 */
Smi->Module[ModuleCount].BaseAddress = current->Base;
Smi->Module[ModuleCount].Size = current->Length;
Smi->Module[ModuleCount].Flags = 0; /* Flags ??? (GN) */
Smi->Module[ModuleCount].EntryIndex = ModuleCount;
AnsiName.Length = 0;
AnsiName.MaximumLength = 256;
AnsiName.Buffer = Smi->Module[ModuleCount].Name;
RtlUnicodeStringToAnsiString(&AnsiName,
&current->FullName,
FALSE);
p = strrchr(AnsiName.Buffer, '\\');
if (p == NULL)
{
Smi->Module[ModuleCount].PathLength = 0;
Smi->Module[ModuleCount].NameLength = strlen(AnsiName.Buffer);
}
else
{
p++;
Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
Smi->Module[ModuleCount].NameLength = strlen(p);
}
ModuleCount++;
current_entry = current_entry->Flink;
}
KeReleaseSpinLock(&ModuleListLock, Irql);
return(STATUS_SUCCESS);
}
static VOID
LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
PUNICODE_STRING FullName)
{
UNICODE_STRING Name;
PWCHAR p;
PWCHAR q;
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;
}
DPRINT("p %S\n", p);
RtlCreateUnicodeString(BaseName, Name.Buffer);
RtlFreeUnicodeString(&Name);
}
static LONG
LdrpCompareModuleNames(IN PUNICODE_STRING String1,
IN PUNICODE_STRING String2)
{
ULONG len1, len2;
PWCHAR s1, s2;
WCHAR c1, c2;
if (String1 && String2)
{
len1 = String1->Length / sizeof(WCHAR);
len2 = String2->Length / sizeof(WCHAR);
s1 = String1->Buffer;
s2 = String2->Buffer;
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 %x\n", Module);
KeReleaseSpinLock(&ModuleListLock, Irql);
return(Module);
}
Entry = Entry->Flink;
}
KeReleaseSpinLock(&ModuleListLock, Irql);
CPRINT("LdrpGetModuleObject: Failed to find dll %wZ\n", ModuleName);
return(NULL);
}
/* ---------------------------------------------- PE Module support */
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;
HANDLE ModuleHandle;
PMODULE_OBJECT CreatedModuleObject;
PVOID *ImportAddressList;
PULONG FunctionNameList;
PCHAR pName;
WORD Hint;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ModuleName;
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)
{
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;
}
CPRINT("DriverBase: %x\n", 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 + 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
{
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);
// 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 = PESectionHeaders[Idx].PointerToRawData +
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)(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);
Status = LdrLoadModule(&ModuleName, &LibraryModuleObject);
if (!NT_SUCCESS(Status))
{
CPRINT("Unknown import module: %wZ (Status %lx)\n", &ModuleName, 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 = (*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++;
}
RtlFreeUnicodeString(&ModuleName);
ImportModuleDirectory++;
}
}
/* Create ModuleName string */
wcscpy(NameBuffer, DRIVER_ROOT_NAME);
if (wcsrchr(FileName->Buffer, '\\') != 0)
{
wcscat(NameBuffer, wcsrchr(FileName->Buffer, '\\') + 1);
}
else
{
wcscat(NameBuffer, FileName->Buffer);
}
RtlInitUnicodeString (&ModuleName, NameBuffer);
CPRINT("Module name is: %wZ\n", &ModuleName);
/* Initialize ObjectAttributes for ModuleObject */
InitializeObjectAttributes(&ObjectAttributes,
&ModuleName,
0,
NULL,
NULL);
/* Create module object */
ModuleHandle = 0;
Status = ObCreateObject(&ModuleHandle,
STANDARD_RIGHTS_REQUIRED,
&ObjectAttributes,
IoDriverObjectType,
(PVOID*)&CreatedModuleObject);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* 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));
ModuleTextSection->Base = (ULONG)DriverBase;
ModuleTextSection->Length = DriverSize;
ModuleTextSection->SymbolsBase = NULL;
ModuleTextSection->SymbolsLength = 0;
ModuleTextSection->Name =
ExAllocatePool(NonPagedPool,
(wcslen(NameBuffer) + 1) * sizeof(WCHAR));
wcscpy(ModuleTextSection->Name, NameBuffer);
InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
CreatedModuleObject->TextSection = ModuleTextSection;
*ModuleObject = CreatedModuleObject;
DPRINT("Loading Module %wZ...\n", FileName);
if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
{
DbgPrint("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++)
{
// 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);
}
/* 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 = PESectionHeaders[Idx].PointerToRawData + 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;
PDWORD 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);
}
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 = (*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;
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)
{
for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
{
#if 0
DPRINT(" Name:%s NameList[%d]:%s\n",
Name,
Idx,
(DWORD) ModuleObject->Base + NameList[Idx]);
#endif
if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
{
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;
}
}
}
else /* use hint */
{
ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
FunctionList[Hint - ExportDir->Base]);
}
if (ExportAddress == 0)
{
CPRINT("Export not found for %d:%s\n",
Hint,
Name != NULL ? Name : "(Ordinal)");
KeBugCheck(0);
}
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 + ImportModuleBase);
NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + 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)");
for (;;);
}
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 */