From 3111dda7052606cb5c174320453a50b0132cfd12 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Fri, 23 Feb 2007 05:39:42 +0000 Subject: [PATCH] - 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 --- reactos/ntoskrnl/ldr/loader.c | 377 -------------------------- reactos/ntoskrnl/mm/section.c | 2 +- reactos/ntoskrnl/mm/sysldr.c | 484 ++++++++++++++++++++++++++++++++++ 3 files changed, 485 insertions(+), 378 deletions(-) diff --git a/reactos/ntoskrnl/ldr/loader.c b/reactos/ntoskrnl/ldr/loader.c index c1bebb70ba0..3742730673c 100644 --- a/reactos/ntoskrnl/ldr/loader.c +++ b/reactos/ntoskrnl/ldr/loader.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index 1afbbc8e200..821dc058446 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -3292,7 +3292,7 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject, Status = ObReferenceObjectByHandle(FileHandle, FileAccess, IoFileObjectType, - UserMode, + ExGetPreviousMode(), (PVOID*)(PVOID)&FileObject, NULL); diff --git a/reactos/ntoskrnl/mm/sysldr.c b/reactos/ntoskrnl/mm/sysldr.c index a844b85b5be..600f4e53e4d 100644 --- a/reactos/ntoskrnl/mm/sysldr.c +++ b/reactos/ntoskrnl/mm/sysldr.c @@ -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; +} +