mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
- Fix MmCreateImageSection to use previous mode instead of hardcoding UserMode.
- Implement MiProcessLoaderEntry for adding/removing entries on the PsLoadedModuleList. - Move MmLoadSystemImage from loader.c to sysldr.c - Update MmLoadSystemImage: - Use MmSystemLoadLock. - Support returning the entry for an already-loaded image, instead of loading it twice. - Use Section APIs to map the image... we're still doing a dirty ZwReadFile hack, but at least now we can depend on the PE code to validate the image (so removed the hardcoded validation). - Add more generic cleanup got so we can just jump to it. - Add more stub code and detection code for upcoming features. svn path=/trunk/; revision=25883
This commit is contained in:
parent
736a4de31f
commit
3111dda705
3 changed files with 485 additions and 378 deletions
|
@ -20,15 +20,6 @@
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiResolveImageReferences(IN PVOID ImageBase,
|
||||
IN PUNICODE_STRING ImageFileDirectory,
|
||||
IN PUNICODE_STRING NamePrefix OPTIONAL,
|
||||
OUT PCHAR *MissingApi,
|
||||
OUT PWCHAR *MissingDriver,
|
||||
OUT PLOAD_IMPORTS *LoadImports);
|
||||
|
||||
static LONG
|
||||
LdrpCompareModuleNames (
|
||||
IN PUNICODE_STRING String1,
|
||||
|
@ -168,372 +159,4 @@ LdrUnloadModule ( PLDR_DATA_TABLE_ENTRY ModuleObject )
|
|||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
//
|
||||
// Used by NtLoadDriver/IoMgr
|
||||
//
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmLoadSystemImage(IN PUNICODE_STRING FileName,
|
||||
IN PUNICODE_STRING NamePrefix OPTIONAL,
|
||||
IN PUNICODE_STRING LoadedName OPTIONAL,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *ModuleObject,
|
||||
OUT PVOID *ImageBaseAddress)
|
||||
{
|
||||
PVOID ModuleLoadBase;
|
||||
NTSTATUS Status;
|
||||
HANDLE FileHandle;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
PLDR_DATA_TABLE_ENTRY Module;
|
||||
FILE_STANDARD_INFORMATION FileStdInfo;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
unsigned int DriverSize, Idx;
|
||||
ULONG CurrentSize;
|
||||
PVOID DriverBase;
|
||||
PIMAGE_DOS_HEADER PEDosHeader;
|
||||
PIMAGE_NT_HEADERS PENtHeaders;
|
||||
PIMAGE_SECTION_HEADER PESectionHeaders;
|
||||
KIRQL Irql;
|
||||
PIMAGE_NT_HEADERS NtHeader;
|
||||
UNICODE_STRING BaseName, BaseDirectory, PrefixName;
|
||||
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
||||
ULONG EntrySize;
|
||||
PLOAD_IMPORTS LoadedImports = (PVOID)-2;
|
||||
PCHAR MissingApiName, Buffer;
|
||||
PWCHAR MissingDriverName;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Detect session-load */
|
||||
if (Flags)
|
||||
{
|
||||
/* Sanity checks */
|
||||
ASSERT(NamePrefix == NULL);
|
||||
ASSERT(LoadedName == NULL);
|
||||
|
||||
/* Make sure the process is in session too */
|
||||
if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (ModuleObject) *ModuleObject = NULL;
|
||||
if (ImageBaseAddress) *ImageBaseAddress = NULL;
|
||||
|
||||
/* Allocate a buffer we'll use for names */
|
||||
Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
|
||||
if (!Buffer)
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* Check for a separator */
|
||||
if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
|
||||
{
|
||||
PWCHAR p;
|
||||
ULONG BaseLength;
|
||||
|
||||
/* Loop the path until we get to the base name */
|
||||
p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
|
||||
while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
|
||||
|
||||
/* Get the length */
|
||||
BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
|
||||
BaseLength *= sizeof(WCHAR);
|
||||
|
||||
/* Setup the string */
|
||||
BaseName.Length = (USHORT)BaseLength;
|
||||
BaseName.Buffer = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, we already have a base name */
|
||||
BaseName.Length = FileName->Length;
|
||||
BaseName.Buffer = FileName->Buffer;
|
||||
}
|
||||
|
||||
/* Setup the maximum length */
|
||||
BaseName.MaximumLength = BaseName.Length;
|
||||
|
||||
/* Now compute the base directory */
|
||||
BaseDirectory = *FileName;
|
||||
BaseDirectory.Length -= BaseName.Length;
|
||||
BaseDirectory.MaximumLength = BaseDirectory.Length;
|
||||
|
||||
/* And the prefix, which for now is just the name itself */
|
||||
PrefixName = *FileName;
|
||||
|
||||
/* Check if we have a prefix */
|
||||
if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
|
||||
|
||||
/* Check if we already have a name, use it instead */
|
||||
if (LoadedName) BaseName = *LoadedName;
|
||||
|
||||
/* Open the Module */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
FileName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = ZwOpenFile(&FileHandle,
|
||||
GENERIC_READ,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Could not open module file: %wZ (Status 0x%08lx)\n", FileName, Status);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
|
||||
/* 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");
|
||||
NtClose(FileHandle);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
|
||||
/* Allocate nonpageable memory for driver */
|
||||
ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
|
||||
FileStdInfo.EndOfFile.u.LowPart,
|
||||
TAG_DRIVER_MEM);
|
||||
if (ModuleLoadBase == NULL)
|
||||
{
|
||||
DPRINT("Could not allocate memory for module");
|
||||
NtClose(FileHandle);
|
||||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||||
}
|
||||
|
||||
|
||||
/* Load driver into memory chunk */
|
||||
Status = ZwReadFile(FileHandle,
|
||||
0, 0, 0,
|
||||
&IoStatusBlock,
|
||||
ModuleLoadBase,
|
||||
FileStdInfo.EndOfFile.u.LowPart,
|
||||
0, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Could not read module file into memory");
|
||||
ExFreePool(ModuleLoadBase);
|
||||
NtClose(FileHandle);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
|
||||
ZwClose(FileHandle);
|
||||
|
||||
DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
|
||||
|
||||
/* Get header pointers */
|
||||
PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
|
||||
PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
|
||||
NtHeader = PENtHeaders;
|
||||
PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
|
||||
|
||||
|
||||
/* Check file magic numbers */
|
||||
if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
DPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (PEDosHeader->e_lfanew == 0)
|
||||
{
|
||||
DPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (PENtHeaders->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
DPRINT("Incorrect PE magic: %08x\n", PENtHeaders->Signature);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
DPRINT("Incorrect Architechture: %04x\n", PENtHeaders->FileHeader.Machine);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: if image is fixed-address load, then fail */
|
||||
|
||||
/* FIXME: check/verify OS version number */
|
||||
|
||||
DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
|
||||
PENtHeaders->OptionalHeader.Magic,
|
||||
PENtHeaders->OptionalHeader.MajorLinkerVersion,
|
||||
PENtHeaders->OptionalHeader.MinorLinkerVersion);
|
||||
DPRINT("Entry Point:%08lx\n", PENtHeaders->OptionalHeader.AddressOfEntryPoint);
|
||||
|
||||
/* Determine the size of the module */
|
||||
DriverSize = 0;
|
||||
for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
|
||||
{
|
||||
if (!(PESectionHeaders[Idx].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
||||
{
|
||||
CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
|
||||
DriverSize = max(DriverSize, CurrentSize);
|
||||
}
|
||||
}
|
||||
DriverSize = ROUND_UP(DriverSize, PENtHeaders->OptionalHeader.SectionAlignment);
|
||||
DPRINT("DriverSize %x, SizeOfImage %x\n",DriverSize, PENtHeaders->OptionalHeader.SizeOfImage);
|
||||
|
||||
/* Allocate a virtual section for the module */
|
||||
DriverBase = NULL;
|
||||
DriverBase = MmAllocateSection(DriverSize, DriverBase);
|
||||
if (DriverBase == 0)
|
||||
{
|
||||
DPRINT("Failed to allocate a virtual section for driver\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
DPRINT("DriverBase for %wZ: %x\n", FileName, DriverBase);
|
||||
|
||||
/* Copy headers over */
|
||||
memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
|
||||
|
||||
/* Copy image sections into virtual section */
|
||||
for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
|
||||
{
|
||||
CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
|
||||
/* Copy current section into current offset of virtual section */
|
||||
if (CurrentSize <= DriverSize &&
|
||||
PESectionHeaders[Idx].SizeOfRawData)
|
||||
{
|
||||
DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
|
||||
PESectionHeaders[Idx].VirtualAddress + (ULONG_PTR)DriverBase);
|
||||
memcpy((PVOID)((ULONG_PTR)DriverBase + PESectionHeaders[Idx].VirtualAddress),
|
||||
(PVOID)((ULONG_PTR)ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
|
||||
PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
|
||||
? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
|
||||
}
|
||||
}
|
||||
|
||||
/* Relocate the driver */
|
||||
Status = LdrRelocateImageWithBias(DriverBase,
|
||||
0,
|
||||
"SYSLDR",
|
||||
STATUS_SUCCESS,
|
||||
STATUS_CONFLICTING_ADDRESSES,
|
||||
STATUS_INVALID_IMAGE_FORMAT);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Fail */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Calculate the size we'll need for the entry and allocate it */
|
||||
EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
|
||||
BaseName.Length +
|
||||
sizeof(UNICODE_NULL);
|
||||
|
||||
/* Allocate the entry */
|
||||
LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
|
||||
if (!LdrEntry)
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* Setup the entry */
|
||||
LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
|
||||
LdrEntry->LoadCount = 1;
|
||||
LdrEntry->LoadedImports = LoadedImports;
|
||||
LdrEntry->PatchInformation = NULL;
|
||||
|
||||
/* Check the version */
|
||||
if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
|
||||
(NtHeader->OptionalHeader.MajorImageVersion >= 5))
|
||||
{
|
||||
/* Mark this image as a native image */
|
||||
LdrEntry->Flags |= 0x80000000;
|
||||
}
|
||||
|
||||
/* Setup the rest of the entry */
|
||||
LdrEntry->DllBase = DriverBase;
|
||||
LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)DriverBase +
|
||||
NtHeader->OptionalHeader.AddressOfEntryPoint);
|
||||
LdrEntry->SizeOfImage = DriverSize;
|
||||
LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
|
||||
LdrEntry->SectionPointer = LdrEntry;
|
||||
|
||||
/* Now write the DLL name */
|
||||
LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
|
||||
LdrEntry->BaseDllName.Length = BaseName.Length;
|
||||
LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
|
||||
|
||||
/* Copy and null-terminate it */
|
||||
RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
|
||||
BaseName.Buffer,
|
||||
BaseName.Length);
|
||||
LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;
|
||||
|
||||
/* Now allocate the full name */
|
||||
LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
|
||||
PrefixName.Length +
|
||||
sizeof(UNICODE_NULL),
|
||||
TAG_LDR_WSTR);
|
||||
if (!LdrEntry->FullDllName.Buffer)
|
||||
{
|
||||
/* Don't fail, just set it to zero */
|
||||
LdrEntry->FullDllName.Length = 0;
|
||||
LdrEntry->FullDllName.MaximumLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set it up */
|
||||
LdrEntry->FullDllName.Length = PrefixName.Length;
|
||||
LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
|
||||
|
||||
/* Copy and null-terminate */
|
||||
RtlCopyMemory(LdrEntry->FullDllName.Buffer,
|
||||
PrefixName.Buffer,
|
||||
PrefixName.Length);
|
||||
LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;
|
||||
}
|
||||
|
||||
/* Insert the entry */
|
||||
KeAcquireSpinLock(&PsLoadedModuleSpinLock, &Irql);
|
||||
InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks);
|
||||
KeReleaseSpinLock(&PsLoadedModuleSpinLock, Irql);
|
||||
|
||||
/* Resolve imports */
|
||||
MissingApiName = Buffer;
|
||||
Status = MiResolveImageReferences(DriverBase,
|
||||
&BaseDirectory,
|
||||
NULL,
|
||||
&MissingApiName,
|
||||
&MissingDriverName,
|
||||
&LoadedImports);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Fail */
|
||||
ExFreePool(LdrEntry->FullDllName.Buffer);
|
||||
ExFreePool(LdrEntry);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Return */
|
||||
Module = LdrEntry;
|
||||
|
||||
/* Cleanup */
|
||||
ExFreePool(ModuleLoadBase);
|
||||
|
||||
if (ModuleObject) *ModuleObject = Module;
|
||||
if (ImageBaseAddress) *ImageBaseAddress = Module->DllBase;
|
||||
|
||||
/* Hook for KDB on loading a driver. */
|
||||
KDB_LOADDRIVER_HOOK(FileName, Module);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -3292,7 +3292,7 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
|
|||
Status = ObReferenceObjectByHandle(FileHandle,
|
||||
FileAccess,
|
||||
IoFileObjectType,
|
||||
UserMode,
|
||||
ExGetPreviousMode(),
|
||||
(PVOID*)(PVOID)&FileObject,
|
||||
NULL);
|
||||
|
||||
|
|
|
@ -21,6 +21,24 @@ KMUTANT MmSystemLoadLock;
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
|
||||
IN BOOLEAN Insert)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
|
||||
/* Acquire the lock */
|
||||
KeAcquireSpinLock(&PsLoadedModuleSpinLock, &OldIrql);
|
||||
|
||||
/* Insert or remove from the list */
|
||||
Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
|
||||
RemoveEntryList(&LdrEntry->InLoadOrderLinks);
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||||
|
@ -1019,3 +1037,469 @@ MmCheckSystemImage(IN HANDLE ImageHandle,
|
|||
ZwClose(SectionHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmLoadSystemImage(IN PUNICODE_STRING FileName,
|
||||
IN PUNICODE_STRING NamePrefix OPTIONAL,
|
||||
IN PUNICODE_STRING LoadedName OPTIONAL,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *ModuleObject,
|
||||
OUT PVOID *ImageBaseAddress)
|
||||
{
|
||||
PVOID ModuleLoadBase = NULL;
|
||||
NTSTATUS Status;
|
||||
HANDLE FileHandle = NULL;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
FILE_STANDARD_INFORMATION FileStdInfo;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
ULONG DriverSize = 0, Size, i;
|
||||
PVOID DriverBase;
|
||||
PIMAGE_SECTION_HEADER SectionHeaders;
|
||||
PIMAGE_NT_HEADERS NtHeader;
|
||||
UNICODE_STRING BaseName, BaseDirectory, PrefixName;
|
||||
PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
|
||||
ULONG EntrySize;
|
||||
PLOAD_IMPORTS LoadedImports = (PVOID)-2;
|
||||
PCHAR MissingApiName, Buffer;
|
||||
PWCHAR MissingDriverName;
|
||||
HANDLE SectionHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
PVOID Section = NULL;
|
||||
BOOLEAN LockOwned = FALSE;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Detect session-load */
|
||||
if (Flags)
|
||||
{
|
||||
/* Sanity checks */
|
||||
ASSERT(NamePrefix == NULL);
|
||||
ASSERT(LoadedName == NULL);
|
||||
|
||||
/* Make sure the process is in session too */
|
||||
if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (ModuleObject) *ModuleObject = NULL;
|
||||
if (ImageBaseAddress) *ImageBaseAddress = NULL;
|
||||
|
||||
/* Allocate a buffer we'll use for names */
|
||||
Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
|
||||
if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* Check for a separator */
|
||||
if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
|
||||
{
|
||||
PWCHAR p;
|
||||
ULONG BaseLength;
|
||||
|
||||
/* Loop the path until we get to the base name */
|
||||
p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
|
||||
while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
|
||||
|
||||
/* Get the length */
|
||||
BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
|
||||
BaseLength *= sizeof(WCHAR);
|
||||
|
||||
/* Setup the string */
|
||||
BaseName.Length = (USHORT)BaseLength;
|
||||
BaseName.Buffer = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, we already have a base name */
|
||||
BaseName.Length = FileName->Length;
|
||||
BaseName.Buffer = FileName->Buffer;
|
||||
}
|
||||
|
||||
/* Setup the maximum length */
|
||||
BaseName.MaximumLength = BaseName.Length;
|
||||
|
||||
/* Now compute the base directory */
|
||||
BaseDirectory = *FileName;
|
||||
BaseDirectory.Length -= BaseName.Length;
|
||||
BaseDirectory.MaximumLength = BaseDirectory.Length;
|
||||
|
||||
/* And the prefix, which for now is just the name itself */
|
||||
PrefixName = *FileName;
|
||||
|
||||
/* Check if we have a prefix */
|
||||
if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
|
||||
|
||||
/* Check if we already have a name, use it instead */
|
||||
if (LoadedName) BaseName = *LoadedName;
|
||||
|
||||
/* Acquire the load lock */
|
||||
LoaderScan:
|
||||
ASSERT(LockOwned == FALSE);
|
||||
LockOwned = TRUE;
|
||||
KeEnterCriticalRegion();
|
||||
KeWaitForSingleObject(&MmSystemLoadLock,
|
||||
WrVirtualMemory,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
/* Scan the module list */
|
||||
NextEntry = PsLoadedModuleList.Flink;
|
||||
while (NextEntry != &PsLoadedModuleList)
|
||||
{
|
||||
/* Get the entry and compare the names */
|
||||
LdrEntry = CONTAINING_RECORD(NextEntry,
|
||||
LDR_DATA_TABLE_ENTRY,
|
||||
InLoadOrderLinks);
|
||||
if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
|
||||
{
|
||||
/* Found it, break out */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Keep scanning */
|
||||
NextEntry = NextEntry->Flink;
|
||||
}
|
||||
|
||||
/* Check if we found the image */
|
||||
if (NextEntry != &PsLoadedModuleList)
|
||||
{
|
||||
/* Check if we had already mapped a section */
|
||||
if (Section)
|
||||
{
|
||||
/* Dereference and clear */
|
||||
ObDereferenceObject(Section);
|
||||
Section = NULL;
|
||||
}
|
||||
|
||||
/* Check if this was supposed to be a session load */
|
||||
if (!Flags)
|
||||
{
|
||||
/* It wasn't, so just return the data */
|
||||
*ModuleObject = LdrEntry;
|
||||
*ImageBaseAddress = LdrEntry->DllBase;
|
||||
Status = STATUS_IMAGE_ALREADY_LOADED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't support session loading yet */
|
||||
DPRINT1("Unsupported Session-Load!\n");
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
/* Do cleanup */
|
||||
goto Quickie;
|
||||
}
|
||||
else if (!Section)
|
||||
{
|
||||
/* It wasn't loaded, and we didn't have a previous attempt */
|
||||
KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
|
||||
KeLeaveCriticalRegion();
|
||||
LockOwned = FALSE;
|
||||
|
||||
/* Check if KD is enabled */
|
||||
if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
|
||||
{
|
||||
/* FIXME: Attempt to get image from KD */
|
||||
}
|
||||
|
||||
/* We don't have a valid entry */
|
||||
LdrEntry = NULL;
|
||||
|
||||
/* Setup image attributes */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
FileName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Open the image */
|
||||
Status = ZwOpenFile(&FileHandle,
|
||||
FILE_EXECUTE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
|
||||
/* Validate it */
|
||||
Status = MmCheckSystemImage(FileHandle, FALSE);
|
||||
if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
|
||||
(Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
|
||||
(Status == STATUS_INVALID_IMAGE_FORMAT))
|
||||
{
|
||||
/* Fail loading */
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Get image size */
|
||||
Status = ZwQueryInformationFile(FileHandle,
|
||||
&IoStatusBlock,
|
||||
&FileStdInfo,
|
||||
sizeof(FileStdInfo),
|
||||
FileStandardInformation);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
|
||||
/* Allocate memory for image */
|
||||
ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
|
||||
FileStdInfo.EndOfFile.u.LowPart,
|
||||
TAG_DRIVER_MEM);
|
||||
|
||||
/* Read the image */
|
||||
Status = ZwReadFile(FileHandle,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&IoStatusBlock,
|
||||
ModuleLoadBase,
|
||||
FileStdInfo.EndOfFile.u.LowPart,
|
||||
0,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
|
||||
/* Check if this is a session-load */
|
||||
if (Flags)
|
||||
{
|
||||
/* Then we only need read and execute */
|
||||
DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, we can allow write access */
|
||||
DesiredAccess = SECTION_ALL_ACCESS;
|
||||
}
|
||||
|
||||
/* Initialize the attributes for the section */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
NULL,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Create the section */
|
||||
Status = ZwCreateSection(&SectionHandle,
|
||||
DesiredAccess,
|
||||
&ObjectAttributes,
|
||||
NULL,
|
||||
PAGE_EXECUTE,
|
||||
SEC_IMAGE,
|
||||
FileHandle);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
|
||||
/* Now get the section pointer */
|
||||
Status = ObReferenceObjectByHandle(SectionHandle,
|
||||
SECTION_MAP_EXECUTE,
|
||||
MmSectionObjectType,
|
||||
KernelMode,
|
||||
&Section,
|
||||
NULL);
|
||||
ZwClose(SectionHandle);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
|
||||
/* Check if this was supposed to be a session-load */
|
||||
if (Flags)
|
||||
{
|
||||
/* We don't support session loading yet */
|
||||
DPRINT1("Unsupported Session-Load!\n");
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
/* Check the loader list again, we should end up in the path below */
|
||||
goto LoaderScan;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't have a valid entry */
|
||||
LdrEntry = NULL;
|
||||
}
|
||||
|
||||
/* We should have a valid module base */
|
||||
ASSERT(ModuleLoadBase != NULL);
|
||||
|
||||
/* Get header pointers */
|
||||
NtHeader = RtlImageNtHeader(ModuleLoadBase);
|
||||
|
||||
/* Get header pointers */
|
||||
SectionHeaders = IMAGE_FIRST_SECTION(NtHeader);
|
||||
|
||||
/* Determine the size of the module */
|
||||
for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
/* Skip this section if we're not supposed to load it */
|
||||
if (!(SectionHeaders[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
||||
{
|
||||
/* Add the size of this section into the total size */
|
||||
Size = SectionHeaders[i].VirtualAddress +
|
||||
SectionHeaders[i].Misc.VirtualSize;
|
||||
DriverSize = max(DriverSize, Size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Round up the driver size to section alignment */
|
||||
DriverSize = ROUND_UP(DriverSize, NtHeader->OptionalHeader.SectionAlignment);
|
||||
|
||||
/* Allocate a virtual section for the module */
|
||||
DriverBase = MmAllocateSection(DriverSize, NULL);
|
||||
|
||||
/* Copy headers over */
|
||||
RtlCopyMemory(DriverBase,
|
||||
ModuleLoadBase,
|
||||
NtHeader->OptionalHeader.SizeOfHeaders);
|
||||
|
||||
/* Copy image sections into virtual section */
|
||||
for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
/* Get the size of this section and check if it's valid and on-disk */
|
||||
Size = SectionHeaders[i].VirtualAddress +
|
||||
SectionHeaders[i].Misc.VirtualSize;
|
||||
if ((Size <= DriverSize) && (SectionHeaders[i].SizeOfRawData))
|
||||
{
|
||||
/* Copy the data from the disk to the image */
|
||||
RtlCopyMemory((PVOID)((ULONG_PTR)DriverBase +
|
||||
SectionHeaders[i].VirtualAddress),
|
||||
(PVOID)((ULONG_PTR)ModuleLoadBase +
|
||||
SectionHeaders[i].PointerToRawData),
|
||||
SectionHeaders[i].Misc.VirtualSize >
|
||||
SectionHeaders[i].SizeOfRawData ?
|
||||
SectionHeaders[i].SizeOfRawData :
|
||||
SectionHeaders[i].Misc.VirtualSize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Relocate the driver */
|
||||
Status = LdrRelocateImageWithBias(DriverBase,
|
||||
0,
|
||||
"SYSLDR",
|
||||
STATUS_SUCCESS,
|
||||
STATUS_CONFLICTING_ADDRESSES,
|
||||
STATUS_INVALID_IMAGE_FORMAT);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
|
||||
/* Calculate the size we'll need for the entry and allocate it */
|
||||
EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
|
||||
BaseName.Length +
|
||||
sizeof(UNICODE_NULL);
|
||||
|
||||
/* Allocate the entry */
|
||||
LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
|
||||
if (!LdrEntry)
|
||||
{
|
||||
/* Fail */
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Setup the entry */
|
||||
LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
|
||||
LdrEntry->LoadCount = 1;
|
||||
LdrEntry->LoadedImports = LoadedImports;
|
||||
LdrEntry->PatchInformation = NULL;
|
||||
|
||||
/* Check the version */
|
||||
if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
|
||||
(NtHeader->OptionalHeader.MajorImageVersion >= 5))
|
||||
{
|
||||
/* Mark this image as a native image */
|
||||
LdrEntry->Flags |= 0x80000000;
|
||||
}
|
||||
|
||||
/* Setup the rest of the entry */
|
||||
LdrEntry->DllBase = DriverBase;
|
||||
LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)DriverBase +
|
||||
NtHeader->OptionalHeader.AddressOfEntryPoint);
|
||||
LdrEntry->SizeOfImage = DriverSize;
|
||||
LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
|
||||
LdrEntry->SectionPointer = LdrEntry;
|
||||
|
||||
/* Now write the DLL name */
|
||||
LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
|
||||
LdrEntry->BaseDllName.Length = BaseName.Length;
|
||||
LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
|
||||
|
||||
/* Copy and null-terminate it */
|
||||
RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
|
||||
BaseName.Buffer,
|
||||
BaseName.Length);
|
||||
LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;
|
||||
|
||||
/* Now allocate the full name */
|
||||
LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
|
||||
PrefixName.Length +
|
||||
sizeof(UNICODE_NULL),
|
||||
TAG_LDR_WSTR);
|
||||
if (!LdrEntry->FullDllName.Buffer)
|
||||
{
|
||||
/* Don't fail, just set it to zero */
|
||||
LdrEntry->FullDllName.Length = 0;
|
||||
LdrEntry->FullDllName.MaximumLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set it up */
|
||||
LdrEntry->FullDllName.Length = PrefixName.Length;
|
||||
LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
|
||||
|
||||
/* Copy and null-terminate */
|
||||
RtlCopyMemory(LdrEntry->FullDllName.Buffer,
|
||||
PrefixName.Buffer,
|
||||
PrefixName.Length);
|
||||
LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;
|
||||
}
|
||||
|
||||
/* Add the entry */
|
||||
MiProcessLoaderEntry(LdrEntry, TRUE);
|
||||
|
||||
/* Resolve imports */
|
||||
MissingApiName = Buffer;
|
||||
Status = MiResolveImageReferences(DriverBase,
|
||||
&BaseDirectory,
|
||||
NULL,
|
||||
&MissingApiName,
|
||||
&MissingDriverName,
|
||||
&LoadedImports);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Fail */
|
||||
MiProcessLoaderEntry(LdrEntry, FALSE);
|
||||
|
||||
/* Check if we need to free the name */
|
||||
if (LdrEntry->FullDllName.Buffer)
|
||||
{
|
||||
/* Free it */
|
||||
ExFreePool(LdrEntry->FullDllName.Buffer);
|
||||
}
|
||||
|
||||
/* Free the entry itself */
|
||||
ExFreePool(LdrEntry);
|
||||
LdrEntry = NULL;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
if (ModuleObject) *ModuleObject = LdrEntry;
|
||||
if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;
|
||||
|
||||
/* Hook for KDB on loading a driver. */
|
||||
KDB_LOADDRIVER_HOOK(FileName, LdrEntry);
|
||||
|
||||
Quickie:
|
||||
/* If we have a file handle, close it */
|
||||
if (FileHandle) ZwClose(FileHandle);
|
||||
|
||||
/* Cleanup */
|
||||
if (ModuleLoadBase) ExFreePool(ModuleLoadBase);
|
||||
|
||||
/* Check if we have the lock acquired */
|
||||
if (LockOwned)
|
||||
{
|
||||
/* Release the lock */
|
||||
KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
|
||||
KeLeaveCriticalRegion();
|
||||
LockOwned = FALSE;
|
||||
}
|
||||
|
||||
/* Check if we had a prefix */
|
||||
if (NamePrefix) ExFreePool(PrefixName.Buffer);
|
||||
|
||||
/* Free the name buffer and return status */
|
||||
ExFreePool(Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue