--- /dev/null
- PVOID PsNtosImageBase;\r
+/*\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
+/* GLOBALS *******************************************************************/\r
+\r
+LIST_ENTRY PsLoadedModuleList;\r
+KSPIN_LOCK PsLoadedModuleSpinLock;\r
- PsNtosImageBase = LdrEntry->DllBase;\r
++ULONG PsNtosImageBase;\r
+KMUTANT MmSystemLoadLock;\r
+extern ULONG NtGlobalFlag;\r
+\r
+/* FUNCTIONS *****************************************************************/\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
+ /* Check if there's no imports or if we're a boot driver */\r
+ if ((ImportList == (PVOID)-1) || (ImportList == (PVOID)-2))\r
+ {\r
+ /* Then there's nothing to do */\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ /* Otherwise, FIXME */\r
+ DPRINT1("Imports not dereferenced!\n");\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
+ PMM_DLL_INITIALIZE DllInit;\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
+ /* FIXME: TODO */\r
+ DPRINT1("DllInitialize not called!\n");\r
+ return STATUS_UNSUCCESSFUL;\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
+ ExFreePool(ForwardName);\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;\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 and set the count */\r
+ RtlZeroMemory(LoadedImports, LoadedImportsSize);\r
+ LoadedImports->Count = ImportCount;\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) ExFreePool(LoadedImports);\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) ExFreePool(LoadedImports);\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[ImportCount] = LdrEntry;\r
+ ImportCount++;\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) ExFreePool(LoadedImports);\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) ExFreePool(LoadedImports);\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
+ ExFreePool(LoadedImports);\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
+ ExFreePool(LoadedImports);\r
+ LoadedImports = (PLOAD_IMPORTS)ImportEntry;\r
+ }\r
+ else if (ImportCount != LoadedImports->Count)\r
+ {\r
+ /* FIXME: Can this happen? */\r
+ DPRINT1("Unhandled scenario\n");\r
+ while (TRUE);\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 old address */\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;\r
+ PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;\r
+ ULONG EntrySize;\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
+ 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 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 = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;\r
+ LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;\r
+ LdrEntry->SectionPointer = LdrEntry;\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
+ ExFreePool(LdrEntry);\r
+ LdrEntry = NULL;\r
+ goto Quickie;\r
+ }\r
+\r
+ if (ModuleObject) *ModuleObject = LdrEntry;\r
+ if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
+\r
+ /* Hook for KDB on loading a driver. */\r
+ KDB_LOADDRIVER_HOOK(FileName, LdrEntry);\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
+ ExFreePool(Buffer);\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