2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GCC's incompetence strikes again */
18 sprintf_nt(IN PCHAR Buffer
,
24 vsprintf(Buffer
, Format
, ap
);
28 /* GLOBALS *******************************************************************/
30 LIST_ENTRY PsLoadedModuleList
;
31 LIST_ENTRY MmLoadedUserImageList
;
32 KSPIN_LOCK PsLoadedModuleSpinLock
;
33 ERESOURCE PsLoadedModuleResource
;
34 ULONG_PTR PsNtosImageBase
;
35 KMUTANT MmSystemLoadLock
;
37 PVOID MmUnloadedDrivers
;
38 PVOID MmLastUnloadedDrivers
;
39 PVOID MmTriageActionTaken
;
42 /* FUNCTIONS *****************************************************************/
46 MiCacheImageSymbols(IN PVOID BaseAddress
)
49 PVOID DebugDirectory
= NULL
;
52 /* Make sure it's safe to access the image */
55 /* Get the debug directory */
56 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
58 IMAGE_DIRECTORY_ENTRY_DEBUG
,
61 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
67 /* Return the directory */
68 return DebugDirectory
;
73 MiFreeBootDriverMemory(PVOID BaseAddress
,
79 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
82 MmDeleteVirtualMapping(NULL
,
83 (PVOID
)((ULONG_PTR
)BaseAddress
+ i
* PAGE_SIZE
),
92 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
94 IN PUNICODE_STRING FileName
,
95 IN BOOLEAN SessionLoad
,
96 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
98 PROS_SECTION_OBJECT Section
= *SectionPtr
;
104 LARGE_INTEGER SectionOffset
= {{0, 0}};
105 BOOLEAN LoadSymbols
= FALSE
;
110 /* Detect session load */
114 DPRINT1("Session loading not yet supported!\n");
118 /* Not session load, shouldn't have an entry */
119 ASSERT(LdrEntry
== NULL
);
121 /* Attach to the system process */
122 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
124 /* Check if we need to load symbols */
125 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
129 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
133 Process
= PsGetCurrentProcess();
134 Status
= MmMapViewOfSection(Section
,
145 /* Re-enable the flag */
146 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
148 /* Check if we failed with distinguished status code */
149 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
151 /* Change it to something more generic */
152 Status
= STATUS_INVALID_IMAGE_FORMAT
;
155 /* Now check if we failed */
156 if (!NT_SUCCESS(Status
))
158 /* Detach and return */
159 KeUnstackDetachProcess(&ApcState
);
163 /* Get the driver size */
164 DriverSize
= Section
->ImageSection
->ImageSize
;
166 /* Allocate a virtual section for the module */
167 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
168 *ImageBase
= DriverBase
;
171 RtlCopyMemory(DriverBase
, Base
, DriverSize
);
173 /* Now unmap the view */
174 Status
= MmUnmapViewOfSection(Process
, Base
);
175 ASSERT(NT_SUCCESS(Status
));
177 /* Detach and return status */
178 KeUnstackDetachProcess(&ApcState
);
184 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
188 /* Check if there's no imports or if we're a boot driver */
189 if ((ImportList
== (PVOID
)-1) ||
190 (ImportList
== (PVOID
)-2) ||
191 (ImportList
->Count
== 0))
193 /* Then there's nothing to do */
194 return STATUS_SUCCESS
;
197 /* Otherwise, FIXME */
198 DPRINT1("%u imports not dereferenced!\n", ImportList
->Count
);
199 for (i
= 0; i
< ImportList
->Count
; i
++)
201 DPRINT1("%wZ <%wZ>\n", &ImportList
->Entry
[i
]->FullDllName
, &ImportList
->Entry
[i
]->BaseDllName
);
203 return STATUS_UNSUCCESSFUL
;
208 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
212 /* Check if there's no imports or we're a boot driver or only one entry */
213 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
214 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
215 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
221 /* Otherwise, free the import list */
222 ExFreePool(LdrEntry
->LoadedImports
);
227 MiFindExportedRoutineByName(IN PVOID DllBase
,
228 IN PANSI_STRING ExportName
)
231 PUSHORT OrdinalTable
;
232 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
233 LONG Low
= 0, Mid
= 0, High
, Ret
;
240 /* Get the export directory */
241 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
243 IMAGE_DIRECTORY_ENTRY_EXPORT
,
245 if (!ExportDirectory
) return NULL
;
247 /* Setup name tables */
248 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
249 ExportDirectory
->AddressOfNames
);
250 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
251 ExportDirectory
->AddressOfNameOrdinals
);
253 /* Do a binary search */
254 High
= ExportDirectory
->NumberOfNames
- 1;
257 /* Get new middle value */
258 Mid
= (Low
+ High
) >> 1;
261 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
279 /* Check if we couldn't find it */
280 if (High
< Low
) return NULL
;
282 /* Otherwise, this is the ordinal */
283 Ordinal
= OrdinalTable
[Mid
];
285 /* Resolve the address and write it */
286 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
287 ExportDirectory
->AddressOfFunctions
);
288 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
291 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
292 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
298 MiLocateExportName(IN PVOID DllBase
,
302 PUSHORT OrdinalTable
;
303 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
304 LONG Low
= 0, Mid
= 0, High
, Ret
;
311 /* Get the export directory */
312 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
314 IMAGE_DIRECTORY_ENTRY_EXPORT
,
316 if (!ExportDirectory
) return NULL
;
318 /* Setup name tables */
319 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
320 ExportDirectory
->AddressOfNames
);
321 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
322 ExportDirectory
->AddressOfNameOrdinals
);
324 /* Do a binary search */
325 High
= ExportDirectory
->NumberOfNames
- 1;
328 /* Get new middle value */
329 Mid
= (Low
+ High
) >> 1;
332 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
350 /* Check if we couldn't find it */
351 if (High
< Low
) return NULL
;
353 /* Otherwise, this is the ordinal */
354 Ordinal
= OrdinalTable
[Mid
];
356 /* Resolve the address and write it */
357 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
358 ExportDirectory
->AddressOfFunctions
);
359 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
361 /* Check if the function is actually a forwarder */
362 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
363 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
375 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
376 IN PLIST_ENTRY ListHead
)
378 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
379 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
380 PMM_DLL_INITIALIZE DllInit
;
381 UNICODE_STRING RegPath
, ImportName
;
384 /* Try to see if the image exports a DllInitialize routine */
385 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
387 if (!DllInit
) return STATUS_SUCCESS
;
389 /* Do a temporary copy of BaseDllName called ImportName
390 * because we'll alter the length of the string
392 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
393 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
394 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
396 /* Obtain the path to this dll's service in the registry */
397 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
398 ImportName
.Length
+ sizeof(UNICODE_NULL
);
399 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
400 RegPath
.MaximumLength
,
403 /* Check if this allocation was unsuccessful */
404 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
406 /* Build and append the service name itself */
407 RegPath
.Length
= ServicesKeyName
.Length
;
408 RtlCopyMemory(RegPath
.Buffer
,
409 ServicesKeyName
.Buffer
,
410 ServicesKeyName
.Length
);
412 /* Check if there is a dot in the filename */
413 if (wcschr(ImportName
.Buffer
, L
'.'))
415 /* Remove the extension */
416 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
417 ImportName
.Buffer
) * sizeof(WCHAR
);
420 /* Append service name (the basename without extension) */
421 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
423 /* Now call the DllInit func */
424 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
425 Status
= DllInit(&RegPath
);
428 ExFreePool(RegPath
.Buffer
);
430 /* Return status value which DllInitialize returned */
436 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
441 /* Acquire module list lock */
442 KeEnterCriticalRegion();
443 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
445 /* Acquire the spinlock too as we will insert or remove the entry */
446 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
448 /* Insert or remove from the list */
449 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
450 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
453 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
454 ExReleaseResourceLite(&PsLoadedModuleResource
);
455 KeLeaveCriticalRegion();
460 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
465 ULONG_PTR OldBaseTop
, Delta
;
466 PLDR_DATA_TABLE_ENTRY LdrEntry
;
467 PLIST_ENTRY NextEntry
;
469 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
472 /* Calculate the top and delta */
473 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
474 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
476 /* Loop the loader block */
477 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
478 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
479 NextEntry
= NextEntry
->Flink
)
481 /* Get the loader entry */
482 LdrEntry
= CONTAINING_RECORD(NextEntry
,
483 LDR_DATA_TABLE_ENTRY
,
486 /* Get the import table */
487 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
489 IMAGE_DIRECTORY_ENTRY_IMPORT
,
491 if (!ImportDescriptor
) continue;
493 /* Make sure we have an IAT */
494 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
495 while ((ImportDescriptor
->Name
) &&
496 (ImportDescriptor
->OriginalFirstThunk
))
498 /* Get the image thunk */
499 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
500 ImportDescriptor
->FirstThunk
);
503 /* Check if it's within this module */
504 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
507 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
508 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
509 *ImageThunk
+= Delta
;
512 /* Go to the next thunk */
516 /* Go to the next import */
524 MiSnapThunk(IN PVOID DllBase
,
526 IN PIMAGE_THUNK_DATA Name
,
527 IN PIMAGE_THUNK_DATA Address
,
528 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
530 IN BOOLEAN SnapForwarder
,
531 OUT PCHAR
*MissingApi
)
536 PUSHORT OrdinalTable
;
537 PIMAGE_IMPORT_BY_NAME NameImport
;
539 ULONG Low
= 0, Mid
= 0, High
;
542 PCHAR MissingForwarder
;
543 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
546 UNICODE_STRING ForwarderName
;
547 PLIST_ENTRY NextEntry
;
548 PLDR_DATA_TABLE_ENTRY LdrEntry
;
549 ULONG ForwardExportSize
;
550 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
551 PIMAGE_IMPORT_BY_NAME ForwardName
;
553 IMAGE_THUNK_DATA ForwardThunk
;
556 /* Check if this is an ordinal */
557 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
558 if ((IsOrdinal
) && !(SnapForwarder
))
560 /* Get the ordinal number and set it as missing */
561 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
562 ExportDirectory
->Base
);
563 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
567 /* Get the VA if we don't have to snap */
568 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
569 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
571 /* Copy the procedure name */
573 (PCHAR
)&NameImport
->Name
[0],
574 MAXIMUM_FILENAME_LENGTH
- 1);
576 /* Setup name tables */
577 DPRINT("Import name: %s\n", NameImport
->Name
);
578 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
579 ExportDirectory
->AddressOfNames
);
580 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
581 ExportDirectory
->AddressOfNameOrdinals
);
583 /* Get the hint and check if it's valid */
584 Hint
= NameImport
->Hint
;
585 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
586 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
588 /* We have a match, get the ordinal number from here */
589 Ordinal
= OrdinalTable
[Hint
];
593 /* Do a binary search */
594 High
= ExportDirectory
->NumberOfNames
- 1;
597 /* Get new middle value */
598 Mid
= (Low
+ High
) >> 1;
601 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
619 /* Check if we couldn't find it */
620 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
622 /* Otherwise, this is the ordinal */
623 Ordinal
= OrdinalTable
[Mid
];
627 /* Check if the ordinal is invalid */
628 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
631 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
635 /* In case the forwarder is missing */
636 MissingForwarder
= NameBuffer
;
638 /* Resolve the address and write it */
639 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
640 ExportDirectory
->AddressOfFunctions
);
641 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
643 /* Assume success from now on */
644 Status
= STATUS_SUCCESS
;
646 /* Check if the function is actually a forwarder */
647 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
648 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
650 /* Now assume failure in case the forwarder doesn't exist */
651 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
653 /* Build the forwarder name */
654 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
655 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
658 DllName
.MaximumLength
= DllName
.Length
;
661 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
665 /* We failed, just return an error */
669 /* Loop the module list */
670 NextEntry
= PsLoadedModuleList
.Flink
;
671 while (NextEntry
!= &PsLoadedModuleList
)
673 /* Get the loader entry */
674 LdrEntry
= CONTAINING_RECORD(NextEntry
,
675 LDR_DATA_TABLE_ENTRY
,
678 /* Check if it matches */
679 if (RtlPrefixString((PSTRING
)&ForwarderName
,
680 (PSTRING
)&LdrEntry
->BaseDllName
,
683 /* Get the forwarder export directory */
684 ForwardExportDirectory
=
685 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
687 IMAGE_DIRECTORY_ENTRY_EXPORT
,
689 if (!ForwardExportDirectory
) break;
691 /* Allocate a name entry */
692 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
694 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
695 sizeof(*ForwardName
) +
698 if (!ForwardName
) break;
701 RtlCopyMemory(&ForwardName
->Name
[0],
702 DllName
.Buffer
+ DllName
.Length
,
704 ForwardName
->Hint
= 0;
706 /* Set the new address */
707 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
709 /* Snap the forwarder */
710 Status
= MiSnapThunk(LdrEntry
->DllBase
,
714 ForwardExportDirectory
,
719 /* Free the forwarder name and set the thunk */
720 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
721 Address
->u1
= ForwardThunk
.u1
;
725 /* Go to the next entry */
726 NextEntry
= NextEntry
->Flink
;
730 RtlFreeUnicodeString(&ForwarderName
);
740 MmUnloadSystemImage(IN PVOID ImageHandle
)
742 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
743 PVOID BaseAddress
= LdrEntry
->DllBase
;
746 BOOLEAN HadEntry
= FALSE
;
748 /* Acquire the loader lock */
749 KeEnterCriticalRegion();
750 KeWaitForSingleObject(&MmSystemLoadLock
,
756 /* Check if this driver was loaded at boot and didn't get imports parsed */
757 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
759 /* We should still be alive */
760 ASSERT(LdrEntry
->LoadCount
!= 0);
761 LdrEntry
->LoadCount
--;
763 /* Check if we're still loaded */
764 if (LdrEntry
->LoadCount
) goto Done
;
766 /* We should cleanup... are symbols loaded */
767 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
769 /* Create the ANSI name */
770 Status
= RtlUnicodeStringToAnsiString(&TempName
,
771 &LdrEntry
->BaseDllName
,
773 if (NT_SUCCESS(Status
))
775 /* Unload the symbols */
776 DbgUnLoadImageSymbols(&TempName
,
778 (ULONG_PTR
)ZwCurrentProcess());
779 RtlFreeAnsiString(&TempName
);
783 /* FIXME: Free the driver */
784 //MmFreeSection(LdrEntry->DllBase);
786 /* Check if we're linked in */
787 if (LdrEntry
->InLoadOrderLinks
.Flink
)
790 MiProcessLoaderEntry(LdrEntry
, FALSE
);
794 /* Dereference and clear the imports */
795 MiDereferenceImports(LdrEntry
->LoadedImports
);
796 MiClearImports(LdrEntry
);
798 /* Check if the entry needs to go away */
801 /* Check if it had a name */
802 if (LdrEntry
->FullDllName
.Buffer
)
805 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
808 /* Check if we had a section */
809 if (LdrEntry
->SectionPointer
)
812 ObDereferenceObject(LdrEntry
->SectionPointer
);
816 ExFreePool(LdrEntry
);
819 /* Release the system lock and return */
821 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
822 KeLeaveCriticalRegion();
823 return STATUS_SUCCESS
;
828 MiResolveImageReferences(IN PVOID ImageBase
,
829 IN PUNICODE_STRING ImageFileDirectory
,
830 IN PUNICODE_STRING NamePrefix OPTIONAL
,
831 OUT PCHAR
*MissingApi
,
832 OUT PWCHAR
*MissingDriver
,
833 OUT PLOAD_IMPORTS
*LoadImports
)
835 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
836 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
837 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
838 PLOAD_IMPORTS LoadedImports
, NewImports
;
839 ULONG GdiLink
, NormalLink
, i
;
840 BOOLEAN ReferenceNeeded
, Loaded
;
841 ANSI_STRING TempString
;
842 UNICODE_STRING NameString
, DllName
;
843 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
844 PVOID ImportBase
, DllBase
;
845 PLIST_ENTRY NextEntry
;
846 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
848 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
850 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
851 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
853 /* Assume no imports */
854 *LoadImports
= (PVOID
)-2;
856 /* Get the import descriptor */
857 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
859 IMAGE_DIRECTORY_ENTRY_IMPORT
,
861 if (!ImportDescriptor
) return STATUS_SUCCESS
;
863 /* Loop all imports to count them */
864 for (CurrentImport
= ImportDescriptor
;
865 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
872 /* Make sure we have non-zero imports */
875 /* Calculate and allocate the list we'll need */
876 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
877 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
883 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
889 LoadedImports
= NULL
;
892 /* Reset the import count and loop descriptors again */
893 ImportCount
= GdiLink
= NormalLink
= 0;
894 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
897 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
899 /* Check if this is a GDI driver */
901 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
903 /* We can also allow dxapi */
904 NormalLink
= NormalLink
|
905 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
906 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
908 /* Check if this is a valid GDI driver */
909 if ((GdiLink
) && (NormalLink
))
911 /* It's not, it's importing stuff it shouldn't be! */
912 MiDereferenceImports(LoadedImports
);
913 if (LoadedImports
) ExFreePool(LoadedImports
);
914 return STATUS_PROCEDURE_NOT_FOUND
;
917 /* Check if this is a "core" import, which doesn't get referenced */
918 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
919 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
920 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
922 /* Don't reference this */
923 ReferenceNeeded
= FALSE
;
927 /* Reference these modules */
928 ReferenceNeeded
= TRUE
;
931 /* Now setup a unicode string for the import */
932 RtlInitAnsiString(&TempString
, ImportName
);
933 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
934 if (!NT_SUCCESS(Status
))
937 MiDereferenceImports(LoadedImports
);
938 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
942 /* We don't support name prefixes yet */
943 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
945 /* Remember that we haven't loaded the import at this point */
950 /* Loop the driver list */
951 NextEntry
= PsLoadedModuleList
.Flink
;
952 while (NextEntry
!= &PsLoadedModuleList
)
954 /* Get the loader entry and compare the name */
955 LdrEntry
= CONTAINING_RECORD(NextEntry
,
956 LDR_DATA_TABLE_ENTRY
,
958 if (RtlEqualUnicodeString(&NameString
,
959 &LdrEntry
->BaseDllName
,
962 /* Get the base address */
963 ImportBase
= LdrEntry
->DllBase
;
965 /* Check if we haven't loaded yet, and we need references */
966 if (!(Loaded
) && (ReferenceNeeded
))
968 /* Make sure we're not already loading */
969 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
971 /* Increase the load count */
972 LdrEntry
->LoadCount
++;
976 /* Done, break out */
980 /* Go to the next entry */
981 NextEntry
= NextEntry
->Flink
;
984 /* Check if we haven't loaded the import yet */
987 /* Setup the import DLL name */
988 DllName
.MaximumLength
= NameString
.Length
+
989 ImageFileDirectory
->Length
+
990 sizeof(UNICODE_NULL
);
991 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
992 DllName
.MaximumLength
,
996 /* Setup the base length and copy it */
997 DllName
.Length
= ImageFileDirectory
->Length
;
998 RtlCopyMemory(DllName
.Buffer
,
999 ImageFileDirectory
->Buffer
,
1000 ImageFileDirectory
->Length
);
1002 /* Now add the import name and null-terminate it */
1003 RtlAppendStringToString((PSTRING
)&DllName
,
1004 (PSTRING
)&NameString
);
1005 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / sizeof(WCHAR
)] = UNICODE_NULL
;
1007 /* Load the image */
1008 Status
= MmLoadSystemImage(&DllName
,
1014 if (NT_SUCCESS(Status
))
1016 /* We can free the DLL Name */
1017 ExFreePool(DllName
.Buffer
);
1021 /* Fill out the information for the error */
1022 *MissingDriver
= DllName
.Buffer
;
1023 *(PULONG
)MissingDriver
|= 1;
1029 /* We're out of resources */
1030 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1033 /* Check if we're OK until now */
1034 if (NT_SUCCESS(Status
))
1036 /* We're now loaded */
1040 ASSERT(DllBase
= DllEntry
->DllBase
);
1042 /* Call the initialization routines */
1043 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1044 if (!NT_SUCCESS(Status
))
1046 /* We failed, unload the image */
1047 MmUnloadSystemImage(DllEntry
);
1053 /* Check if we failed by here */
1054 if (!NT_SUCCESS(Status
))
1056 /* Cleanup and return */
1057 RtlFreeUnicodeString(&NameString
);
1058 MiDereferenceImports(LoadedImports
);
1059 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1063 /* Loop again to make sure that everything is OK */
1067 /* Check if we're support to reference this import */
1068 if ((ReferenceNeeded
) && (LoadedImports
))
1070 /* Make sure we're not already loading */
1071 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1074 LoadedImports
->Entry
[LoadedImports
->Count
] = LdrEntry
;
1075 LoadedImports
->Count
++;
1079 /* Free the import name */
1080 RtlFreeUnicodeString(&NameString
);
1082 /* Set the missing driver name and get the export directory */
1083 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1084 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1086 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1088 if (!ExportDirectory
)
1090 /* Cleanup and return */
1091 MiDereferenceImports(LoadedImports
);
1092 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1093 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1096 /* Make sure we have an IAT */
1097 if (ImportDescriptor
->OriginalFirstThunk
)
1099 /* Get the first thunks */
1100 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1101 ImportDescriptor
->OriginalFirstThunk
);
1102 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1103 ImportDescriptor
->FirstThunk
);
1106 while (OrigThunk
->u1
.AddressOfData
)
1109 Status
= MiSnapThunk(ImportBase
,
1117 if (!NT_SUCCESS(Status
))
1119 /* Cleanup and return */
1120 MiDereferenceImports(LoadedImports
);
1121 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1125 /* Reset the buffer */
1126 *MissingApi
= MissingApiBuffer
;
1130 /* Go to the next import */
1134 /* Check if we have an import list */
1137 /* Reset the count again, and loop entries*/
1139 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1141 if (LoadedImports
->Entry
[i
])
1143 /* Got an entry, OR it with 1 in case it's the single entry */
1144 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1149 /* Check if we had no imports */
1152 /* Free the list and set it to no imports */
1153 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1154 LoadedImports
= (PVOID
)-2;
1156 else if (ImportCount
== 1)
1158 /* Just one entry, we can free the table and only use our entry */
1159 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1160 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1162 else if (ImportCount
!= LoadedImports
->Count
)
1164 /* Allocate a new list */
1165 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1166 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1172 NewImports
->Count
= 0;
1174 /* Loop all the imports */
1175 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1177 /* Make sure it's valid */
1178 if (LoadedImports
->Entry
[i
])
1181 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1182 NewImports
->Count
++;
1186 /* Free the old copy */
1187 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1188 LoadedImports
= NewImports
;
1192 /* Return the list */
1193 *LoadImports
= LoadedImports
;
1196 /* Return success */
1197 return STATUS_SUCCESS
;
1202 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1204 PLIST_ENTRY NextEntry
;
1206 PIMAGE_NT_HEADERS NtHeader
;
1207 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1208 PIMAGE_FILE_HEADER FileHeader
;
1209 BOOLEAN ValidRelocs
;
1210 PIMAGE_DATA_DIRECTORY DataDirectory
;
1211 PVOID DllBase
, NewImageAddress
;
1214 /* Loop driver list */
1215 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1216 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1217 NextEntry
= NextEntry
->Flink
)
1219 /* Get the loader entry and NT header */
1220 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1221 LDR_DATA_TABLE_ENTRY
,
1223 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1226 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1228 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1229 &LdrEntry
->FullDllName
);
1231 /* Skip kernel and HAL */
1232 /* ROS HACK: Skip BOOTVID/KDCOM too */
1234 if (i
<= 4) continue;
1236 /* Skip non-drivers */
1237 if (!NtHeader
) continue;
1239 /* Get the file header and make sure we can relocate */
1240 FileHeader
= &NtHeader
->FileHeader
;
1241 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1242 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1243 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1245 /* Everything made sense until now, check the relocation section too */
1246 DataDirectory
= &NtHeader
->OptionalHeader
.
1247 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1248 if (!DataDirectory
->VirtualAddress
)
1250 /* We don't really have relocations */
1251 ValidRelocs
= FALSE
;
1255 /* Make sure the size is valid */
1256 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1257 LdrEntry
->SizeOfImage
)
1259 /* They're not, skip */
1263 /* We have relocations */
1267 /* Remember the original address */
1268 DllBase
= LdrEntry
->DllBase
;
1270 /* Allocate a virtual section for the module */
1271 NewImageAddress
= MmAllocateSection(LdrEntry
->SizeOfImage
, NULL
);
1272 if (!NewImageAddress
)
1274 /* Shouldn't happen */
1275 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1280 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1281 ASSERT(ExpInitializationPhase
== 0);
1283 /* Now copy the entire driver over */
1284 RtlCopyMemory(NewImageAddress
, DllBase
, LdrEntry
->SizeOfImage
);
1287 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1289 /* Set the image base to the address where the loader put it */
1290 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1291 NtHeader
= RtlImageNtHeader(NewImageAddress
);
1292 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1294 /* Check if we had relocations */
1297 /* Relocate the image */
1298 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1302 STATUS_CONFLICTING_ADDRESSES
,
1303 STATUS_INVALID_IMAGE_FORMAT
);
1304 if (!NT_SUCCESS(Status
))
1306 /* This shouldn't happen */
1307 DPRINT1("Relocations failed!\n");
1312 /* Update the loader entry */
1313 LdrEntry
->DllBase
= NewImageAddress
;
1315 /* Update the thunks */
1316 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1317 MiUpdateThunks(LoaderBlock
,
1320 LdrEntry
->SizeOfImage
);
1322 /* Update the loader entry */
1323 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1324 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1325 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1326 LdrEntry
->SizeOfImage
= LdrEntry
->SizeOfImage
;
1328 /* Free the old copy */
1329 MiFreeBootDriverMemory(DllBase
, LdrEntry
->SizeOfImage
);
1335 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1337 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1338 PLIST_ENTRY ListHead
, NextEntry
;
1341 /* Setup the loaded module list and locks */
1342 ExInitializeResourceLite(&PsLoadedModuleResource
);
1343 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1344 InitializeListHead(&PsLoadedModuleList
);
1346 /* Get loop variables and the kernel entry */
1347 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1348 NextEntry
= ListHead
->Flink
;
1349 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1350 LDR_DATA_TABLE_ENTRY
,
1352 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1354 /* Loop the loader block */
1355 while (NextEntry
!= ListHead
)
1357 /* Get the loader entry */
1358 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1359 LDR_DATA_TABLE_ENTRY
,
1362 /* FIXME: ROS HACK. Make sure this is a driver */
1363 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1365 /* Skip this entry */
1366 NextEntry
= NextEntry
->Flink
;
1370 /* Calculate the size we'll need and allocate a copy */
1371 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1372 LdrEntry
->BaseDllName
.MaximumLength
+
1373 sizeof(UNICODE_NULL
);
1374 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1375 if (!NewEntry
) return FALSE
;
1377 /* Copy the entry over */
1378 *NewEntry
= *LdrEntry
;
1380 /* Allocate the name */
1381 NewEntry
->FullDllName
.Buffer
=
1382 ExAllocatePoolWithTag(PagedPool
,
1383 LdrEntry
->FullDllName
.MaximumLength
+
1384 sizeof(UNICODE_NULL
),
1386 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1388 /* Set the base name */
1389 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1391 /* Copy the full and base name */
1392 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1393 LdrEntry
->FullDllName
.Buffer
,
1394 LdrEntry
->FullDllName
.MaximumLength
);
1395 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1396 LdrEntry
->BaseDllName
.Buffer
,
1397 LdrEntry
->BaseDllName
.MaximumLength
);
1399 /* Null-terminate the base name */
1400 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1401 sizeof(WCHAR
)] = UNICODE_NULL
;
1403 /* Insert the entry into the list */
1404 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1405 NextEntry
= NextEntry
->Flink
;
1408 /* Build the import lists for the boot drivers */
1409 //MiBuildImportsForBootDrivers();
1417 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1419 PIMAGE_NT_HEADERS NtHeader
;
1422 /* Get NT Headers */
1423 NtHeader
= RtlImageNtHeader(BaseAddress
);
1426 /* Check if this image is only safe for UP while we have 2+ CPUs */
1427 if ((KeNumberProcessors
> 1) &&
1428 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1435 /* Otherwise, it's safe */
1441 MmCheckSystemImage(IN HANDLE ImageHandle
,
1442 IN BOOLEAN PurgeSection
)
1445 HANDLE SectionHandle
;
1446 PVOID ViewBase
= NULL
;
1447 SIZE_T ViewSize
= 0;
1448 IO_STATUS_BLOCK IoStatusBlock
;
1449 FILE_STANDARD_INFORMATION FileStandardInfo
;
1450 KAPC_STATE ApcState
;
1453 /* Create a section for the DLL */
1454 Status
= ZwCreateSection(&SectionHandle
,
1455 SECTION_MAP_EXECUTE
,
1461 if (!NT_SUCCESS(Status
)) return Status
;
1463 /* Make sure we're in the system process */
1464 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1467 Status
= ZwMapViewOfSection(SectionHandle
,
1477 if (!NT_SUCCESS(Status
))
1479 /* We failed, close the handle and return */
1480 KeUnstackDetachProcess(&ApcState
);
1481 ZwClose(SectionHandle
);
1485 /* Now query image information */
1486 Status
= ZwQueryInformationFile(ImageHandle
,
1489 sizeof(FileStandardInfo
),
1490 FileStandardInformation
);
1491 if ( NT_SUCCESS(Status
) )
1493 /* First, verify the checksum */
1494 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1500 /* Set checksum failure */
1501 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1504 /* Check that it's a valid SMP image if we have more then one CPU */
1505 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1507 /* Otherwise it's not the right image */
1508 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1512 /* Unmap the section, close the handle, and return status */
1513 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1514 KeUnstackDetachProcess(&ApcState
);
1515 ZwClose(SectionHandle
);
1521 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1522 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1523 IN PUNICODE_STRING LoadedName OPTIONAL
,
1525 OUT PVOID
*ModuleObject
,
1526 OUT PVOID
*ImageBaseAddress
)
1528 PVOID ModuleLoadBase
= NULL
;
1530 HANDLE FileHandle
= NULL
;
1531 OBJECT_ATTRIBUTES ObjectAttributes
;
1532 IO_STATUS_BLOCK IoStatusBlock
;
1533 PIMAGE_NT_HEADERS NtHeader
;
1534 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
1535 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1536 ULONG EntrySize
, DriverSize
;
1537 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1538 PCHAR MissingApiName
, Buffer
;
1539 PWCHAR MissingDriverName
;
1540 HANDLE SectionHandle
;
1541 ACCESS_MASK DesiredAccess
;
1542 PVOID Section
= NULL
;
1543 BOOLEAN LockOwned
= FALSE
;
1544 PLIST_ENTRY NextEntry
;
1545 IMAGE_INFO ImageInfo
;
1549 /* Detect session-load */
1553 ASSERT(NamePrefix
== NULL
);
1554 ASSERT(LoadedName
== NULL
);
1556 /* Make sure the process is in session too */
1557 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1560 /* Allocate a buffer we'll use for names */
1561 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1562 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1564 /* Check for a separator */
1565 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1570 /* Loop the path until we get to the base name */
1571 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1572 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1574 /* Get the length */
1575 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1576 BaseLength
*= sizeof(WCHAR
);
1578 /* Setup the string */
1579 BaseName
.Length
= (USHORT
)BaseLength
;
1580 BaseName
.Buffer
= p
;
1584 /* Otherwise, we already have a base name */
1585 BaseName
.Length
= FileName
->Length
;
1586 BaseName
.Buffer
= FileName
->Buffer
;
1589 /* Setup the maximum length */
1590 BaseName
.MaximumLength
= BaseName
.Length
;
1592 /* Now compute the base directory */
1593 BaseDirectory
= *FileName
;
1594 BaseDirectory
.Length
-= BaseName
.Length
;
1595 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1597 /* And the prefix, which for now is just the name itself */
1598 PrefixName
= *FileName
;
1600 /* Check if we have a prefix */
1601 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1603 /* Check if we already have a name, use it instead */
1604 if (LoadedName
) BaseName
= *LoadedName
;
1606 /* Acquire the load lock */
1608 ASSERT(LockOwned
== FALSE
);
1610 KeEnterCriticalRegion();
1611 KeWaitForSingleObject(&MmSystemLoadLock
,
1617 /* Scan the module list */
1618 NextEntry
= PsLoadedModuleList
.Flink
;
1619 while (NextEntry
!= &PsLoadedModuleList
)
1621 /* Get the entry and compare the names */
1622 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1623 LDR_DATA_TABLE_ENTRY
,
1625 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1627 /* Found it, break out */
1632 NextEntry
= NextEntry
->Flink
;
1635 /* Check if we found the image */
1636 if (NextEntry
!= &PsLoadedModuleList
)
1638 /* Check if we had already mapped a section */
1641 /* Dereference and clear */
1642 ObDereferenceObject(Section
);
1646 /* Check if this was supposed to be a session load */
1649 /* It wasn't, so just return the data */
1650 *ModuleObject
= LdrEntry
;
1651 *ImageBaseAddress
= LdrEntry
->DllBase
;
1652 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1656 /* We don't support session loading yet */
1657 DPRINT1("Unsupported Session-Load!\n");
1666 /* It wasn't loaded, and we didn't have a previous attempt */
1667 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1668 KeLeaveCriticalRegion();
1671 /* Check if KD is enabled */
1672 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1674 /* FIXME: Attempt to get image from KD */
1677 /* We don't have a valid entry */
1680 /* Setup image attributes */
1681 InitializeObjectAttributes(&ObjectAttributes
,
1683 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1687 /* Open the image */
1688 Status
= ZwOpenFile(&FileHandle
,
1692 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1694 if (!NT_SUCCESS(Status
)) goto Quickie
;
1697 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1698 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1699 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1700 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1706 /* Check if this is a session-load */
1709 /* Then we only need read and execute */
1710 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1714 /* Otherwise, we can allow write access */
1715 DesiredAccess
= SECTION_ALL_ACCESS
;
1718 /* Initialize the attributes for the section */
1719 InitializeObjectAttributes(&ObjectAttributes
,
1721 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1725 /* Create the section */
1726 Status
= ZwCreateSection(&SectionHandle
,
1733 if (!NT_SUCCESS(Status
)) goto Quickie
;
1735 /* Now get the section pointer */
1736 Status
= ObReferenceObjectByHandle(SectionHandle
,
1737 SECTION_MAP_EXECUTE
,
1738 MmSectionObjectType
,
1742 ZwClose(SectionHandle
);
1743 if (!NT_SUCCESS(Status
)) goto Quickie
;
1745 /* Check if this was supposed to be a session-load */
1748 /* We don't support session loading yet */
1749 DPRINT1("Unsupported Session-Load!\n");
1753 /* Check the loader list again, we should end up in the path below */
1758 /* We don't have a valid entry */
1762 /* Load the image */
1763 Status
= MiLoadImageSection(&Section
,
1768 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1770 /* Get the size of the driver */
1771 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1773 /* Make sure we're not being loaded into session space */
1776 /* Check for success */
1777 if (NT_SUCCESS(Status
))
1779 /* FIXME: Support large pages for drivers */
1782 /* Dereference the section */
1783 ObDereferenceObject(Section
);
1787 /* Get the NT Header */
1788 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1790 /* Relocate the driver */
1791 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1795 STATUS_CONFLICTING_ADDRESSES
,
1796 STATUS_INVALID_IMAGE_FORMAT
);
1797 if (!NT_SUCCESS(Status
)) goto Quickie
;
1799 /* Calculate the size we'll need for the entry and allocate it */
1800 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1802 sizeof(UNICODE_NULL
);
1804 /* Allocate the entry */
1805 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1809 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1813 /* Setup the entry */
1814 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1815 LdrEntry
->LoadCount
= 1;
1816 LdrEntry
->LoadedImports
= LoadedImports
;
1817 LdrEntry
->PatchInformation
= NULL
;
1819 /* Check the version */
1820 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1821 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1823 /* Mark this image as a native image */
1824 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
1827 /* Setup the rest of the entry */
1828 LdrEntry
->DllBase
= ModuleLoadBase
;
1829 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1830 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1831 LdrEntry
->SizeOfImage
= DriverSize
;
1832 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1833 LdrEntry
->SectionPointer
= Section
;
1835 /* Now write the DLL name */
1836 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1837 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1838 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1840 /* Copy and null-terminate it */
1841 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1844 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1846 /* Now allocate the full name */
1847 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1849 sizeof(UNICODE_NULL
),
1851 if (!LdrEntry
->FullDllName
.Buffer
)
1853 /* Don't fail, just set it to zero */
1854 LdrEntry
->FullDllName
.Length
= 0;
1855 LdrEntry
->FullDllName
.MaximumLength
= 0;
1860 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1861 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1863 /* Copy and null-terminate */
1864 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1867 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1871 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1873 /* Resolve imports */
1874 MissingApiName
= Buffer
;
1875 Status
= MiResolveImageReferences(ModuleLoadBase
,
1881 if (!NT_SUCCESS(Status
))
1884 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1886 /* Check if we need to free the name */
1887 if (LdrEntry
->FullDllName
.Buffer
)
1890 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1893 /* Free the entry itself */
1894 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
1899 /* Update the loader entry */
1900 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
1901 LDRP_ENTRY_PROCESSED
|
1903 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
1904 LdrEntry
->LoadedImports
= LoadedImports
;
1906 /* FIXME: Apply driver verifier */
1908 /* FIXME: Write-protect the system image */
1910 /* Check if notifications are enabled */
1911 if (PsImageNotifyEnabled
)
1913 /* Fill out the notification data */
1914 ImageInfo
.Properties
= 0;
1915 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
1916 ImageInfo
.SystemModeImage
= TRUE
;
1917 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
1918 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
1919 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
1921 /* Send the notification */
1922 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
1925 #if defined(KDBG) || defined(_WINKD_)
1926 /* MiCacheImageSymbols doesn't detect rossym */
1929 /* Check if there's symbols */
1930 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
1933 /* Check if the system root is present */
1934 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
1935 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
1937 /* Add the system root */
1938 UnicodeTemp
= PrefixName
;
1939 UnicodeTemp
.Buffer
+= 11;
1940 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
1943 &SharedUserData
->NtSystemRoot
[2],
1948 /* Build the name */
1949 sprintf_nt(Buffer
, "%wZ", &BaseName
);
1952 /* Setup the ansi string */
1953 RtlInitString(&AnsiTemp
, Buffer
);
1955 /* Notify the debugger */
1956 DbgLoadImageSymbols(&AnsiTemp
,
1958 (ULONG_PTR
)ZwCurrentProcess());
1959 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
1962 /* FIXME: Page the driver */
1963 ASSERT(Section
== NULL
);
1965 /* Return pointers */
1966 *ModuleObject
= LdrEntry
;
1967 *ImageBaseAddress
= LdrEntry
->DllBase
;
1970 /* If we have a file handle, close it */
1971 if (FileHandle
) ZwClose(FileHandle
);
1973 /* Check if we have the lock acquired */
1976 /* Release the lock */
1977 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1978 KeLeaveCriticalRegion();
1982 /* Check if we had a prefix */
1983 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1985 /* Free the name buffer and return status */
1986 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
1995 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
1997 PVOID ProcAddress
= NULL
;
1998 ANSI_STRING AnsiRoutineName
;
2000 PLIST_ENTRY NextEntry
;
2001 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2002 BOOLEAN Found
= FALSE
;
2003 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
2004 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
2007 /* Convert routine to ansi name */
2008 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
2011 if (!NT_SUCCESS(Status
)) return NULL
;
2014 KeEnterCriticalRegion();
2015 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
2017 /* Loop the loaded module list */
2018 NextEntry
= PsLoadedModuleList
.Flink
;
2019 while (NextEntry
!= &PsLoadedModuleList
)
2022 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2023 LDR_DATA_TABLE_ENTRY
,
2026 /* Check if it's the kernel or HAL */
2027 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
2033 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
2040 /* Check if we found a valid binary */
2043 /* Find the procedure name */
2044 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
2047 /* Break out if we found it or if we already tried both modules */
2048 if (ProcAddress
) break;
2049 if (Modules
== 2) break;
2053 NextEntry
= NextEntry
->Flink
;
2056 /* Release the lock */
2057 ExReleaseResourceLite(&PsLoadedModuleResource
);
2058 KeLeaveCriticalRegion();
2060 /* Free the string and return */
2061 RtlFreeAnsiString(&AnsiRoutineName
);