-/*\r
-* PROJECT: ReactOS Kernel\r
-* LICENSE: GPL - See COPYING in the top level directory\r
-* FILE: ntoskrnl/mm/sysldr.c\r
-* PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.\r
-* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)\r
-*/\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* GCC's incompetence strikes again */\r
-VOID\r
-sprintf_nt(IN PCHAR Buffer,\r
- IN PCHAR Format,\r
- IN ...)\r
-{\r
- va_list ap;\r
- va_start(ap, Format);\r
- vsprintf(Buffer, Format, ap);\r
- va_end(ap);\r
-}\r
-\r
-/* GLOBALS *******************************************************************/\r
-\r
-LIST_ENTRY PsLoadedModuleList;\r
-KSPIN_LOCK PsLoadedModuleSpinLock;\r
-ULONG PsNtosImageBase;\r
-KMUTANT MmSystemLoadLock;\r
-extern ULONG NtGlobalFlag;\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-PVOID\r
-NTAPI\r
-MiCacheImageSymbols(IN PVOID BaseAddress)\r
-{\r
- ULONG DebugSize;\r
- PVOID DebugDirectory = NULL;\r
- PAGED_CODE();\r
-\r
- /* Make sure it's safe to access the image */\r
- _SEH_TRY\r
- {\r
- /* Get the debug directory */\r
- DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_DEBUG,\r
- &DebugSize);\r
- }\r
- _SEH_HANDLE\r
- {\r
- /* Nothing */\r
- }\r
- _SEH_END;\r
-\r
- /* Return the directory */\r
- return DebugDirectory;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiFreeBootDriverMemory(PVOID BaseAddress,\r
- ULONG Length)\r
-{\r
- ULONG i;\r
-\r
- /* Loop each page */\r
- for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)\r
- {\r
- /* Free the page */\r
- MmDeleteVirtualMapping(NULL,\r
- (PVOID)((ULONG_PTR)BaseAddress + i * PAGE_SIZE),\r
- TRUE,\r
- NULL,\r
- NULL);\r
- }\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiLoadImageSection(IN OUT PVOID *SectionPtr,\r
- OUT PVOID *ImageBase,\r
- IN PUNICODE_STRING FileName,\r
- IN BOOLEAN SessionLoad,\r
- IN PLDR_DATA_TABLE_ENTRY LdrEntry)\r
-{\r
- PROS_SECTION_OBJECT Section = *SectionPtr;\r
- NTSTATUS Status;\r
- PEPROCESS Process;\r
- PVOID Base = NULL;\r
- SIZE_T ViewSize = 0;\r
- KAPC_STATE ApcState;\r
- LARGE_INTEGER SectionOffset = {{0}};\r
- BOOLEAN LoadSymbols = FALSE;\r
- ULONG DriverSize;\r
- PVOID DriverBase;\r
- PAGED_CODE();\r
-\r
- /* Detect session load */\r
- if (SessionLoad)\r
- {\r
- /* Fail */\r
- DPRINT1("Session loading not yet supported!\n");\r
- while (TRUE);\r
- }\r
-\r
- /* Not session load, shouldn't have an entry */\r
- ASSERT(LdrEntry == NULL);\r
-\r
- /* Attach to the system process */\r
- KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);\r
-\r
- /* Check if we need to load symbols */\r
- if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)\r
- {\r
- /* Yes we do */\r
- LoadSymbols = TRUE;\r
- NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;\r
- }\r
-\r
- /* Map the driver */\r
- Process = PsGetCurrentProcess();\r
- Status = MmMapViewOfSection(Section,\r
- Process,\r
- &Base,\r
- 0,\r
- 0,\r
- &SectionOffset,\r
- &ViewSize,\r
- ViewUnmap,\r
- 0,\r
- PAGE_EXECUTE);\r
-\r
- /* Re-enable the flag */\r
- if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;\r
-\r
- /* Check if we failed with distinguished status code */\r
- if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)\r
- {\r
- /* Change it to something more generic */\r
- Status = STATUS_INVALID_IMAGE_FORMAT;\r
- }\r
-\r
- /* Now check if we failed */\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Detach and return */\r
- KeUnstackDetachProcess(&ApcState);\r
- return Status;\r
- }\r
-\r
- /* Get the driver size */\r
- DriverSize = Section->ImageSection->ImageSize;\r
-\r
- /* Allocate a virtual section for the module */\r
- DriverBase = MmAllocateSection(DriverSize, NULL);\r
- *ImageBase = DriverBase;\r
-\r
- /* Copy the image */\r
- RtlCopyMemory(DriverBase, Base, DriverSize);\r
-\r
- /* Now unmap the view */\r
- Status = MmUnmapViewOfSection(Process, Base);\r
- ASSERT(NT_SUCCESS(Status));\r
-\r
- /* Detach and return status */\r
- KeUnstackDetachProcess(&ApcState);\r
- return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiDereferenceImports(IN PLOAD_IMPORTS ImportList)\r
-{\r
- SIZE_T i;\r
-\r
- /* Check if there's no imports or if we're a boot driver */\r
- if ((ImportList == (PVOID)-1) ||\r
- (ImportList == (PVOID)-2) ||\r
- (ImportList->Count == 0))\r
- {\r
- /* Then there's nothing to do */\r
- return STATUS_SUCCESS;\r
- }\r
-\r
- /* Otherwise, FIXME */\r
- DPRINT1("%u imports not dereferenced!\n", ImportList->Count);\r
- for (i = 0; i < ImportList->Count; i++)\r
- {\r
- DPRINT1("%wZ <%wZ>\n", &ImportList->Entry[i]->FullDllName, &ImportList->Entry[i]->BaseDllName);\r
- }\r
- return STATUS_UNSUCCESSFUL;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)\r
-{\r
- PAGED_CODE();\r
-\r
- /* Check if there's no imports or we're a boot driver or only one entry */\r
- if ((LdrEntry->LoadedImports == (PVOID)-1) ||\r
- (LdrEntry->LoadedImports == (PVOID)-2) ||\r
- ((ULONG_PTR)LdrEntry->LoadedImports & 1))\r
- {\r
- /* Nothing to do */\r
- return;\r
- }\r
-\r
- /* Otherwise, free the import list */\r
- ExFreePool(LdrEntry->LoadedImports);\r
-}\r
-\r
-PVOID\r
-NTAPI\r
-MiFindExportedRoutineByName(IN PVOID DllBase,\r
- IN PANSI_STRING ExportName)\r
-{\r
- PULONG NameTable;\r
- PUSHORT OrdinalTable;\r
- PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
- LONG Low = 0, Mid = 0, High, Ret;\r
- USHORT Ordinal;\r
- PVOID Function;\r
- ULONG ExportSize;\r
- PULONG ExportTable;\r
- PAGED_CODE();\r
-\r
- /* Get the export directory */\r
- ExportDirectory = RtlImageDirectoryEntryToData(DllBase,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_EXPORT,\r
- &ExportSize);\r
- if (!ExportDirectory) return NULL;\r
-\r
- /* Setup name tables */\r
- NameTable = (PULONG)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfNames);\r
- OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfNameOrdinals);\r
-\r
- /* Do a binary search */\r
- High = ExportDirectory->NumberOfNames - 1;\r
- while (High >= Low)\r
- {\r
- /* Get new middle value */\r
- Mid = (Low + High) >> 1;\r
-\r
- /* Compare name */\r
- Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);\r
- if (Ret < 0)\r
- {\r
- /* Update high */\r
- High = Mid - 1;\r
- }\r
- else if (Ret > 0)\r
- {\r
- /* Update low */\r
- Low = Mid + 1;\r
- }\r
- else\r
- {\r
- /* We got it */\r
- break;\r
- }\r
- }\r
-\r
- /* Check if we couldn't find it */\r
- if (High < Low) return NULL;\r
-\r
- /* Otherwise, this is the ordinal */\r
- Ordinal = OrdinalTable[Mid];\r
-\r
- /* Resolve the address and write it */\r
- ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfFunctions);\r
- Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);\r
-\r
- /* We found it! */\r
- ASSERT((Function > (PVOID)ExportDirectory) &&\r
- (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));\r
- return Function;\r
-}\r
-\r
-PVOID\r
-NTAPI\r
-MiLocateExportName(IN PVOID DllBase,\r
- IN PCHAR ExportName)\r
-{\r
- PULONG NameTable;\r
- PUSHORT OrdinalTable;\r
- PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
- LONG Low = 0, Mid = 0, High, Ret;\r
- USHORT Ordinal;\r
- PVOID Function;\r
- ULONG ExportSize;\r
- PULONG ExportTable;\r
- PAGED_CODE();\r
-\r
- /* Get the export directory */\r
- ExportDirectory = RtlImageDirectoryEntryToData(DllBase,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_EXPORT,\r
- &ExportSize);\r
- if (!ExportDirectory) return NULL;\r
-\r
- /* Setup name tables */\r
- NameTable = (PULONG)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfNames);\r
- OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfNameOrdinals);\r
-\r
- /* Do a binary search */\r
- High = ExportDirectory->NumberOfNames - 1;\r
- while (High >= Low)\r
- {\r
- /* Get new middle value */\r
- Mid = (Low + High) >> 1;\r
-\r
- /* Compare name */\r
- Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);\r
- if (Ret < 0)\r
- {\r
- /* Update high */\r
- High = Mid - 1;\r
- }\r
- else if (Ret > 0)\r
- {\r
- /* Update low */\r
- Low = Mid + 1;\r
- }\r
- else\r
- {\r
- /* We got it */\r
- break;\r
- }\r
- }\r
-\r
- /* Check if we couldn't find it */\r
- if (High < Low) return NULL;\r
-\r
- /* Otherwise, this is the ordinal */\r
- Ordinal = OrdinalTable[Mid];\r
-\r
- /* Resolve the address and write it */\r
- ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfFunctions);\r
- Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);\r
-\r
- /* Check if the function is actually a forwarder */\r
- if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&\r
- ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))\r
- {\r
- /* It is, fail */\r
- return NULL;\r
- }\r
-\r
- /* We found it */\r
- return Function;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,\r
- IN PLIST_ENTRY ListHead)\r
-{\r
- UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(\r
- L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");\r
- PMM_DLL_INITIALIZE DllInit;\r
- UNICODE_STRING RegPath, ImportName;\r
- NTSTATUS Status;\r
-\r
- /* Try to see if the image exports a DllInitialize routine */\r
- DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,\r
- "DllInitialize");\r
- if (!DllInit) return STATUS_SUCCESS;\r
-\r
- /* Do a temporary copy of BaseDllName called ImportName\r
- * because we'll alter the length of the string\r
- */\r
- ImportName.Length = LdrEntry->BaseDllName.Length;\r
- ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;\r
- ImportName.Buffer = LdrEntry->BaseDllName.Buffer;\r
-\r
- /* Obtain the path to this dll's service in the registry */\r
- RegPath.MaximumLength = ServicesKeyName.Length +\r
- ImportName.Length + sizeof(UNICODE_NULL);\r
- RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,\r
- RegPath.MaximumLength,\r
- TAG_LDR_WSTR);\r
-\r
- /* Check if this allocation was unsuccessful */\r
- if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
- /* Build and append the service name itself */\r
- RegPath.Length = ServicesKeyName.Length;\r
- RtlCopyMemory(RegPath.Buffer,\r
- ServicesKeyName.Buffer,\r
- ServicesKeyName.Length);\r
-\r
- /* Check if there is a dot in the filename */\r
- if (wcschr(ImportName.Buffer, L'.'))\r
- {\r
- /* Remove the extension */\r
- ImportName.Length = (wcschr(ImportName.Buffer, L'.') -\r
- ImportName.Buffer) * sizeof(WCHAR);\r
- }\r
-\r
- /* Append service name (the basename without extension) */\r
- RtlAppendUnicodeStringToString(&RegPath, &ImportName);\r
-\r
- /* Now call the DllInit func */\r
- DPRINT("Calling DllInit(%wZ)\n", &RegPath);\r
- Status = DllInit(&RegPath);\r
-\r
- /* Clean up */\r
- ExFreePool(RegPath.Buffer);\r
-\r
- /* Return status value which DllInitialize returned */\r
- return Status;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,\r
- IN BOOLEAN Insert)\r
-{\r
- KIRQL OldIrql;\r
-\r
- /* Acquire the lock */\r
- KeAcquireSpinLock(&PsLoadedModuleSpinLock, &OldIrql);\r
-\r
- /* Insert or remove from the list */\r
- Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :\r
- RemoveEntryList(&LdrEntry->InLoadOrderLinks);\r
-\r
- /* Release the lock */\r
- KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,\r
- IN PVOID OldBase,\r
- IN PVOID NewBase,\r
- IN ULONG Size)\r
-{\r
- ULONG_PTR OldBaseTop, Delta;\r
- PLDR_DATA_TABLE_ENTRY LdrEntry;\r
- PLIST_ENTRY NextEntry;\r
- ULONG ImportSize;\r
- PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;\r
- PULONG ImageThunk;\r
-\r
- /* Calculate the top and delta */\r
- OldBaseTop = (ULONG_PTR)OldBase + Size - 1;\r
- Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;\r
-\r
- /* Loop the loader block */\r
- for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;\r
- NextEntry != &LoaderBlock->LoadOrderListHead;\r
- NextEntry = NextEntry->Flink)\r
- {\r
- /* Get the loader entry */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
-\r
- /* Get the import table */\r
- ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_IMPORT,\r
- &ImportSize);\r
- if (!ImportDescriptor) continue;\r
-\r
- /* Make sure we have an IAT */\r
- DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);\r
- while ((ImportDescriptor->Name) &&\r
- (ImportDescriptor->OriginalFirstThunk))\r
- {\r
- /* Get the image thunk */\r
- ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +\r
- ImportDescriptor->FirstThunk);\r
- while (*ImageThunk)\r
- {\r
- /* Check if it's within this module */\r
- if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))\r
- {\r
- /* Relocate it */\r
- DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",\r
- ImageThunk, *ImageThunk, *ImageThunk + Delta);\r
- *ImageThunk += Delta;\r
- }\r
-\r
- /* Go to the next thunk */\r
- ImageThunk++;\r
- }\r
-\r
- /* Go to the next import */\r
- ImportDescriptor++;\r
- }\r
- }\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiSnapThunk(IN PVOID DllBase,\r
- IN PVOID ImageBase,\r
- IN PIMAGE_THUNK_DATA Name,\r
- IN PIMAGE_THUNK_DATA Address,\r
- IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,\r
- IN ULONG ExportSize,\r
- IN BOOLEAN SnapForwarder,\r
- OUT PCHAR *MissingApi)\r
-{\r
- BOOLEAN IsOrdinal;\r
- USHORT Ordinal;\r
- PULONG NameTable;\r
- PUSHORT OrdinalTable;\r
- PIMAGE_IMPORT_BY_NAME NameImport;\r
- USHORT Hint;\r
- ULONG Low = 0, Mid = 0, High;\r
- LONG Ret;\r
- NTSTATUS Status;\r
- PCHAR MissingForwarder;\r
- CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];\r
- PULONG ExportTable;\r
- ANSI_STRING DllName;\r
- UNICODE_STRING ForwarderName;\r
- PLIST_ENTRY NextEntry;\r
- PLDR_DATA_TABLE_ENTRY LdrEntry;\r
- ULONG ForwardExportSize;\r
- PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;\r
- PIMAGE_IMPORT_BY_NAME ForwardName;\r
- ULONG ForwardLength;\r
- IMAGE_THUNK_DATA ForwardThunk;\r
- PAGED_CODE();\r
-\r
- /* Check if this is an ordinal */\r
- IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);\r
- if ((IsOrdinal) && !(SnapForwarder))\r
- {\r
- /* Get the ordinal number and set it as missing */\r
- Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -\r
- ExportDirectory->Base);\r
- *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;\r
- }\r
- else\r
- {\r
- /* Get the VA if we don't have to snap */\r
- if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;\r
- NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;\r
-\r
- /* Copy the procedure name */\r
- strncpy(*MissingApi,\r
- (PCHAR)&NameImport->Name[0],\r
- MAXIMUM_FILENAME_LENGTH - 1);\r
-\r
- /* Setup name tables */\r
- DPRINT("Import name: %s\n", NameImport->Name);\r
- NameTable = (PULONG)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfNames);\r
- OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfNameOrdinals);\r
-\r
- /* Get the hint and check if it's valid */\r
- Hint = NameImport->Hint;\r
- if ((Hint < ExportDirectory->NumberOfNames) &&\r
- !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))\r
- {\r
- /* We have a match, get the ordinal number from here */\r
- Ordinal = OrdinalTable[Hint];\r
- }\r
- else\r
- {\r
- /* Do a binary search */\r
- High = ExportDirectory->NumberOfNames - 1;\r
- while (High >= Low)\r
- {\r
- /* Get new middle value */\r
- Mid = (Low + High) >> 1;\r
-\r
- /* Compare name */\r
- Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);\r
- if (Ret < 0)\r
- {\r
- /* Update high */\r
- High = Mid - 1;\r
- }\r
- else if (Ret > 0)\r
- {\r
- /* Update low */\r
- Low = Mid + 1;\r
- }\r
- else\r
- {\r
- /* We got it */\r
- break;\r
- }\r
- }\r
-\r
- /* Check if we couldn't find it */\r
- if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
-\r
- /* Otherwise, this is the ordinal */\r
- Ordinal = OrdinalTable[Mid];\r
- }\r
- }\r
-\r
- /* Check if the ordinal is invalid */\r
- if (Ordinal >= ExportDirectory->NumberOfFunctions)\r
- {\r
- /* Fail */\r
- Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;\r
- }\r
- else\r
- {\r
- /* In case the forwarder is missing */\r
- MissingForwarder = NameBuffer;\r
-\r
- /* Resolve the address and write it */\r
- ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
- ExportDirectory->AddressOfFunctions);\r
- Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];\r
-\r
- /* Assume success from now on */\r
- Status = STATUS_SUCCESS;\r
-\r
- /* Check if the function is actually a forwarder */\r
- if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&\r
- (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))\r
- {\r
- /* Now assume failure in case the forwarder doesn't exist */\r
- Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
-\r
- /* Build the forwarder name */\r
- DllName.Buffer = (PCHAR)Address->u1.Function;\r
- DllName.Length = strchr(DllName.Buffer, '.') -\r
- DllName.Buffer +\r
- sizeof(ANSI_NULL);\r
- DllName.MaximumLength = DllName.Length;\r
-\r
- /* Convert it */\r
- if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,\r
- &DllName,\r
- TRUE)))\r
- {\r
- /* We failed, just return an error */\r
- return Status;\r
- }\r
-\r
- /* Loop the module list */\r
- NextEntry = PsLoadedModuleList.Flink;\r
- while (NextEntry != &PsLoadedModuleList)\r
- {\r
- /* Get the loader entry */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
-\r
- /* Check if it matches */\r
- if (RtlPrefixString((PSTRING)&ForwarderName,\r
- (PSTRING)&LdrEntry->BaseDllName,\r
- TRUE))\r
- {\r
- /* Get the forwarder export directory */\r
- ForwardExportDirectory =\r
- RtlImageDirectoryEntryToData(LdrEntry->DllBase,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_EXPORT,\r
- &ForwardExportSize);\r
- if (!ForwardExportDirectory) break;\r
-\r
- /* Allocate a name entry */\r
- ForwardLength = strlen(DllName.Buffer + DllName.Length) +\r
- sizeof(ANSI_NULL);\r
- ForwardName = ExAllocatePoolWithTag(PagedPool,\r
- sizeof(*ForwardName) +\r
- ForwardLength,\r
- TAG_LDR_WSTR);\r
- if (!ForwardName) break;\r
-\r
- /* Copy the data */\r
- RtlCopyMemory(&ForwardName->Name[0],\r
- DllName.Buffer + DllName.Length,\r
- ForwardLength);\r
- ForwardName->Hint = 0;\r
-\r
- /* Set the new address */\r
- *(PULONG)&ForwardThunk.u1.AddressOfData = (ULONG)ForwardName;\r
-\r
- /* Snap the forwarder */\r
- Status = MiSnapThunk(LdrEntry->DllBase,\r
- ImageBase,\r
- &ForwardThunk,\r
- &ForwardThunk,\r
- ForwardExportDirectory,\r
- ForwardExportSize,\r
- TRUE,\r
- &MissingForwarder);\r
-\r
- /* Free the forwarder name and set the thunk */\r
- ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);\r
- Address->u1 = ForwardThunk.u1;\r
- break;\r
- }\r
-\r
- /* Go to the next entry */\r
- NextEntry = NextEntry->Flink;\r
- }\r
-\r
- /* Free the name */\r
- RtlFreeUnicodeString(&ForwarderName);\r
- }\r
- }\r
-\r
- /* Return status */\r
- return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmUnloadSystemImage(IN PVOID ImageHandle)\r
-{\r
- PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;\r
- PVOID BaseAddress = LdrEntry->DllBase;\r
- NTSTATUS Status;\r
- ANSI_STRING TempName;\r
- BOOLEAN HadEntry = FALSE;\r
-\r
- /* Acquire the loader lock */\r
- KeEnterCriticalRegion();\r
- KeWaitForSingleObject(&MmSystemLoadLock,\r
- WrVirtualMemory,\r
- KernelMode,\r
- FALSE,\r
- NULL);\r
-\r
- /* Check if this driver was loaded at boot and didn't get imports parsed */\r
- if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;\r
-\r
- /* We should still be alive */\r
- ASSERT(LdrEntry->LoadCount != 0);\r
- LdrEntry->LoadCount--;\r
-\r
- /* Check if we're still loaded */\r
- if (LdrEntry->LoadCount) goto Done;\r
-\r
- /* We should cleanup... are symbols loaded */\r
- if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)\r
- {\r
- /* Create the ANSI name */\r
- Status = RtlUnicodeStringToAnsiString(&TempName,\r
- &LdrEntry->BaseDllName,\r
- TRUE);\r
- if (NT_SUCCESS(Status))\r
- {\r
- /* Unload the symbols */\r
- DbgUnLoadImageSymbols(&TempName, BaseAddress, -1);\r
- RtlFreeAnsiString(&TempName);\r
- }\r
- }\r
-\r
- /* FIXME: Free the driver */\r
- //MmFreeSection(LdrEntry->DllBase);\r
-\r
- /* Check if we're linked in */\r
- if (LdrEntry->InLoadOrderLinks.Flink)\r
- {\r
- /* Remove us */\r
- MiProcessLoaderEntry(LdrEntry, FALSE);\r
- HadEntry = TRUE;\r
- }\r
-\r
- /* Dereference and clear the imports */\r
- MiDereferenceImports(LdrEntry->LoadedImports);\r
- MiClearImports(LdrEntry);\r
-\r
- /* Check if the entry needs to go away */\r
- if (HadEntry)\r
- {\r
- /* Check if it had a name */\r
- if (LdrEntry->FullDllName.Buffer)\r
- {\r
- /* Free it */\r
- ExFreePool(LdrEntry->FullDllName.Buffer);\r
- }\r
-\r
- /* Check if we had a section */\r
- if (LdrEntry->SectionPointer)\r
- {\r
- /* Dereference it */\r
- ObDereferenceObject(LdrEntry->SectionPointer);\r
- }\r
-\r
- /* Free the entry */\r
- ExFreePool(LdrEntry);\r
- }\r
-\r
- /* Release the system lock and return */\r
-Done:\r
- KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
- KeLeaveCriticalRegion();\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiResolveImageReferences(IN PVOID ImageBase,\r
- IN PUNICODE_STRING ImageFileDirectory,\r
- IN PUNICODE_STRING NamePrefix OPTIONAL,\r
- OUT PCHAR *MissingApi,\r
- OUT PWCHAR *MissingDriver,\r
- OUT PLOAD_IMPORTS *LoadImports)\r
-{\r
- PCHAR MissingApiBuffer = *MissingApi, ImportName;\r
- PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;\r
- ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;\r
- PLOAD_IMPORTS LoadedImports, NewImports;\r
- ULONG GdiLink, NormalLink, i;\r
- BOOLEAN ReferenceNeeded, Loaded;\r
- ANSI_STRING TempString;\r
- UNICODE_STRING NameString, DllName;\r
- PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;\r
- PVOID ImportBase, DllBase;\r
- PLIST_ENTRY NextEntry;\r
- PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
- NTSTATUS Status;\r
- PIMAGE_THUNK_DATA OrigThunk, FirstThunk;\r
- PAGED_CODE();\r
- DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",\r
- __FUNCTION__, ImageBase, ImageFileDirectory);\r
-\r
- /* Assume no imports */\r
- *LoadImports = (PVOID)-2;\r
-\r
- /* Get the import descriptor */\r
- ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_IMPORT,\r
- &ImportSize);\r
- if (!ImportDescriptor) return STATUS_SUCCESS;\r
-\r
- /* Loop all imports to count them */\r
- for (CurrentImport = ImportDescriptor;\r
- (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);\r
- CurrentImport++)\r
- {\r
- /* One more */\r
- ImportCount++;\r
- }\r
-\r
- /* Make sure we have non-zero imports */\r
- if (ImportCount)\r
- {\r
- /* Calculate and allocate the list we'll need */\r
- LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);\r
- LoadedImports = ExAllocatePoolWithTag(PagedPool,\r
- LoadedImportsSize,\r
- TAG_LDR_WSTR);\r
- if (LoadedImports)\r
- {\r
- /* Zero it */\r
- RtlZeroMemory(LoadedImports, LoadedImportsSize);\r
- }\r
- }\r
- else\r
- {\r
- /* No table */\r
- LoadedImports = NULL;\r
- }\r
-\r
- /* Reset the import count and loop descriptors again */\r
- ImportCount = GdiLink = NormalLink = 0;\r
- while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))\r
- {\r
- /* Get the name */\r
- ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);\r
-\r
- /* Check if this is a GDI driver */\r
- GdiLink = GdiLink |\r
- !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));\r
-\r
- /* We can also allow dxapi */\r
- NormalLink = NormalLink |\r
- ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&\r
- (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));\r
-\r
- /* Check if this is a valid GDI driver */\r
- if ((GdiLink) && (NormalLink))\r
- {\r
- /* It's not, it's importing stuff it shouldn't be! */\r
- MiDereferenceImports(LoadedImports);\r
- if (LoadedImports) ExFreePool(LoadedImports);\r
- return STATUS_PROCEDURE_NOT_FOUND;\r
- }\r
-\r
- /* Check if this is a "core" import, which doesn't get referenced */\r
- if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||\r
- !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||\r
- !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))\r
- {\r
- /* Don't reference this */\r
- ReferenceNeeded = FALSE;\r
- }\r
- else\r
- {\r
- /* Reference these modules */\r
- ReferenceNeeded = TRUE;\r
- }\r
-\r
- /* Now setup a unicode string for the import */\r
- RtlInitAnsiString(&TempString, ImportName);\r
- Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Failed */\r
- MiDereferenceImports(LoadedImports);\r
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- return Status;\r
- }\r
-\r
- /* We don't support name prefixes yet */\r
- if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");\r
-\r
- /* Remember that we haven't loaded the import at this point */\r
-CheckDllState:\r
- Loaded = FALSE;\r
- ImportBase = NULL;\r
-\r
- /* Loop the driver list */\r
- NextEntry = PsLoadedModuleList.Flink;\r
- while (NextEntry != &PsLoadedModuleList)\r
- {\r
- /* Get the loader entry and compare the name */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
- if (RtlEqualUnicodeString(&NameString,\r
- &LdrEntry->BaseDllName,\r
- TRUE))\r
- {\r
- /* Get the base address */\r
- ImportBase = LdrEntry->DllBase;\r
-\r
- /* Check if we haven't loaded yet, and we need references */\r
- if (!(Loaded) && (ReferenceNeeded))\r
- {\r
- /* Make sure we're not already loading */\r
- if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))\r
- {\r
- /* Increase the load count */\r
- LdrEntry->LoadCount++;\r
- }\r
- }\r
-\r
- /* Done, break out */\r
- break;\r
- }\r
-\r
- /* Go to the next entry */\r
- NextEntry = NextEntry->Flink;\r
- }\r
-\r
- /* Check if we haven't loaded the import yet */\r
- if (!ImportBase)\r
- {\r
- /* Setup the import DLL name */\r
- DllName.MaximumLength = NameString.Length +\r
- ImageFileDirectory->Length +\r
- sizeof(UNICODE_NULL);\r
- DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,\r
- DllName.MaximumLength,\r
- TAG_LDR_WSTR);\r
- if (DllName.Buffer)\r
- {\r
- /* Setup the base length and copy it */\r
- DllName.Length = ImageFileDirectory->Length;\r
- RtlCopyMemory(DllName.Buffer,\r
- ImageFileDirectory->Buffer,\r
- ImageFileDirectory->Length);\r
-\r
- /* Now add the import name and null-terminate it */\r
- RtlAppendStringToString((PSTRING)&DllName,\r
- (PSTRING)&NameString);\r
- DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;\r
-\r
- /* Load the image */\r
- Status = MmLoadSystemImage(&DllName,\r
- NamePrefix,\r
- NULL,\r
- 0,\r
- (PVOID)&DllEntry,\r
- &DllBase);\r
- if (NT_SUCCESS(Status))\r
- {\r
- /* We can free the DLL Name */\r
- ExFreePool(DllName.Buffer);\r
- }\r
- else\r
- {\r
- /* Fill out the information for the error */\r
- *MissingDriver = DllName.Buffer;\r
- *(PULONG)MissingDriver |= 1;\r
- *MissingApi = NULL;\r
- }\r
- }\r
- else\r
- {\r
- /* We're out of resources */\r
- Status = STATUS_INSUFFICIENT_RESOURCES;\r
- }\r
-\r
- /* Check if we're OK until now */\r
- if (NT_SUCCESS(Status))\r
- {\r
- /* We're now loaded */\r
- Loaded = TRUE;\r
-\r
- /* Sanity check */\r
- ASSERT(DllBase = DllEntry->DllBase);\r
-\r
- /* Call the initialization routines */\r
- Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* We failed, unload the image */\r
- MmUnloadSystemImage(DllEntry);\r
- while (TRUE);\r
- Loaded = FALSE;\r
- }\r
- }\r
-\r
- /* Check if we failed by here */\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Cleanup and return */\r
- RtlFreeUnicodeString(&NameString);\r
- MiDereferenceImports(LoadedImports);\r
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- return Status;\r
- }\r
-\r
- /* Loop again to make sure that everything is OK */\r
- goto CheckDllState;\r
- }\r
-\r
- /* Check if we're support to reference this import */\r
- if ((ReferenceNeeded) && (LoadedImports))\r
- {\r
- /* Make sure we're not already loading */\r
- if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))\r
- {\r
- /* Add the entry */\r
- LoadedImports->Entry[LoadedImports->Count] = LdrEntry;\r
- LoadedImports->Count++;\r
- }\r
- }\r
-\r
- /* Free the import name */\r
- RtlFreeUnicodeString(&NameString);\r
-\r
- /* Set the missing driver name and get the export directory */\r
- *MissingDriver = LdrEntry->BaseDllName.Buffer;\r
- ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_EXPORT,\r
- &ExportSize);\r
- if (!ExportDirectory)\r
- {\r
- /* Cleanup and return */\r
- MiDereferenceImports(LoadedImports);\r
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
- }\r
-\r
- /* Make sure we have an IAT */\r
- if (ImportDescriptor->OriginalFirstThunk)\r
- {\r
- /* Get the first thunks */\r
- OrigThunk = (PVOID)((ULONG_PTR)ImageBase +\r
- ImportDescriptor->OriginalFirstThunk);\r
- FirstThunk = (PVOID)((ULONG_PTR)ImageBase +\r
- ImportDescriptor->FirstThunk);\r
-\r
- /* Loop the IAT */\r
- while (OrigThunk->u1.AddressOfData)\r
- {\r
- /* Snap thunk */\r
- Status = MiSnapThunk(ImportBase,\r
- ImageBase,\r
- OrigThunk++,\r
- FirstThunk++,\r
- ExportDirectory,\r
- ExportSize,\r
- FALSE,\r
- MissingApi);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Cleanup and return */\r
- MiDereferenceImports(LoadedImports);\r
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- return Status;\r
- }\r
-\r
- /* Reset the buffer */\r
- *MissingApi = MissingApiBuffer;\r
- }\r
- }\r
-\r
- /* Go to the next import */\r
- ImportDescriptor++;\r
- }\r
-\r
- /* Check if we have an import list */\r
- if (LoadedImports)\r
- {\r
- /* Reset the count again, and loop entries*/\r
- ImportCount = 0;\r
- for (i = 0; i < LoadedImports->Count; i++)\r
- {\r
- if (LoadedImports->Entry[i])\r
- {\r
- /* Got an entry, OR it with 1 in case it's the single entry */\r
- ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);\r
- ImportCount++;\r
- }\r
- }\r
-\r
- /* Check if we had no imports */\r
- if (!ImportCount)\r
- {\r
- /* Free the list and set it to no imports */\r
- ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- LoadedImports = (PVOID)-2;\r
- }\r
- else if (ImportCount == 1)\r
- {\r
- /* Just one entry, we can free the table and only use our entry */\r
- ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- LoadedImports = (PLOAD_IMPORTS)ImportEntry;\r
- }\r
- else if (ImportCount != LoadedImports->Count)\r
- {\r
- /* Allocate a new list */\r
- LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);\r
- NewImports = ExAllocatePoolWithTag(PagedPool,\r
- LoadedImportsSize,\r
- TAG_LDR_WSTR);\r
- if (NewImports)\r
- {\r
- /* Set count */\r
- NewImports->Count = 0;\r
-\r
- /* Loop all the imports */\r
- for (i = 0; i < LoadedImports->Count; i++)\r
- {\r
- /* Make sure it's valid */\r
- if (LoadedImports->Entry[i])\r
- {\r
- /* Copy it */\r
- NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];\r
- NewImports->Count++;\r
- }\r
- }\r
-\r
- /* Free the old copy */\r
- ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
- LoadedImports = NewImports;\r
- }\r
- }\r
-\r
- /* Return the list */\r
- *LoadImports = LoadedImports;\r
- }\r
-\r
- /* Return success */\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
- PLIST_ENTRY NextEntry;\r
- ULONG i = 0;\r
- PIMAGE_NT_HEADERS NtHeader;\r
- PLDR_DATA_TABLE_ENTRY LdrEntry;\r
- PIMAGE_FILE_HEADER FileHeader;\r
- BOOLEAN ValidRelocs;\r
- PIMAGE_DATA_DIRECTORY DataDirectory;\r
- PVOID DllBase, NewImageAddress;\r
- NTSTATUS Status;\r
-\r
- /* Loop driver list */\r
- for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;\r
- NextEntry != &LoaderBlock->LoadOrderListHead;\r
- NextEntry = NextEntry->Flink)\r
- {\r
- /* Get the loader entry and NT header */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
- NtHeader = RtlImageNtHeader(LdrEntry->DllBase);\r
-\r
- /* Debug info */\r
- DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",\r
- LdrEntry->DllBase,\r
- (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,\r
- &LdrEntry->FullDllName);\r
-\r
- /* Skip kernel and HAL */\r
- /* ROS HACK: Skip BOOTVID/KDCOM too */\r
- i++;\r
- if (i <= 4) continue;\r
-\r
- /* Skip non-drivers */\r
- if (!NtHeader) continue;\r
-\r
- /* Get the file header and make sure we can relocate */\r
- FileHeader = &NtHeader->FileHeader;\r
- if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;\r
- if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <\r
- IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;\r
-\r
- /* Everything made sense until now, check the relocation section too */\r
- DataDirectory = &NtHeader->OptionalHeader.\r
- DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
- if (!DataDirectory->VirtualAddress)\r
- {\r
- /* We don't really have relocations */\r
- ValidRelocs = FALSE;\r
- }\r
- else\r
- {\r
- /* Make sure the size is valid */\r
- if ((DataDirectory->VirtualAddress + DataDirectory->Size) >\r
- LdrEntry->SizeOfImage)\r
- {\r
- /* They're not, skip */\r
- continue;\r
- }\r
-\r
- /* We have relocations */\r
- ValidRelocs = TRUE;\r
- }\r
-\r
- /* Remember the original address */\r
- DllBase = LdrEntry->DllBase;\r
-\r
- /* Allocate a virtual section for the module */\r
- NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);\r
- if (!NewImageAddress)\r
- {\r
- /* Shouldn't happen */\r
- DPRINT1("[Mm0]: Couldn't allocate driver section!\n");\r
- while (TRUE);\r
- }\r
-\r
- /* Sanity check */\r
- DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);\r
- ASSERT(ExpInitializationPhase == 0);\r
-\r
- /* Now copy the entire driver over */\r
- RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);\r
-\r
- /* Sanity check */\r
- ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);\r
-\r
- /* Set the image base to the address where the loader put it */\r
- NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;\r
- NtHeader = RtlImageNtHeader(NewImageAddress);\r
- NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;\r
-\r
- /* Check if we had relocations */\r
- if (ValidRelocs)\r
- {\r
- /* Relocate the image */\r
- Status = LdrRelocateImageWithBias(NewImageAddress,\r
- 0,\r
- "SYSLDR",\r
- STATUS_SUCCESS,\r
- STATUS_CONFLICTING_ADDRESSES,\r
- STATUS_INVALID_IMAGE_FORMAT);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* This shouldn't happen */\r
- DPRINT1("Relocations failed!\n");\r
- while (TRUE);\r
- }\r
- }\r
-\r
- /* Update the loader entry */\r
- LdrEntry->DllBase = NewImageAddress;\r
-\r
- /* Update the thunks */\r
- DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);\r
- MiUpdateThunks(LoaderBlock,\r
- DllBase,\r
- NewImageAddress,\r
- LdrEntry->SizeOfImage);\r
-\r
- /* Update the loader entry */\r
- LdrEntry->Flags |= 0x01000000;\r
- LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +\r
- NtHeader->OptionalHeader.AddressOfEntryPoint);\r
- LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;\r
-\r
- /* Free the old copy */\r
- MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);\r
- }\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
- PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;\r
- PLIST_ENTRY ListHead, NextEntry;\r
- ULONG EntrySize;\r
-\r
- /* Setup the loaded module list and lock */\r
- KeInitializeSpinLock(&PsLoadedModuleSpinLock);\r
- InitializeListHead(&PsLoadedModuleList);\r
-\r
- /* Get loop variables and the kernel entry */\r
- ListHead = &LoaderBlock->LoadOrderListHead;\r
- NextEntry = ListHead->Flink;\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
- PsNtosImageBase = (ULONG)LdrEntry->DllBase;\r
-\r
- /* Loop the loader block */\r
- while (NextEntry != ListHead)\r
- {\r
- /* Get the loader entry */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
-\r
- /* FIXME: ROS HACK. Make sure this is a driver */\r
- if (!RtlImageNtHeader(LdrEntry->DllBase))\r
- {\r
- /* Skip this entry */\r
- NextEntry= NextEntry->Flink;\r
- continue;\r
- }\r
-\r
- /* Calculate the size we'll need and allocate a copy */\r
- EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +\r
- LdrEntry->BaseDllName.MaximumLength +\r
- sizeof(UNICODE_NULL);\r
- NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);\r
- if (!NewEntry) return FALSE;\r
-\r
- /* Copy the entry over */\r
- *NewEntry = *LdrEntry;\r
-\r
- /* Allocate the name */\r
- NewEntry->FullDllName.Buffer =\r
- ExAllocatePoolWithTag(PagedPool,\r
- LdrEntry->FullDllName.MaximumLength +\r
- sizeof(UNICODE_NULL),\r
- TAG_LDR_WSTR);\r
- if (!NewEntry->FullDllName.Buffer) return FALSE;\r
-\r
- /* Set the base name */\r
- NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);\r
-\r
- /* Copy the full and base name */\r
- RtlCopyMemory(NewEntry->FullDllName.Buffer,\r
- LdrEntry->FullDllName.Buffer,\r
- LdrEntry->FullDllName.MaximumLength);\r
- RtlCopyMemory(NewEntry->BaseDllName.Buffer,\r
- LdrEntry->BaseDllName.Buffer,\r
- LdrEntry->BaseDllName.MaximumLength);\r
-\r
- /* Null-terminate the base name */\r
- NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /\r
- sizeof(WCHAR)] = UNICODE_NULL;\r
-\r
- /* Insert the entry into the list */\r
- InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);\r
- NextEntry = NextEntry->Flink;\r
- }\r
-\r
- /* Build the import lists for the boot drivers */\r
- //MiBuildImportsForBootDrivers();\r
-\r
- /* We're done */\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)\r
-{\r
- PIMAGE_NT_HEADERS NtHeader;\r
- PAGED_CODE();\r
-\r
- /* Get NT Headers */\r
- NtHeader = RtlImageNtHeader(BaseAddress);\r
- if (NtHeader)\r
- {\r
- /* Check if this image is only safe for UP while we have 2+ CPUs */\r
- if ((KeNumberProcessors > 1) &&\r
- (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))\r
- {\r
- /* Fail */\r
- return FALSE;\r
- }\r
- }\r
-\r
- /* Otherwise, it's safe */\r
- return TRUE;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmCheckSystemImage(IN HANDLE ImageHandle,\r
- IN BOOLEAN PurgeSection)\r
-{\r
- NTSTATUS Status;\r
- HANDLE SectionHandle;\r
- PVOID ViewBase = NULL;\r
- SIZE_T ViewSize = 0;\r
- IO_STATUS_BLOCK IoStatusBlock;\r
- FILE_STANDARD_INFORMATION FileStandardInfo;\r
- KAPC_STATE ApcState;\r
- PAGED_CODE();\r
-\r
- /* Create a section for the DLL */\r
- Status = ZwCreateSection(&SectionHandle,\r
- SECTION_MAP_EXECUTE,\r
- NULL,\r
- NULL,\r
- PAGE_EXECUTE,\r
- SEC_COMMIT,\r
- ImageHandle);\r
- if (!NT_SUCCESS(Status)) return Status;\r
-\r
- /* Make sure we're in the system process */\r
- KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);\r
-\r
- /* Map it */\r
- Status = ZwMapViewOfSection(SectionHandle,\r
- NtCurrentProcess(),\r
- &ViewBase,\r
- 0,\r
- 0,\r
- NULL,\r
- &ViewSize,\r
- ViewShare,\r
- 0,\r
- PAGE_EXECUTE);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* We failed, close the handle and return */\r
- KeUnstackDetachProcess(&ApcState);\r
- ZwClose(SectionHandle);\r
- return Status;\r
- }\r
-\r
- /* Now query image information */\r
- Status = ZwQueryInformationFile(ImageHandle,\r
- &IoStatusBlock,\r
- &FileStandardInfo,\r
- sizeof(FileStandardInfo),\r
- FileStandardInformation);\r
- if ( NT_SUCCESS(Status) )\r
- {\r
- /* First, verify the checksum */\r
- if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,\r
- FileStandardInfo.\r
- EndOfFile.LowPart,\r
- FileStandardInfo.\r
- EndOfFile.LowPart))\r
- {\r
- /* Set checksum failure */\r
- Status = STATUS_IMAGE_CHECKSUM_MISMATCH;\r
- }\r
-\r
- /* Check that it's a valid SMP image if we have more then one CPU */\r
- if (!MmVerifyImageIsOkForMpUse(ViewBase))\r
- {\r
- /* Otherwise it's not the right image */\r
- Status = STATUS_IMAGE_MP_UP_MISMATCH;\r
- }\r
- }\r
-\r
- /* Unmap the section, close the handle, and return status */\r
- ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);\r
- KeUnstackDetachProcess(&ApcState);\r
- ZwClose(SectionHandle);\r
- return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmLoadSystemImage(IN PUNICODE_STRING FileName,\r
- IN PUNICODE_STRING NamePrefix OPTIONAL,\r
- IN PUNICODE_STRING LoadedName OPTIONAL,\r
- IN ULONG Flags,\r
- OUT PVOID *ModuleObject,\r
- OUT PVOID *ImageBaseAddress)\r
-{\r
- PVOID ModuleLoadBase = NULL;\r
- NTSTATUS Status;\r
- HANDLE FileHandle = NULL;\r
- OBJECT_ATTRIBUTES ObjectAttributes;\r
- IO_STATUS_BLOCK IoStatusBlock;\r
- PIMAGE_NT_HEADERS NtHeader;\r
- UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;\r
- PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;\r
- ULONG EntrySize, DriverSize;\r
- PLOAD_IMPORTS LoadedImports = (PVOID)-2;\r
- PCHAR MissingApiName, Buffer;\r
- PWCHAR MissingDriverName;\r
- HANDLE SectionHandle;\r
- ACCESS_MASK DesiredAccess;\r
- PVOID Section = NULL;\r
- BOOLEAN LockOwned = FALSE;\r
- PLIST_ENTRY NextEntry;\r
- IMAGE_INFO ImageInfo;\r
- ANSI_STRING AnsiTemp;\r
- PAGED_CODE();\r
-\r
- /* Detect session-load */\r
- if (Flags)\r
- {\r
- /* Sanity checks */\r
- ASSERT(NamePrefix == NULL);\r
- ASSERT(LoadedName == NULL);\r
-\r
- /* Make sure the process is in session too */\r
- if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;\r
- }\r
-\r
- if (ModuleObject) *ModuleObject = NULL;\r
- if (ImageBaseAddress) *ImageBaseAddress = NULL;\r
-\r
- /* Allocate a buffer we'll use for names */\r
- Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);\r
- if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
- /* Check for a separator */\r
- if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)\r
- {\r
- PWCHAR p;\r
- ULONG BaseLength;\r
-\r
- /* Loop the path until we get to the base name */\r
- p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];\r
- while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;\r
-\r
- /* Get the length */\r
- BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);\r
- BaseLength *= sizeof(WCHAR);\r
-\r
- /* Setup the string */\r
- BaseName.Length = (USHORT)BaseLength;\r
- BaseName.Buffer = p;\r
- }\r
- else\r
- {\r
- /* Otherwise, we already have a base name */\r
- BaseName.Length = FileName->Length;\r
- BaseName.Buffer = FileName->Buffer;\r
- }\r
-\r
- /* Setup the maximum length */\r
- BaseName.MaximumLength = BaseName.Length;\r
-\r
- /* Now compute the base directory */\r
- BaseDirectory = *FileName;\r
- BaseDirectory.Length -= BaseName.Length;\r
- BaseDirectory.MaximumLength = BaseDirectory.Length;\r
-\r
- /* And the prefix, which for now is just the name itself */\r
- PrefixName = *FileName;\r
-\r
- /* Check if we have a prefix */\r
- if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");\r
-\r
- /* Check if we already have a name, use it instead */\r
- if (LoadedName) BaseName = *LoadedName;\r
-\r
- /* Acquire the load lock */\r
-LoaderScan:\r
- ASSERT(LockOwned == FALSE);\r
- LockOwned = TRUE;\r
- KeEnterCriticalRegion();\r
- KeWaitForSingleObject(&MmSystemLoadLock,\r
- WrVirtualMemory,\r
- KernelMode,\r
- FALSE,\r
- NULL);\r
-\r
- /* Scan the module list */\r
- NextEntry = PsLoadedModuleList.Flink;\r
- while (NextEntry != &PsLoadedModuleList)\r
- {\r
- /* Get the entry and compare the names */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
- if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))\r
- {\r
- /* Found it, break out */\r
- break;\r
- }\r
-\r
- /* Keep scanning */\r
- NextEntry = NextEntry->Flink;\r
- }\r
-\r
- /* Check if we found the image */\r
- if (NextEntry != &PsLoadedModuleList)\r
- {\r
- /* Check if we had already mapped a section */\r
- if (Section)\r
- {\r
- /* Dereference and clear */\r
- ObDereferenceObject(Section);\r
- Section = NULL;\r
- }\r
-\r
- /* Check if this was supposed to be a session load */\r
- if (!Flags)\r
- {\r
- /* It wasn't, so just return the data */\r
- if (ModuleObject) *ModuleObject = LdrEntry;\r
- if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
- Status = STATUS_IMAGE_ALREADY_LOADED;\r
- }\r
- else\r
- {\r
- /* We don't support session loading yet */\r
- DPRINT1("Unsupported Session-Load!\n");\r
- while (TRUE);\r
- }\r
-\r
- /* Do cleanup */\r
- goto Quickie;\r
- }\r
- else if (!Section)\r
- {\r
- /* It wasn't loaded, and we didn't have a previous attempt */\r
- KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
- KeLeaveCriticalRegion();\r
- LockOwned = FALSE;\r
-\r
- /* Check if KD is enabled */\r
- if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))\r
- {\r
- /* FIXME: Attempt to get image from KD */\r
- }\r
-\r
- /* We don't have a valid entry */\r
- LdrEntry = NULL;\r
-\r
- /* Setup image attributes */\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- FileName,\r
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r
- NULL,\r
- NULL);\r
-\r
- /* Open the image */\r
- Status = ZwOpenFile(&FileHandle,\r
- FILE_EXECUTE,\r
- &ObjectAttributes,\r
- &IoStatusBlock,\r
- FILE_SHARE_READ | FILE_SHARE_DELETE,\r
- 0);\r
- if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
- /* Validate it */\r
- Status = MmCheckSystemImage(FileHandle, FALSE);\r
- if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||\r
- (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||\r
- (Status == STATUS_INVALID_IMAGE_FORMAT))\r
- {\r
- /* Fail loading */\r
- goto Quickie;\r
- }\r
-\r
- /* Check if this is a session-load */\r
- if (Flags)\r
- {\r
- /* Then we only need read and execute */\r
- DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;\r
- }\r
- else\r
- {\r
- /* Otherwise, we can allow write access */\r
- DesiredAccess = SECTION_ALL_ACCESS;\r
- }\r
-\r
- /* Initialize the attributes for the section */\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- NULL,\r
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r
- NULL,\r
- NULL);\r
-\r
- /* Create the section */\r
- Status = ZwCreateSection(&SectionHandle,\r
- DesiredAccess,\r
- &ObjectAttributes,\r
- NULL,\r
- PAGE_EXECUTE,\r
- SEC_IMAGE,\r
- FileHandle);\r
- if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
- /* Now get the section pointer */\r
- Status = ObReferenceObjectByHandle(SectionHandle,\r
- SECTION_MAP_EXECUTE,\r
- MmSectionObjectType,\r
- KernelMode,\r
- &Section,\r
- NULL);\r
- ZwClose(SectionHandle);\r
- if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
- /* Check if this was supposed to be a session-load */\r
- if (Flags)\r
- {\r
- /* We don't support session loading yet */\r
- DPRINT1("Unsupported Session-Load!\n");\r
- while (TRUE);\r
- }\r
-\r
- /* Check the loader list again, we should end up in the path below */\r
- goto LoaderScan;\r
- }\r
- else\r
- {\r
- /* We don't have a valid entry */\r
- LdrEntry = NULL;\r
- }\r
-\r
- /* Load the image */\r
- Status = MiLoadImageSection(&Section,\r
- &ModuleLoadBase,\r
- FileName,\r
- FALSE,\r
- NULL);\r
- ASSERT(Status != STATUS_ALREADY_COMMITTED);\r
-\r
- /* Get the size of the driver */\r
- DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;\r
-\r
- /* Make sure we're not being loaded into session space */\r
- if (!Flags)\r
- {\r
- /* Check for success */\r
- if (NT_SUCCESS(Status))\r
- {\r
- /* FIXME: Support large pages for drivers */\r
- }\r
-\r
- /* Dereference the section */\r
- ObDereferenceObject(Section);\r
- Section = NULL;\r
- }\r
-\r
- /* Get the NT Header */\r
- NtHeader = RtlImageNtHeader(ModuleLoadBase);\r
-\r
- /* Relocate the driver */\r
- Status = LdrRelocateImageWithBias(ModuleLoadBase,\r
- 0,\r
- "SYSLDR",\r
- STATUS_SUCCESS,\r
- STATUS_CONFLICTING_ADDRESSES,\r
- STATUS_INVALID_IMAGE_FORMAT);\r
- if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
- /* Calculate the size we'll need for the entry and allocate it */\r
- EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +\r
- BaseName.Length +\r
- sizeof(UNICODE_NULL);\r
-\r
- /* Allocate the entry */\r
- LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);\r
- if (!LdrEntry)\r
- {\r
- /* Fail */\r
- Status = STATUS_INSUFFICIENT_RESOURCES;\r
- goto Quickie;\r
- }\r
-\r
- /* Setup the entry */\r
- LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;\r
- LdrEntry->LoadCount = 1;\r
- LdrEntry->LoadedImports = LoadedImports;\r
- LdrEntry->PatchInformation = NULL;\r
-\r
- /* Check the version */\r
- if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&\r
- (NtHeader->OptionalHeader.MajorImageVersion >= 5))\r
- {\r
- /* Mark this image as a native image */\r
- LdrEntry->Flags |= 0x80000000;\r
- }\r
-\r
- /* Setup the rest of the entry */\r
- LdrEntry->DllBase = ModuleLoadBase;\r
- LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +\r
- NtHeader->OptionalHeader.AddressOfEntryPoint);\r
- LdrEntry->SizeOfImage = DriverSize;\r
- LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;\r
- LdrEntry->SectionPointer = Section;\r
-\r
- /* Now write the DLL name */\r
- LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);\r
- LdrEntry->BaseDllName.Length = BaseName.Length;\r
- LdrEntry->BaseDllName.MaximumLength = BaseName.Length;\r
-\r
- /* Copy and null-terminate it */\r
- RtlCopyMemory(LdrEntry->BaseDllName.Buffer,\r
- BaseName.Buffer,\r
- BaseName.Length);\r
- LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;\r
-\r
- /* Now allocate the full name */\r
- LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,\r
- PrefixName.Length +\r
- sizeof(UNICODE_NULL),\r
- TAG_LDR_WSTR);\r
- if (!LdrEntry->FullDllName.Buffer)\r
- {\r
- /* Don't fail, just set it to zero */\r
- LdrEntry->FullDllName.Length = 0;\r
- LdrEntry->FullDllName.MaximumLength = 0;\r
- }\r
- else\r
- {\r
- /* Set it up */\r
- LdrEntry->FullDllName.Length = PrefixName.Length;\r
- LdrEntry->FullDllName.MaximumLength = PrefixName.Length;\r
-\r
- /* Copy and null-terminate */\r
- RtlCopyMemory(LdrEntry->FullDllName.Buffer,\r
- PrefixName.Buffer,\r
- PrefixName.Length);\r
- LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;\r
- }\r
-\r
- /* Add the entry */\r
- MiProcessLoaderEntry(LdrEntry, TRUE);\r
-\r
- /* Resolve imports */\r
- MissingApiName = Buffer;\r
- Status = MiResolveImageReferences(ModuleLoadBase,\r
- &BaseDirectory,\r
- NULL,\r
- &MissingApiName,\r
- &MissingDriverName,\r
- &LoadedImports);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Fail */\r
- MiProcessLoaderEntry(LdrEntry, FALSE);\r
-\r
- /* Check if we need to free the name */\r
- if (LdrEntry->FullDllName.Buffer)\r
- {\r
- /* Free it */\r
- ExFreePool(LdrEntry->FullDllName.Buffer);\r
- }\r
-\r
- /* Free the entry itself */\r
- ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);\r
- LdrEntry = NULL;\r
- goto Quickie;\r
- }\r
-\r
- /* Update the loader entry */\r
- LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |\r
- LDRP_ENTRY_PROCESSED |\r
- LDRP_MM_LOADED);\r
- LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;\r
- LdrEntry->LoadedImports = LoadedImports;\r
-\r
- /* FIXME: Apply driver verifier */\r
-\r
- /* FIXME: Write-protect the system image */\r
-\r
- /* Check if notifications are enabled */\r
- if (PsImageNotifyEnabled)\r
- {\r
- /* Fill out the notification data */\r
- ImageInfo.Properties = 0;\r
- ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;\r
- ImageInfo.SystemModeImage = TRUE;\r
- ImageInfo.ImageSize = LdrEntry->SizeOfImage;\r
- ImageInfo.ImageBase = LdrEntry->DllBase;\r
- ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;\r
-\r
- /* Send the notification */\r
- PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);\r
- }\r
-\r
- /* Check if there's symbols */\r
-#ifdef KDBG\r
- /* If KDBG is defined, then we always have symbols */\r
- if (TRUE)\r
-#else\r
- if (MiCacheImageSymbols(LdrEntry->DllBase))\r
-#endif\r
- {\r
- /* Check if the system root is present */\r
- if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&\r
- !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))\r
- {\r
- /* Add the system root */\r
- UnicodeTemp = PrefixName;\r
- UnicodeTemp.Buffer += 11;\r
- UnicodeTemp.Length -= (11 * sizeof(WCHAR));\r
- sprintf_nt(Buffer,\r
- "%ws%wZ",\r
- &SharedUserData->NtSystemRoot[2],\r
- &UnicodeTemp);\r
- }\r
- else\r
- {\r
- /* Build the name */\r
- sprintf_nt(Buffer, "%wZ", &BaseName);\r
- }\r
-\r
- /* Setup the ansi string */\r
- RtlInitString(&AnsiTemp, Buffer);\r
-\r
- /* Notify the debugger */\r
- DbgLoadImageSymbols(&AnsiTemp, LdrEntry->DllBase, -1);\r
- LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;\r
- }\r
-\r
- /* FIXME: Page the driver */\r
- ASSERT(Section == NULL);\r
-\r
- /* Return pointers */\r
- if (ModuleObject) *ModuleObject = LdrEntry;\r
- if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
-\r
-Quickie:\r
- /* If we have a file handle, close it */\r
- if (FileHandle) ZwClose(FileHandle);\r
-\r
- /* Check if we have the lock acquired */\r
- if (LockOwned)\r
- {\r
- /* Release the lock */\r
- KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
- KeLeaveCriticalRegion();\r
- LockOwned = FALSE;\r
- }\r
-\r
- /* Check if we had a prefix */\r
- if (NamePrefix) ExFreePool(PrefixName.Buffer);\r
-\r
- /* Free the name buffer and return status */\r
- ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);\r
- return Status;\r
-}\r
-\r
-/*\r
- * @implemented\r
- */\r
-PVOID\r
-NTAPI\r
-MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)\r
-{\r
- PVOID ProcAddress = NULL;\r
- ANSI_STRING AnsiRoutineName;\r
- NTSTATUS Status;\r
- PLIST_ENTRY NextEntry;\r
- extern LIST_ENTRY PsLoadedModuleList;\r
- PLDR_DATA_TABLE_ENTRY LdrEntry;\r
- BOOLEAN Found = FALSE;\r
- UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");\r
- UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");\r
- ULONG Modules = 0;\r
-\r
- /* Convert routine to ansi name */\r
- Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,\r
- SystemRoutineName,\r
- TRUE);\r
- if (!NT_SUCCESS(Status)) return NULL;\r
-\r
- /* Lock the list */\r
- KeEnterCriticalRegion();\r
-\r
- /* Loop the loaded module list */\r
- NextEntry = PsLoadedModuleList.Flink;\r
- while (NextEntry != &PsLoadedModuleList)\r
- {\r
- /* Get the entry */\r
- LdrEntry = CONTAINING_RECORD(NextEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
-\r
- /* Check if it's the kernel or HAL */\r
- if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))\r
- {\r
- /* Found it */\r
- Found = TRUE;\r
- Modules++;\r
- }\r
- else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))\r
- {\r
- /* Found it */\r
- Found = TRUE;\r
- Modules++;\r
- }\r
-\r
- /* Check if we found a valid binary */\r
- if (Found)\r
- {\r
- /* Find the procedure name */\r
- ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,\r
- &AnsiRoutineName);\r
-\r
- /* Break out if we found it or if we already tried both modules */\r
- if (ProcAddress) break;\r
- if (Modules == 2) break;\r
- }\r
-\r
- /* Keep looping */\r
- NextEntry = NextEntry->Flink;\r
- }\r
-\r
- /* Release the lock */\r
- KeLeaveCriticalRegion();\r
-\r
- /* Free the string and return */\r
- RtlFreeAnsiString(&AnsiRoutineName);\r
- return ProcAddress;\r
-}\r
-\r
+/*
+* PROJECT: ReactOS Kernel
+* LICENSE: GPL - See COPYING in the top level directory
+* FILE: ntoskrnl/mm/sysldr.c
+* PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
+* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+*/
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GCC's incompetence strikes again */
+__inline
+VOID
+sprintf_nt(IN PCHAR Buffer,
+ IN PCHAR Format,
+ IN ...)
+{
+ va_list ap;
+ va_start(ap, Format);
+ vsprintf(Buffer, Format, ap);
+ va_end(ap);
+}
+
+/* GLOBALS *******************************************************************/
+
+LIST_ENTRY PsLoadedModuleList;
+KSPIN_LOCK PsLoadedModuleSpinLock;
+ULONG_PTR PsNtosImageBase;
+KMUTANT MmSystemLoadLock;
+extern ULONG NtGlobalFlag;
+
+/* FUNCTIONS *****************************************************************/
+
+PVOID
+NTAPI
+MiCacheImageSymbols(IN PVOID BaseAddress)
+{
+ ULONG DebugSize;
+ PVOID DebugDirectory = NULL;
+ PAGED_CODE();
+
+ /* Make sure it's safe to access the image */
+ _SEH2_TRY
+ {
+ /* Get the debug directory */
+ DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_DEBUG,
+ &DebugSize);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Nothing */
+ }
+ _SEH2_END;
+
+ /* Return the directory */
+ return DebugDirectory;
+}
+
+VOID
+NTAPI
+MiFreeBootDriverMemory(PVOID BaseAddress,
+ ULONG Length)
+{
+ ULONG i;
+
+ /* Loop each page */
+ for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
+ {
+ /* Free the page */
+ MmDeleteVirtualMapping(NULL,
+ (PVOID)((ULONG_PTR)BaseAddress + i * PAGE_SIZE),
+ TRUE,
+ NULL,
+ NULL);
+ }
+}
+
+NTSTATUS
+NTAPI
+MiLoadImageSection(IN OUT PVOID *SectionPtr,
+ OUT PVOID *ImageBase,
+ IN PUNICODE_STRING FileName,
+ IN BOOLEAN SessionLoad,
+ IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ PROS_SECTION_OBJECT Section = *SectionPtr;
+ NTSTATUS Status;
+ PEPROCESS Process;
+ PVOID Base = NULL;
+ SIZE_T ViewSize = 0;
+ KAPC_STATE ApcState;
+ LARGE_INTEGER SectionOffset = {{0, 0}};
+ BOOLEAN LoadSymbols = FALSE;
+ ULONG DriverSize;
+ PVOID DriverBase;
+ PAGED_CODE();
+
+ /* Detect session load */
+ if (SessionLoad)
+ {
+ /* Fail */
+ DPRINT1("Session loading not yet supported!\n");
+ while (TRUE);
+ }
+
+ /* Not session load, shouldn't have an entry */
+ ASSERT(LdrEntry == NULL);
+
+ /* Attach to the system process */
+ KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
+
+ /* Check if we need to load symbols */
+ if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
+ {
+ /* Yes we do */
+ LoadSymbols = TRUE;
+ NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
+ }
+
+ /* Map the driver */
+ Process = PsGetCurrentProcess();
+ Status = MmMapViewOfSection(Section,
+ Process,
+ &Base,
+ 0,
+ 0,
+ &SectionOffset,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_EXECUTE);
+
+ /* Re-enable the flag */
+ if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
+
+ /* Check if we failed with distinguished status code */
+ if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
+ {
+ /* Change it to something more generic */
+ Status = STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ /* Now check if we failed */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Detach and return */
+ KeUnstackDetachProcess(&ApcState);
+ return Status;
+ }
+
+ /* Get the driver size */
+ DriverSize = Section->ImageSection->ImageSize;
+
+ /* Allocate a virtual section for the module */
+ DriverBase = MmAllocateSection(DriverSize, NULL);
+ *ImageBase = DriverBase;
+
+ /* Copy the image */
+ RtlCopyMemory(DriverBase, Base, DriverSize);
+
+ /* Now unmap the view */
+ Status = MmUnmapViewOfSection(Process, Base);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Detach and return status */
+ KeUnstackDetachProcess(&ApcState);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
+{
+ SIZE_T i;
+
+ /* Check if there's no imports or if we're a boot driver */
+ if ((ImportList == (PVOID)-1) ||
+ (ImportList == (PVOID)-2) ||
+ (ImportList->Count == 0))
+ {
+ /* Then there's nothing to do */
+ return STATUS_SUCCESS;
+ }
+
+ /* Otherwise, FIXME */
+ DPRINT1("%u imports not dereferenced!\n", ImportList->Count);
+ for (i = 0; i < ImportList->Count; i++)
+ {
+ DPRINT1("%wZ <%wZ>\n", &ImportList->Entry[i]->FullDllName, &ImportList->Entry[i]->BaseDllName);
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ PAGED_CODE();
+
+ /* Check if there's no imports or we're a boot driver or only one entry */
+ if ((LdrEntry->LoadedImports == (PVOID)-1) ||
+ (LdrEntry->LoadedImports == (PVOID)-2) ||
+ ((ULONG_PTR)LdrEntry->LoadedImports & 1))
+ {
+ /* Nothing to do */
+ return;
+ }
+
+ /* Otherwise, free the import list */
+ ExFreePool(LdrEntry->LoadedImports);
+}
+
+PVOID
+NTAPI
+MiFindExportedRoutineByName(IN PVOID DllBase,
+ IN PANSI_STRING ExportName)
+{
+ PULONG NameTable;
+ PUSHORT OrdinalTable;
+ PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+ LONG Low = 0, Mid = 0, High, Ret;
+ USHORT Ordinal;
+ PVOID Function;
+ ULONG ExportSize;
+ PULONG ExportTable;
+ PAGED_CODE();
+
+ /* Get the export directory */
+ ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportSize);
+ if (!ExportDirectory) return NULL;
+
+ /* Setup name tables */
+ NameTable = (PULONG)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfNames);
+ OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfNameOrdinals);
+
+ /* Do a binary search */
+ High = ExportDirectory->NumberOfNames - 1;
+ while (High >= Low)
+ {
+ /* Get new middle value */
+ Mid = (Low + High) >> 1;
+
+ /* Compare name */
+ Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
+ if (Ret < 0)
+ {
+ /* Update high */
+ High = Mid - 1;
+ }
+ else if (Ret > 0)
+ {
+ /* Update low */
+ Low = Mid + 1;
+ }
+ else
+ {
+ /* We got it */
+ break;
+ }
+ }
+
+ /* Check if we couldn't find it */
+ if (High < Low) return NULL;
+
+ /* Otherwise, this is the ordinal */
+ Ordinal = OrdinalTable[Mid];
+
+ /* Resolve the address and write it */
+ ExportTable = (PULONG)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfFunctions);
+ Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
+
+ /* We found it! */
+ ASSERT(!(Function > (PVOID)ExportDirectory) &&
+ (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
+ return Function;
+}
+
+PVOID
+NTAPI
+MiLocateExportName(IN PVOID DllBase,
+ IN PCHAR ExportName)
+{
+ PULONG NameTable;
+ PUSHORT OrdinalTable;
+ PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+ LONG Low = 0, Mid = 0, High, Ret;
+ USHORT Ordinal;
+ PVOID Function;
+ ULONG ExportSize;
+ PULONG ExportTable;
+ PAGED_CODE();
+
+ /* Get the export directory */
+ ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportSize);
+ if (!ExportDirectory) return NULL;
+
+ /* Setup name tables */
+ NameTable = (PULONG)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfNames);
+ OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfNameOrdinals);
+
+ /* Do a binary search */
+ High = ExportDirectory->NumberOfNames - 1;
+ while (High >= Low)
+ {
+ /* Get new middle value */
+ Mid = (Low + High) >> 1;
+
+ /* Compare name */
+ Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
+ if (Ret < 0)
+ {
+ /* Update high */
+ High = Mid - 1;
+ }
+ else if (Ret > 0)
+ {
+ /* Update low */
+ Low = Mid + 1;
+ }
+ else
+ {
+ /* We got it */
+ break;
+ }
+ }
+
+ /* Check if we couldn't find it */
+ if (High < Low) return NULL;
+
+ /* Otherwise, this is the ordinal */
+ Ordinal = OrdinalTable[Mid];
+
+ /* Resolve the address and write it */
+ ExportTable = (PULONG)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfFunctions);
+ Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
+
+ /* Check if the function is actually a forwarder */
+ if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
+ ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+ {
+ /* It is, fail */
+ return NULL;
+ }
+
+ /* We found it */
+ return Function;
+}
+
+NTSTATUS
+NTAPI
+MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+ IN PLIST_ENTRY ListHead)
+{
+ UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
+ PMM_DLL_INITIALIZE DllInit;
+ UNICODE_STRING RegPath, ImportName;
+ NTSTATUS Status;
+
+ /* Try to see if the image exports a DllInitialize routine */
+ DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
+ "DllInitialize");
+ if (!DllInit) return STATUS_SUCCESS;
+
+ /* Do a temporary copy of BaseDllName called ImportName
+ * because we'll alter the length of the string
+ */
+ ImportName.Length = LdrEntry->BaseDllName.Length;
+ ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
+ ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
+
+ /* Obtain the path to this dll's service in the registry */
+ RegPath.MaximumLength = ServicesKeyName.Length +
+ ImportName.Length + sizeof(UNICODE_NULL);
+ RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ RegPath.MaximumLength,
+ TAG_LDR_WSTR);
+
+ /* Check if this allocation was unsuccessful */
+ if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Build and append the service name itself */
+ RegPath.Length = ServicesKeyName.Length;
+ RtlCopyMemory(RegPath.Buffer,
+ ServicesKeyName.Buffer,
+ ServicesKeyName.Length);
+
+ /* Check if there is a dot in the filename */
+ if (wcschr(ImportName.Buffer, L'.'))
+ {
+ /* Remove the extension */
+ ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
+ ImportName.Buffer) * sizeof(WCHAR);
+ }
+
+ /* Append service name (the basename without extension) */
+ RtlAppendUnicodeStringToString(&RegPath, &ImportName);
+
+ /* Now call the DllInit func */
+ DPRINT("Calling DllInit(%wZ)\n", &RegPath);
+ Status = DllInit(&RegPath);
+
+ /* Clean up */
+ ExFreePool(RegPath.Buffer);
+
+ /* Return status value which DllInitialize returned */
+ return Status;
+}
+
+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,
+ IN PVOID OldBase,
+ IN PVOID NewBase,
+ IN ULONG Size)
+{
+ ULONG_PTR OldBaseTop, Delta;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ PLIST_ENTRY NextEntry;
+ ULONG ImportSize;
+ PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+ PULONG ImageThunk;
+
+ /* Calculate the top and delta */
+ OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
+ Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
+
+ /* Loop the loader block */
+ for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
+ NextEntry != &LoaderBlock->LoadOrderListHead;
+ NextEntry = NextEntry->Flink)
+ {
+ /* Get the loader entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* Get the import table */
+ ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &ImportSize);
+ if (!ImportDescriptor) continue;
+
+ /* Make sure we have an IAT */
+ DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
+ while ((ImportDescriptor->Name) &&
+ (ImportDescriptor->OriginalFirstThunk))
+ {
+ /* Get the image thunk */
+ ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
+ ImportDescriptor->FirstThunk);
+ while (*ImageThunk)
+ {
+ /* Check if it's within this module */
+ if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
+ {
+ /* Relocate it */
+ DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
+ ImageThunk, *ImageThunk, *ImageThunk + Delta);
+ *ImageThunk += Delta;
+ }
+
+ /* Go to the next thunk */
+ ImageThunk++;
+ }
+
+ /* Go to the next import */
+ ImportDescriptor++;
+ }
+ }
+}
+
+NTSTATUS
+NTAPI
+MiSnapThunk(IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA Name,
+ IN PIMAGE_THUNK_DATA Address,
+ IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
+ IN ULONG ExportSize,
+ IN BOOLEAN SnapForwarder,
+ OUT PCHAR *MissingApi)
+{
+ BOOLEAN IsOrdinal;
+ USHORT Ordinal;
+ PULONG NameTable;
+ PUSHORT OrdinalTable;
+ PIMAGE_IMPORT_BY_NAME NameImport;
+ USHORT Hint;
+ ULONG Low = 0, Mid = 0, High;
+ LONG Ret;
+ NTSTATUS Status;
+ PCHAR MissingForwarder;
+ CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
+ PULONG ExportTable;
+ ANSI_STRING DllName;
+ UNICODE_STRING ForwarderName;
+ PLIST_ENTRY NextEntry;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ ULONG ForwardExportSize;
+ PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
+ PIMAGE_IMPORT_BY_NAME ForwardName;
+ ULONG ForwardLength;
+ IMAGE_THUNK_DATA ForwardThunk;
+ PAGED_CODE();
+
+ /* Check if this is an ordinal */
+ IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
+ if ((IsOrdinal) && !(SnapForwarder))
+ {
+ /* Get the ordinal number and set it as missing */
+ Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
+ ExportDirectory->Base);
+ *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
+ }
+ else
+ {
+ /* Get the VA if we don't have to snap */
+ if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
+ NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
+
+ /* Copy the procedure name */
+ strncpy(*MissingApi,
+ (PCHAR)&NameImport->Name[0],
+ MAXIMUM_FILENAME_LENGTH - 1);
+
+ /* Setup name tables */
+ DPRINT("Import name: %s\n", NameImport->Name);
+ NameTable = (PULONG)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfNames);
+ OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfNameOrdinals);
+
+ /* Get the hint and check if it's valid */
+ Hint = NameImport->Hint;
+ if ((Hint < ExportDirectory->NumberOfNames) &&
+ !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
+ {
+ /* We have a match, get the ordinal number from here */
+ Ordinal = OrdinalTable[Hint];
+ }
+ else
+ {
+ /* Do a binary search */
+ High = ExportDirectory->NumberOfNames - 1;
+ while (High >= Low)
+ {
+ /* Get new middle value */
+ Mid = (Low + High) >> 1;
+
+ /* Compare name */
+ Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
+ if (Ret < 0)
+ {
+ /* Update high */
+ High = Mid - 1;
+ }
+ else if (Ret > 0)
+ {
+ /* Update low */
+ Low = Mid + 1;
+ }
+ else
+ {
+ /* We got it */
+ break;
+ }
+ }
+
+ /* Check if we couldn't find it */
+ if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+
+ /* Otherwise, this is the ordinal */
+ Ordinal = OrdinalTable[Mid];
+ }
+ }
+
+ /* Check if the ordinal is invalid */
+ if (Ordinal >= ExportDirectory->NumberOfFunctions)
+ {
+ /* Fail */
+ Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
+ }
+ else
+ {
+ /* In case the forwarder is missing */
+ MissingForwarder = NameBuffer;
+
+ /* Resolve the address and write it */
+ ExportTable = (PULONG)((ULONG_PTR)DllBase +
+ ExportDirectory->AddressOfFunctions);
+ Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
+
+ /* Assume success from now on */
+ Status = STATUS_SUCCESS;
+
+ /* Check if the function is actually a forwarder */
+ if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
+ (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+ {
+ /* Now assume failure in case the forwarder doesn't exist */
+ Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+
+ /* Build the forwarder name */
+ DllName.Buffer = (PCHAR)Address->u1.Function;
+ DllName.Length = strchr(DllName.Buffer, '.') -
+ DllName.Buffer +
+ sizeof(ANSI_NULL);
+ DllName.MaximumLength = DllName.Length;
+
+ /* Convert it */
+ if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
+ &DllName,
+ TRUE)))
+ {
+ /* We failed, just return an error */
+ return Status;
+ }
+
+ /* Loop the module list */
+ NextEntry = PsLoadedModuleList.Flink;
+ while (NextEntry != &PsLoadedModuleList)
+ {
+ /* Get the loader entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* Check if it matches */
+ if (RtlPrefixString((PSTRING)&ForwarderName,
+ (PSTRING)&LdrEntry->BaseDllName,
+ TRUE))
+ {
+ /* Get the forwarder export directory */
+ ForwardExportDirectory =
+ RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ForwardExportSize);
+ if (!ForwardExportDirectory) break;
+
+ /* Allocate a name entry */
+ ForwardLength = strlen(DllName.Buffer + DllName.Length) +
+ sizeof(ANSI_NULL);
+ ForwardName = ExAllocatePoolWithTag(PagedPool,
+ sizeof(*ForwardName) +
+ ForwardLength,
+ TAG_LDR_WSTR);
+ if (!ForwardName) break;
+
+ /* Copy the data */
+ RtlCopyMemory(&ForwardName->Name[0],
+ DllName.Buffer + DllName.Length,
+ ForwardLength);
+ ForwardName->Hint = 0;
+
+ /* Set the new address */
+ ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
+
+ /* Snap the forwarder */
+ Status = MiSnapThunk(LdrEntry->DllBase,
+ ImageBase,
+ &ForwardThunk,
+ &ForwardThunk,
+ ForwardExportDirectory,
+ ForwardExportSize,
+ TRUE,
+ &MissingForwarder);
+
+ /* Free the forwarder name and set the thunk */
+ ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
+ Address->u1 = ForwardThunk.u1;
+ break;
+ }
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Free the name */
+ RtlFreeUnicodeString(&ForwarderName);
+ }
+ }
+
+ /* Return status */
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MmUnloadSystemImage(IN PVOID ImageHandle)
+{
+ PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
+ PVOID BaseAddress = LdrEntry->DllBase;
+ NTSTATUS Status;
+ STRING TempName;
+ BOOLEAN HadEntry = FALSE;
+
+ /* Acquire the loader lock */
+ KeEnterCriticalRegion();
+ KeWaitForSingleObject(&MmSystemLoadLock,
+ WrVirtualMemory,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ /* Check if this driver was loaded at boot and didn't get imports parsed */
+ if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;
+
+ /* We should still be alive */
+ ASSERT(LdrEntry->LoadCount != 0);
+ LdrEntry->LoadCount--;
+
+ /* Check if we're still loaded */
+ if (LdrEntry->LoadCount) goto Done;
+
+ /* We should cleanup... are symbols loaded */
+ if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
+ {
+ /* Create the ANSI name */
+ Status = RtlUnicodeStringToAnsiString(&TempName,
+ &LdrEntry->BaseDllName,
+ TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Unload the symbols */
+ DbgUnLoadImageSymbols(&TempName,
+ BaseAddress,
+ (ULONG_PTR)ZwCurrentProcess());
+ RtlFreeAnsiString(&TempName);
+ }
+ }
+
+ /* FIXME: Free the driver */
+ //MmFreeSection(LdrEntry->DllBase);
+
+ /* Check if we're linked in */
+ if (LdrEntry->InLoadOrderLinks.Flink)
+ {
+ /* Remove us */
+ MiProcessLoaderEntry(LdrEntry, FALSE);
+ HadEntry = TRUE;
+ }
+
+ /* Dereference and clear the imports */
+ MiDereferenceImports(LdrEntry->LoadedImports);
+ MiClearImports(LdrEntry);
+
+ /* Check if the entry needs to go away */
+ if (HadEntry)
+ {
+ /* Check if it had a name */
+ if (LdrEntry->FullDllName.Buffer)
+ {
+ /* Free it */
+ ExFreePool(LdrEntry->FullDllName.Buffer);
+ }
+
+ /* Check if we had a section */
+ if (LdrEntry->SectionPointer)
+ {
+ /* Dereference it */
+ ObDereferenceObject(LdrEntry->SectionPointer);
+ }
+
+ /* Free the entry */
+ ExFreePool(LdrEntry);
+ }
+
+ /* Release the system lock and return */
+Done:
+ KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
+ KeLeaveCriticalRegion();
+ return STATUS_SUCCESS;
+}
+
+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)
+{
+ PCHAR MissingApiBuffer = *MissingApi, ImportName;
+ PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
+ ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
+ PLOAD_IMPORTS LoadedImports, NewImports;
+ ULONG GdiLink, NormalLink, i;
+ BOOLEAN ReferenceNeeded, Loaded;
+ ANSI_STRING TempString;
+ UNICODE_STRING NameString, DllName;
+ PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
+ PVOID ImportBase, DllBase;
+ PLIST_ENTRY NextEntry;
+ PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+ NTSTATUS Status;
+ PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
+ PAGED_CODE();
+ DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
+ __FUNCTION__, ImageBase, ImageFileDirectory);
+
+ /* Assume no imports */
+ *LoadImports = (PVOID)-2;
+
+ /* Get the import descriptor */
+ ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &ImportSize);
+ if (!ImportDescriptor) return STATUS_SUCCESS;
+
+ /* Loop all imports to count them */
+ for (CurrentImport = ImportDescriptor;
+ (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
+ CurrentImport++)
+ {
+ /* One more */
+ ImportCount++;
+ }
+
+ /* Make sure we have non-zero imports */
+ if (ImportCount)
+ {
+ /* Calculate and allocate the list we'll need */
+ LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
+ LoadedImports = ExAllocatePoolWithTag(PagedPool,
+ LoadedImportsSize,
+ TAG_LDR_WSTR);
+ if (LoadedImports)
+ {
+ /* Zero it */
+ RtlZeroMemory(LoadedImports, LoadedImportsSize);
+ }
+ }
+ else
+ {
+ /* No table */
+ LoadedImports = NULL;
+ }
+
+ /* Reset the import count and loop descriptors again */
+ ImportCount = GdiLink = NormalLink = 0;
+ while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
+ {
+ /* Get the name */
+ ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
+
+ /* Check if this is a GDI driver */
+ GdiLink = GdiLink |
+ !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
+
+ /* We can also allow dxapi */
+ NormalLink = NormalLink |
+ ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
+ (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
+
+ /* Check if this is a valid GDI driver */
+ if ((GdiLink) && (NormalLink))
+ {
+ /* It's not, it's importing stuff it shouldn't be! */
+ MiDereferenceImports(LoadedImports);
+ if (LoadedImports) ExFreePool(LoadedImports);
+ return STATUS_PROCEDURE_NOT_FOUND;
+ }
+
+ /* Check if this is a "core" import, which doesn't get referenced */
+ if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
+ !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
+ !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
+ {
+ /* Don't reference this */
+ ReferenceNeeded = FALSE;
+ }
+ else
+ {
+ /* Reference these modules */
+ ReferenceNeeded = TRUE;
+ }
+
+ /* Now setup a unicode string for the import */
+ RtlInitAnsiString(&TempString, ImportName);
+ Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ MiDereferenceImports(LoadedImports);
+ if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ return Status;
+ }
+
+ /* We don't support name prefixes yet */
+ if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
+
+ /* Remember that we haven't loaded the import at this point */
+CheckDllState:
+ Loaded = FALSE;
+ ImportBase = NULL;
+
+ /* Loop the driver list */
+ NextEntry = PsLoadedModuleList.Flink;
+ while (NextEntry != &PsLoadedModuleList)
+ {
+ /* Get the loader entry and compare the name */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+ if (RtlEqualUnicodeString(&NameString,
+ &LdrEntry->BaseDllName,
+ TRUE))
+ {
+ /* Get the base address */
+ ImportBase = LdrEntry->DllBase;
+
+ /* Check if we haven't loaded yet, and we need references */
+ if (!(Loaded) && (ReferenceNeeded))
+ {
+ /* Make sure we're not already loading */
+ if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
+ {
+ /* Increase the load count */
+ LdrEntry->LoadCount++;
+ }
+ }
+
+ /* Done, break out */
+ break;
+ }
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Check if we haven't loaded the import yet */
+ if (!ImportBase)
+ {
+ /* Setup the import DLL name */
+ DllName.MaximumLength = NameString.Length +
+ ImageFileDirectory->Length +
+ sizeof(UNICODE_NULL);
+ DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ DllName.MaximumLength,
+ TAG_LDR_WSTR);
+ if (DllName.Buffer)
+ {
+ /* Setup the base length and copy it */
+ DllName.Length = ImageFileDirectory->Length;
+ RtlCopyMemory(DllName.Buffer,
+ ImageFileDirectory->Buffer,
+ ImageFileDirectory->Length);
+
+ /* Now add the import name and null-terminate it */
+ RtlAppendStringToString((PSTRING)&DllName,
+ (PSTRING)&NameString);
+ DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;
+
+ /* Load the image */
+ Status = MmLoadSystemImage(&DllName,
+ NamePrefix,
+ NULL,
+ 0,
+ (PVOID)&DllEntry,
+ &DllBase);
+ if (NT_SUCCESS(Status))
+ {
+ /* We can free the DLL Name */
+ ExFreePool(DllName.Buffer);
+ }
+ else
+ {
+ /* Fill out the information for the error */
+ *MissingDriver = DllName.Buffer;
+ *(PULONG)MissingDriver |= 1;
+ *MissingApi = NULL;
+ }
+ }
+ else
+ {
+ /* We're out of resources */
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Check if we're OK until now */
+ if (NT_SUCCESS(Status))
+ {
+ /* We're now loaded */
+ Loaded = TRUE;
+
+ /* Sanity check */
+ ASSERT(DllBase = DllEntry->DllBase);
+
+ /* Call the initialization routines */
+ Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, unload the image */
+ MmUnloadSystemImage(DllEntry);
+ while (TRUE);
+ Loaded = FALSE;
+ }
+ }
+
+ /* Check if we failed by here */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Cleanup and return */
+ RtlFreeUnicodeString(&NameString);
+ MiDereferenceImports(LoadedImports);
+ if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ return Status;
+ }
+
+ /* Loop again to make sure that everything is OK */
+ goto CheckDllState;
+ }
+
+ /* Check if we're support to reference this import */
+ if ((ReferenceNeeded) && (LoadedImports))
+ {
+ /* Make sure we're not already loading */
+ if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
+ {
+ /* Add the entry */
+ LoadedImports->Entry[LoadedImports->Count] = LdrEntry;
+ LoadedImports->Count++;
+ }
+ }
+
+ /* Free the import name */
+ RtlFreeUnicodeString(&NameString);
+
+ /* Set the missing driver name and get the export directory */
+ *MissingDriver = LdrEntry->BaseDllName.Buffer;
+ ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportSize);
+ if (!ExportDirectory)
+ {
+ /* Cleanup and return */
+ MiDereferenceImports(LoadedImports);
+ if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+ }
+
+ /* Make sure we have an IAT */
+ if (ImportDescriptor->OriginalFirstThunk)
+ {
+ /* Get the first thunks */
+ OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
+ ImportDescriptor->OriginalFirstThunk);
+ FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
+ ImportDescriptor->FirstThunk);
+
+ /* Loop the IAT */
+ while (OrigThunk->u1.AddressOfData)
+ {
+ /* Snap thunk */
+ Status = MiSnapThunk(ImportBase,
+ ImageBase,
+ OrigThunk++,
+ FirstThunk++,
+ ExportDirectory,
+ ExportSize,
+ FALSE,
+ MissingApi);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Cleanup and return */
+ MiDereferenceImports(LoadedImports);
+ if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ return Status;
+ }
+
+ /* Reset the buffer */
+ *MissingApi = MissingApiBuffer;
+ }
+ }
+
+ /* Go to the next import */
+ ImportDescriptor++;
+ }
+
+ /* Check if we have an import list */
+ if (LoadedImports)
+ {
+ /* Reset the count again, and loop entries*/
+ ImportCount = 0;
+ for (i = 0; i < LoadedImports->Count; i++)
+ {
+ if (LoadedImports->Entry[i])
+ {
+ /* Got an entry, OR it with 1 in case it's the single entry */
+ ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
+ ImportCount++;
+ }
+ }
+
+ /* Check if we had no imports */
+ if (!ImportCount)
+ {
+ /* Free the list and set it to no imports */
+ ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ LoadedImports = (PVOID)-2;
+ }
+ else if (ImportCount == 1)
+ {
+ /* Just one entry, we can free the table and only use our entry */
+ ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ LoadedImports = (PLOAD_IMPORTS)ImportEntry;
+ }
+ else if (ImportCount != LoadedImports->Count)
+ {
+ /* Allocate a new list */
+ LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
+ NewImports = ExAllocatePoolWithTag(PagedPool,
+ LoadedImportsSize,
+ TAG_LDR_WSTR);
+ if (NewImports)
+ {
+ /* Set count */
+ NewImports->Count = 0;
+
+ /* Loop all the imports */
+ for (i = 0; i < LoadedImports->Count; i++)
+ {
+ /* Make sure it's valid */
+ if (LoadedImports->Entry[i])
+ {
+ /* Copy it */
+ NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
+ NewImports->Count++;
+ }
+ }
+
+ /* Free the old copy */
+ ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+ LoadedImports = NewImports;
+ }
+ }
+
+ /* Return the list */
+ *LoadImports = LoadedImports;
+ }
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ PLIST_ENTRY NextEntry;
+ ULONG i = 0;
+ PIMAGE_NT_HEADERS NtHeader;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ PIMAGE_FILE_HEADER FileHeader;
+ BOOLEAN ValidRelocs;
+ PIMAGE_DATA_DIRECTORY DataDirectory;
+ PVOID DllBase, NewImageAddress;
+ NTSTATUS Status;
+
+ /* Loop driver list */
+ for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
+ NextEntry != &LoaderBlock->LoadOrderListHead;
+ NextEntry = NextEntry->Flink)
+ {
+ /* Get the loader entry and NT header */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+ NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
+
+ /* Debug info */
+ DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
+ LdrEntry->DllBase,
+ (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,
+ &LdrEntry->FullDllName);
+
+ /* Skip kernel and HAL */
+ /* ROS HACK: Skip BOOTVID/KDCOM too */
+ i++;
+ if (i <= 4) continue;
+
+ /* Skip non-drivers */
+ if (!NtHeader) continue;
+
+ /* Get the file header and make sure we can relocate */
+ FileHeader = &NtHeader->FileHeader;
+ if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
+ if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
+ IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
+
+ /* Everything made sense until now, check the relocation section too */
+ DataDirectory = &NtHeader->OptionalHeader.
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ if (!DataDirectory->VirtualAddress)
+ {
+ /* We don't really have relocations */
+ ValidRelocs = FALSE;
+ }
+ else
+ {
+ /* Make sure the size is valid */
+ if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
+ LdrEntry->SizeOfImage)
+ {
+ /* They're not, skip */
+ continue;
+ }
+
+ /* We have relocations */
+ ValidRelocs = TRUE;
+ }
+
+ /* Remember the original address */
+ DllBase = LdrEntry->DllBase;
+
+ /* Allocate a virtual section for the module */
+ NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);
+ if (!NewImageAddress)
+ {
+ /* Shouldn't happen */
+ DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
+ while (TRUE);
+ }
+
+ /* Sanity check */
+ DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
+ ASSERT(ExpInitializationPhase == 0);
+
+ /* Now copy the entire driver over */
+ RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);
+
+ /* Sanity check */
+ ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
+
+ /* Set the image base to the address where the loader put it */
+ NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
+ NtHeader = RtlImageNtHeader(NewImageAddress);
+ NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
+
+ /* Check if we had relocations */
+ if (ValidRelocs)
+ {
+ /* Relocate the image */
+ Status = LdrRelocateImageWithBias(NewImageAddress,
+ 0,
+ "SYSLDR",
+ STATUS_SUCCESS,
+ STATUS_CONFLICTING_ADDRESSES,
+ STATUS_INVALID_IMAGE_FORMAT);
+ if (!NT_SUCCESS(Status))
+ {
+ /* This shouldn't happen */
+ DPRINT1("Relocations failed!\n");
+ while (TRUE);
+ }
+ }
+
+ /* Update the loader entry */
+ LdrEntry->DllBase = NewImageAddress;
+
+ /* Update the thunks */
+ DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
+ MiUpdateThunks(LoaderBlock,
+ DllBase,
+ NewImageAddress,
+ LdrEntry->SizeOfImage);
+
+ /* Update the loader entry */
+ LdrEntry->Flags |= 0x01000000;
+ LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
+ NtHeader->OptionalHeader.AddressOfEntryPoint);
+ LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;
+
+ /* Free the old copy */
+ MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);
+ }
+}
+
+BOOLEAN
+NTAPI
+MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
+ PLIST_ENTRY ListHead, NextEntry;
+ ULONG EntrySize;
+
+ /* Setup the loaded module list and lock */
+ KeInitializeSpinLock(&PsLoadedModuleSpinLock);
+ InitializeListHead(&PsLoadedModuleList);
+
+ /* Get loop variables and the kernel entry */
+ ListHead = &LoaderBlock->LoadOrderListHead;
+ NextEntry = ListHead->Flink;
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+ PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
+
+ /* Loop the loader block */
+ while (NextEntry != ListHead)
+ {
+ /* Get the loader entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* FIXME: ROS HACK. Make sure this is a driver */
+ if (!RtlImageNtHeader(LdrEntry->DllBase))
+ {
+ /* Skip this entry */
+ NextEntry= NextEntry->Flink;
+ continue;
+ }
+
+ /* Calculate the size we'll need and allocate a copy */
+ EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
+ LdrEntry->BaseDllName.MaximumLength +
+ sizeof(UNICODE_NULL);
+ NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
+ if (!NewEntry) return FALSE;
+
+ /* Copy the entry over */
+ *NewEntry = *LdrEntry;
+
+ /* Allocate the name */
+ NewEntry->FullDllName.Buffer =
+ ExAllocatePoolWithTag(PagedPool,
+ LdrEntry->FullDllName.MaximumLength +
+ sizeof(UNICODE_NULL),
+ TAG_LDR_WSTR);
+ if (!NewEntry->FullDllName.Buffer) return FALSE;
+
+ /* Set the base name */
+ NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
+
+ /* Copy the full and base name */
+ RtlCopyMemory(NewEntry->FullDllName.Buffer,
+ LdrEntry->FullDllName.Buffer,
+ LdrEntry->FullDllName.MaximumLength);
+ RtlCopyMemory(NewEntry->BaseDllName.Buffer,
+ LdrEntry->BaseDllName.Buffer,
+ LdrEntry->BaseDllName.MaximumLength);
+
+ /* Null-terminate the base name */
+ NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
+ sizeof(WCHAR)] = UNICODE_NULL;
+
+ /* Insert the entry into the list */
+ InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Build the import lists for the boot drivers */
+ //MiBuildImportsForBootDrivers();
+
+ /* We're done */
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
+{
+ PIMAGE_NT_HEADERS NtHeader;
+ PAGED_CODE();
+
+ /* Get NT Headers */
+ NtHeader = RtlImageNtHeader(BaseAddress);
+ if (NtHeader)
+ {
+ /* Check if this image is only safe for UP while we have 2+ CPUs */
+ if ((KeNumberProcessors > 1) &&
+ (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
+ {
+ /* Fail */
+ return FALSE;
+ }
+ }
+
+ /* Otherwise, it's safe */
+ return TRUE;
+}
+
+NTSTATUS
+NTAPI
+MmCheckSystemImage(IN HANDLE ImageHandle,
+ IN BOOLEAN PurgeSection)
+{
+ NTSTATUS Status;
+ HANDLE SectionHandle;
+ PVOID ViewBase = NULL;
+ SIZE_T ViewSize = 0;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ KAPC_STATE ApcState;
+ PAGED_CODE();
+
+ /* Create a section for the DLL */
+ Status = ZwCreateSection(&SectionHandle,
+ SECTION_MAP_EXECUTE,
+ NULL,
+ NULL,
+ PAGE_EXECUTE,
+ SEC_COMMIT,
+ ImageHandle);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Make sure we're in the system process */
+ KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
+
+ /* Map it */
+ Status = ZwMapViewOfSection(SectionHandle,
+ NtCurrentProcess(),
+ &ViewBase,
+ 0,
+ 0,
+ NULL,
+ &ViewSize,
+ ViewShare,
+ 0,
+ PAGE_EXECUTE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, close the handle and return */
+ KeUnstackDetachProcess(&ApcState);
+ ZwClose(SectionHandle);
+ return Status;
+ }
+
+ /* Now query image information */
+ Status = ZwQueryInformationFile(ImageHandle,
+ &IoStatusBlock,
+ &FileStandardInfo,
+ sizeof(FileStandardInfo),
+ FileStandardInformation);
+ if ( NT_SUCCESS(Status) )
+ {
+ /* First, verify the checksum */
+ if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
+ FileStandardInfo.
+ EndOfFile.LowPart,
+ FileStandardInfo.
+ EndOfFile.LowPart))
+ {
+ /* Set checksum failure */
+ Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
+ }
+
+ /* Check that it's a valid SMP image if we have more then one CPU */
+ if (!MmVerifyImageIsOkForMpUse(ViewBase))
+ {
+ /* Otherwise it's not the right image */
+ Status = STATUS_IMAGE_MP_UP_MISMATCH;
+ }
+ }
+
+ /* Unmap the section, close the handle, and return status */
+ ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
+ KeUnstackDetachProcess(&ApcState);
+ 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;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIMAGE_NT_HEADERS NtHeader;
+ UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
+ PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
+ ULONG EntrySize, DriverSize;
+ PLOAD_IMPORTS LoadedImports = (PVOID)-2;
+ PCHAR MissingApiName, Buffer;
+ PWCHAR MissingDriverName;
+ HANDLE SectionHandle;
+ ACCESS_MASK DesiredAccess;
+ PVOID Section = NULL;
+ BOOLEAN LockOwned = FALSE;
+ PLIST_ENTRY NextEntry;
+ IMAGE_INFO ImageInfo;
+ STRING AnsiTemp;
+ 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 */
+ if (ModuleObject) *ModuleObject = LdrEntry;
+ if (ImageBaseAddress) *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 | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+
+ /* Open the image */
+ Status = ZwOpenFile(&FileHandle,
+ FILE_EXECUTE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_DELETE,
+ 0);
+ 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;
+ }
+
+ /* 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;
+ }
+
+ /* Load the image */
+ Status = MiLoadImageSection(&Section,
+ &ModuleLoadBase,
+ FileName,
+ FALSE,
+ NULL);
+ ASSERT(Status != STATUS_ALREADY_COMMITTED);
+
+ /* Get the size of the driver */
+ DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
+
+ /* Make sure we're not being loaded into session space */
+ if (!Flags)
+ {
+ /* Check for success */
+ if (NT_SUCCESS(Status))
+ {
+ /* FIXME: Support large pages for drivers */
+ }
+
+ /* Dereference the section */
+ ObDereferenceObject(Section);
+ Section = NULL;
+ }
+
+ /* Get the NT Header */
+ NtHeader = RtlImageNtHeader(ModuleLoadBase);
+
+ /* Relocate the driver */
+ Status = LdrRelocateImageWithBias(ModuleLoadBase,
+ 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 = ModuleLoadBase;
+ LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
+ NtHeader->OptionalHeader.AddressOfEntryPoint);
+ LdrEntry->SizeOfImage = DriverSize;
+ LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
+ LdrEntry->SectionPointer = Section;
+
+ /* 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(ModuleLoadBase,
+ &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 */
+ ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
+ LdrEntry = NULL;
+ goto Quickie;
+ }
+
+ /* Update the loader entry */
+ LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
+ LDRP_ENTRY_PROCESSED |
+ LDRP_MM_LOADED);
+ LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
+ LdrEntry->LoadedImports = LoadedImports;
+
+ /* FIXME: Apply driver verifier */
+
+ /* FIXME: Write-protect the system image */
+
+ /* Check if notifications are enabled */
+ if (PsImageNotifyEnabled)
+ {
+ /* Fill out the notification data */
+ ImageInfo.Properties = 0;
+ ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
+ ImageInfo.SystemModeImage = TRUE;
+ ImageInfo.ImageSize = LdrEntry->SizeOfImage;
+ ImageInfo.ImageBase = LdrEntry->DllBase;
+ ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
+
+ /* Send the notification */
+ PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
+ }
+
+ /* Check if there's symbols */
+#ifdef KDBG
+ /* If KDBG is defined, then we always have symbols */
+ if (TRUE)
+#else
+ if (MiCacheImageSymbols(LdrEntry->DllBase))
+#endif
+ {
+ /* Check if the system root is present */
+ if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
+ !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
+ {
+ /* Add the system root */
+ UnicodeTemp = PrefixName;
+ UnicodeTemp.Buffer += 11;
+ UnicodeTemp.Length -= (11 * sizeof(WCHAR));
+ sprintf_nt(Buffer,
+ "%ws%wZ",
+ &SharedUserData->NtSystemRoot[2],
+ &UnicodeTemp);
+ }
+ else
+ {
+ /* Build the name */
+ sprintf_nt(Buffer, "%wZ", &BaseName);
+ }
+
+ /* Setup the ansi string */
+ RtlInitString(&AnsiTemp, Buffer);
+
+ /* Notify the debugger */
+ DbgLoadImageSymbols(&AnsiTemp,
+ LdrEntry->DllBase,
+ (ULONG_PTR)ZwCurrentProcess());
+ LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
+ }
+
+ /* FIXME: Page the driver */
+ ASSERT(Section == NULL);
+
+ /* Return pointers */
+ if (ModuleObject) *ModuleObject = LdrEntry;
+ if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;
+
+Quickie:
+ /* If we have a file handle, close it */
+ if (FileHandle) ZwClose(FileHandle);
+
+ /* 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 */
+ ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+PVOID
+NTAPI
+MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
+{
+ PVOID ProcAddress = NULL;
+ ANSI_STRING AnsiRoutineName;
+ NTSTATUS Status;
+ PLIST_ENTRY NextEntry;
+ extern LIST_ENTRY PsLoadedModuleList;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ BOOLEAN Found = FALSE;
+ UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
+ UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
+ ULONG Modules = 0;
+
+ /* Convert routine to ansi name */
+ Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
+ SystemRoutineName,
+ TRUE);
+ if (!NT_SUCCESS(Status)) return NULL;
+
+ /* Lock the list */
+ KeEnterCriticalRegion();
+
+ /* Loop the loaded module list */
+ NextEntry = PsLoadedModuleList.Flink;
+ while (NextEntry != &PsLoadedModuleList)
+ {
+ /* Get the entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* Check if it's the kernel or HAL */
+ if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
+ {
+ /* Found it */
+ Found = TRUE;
+ Modules++;
+ }
+ else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
+ {
+ /* Found it */
+ Found = TRUE;
+ Modules++;
+ }
+
+ /* Check if we found a valid binary */
+ if (Found)
+ {
+ /* Find the procedure name */
+ ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
+ &AnsiRoutineName);
+
+ /* Break out if we found it or if we already tried both modules */
+ if (ProcAddress) break;
+ if (Modules == 2) break;
+ }
+
+ /* Keep looping */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Release the lock */
+ KeLeaveCriticalRegion();
+
+ /* Free the string and return */
+ RtlFreeAnsiString(&AnsiRoutineName);
+ return ProcAddress;
+}
+