mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 16:03:00 +00:00

on the list. This makes the registry, and dll loading case insensitive when we are on a case preserving filesystem. ntoskrnl/ex/power.c: My own contributions to the poweroff message list. ntoskrnl/mm/npool.c: Fixed bit-rot in whole page alloc. That's how i found the bug below. se/semgr.c, lib/rtl/sd.c: semgr, when creating a SECURITY_DESCRIPTOR, anded the PRESENT and DEFAULT flags rather than oring them for group, dacl, and sacl, leading to RtlLengthSecurityDescriptor giving the wrong length to sdcache. When sdcache would copy the security descriptor, it would be too short, and the bound check from the whole-page allocator would go off. I fixed this and made rtl/sd.c use the ROUND_UP macro and RtlLengthSid. This is cleaner. It may not be completely correct yet but it no-longer truncates security descriptors into the cache, which means that the Owner, Group and etc SIDs should now actually work right when coming from the cache, no matter what happens in the heap. They probably seemed to work before simply because they trashed the ends of their blocks and never moved in the cache. svn path=/trunk/; revision=11040
1578 lines
47 KiB
C
1578 lines
47 KiB
C
/* $Id: loader.c,v 1.144 2004/09/25 06:41:16 arty 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 <ntoskrnl.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,
|
|
OBJ_CASE_INSENSITIVE,
|
|
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,
|
|
¤t->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;
|
|
|
|
/* NULL-terminate */
|
|
NameString.MaximumLength++;
|
|
NameBuffer[NameString.Length / sizeof(WCHAR)] = 0;
|
|
|
|
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;
|
|
|
|
CreatedModuleObject->FullName.Length = 0;
|
|
CreatedModuleObject->FullName.MaximumLength = FileName->Length + sizeof(UNICODE_NULL);
|
|
CreatedModuleObject->FullName.Buffer = ExAllocatePool(PagedPool, CreatedModuleObject->FullName.MaximumLength);
|
|
RtlCopyUnicodeString(&CreatedModuleObject->FullName, FileName);
|
|
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,
|
|
(CreatedModuleObject->BaseName.Length + 1) * sizeof(WCHAR));
|
|
RtlCopyMemory(ModuleTextSection->Name,
|
|
CreatedModuleObject->BaseName.Buffer,
|
|
CreatedModuleObject->BaseName.Length);
|
|
ModuleTextSection->Name[CreatedModuleObject->BaseName.Length / sizeof(WCHAR)] = 0;
|
|
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 */
|