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 KSPIN_LOCK PsLoadedModuleSpinLock
;
32 ULONG PsNtosImageBase
;
33 KMUTANT MmSystemLoadLock
;
34 extern ULONG NtGlobalFlag
;
36 /* FUNCTIONS *****************************************************************/
40 MiCacheImageSymbols(IN PVOID BaseAddress
)
43 PVOID DebugDirectory
= NULL
;
46 /* Make sure it's safe to access the image */
49 /* Get the debug directory */
50 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
52 IMAGE_DIRECTORY_ENTRY_DEBUG
,
55 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
61 /* Return the directory */
62 return DebugDirectory
;
67 MiFreeBootDriverMemory(PVOID BaseAddress
,
73 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
76 MmDeleteVirtualMapping(NULL
,
77 (PVOID
)((ULONG_PTR
)BaseAddress
+ i
* PAGE_SIZE
),
86 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
88 IN PUNICODE_STRING FileName
,
89 IN BOOLEAN SessionLoad
,
90 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
92 PROS_SECTION_OBJECT Section
= *SectionPtr
;
98 LARGE_INTEGER SectionOffset
= {{0, 0}};
99 BOOLEAN LoadSymbols
= FALSE
;
104 /* Detect session load */
108 DPRINT1("Session loading not yet supported!\n");
112 /* Not session load, shouldn't have an entry */
113 ASSERT(LdrEntry
== NULL
);
115 /* Attach to the system process */
116 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
118 /* Check if we need to load symbols */
119 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
123 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
127 Process
= PsGetCurrentProcess();
128 Status
= MmMapViewOfSection(Section
,
139 /* Re-enable the flag */
140 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
142 /* Check if we failed with distinguished status code */
143 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
145 /* Change it to something more generic */
146 Status
= STATUS_INVALID_IMAGE_FORMAT
;
149 /* Now check if we failed */
150 if (!NT_SUCCESS(Status
))
152 /* Detach and return */
153 KeUnstackDetachProcess(&ApcState
);
157 /* Get the driver size */
158 DriverSize
= Section
->ImageSection
->ImageSize
;
160 /* Allocate a virtual section for the module */
161 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
162 *ImageBase
= DriverBase
;
165 RtlCopyMemory(DriverBase
, Base
, DriverSize
);
167 /* Now unmap the view */
168 Status
= MmUnmapViewOfSection(Process
, Base
);
169 ASSERT(NT_SUCCESS(Status
));
171 /* Detach and return status */
172 KeUnstackDetachProcess(&ApcState
);
178 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
182 /* Check if there's no imports or if we're a boot driver */
183 if ((ImportList
== (PVOID
)-1) ||
184 (ImportList
== (PVOID
)-2) ||
185 (ImportList
->Count
== 0))
187 /* Then there's nothing to do */
188 return STATUS_SUCCESS
;
191 /* Otherwise, FIXME */
192 DPRINT1("%u imports not dereferenced!\n", ImportList
->Count
);
193 for (i
= 0; i
< ImportList
->Count
; i
++)
195 DPRINT1("%wZ <%wZ>\n", &ImportList
->Entry
[i
]->FullDllName
, &ImportList
->Entry
[i
]->BaseDllName
);
197 return STATUS_UNSUCCESSFUL
;
202 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
206 /* Check if there's no imports or we're a boot driver or only one entry */
207 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
208 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
209 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
215 /* Otherwise, free the import list */
216 ExFreePool(LdrEntry
->LoadedImports
);
221 MiFindExportedRoutineByName(IN PVOID DllBase
,
222 IN PANSI_STRING ExportName
)
225 PUSHORT OrdinalTable
;
226 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
227 LONG Low
= 0, Mid
= 0, High
, Ret
;
234 /* Get the export directory */
235 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
237 IMAGE_DIRECTORY_ENTRY_EXPORT
,
239 if (!ExportDirectory
) return NULL
;
241 /* Setup name tables */
242 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
243 ExportDirectory
->AddressOfNames
);
244 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
245 ExportDirectory
->AddressOfNameOrdinals
);
247 /* Do a binary search */
248 High
= ExportDirectory
->NumberOfNames
- 1;
251 /* Get new middle value */
252 Mid
= (Low
+ High
) >> 1;
255 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
273 /* Check if we couldn't find it */
274 if (High
< Low
) return NULL
;
276 /* Otherwise, this is the ordinal */
277 Ordinal
= OrdinalTable
[Mid
];
279 /* Resolve the address and write it */
280 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
281 ExportDirectory
->AddressOfFunctions
);
282 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
285 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
286 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
292 MiLocateExportName(IN PVOID DllBase
,
296 PUSHORT OrdinalTable
;
297 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
298 LONG Low
= 0, Mid
= 0, High
, Ret
;
305 /* Get the export directory */
306 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
308 IMAGE_DIRECTORY_ENTRY_EXPORT
,
310 if (!ExportDirectory
) return NULL
;
312 /* Setup name tables */
313 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
314 ExportDirectory
->AddressOfNames
);
315 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
316 ExportDirectory
->AddressOfNameOrdinals
);
318 /* Do a binary search */
319 High
= ExportDirectory
->NumberOfNames
- 1;
322 /* Get new middle value */
323 Mid
= (Low
+ High
) >> 1;
326 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
344 /* Check if we couldn't find it */
345 if (High
< Low
) return NULL
;
347 /* Otherwise, this is the ordinal */
348 Ordinal
= OrdinalTable
[Mid
];
350 /* Resolve the address and write it */
351 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
352 ExportDirectory
->AddressOfFunctions
);
353 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
355 /* Check if the function is actually a forwarder */
356 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
357 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
369 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
370 IN PLIST_ENTRY ListHead
)
372 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
373 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
374 PMM_DLL_INITIALIZE DllInit
;
375 UNICODE_STRING RegPath
, ImportName
;
378 /* Try to see if the image exports a DllInitialize routine */
379 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
381 if (!DllInit
) return STATUS_SUCCESS
;
383 /* Do a temporary copy of BaseDllName called ImportName
384 * because we'll alter the length of the string
386 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
387 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
388 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
390 /* Obtain the path to this dll's service in the registry */
391 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
392 ImportName
.Length
+ sizeof(UNICODE_NULL
);
393 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
394 RegPath
.MaximumLength
,
397 /* Check if this allocation was unsuccessful */
398 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
400 /* Build and append the service name itself */
401 RegPath
.Length
= ServicesKeyName
.Length
;
402 RtlCopyMemory(RegPath
.Buffer
,
403 ServicesKeyName
.Buffer
,
404 ServicesKeyName
.Length
);
406 /* Check if there is a dot in the filename */
407 if (wcschr(ImportName
.Buffer
, L
'.'))
409 /* Remove the extension */
410 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
411 ImportName
.Buffer
) * sizeof(WCHAR
);
414 /* Append service name (the basename without extension) */
415 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
417 /* Now call the DllInit func */
418 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
419 Status
= DllInit(&RegPath
);
422 ExFreePool(RegPath
.Buffer
);
424 /* Return status value which DllInitialize returned */
430 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
435 /* Acquire the lock */
436 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
438 /* Insert or remove from the list */
439 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
440 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
442 /* Release the lock */
443 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
448 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
453 ULONG_PTR OldBaseTop
, Delta
;
454 PLDR_DATA_TABLE_ENTRY LdrEntry
;
455 PLIST_ENTRY NextEntry
;
457 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
460 /* Calculate the top and delta */
461 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
462 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
464 /* Loop the loader block */
465 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
466 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
467 NextEntry
= NextEntry
->Flink
)
469 /* Get the loader entry */
470 LdrEntry
= CONTAINING_RECORD(NextEntry
,
471 LDR_DATA_TABLE_ENTRY
,
474 /* Get the import table */
475 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
477 IMAGE_DIRECTORY_ENTRY_IMPORT
,
479 if (!ImportDescriptor
) continue;
481 /* Make sure we have an IAT */
482 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
483 while ((ImportDescriptor
->Name
) &&
484 (ImportDescriptor
->OriginalFirstThunk
))
486 /* Get the image thunk */
487 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
488 ImportDescriptor
->FirstThunk
);
491 /* Check if it's within this module */
492 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
495 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
496 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
497 *ImageThunk
+= Delta
;
500 /* Go to the next thunk */
504 /* Go to the next import */
512 MiSnapThunk(IN PVOID DllBase
,
514 IN PIMAGE_THUNK_DATA Name
,
515 IN PIMAGE_THUNK_DATA Address
,
516 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
518 IN BOOLEAN SnapForwarder
,
519 OUT PCHAR
*MissingApi
)
524 PUSHORT OrdinalTable
;
525 PIMAGE_IMPORT_BY_NAME NameImport
;
527 ULONG Low
= 0, Mid
= 0, High
;
530 PCHAR MissingForwarder
;
531 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
534 UNICODE_STRING ForwarderName
;
535 PLIST_ENTRY NextEntry
;
536 PLDR_DATA_TABLE_ENTRY LdrEntry
;
537 ULONG ForwardExportSize
;
538 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
539 PIMAGE_IMPORT_BY_NAME ForwardName
;
541 IMAGE_THUNK_DATA ForwardThunk
;
544 /* Check if this is an ordinal */
545 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
546 if ((IsOrdinal
) && !(SnapForwarder
))
548 /* Get the ordinal number and set it as missing */
549 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
550 ExportDirectory
->Base
);
551 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
555 /* Get the VA if we don't have to snap */
556 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
557 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
559 /* Copy the procedure name */
561 (PCHAR
)&NameImport
->Name
[0],
562 MAXIMUM_FILENAME_LENGTH
- 1);
564 /* Setup name tables */
565 DPRINT("Import name: %s\n", NameImport
->Name
);
566 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
567 ExportDirectory
->AddressOfNames
);
568 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
569 ExportDirectory
->AddressOfNameOrdinals
);
571 /* Get the hint and check if it's valid */
572 Hint
= NameImport
->Hint
;
573 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
574 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
576 /* We have a match, get the ordinal number from here */
577 Ordinal
= OrdinalTable
[Hint
];
581 /* Do a binary search */
582 High
= ExportDirectory
->NumberOfNames
- 1;
585 /* Get new middle value */
586 Mid
= (Low
+ High
) >> 1;
589 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
607 /* Check if we couldn't find it */
608 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
610 /* Otherwise, this is the ordinal */
611 Ordinal
= OrdinalTable
[Mid
];
615 /* Check if the ordinal is invalid */
616 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
619 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
623 /* In case the forwarder is missing */
624 MissingForwarder
= NameBuffer
;
626 /* Resolve the address and write it */
627 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
628 ExportDirectory
->AddressOfFunctions
);
629 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
631 /* Assume success from now on */
632 Status
= STATUS_SUCCESS
;
634 /* Check if the function is actually a forwarder */
635 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
636 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
638 /* Now assume failure in case the forwarder doesn't exist */
639 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
641 /* Build the forwarder name */
642 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
643 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
646 DllName
.MaximumLength
= DllName
.Length
;
649 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
653 /* We failed, just return an error */
657 /* Loop the module list */
658 NextEntry
= PsLoadedModuleList
.Flink
;
659 while (NextEntry
!= &PsLoadedModuleList
)
661 /* Get the loader entry */
662 LdrEntry
= CONTAINING_RECORD(NextEntry
,
663 LDR_DATA_TABLE_ENTRY
,
666 /* Check if it matches */
667 if (RtlPrefixString((PSTRING
)&ForwarderName
,
668 (PSTRING
)&LdrEntry
->BaseDllName
,
671 /* Get the forwarder export directory */
672 ForwardExportDirectory
=
673 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
675 IMAGE_DIRECTORY_ENTRY_EXPORT
,
677 if (!ForwardExportDirectory
) break;
679 /* Allocate a name entry */
680 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
682 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
683 sizeof(*ForwardName
) +
686 if (!ForwardName
) break;
689 RtlCopyMemory(&ForwardName
->Name
[0],
690 DllName
.Buffer
+ DllName
.Length
,
692 ForwardName
->Hint
= 0;
694 /* Set the new address */
695 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
697 /* Snap the forwarder */
698 Status
= MiSnapThunk(LdrEntry
->DllBase
,
702 ForwardExportDirectory
,
707 /* Free the forwarder name and set the thunk */
708 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
709 Address
->u1
= ForwardThunk
.u1
;
713 /* Go to the next entry */
714 NextEntry
= NextEntry
->Flink
;
718 RtlFreeUnicodeString(&ForwarderName
);
728 MmUnloadSystemImage(IN PVOID ImageHandle
)
730 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
731 PVOID BaseAddress
= LdrEntry
->DllBase
;
733 ANSI_STRING TempName
;
734 BOOLEAN HadEntry
= FALSE
;
736 /* Acquire the loader lock */
737 KeEnterCriticalRegion();
738 KeWaitForSingleObject(&MmSystemLoadLock
,
744 /* Check if this driver was loaded at boot and didn't get imports parsed */
745 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
747 /* We should still be alive */
748 ASSERT(LdrEntry
->LoadCount
!= 0);
749 LdrEntry
->LoadCount
--;
751 /* Check if we're still loaded */
752 if (LdrEntry
->LoadCount
) goto Done
;
754 /* We should cleanup... are symbols loaded */
755 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
757 /* Create the ANSI name */
758 Status
= RtlUnicodeStringToAnsiString(&TempName
,
759 &LdrEntry
->BaseDllName
,
761 if (NT_SUCCESS(Status
))
763 /* Unload the symbols */
764 DbgUnLoadImageSymbols(&TempName
, BaseAddress
, -1);
765 RtlFreeAnsiString(&TempName
);
769 /* FIXME: Free the driver */
770 //MmFreeSection(LdrEntry->DllBase);
772 /* Check if we're linked in */
773 if (LdrEntry
->InLoadOrderLinks
.Flink
)
776 MiProcessLoaderEntry(LdrEntry
, FALSE
);
780 /* Dereference and clear the imports */
781 MiDereferenceImports(LdrEntry
->LoadedImports
);
782 MiClearImports(LdrEntry
);
784 /* Check if the entry needs to go away */
787 /* Check if it had a name */
788 if (LdrEntry
->FullDllName
.Buffer
)
791 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
794 /* Check if we had a section */
795 if (LdrEntry
->SectionPointer
)
798 ObDereferenceObject(LdrEntry
->SectionPointer
);
802 ExFreePool(LdrEntry
);
805 /* Release the system lock and return */
807 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
808 KeLeaveCriticalRegion();
809 return STATUS_SUCCESS
;
814 MiResolveImageReferences(IN PVOID ImageBase
,
815 IN PUNICODE_STRING ImageFileDirectory
,
816 IN PUNICODE_STRING NamePrefix OPTIONAL
,
817 OUT PCHAR
*MissingApi
,
818 OUT PWCHAR
*MissingDriver
,
819 OUT PLOAD_IMPORTS
*LoadImports
)
821 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
822 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
823 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
824 PLOAD_IMPORTS LoadedImports
, NewImports
;
825 ULONG GdiLink
, NormalLink
, i
;
826 BOOLEAN ReferenceNeeded
, Loaded
;
827 ANSI_STRING TempString
;
828 UNICODE_STRING NameString
, DllName
;
829 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
830 PVOID ImportBase
, DllBase
;
831 PLIST_ENTRY NextEntry
;
832 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
834 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
836 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
837 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
839 /* Assume no imports */
840 *LoadImports
= (PVOID
)-2;
842 /* Get the import descriptor */
843 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
845 IMAGE_DIRECTORY_ENTRY_IMPORT
,
847 if (!ImportDescriptor
) return STATUS_SUCCESS
;
849 /* Loop all imports to count them */
850 for (CurrentImport
= ImportDescriptor
;
851 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
858 /* Make sure we have non-zero imports */
861 /* Calculate and allocate the list we'll need */
862 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
863 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
869 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
875 LoadedImports
= NULL
;
878 /* Reset the import count and loop descriptors again */
879 ImportCount
= GdiLink
= NormalLink
= 0;
880 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
883 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
885 /* Check if this is a GDI driver */
887 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
889 /* We can also allow dxapi */
890 NormalLink
= NormalLink
|
891 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
892 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
894 /* Check if this is a valid GDI driver */
895 if ((GdiLink
) && (NormalLink
))
897 /* It's not, it's importing stuff it shouldn't be! */
898 MiDereferenceImports(LoadedImports
);
899 if (LoadedImports
) ExFreePool(LoadedImports
);
900 return STATUS_PROCEDURE_NOT_FOUND
;
903 /* Check if this is a "core" import, which doesn't get referenced */
904 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
905 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
906 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
908 /* Don't reference this */
909 ReferenceNeeded
= FALSE
;
913 /* Reference these modules */
914 ReferenceNeeded
= TRUE
;
917 /* Now setup a unicode string for the import */
918 RtlInitAnsiString(&TempString
, ImportName
);
919 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
920 if (!NT_SUCCESS(Status
))
923 MiDereferenceImports(LoadedImports
);
924 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
928 /* We don't support name prefixes yet */
929 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
931 /* Remember that we haven't loaded the import at this point */
936 /* Loop the driver list */
937 NextEntry
= PsLoadedModuleList
.Flink
;
938 while (NextEntry
!= &PsLoadedModuleList
)
940 /* Get the loader entry and compare the name */
941 LdrEntry
= CONTAINING_RECORD(NextEntry
,
942 LDR_DATA_TABLE_ENTRY
,
944 if (RtlEqualUnicodeString(&NameString
,
945 &LdrEntry
->BaseDllName
,
948 /* Get the base address */
949 ImportBase
= LdrEntry
->DllBase
;
951 /* Check if we haven't loaded yet, and we need references */
952 if (!(Loaded
) && (ReferenceNeeded
))
954 /* Make sure we're not already loading */
955 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
957 /* Increase the load count */
958 LdrEntry
->LoadCount
++;
962 /* Done, break out */
966 /* Go to the next entry */
967 NextEntry
= NextEntry
->Flink
;
970 /* Check if we haven't loaded the import yet */
973 /* Setup the import DLL name */
974 DllName
.MaximumLength
= NameString
.Length
+
975 ImageFileDirectory
->Length
+
976 sizeof(UNICODE_NULL
);
977 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
978 DllName
.MaximumLength
,
982 /* Setup the base length and copy it */
983 DllName
.Length
= ImageFileDirectory
->Length
;
984 RtlCopyMemory(DllName
.Buffer
,
985 ImageFileDirectory
->Buffer
,
986 ImageFileDirectory
->Length
);
988 /* Now add the import name and null-terminate it */
989 RtlAppendStringToString((PSTRING
)&DllName
,
990 (PSTRING
)&NameString
);
991 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
994 Status
= MmLoadSystemImage(&DllName
,
1000 if (NT_SUCCESS(Status
))
1002 /* We can free the DLL Name */
1003 ExFreePool(DllName
.Buffer
);
1007 /* Fill out the information for the error */
1008 *MissingDriver
= DllName
.Buffer
;
1009 *(PULONG
)MissingDriver
|= 1;
1015 /* We're out of resources */
1016 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1019 /* Check if we're OK until now */
1020 if (NT_SUCCESS(Status
))
1022 /* We're now loaded */
1026 ASSERT(DllBase
= DllEntry
->DllBase
);
1028 /* Call the initialization routines */
1029 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1030 if (!NT_SUCCESS(Status
))
1032 /* We failed, unload the image */
1033 MmUnloadSystemImage(DllEntry
);
1039 /* Check if we failed by here */
1040 if (!NT_SUCCESS(Status
))
1042 /* Cleanup and return */
1043 RtlFreeUnicodeString(&NameString
);
1044 MiDereferenceImports(LoadedImports
);
1045 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1049 /* Loop again to make sure that everything is OK */
1053 /* Check if we're support to reference this import */
1054 if ((ReferenceNeeded
) && (LoadedImports
))
1056 /* Make sure we're not already loading */
1057 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1060 LoadedImports
->Entry
[LoadedImports
->Count
] = LdrEntry
;
1061 LoadedImports
->Count
++;
1065 /* Free the import name */
1066 RtlFreeUnicodeString(&NameString
);
1068 /* Set the missing driver name and get the export directory */
1069 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1070 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1072 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1074 if (!ExportDirectory
)
1076 /* Cleanup and return */
1077 MiDereferenceImports(LoadedImports
);
1078 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1079 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1082 /* Make sure we have an IAT */
1083 if (ImportDescriptor
->OriginalFirstThunk
)
1085 /* Get the first thunks */
1086 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1087 ImportDescriptor
->OriginalFirstThunk
);
1088 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1089 ImportDescriptor
->FirstThunk
);
1092 while (OrigThunk
->u1
.AddressOfData
)
1095 Status
= MiSnapThunk(ImportBase
,
1103 if (!NT_SUCCESS(Status
))
1105 /* Cleanup and return */
1106 MiDereferenceImports(LoadedImports
);
1107 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1111 /* Reset the buffer */
1112 *MissingApi
= MissingApiBuffer
;
1116 /* Go to the next import */
1120 /* Check if we have an import list */
1123 /* Reset the count again, and loop entries*/
1125 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1127 if (LoadedImports
->Entry
[i
])
1129 /* Got an entry, OR it with 1 in case it's the single entry */
1130 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1135 /* Check if we had no imports */
1138 /* Free the list and set it to no imports */
1139 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1140 LoadedImports
= (PVOID
)-2;
1142 else if (ImportCount
== 1)
1144 /* Just one entry, we can free the table and only use our entry */
1145 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1146 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1148 else if (ImportCount
!= LoadedImports
->Count
)
1150 /* Allocate a new list */
1151 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1152 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1158 NewImports
->Count
= 0;
1160 /* Loop all the imports */
1161 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1163 /* Make sure it's valid */
1164 if (LoadedImports
->Entry
[i
])
1167 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1168 NewImports
->Count
++;
1172 /* Free the old copy */
1173 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1174 LoadedImports
= NewImports
;
1178 /* Return the list */
1179 *LoadImports
= LoadedImports
;
1182 /* Return success */
1183 return STATUS_SUCCESS
;
1188 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1190 PLIST_ENTRY NextEntry
;
1192 PIMAGE_NT_HEADERS NtHeader
;
1193 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1194 PIMAGE_FILE_HEADER FileHeader
;
1195 BOOLEAN ValidRelocs
;
1196 PIMAGE_DATA_DIRECTORY DataDirectory
;
1197 PVOID DllBase
, NewImageAddress
;
1200 /* Loop driver list */
1201 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1202 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1203 NextEntry
= NextEntry
->Flink
)
1205 /* Get the loader entry and NT header */
1206 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1207 LDR_DATA_TABLE_ENTRY
,
1209 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1212 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1214 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1215 &LdrEntry
->FullDllName
);
1217 /* Skip kernel and HAL */
1218 /* ROS HACK: Skip BOOTVID/KDCOM too */
1220 if (i
<= 4) continue;
1222 /* Skip non-drivers */
1223 if (!NtHeader
) continue;
1225 /* Get the file header and make sure we can relocate */
1226 FileHeader
= &NtHeader
->FileHeader
;
1227 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1228 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1229 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1231 /* Everything made sense until now, check the relocation section too */
1232 DataDirectory
= &NtHeader
->OptionalHeader
.
1233 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1234 if (!DataDirectory
->VirtualAddress
)
1236 /* We don't really have relocations */
1237 ValidRelocs
= FALSE
;
1241 /* Make sure the size is valid */
1242 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1243 LdrEntry
->SizeOfImage
)
1245 /* They're not, skip */
1249 /* We have relocations */
1253 /* Remember the original address */
1254 DllBase
= LdrEntry
->DllBase
;
1256 /* Allocate a virtual section for the module */
1257 NewImageAddress
= MmAllocateSection(LdrEntry
->SizeOfImage
, NULL
);
1258 if (!NewImageAddress
)
1260 /* Shouldn't happen */
1261 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1266 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1267 ASSERT(ExpInitializationPhase
== 0);
1269 /* Now copy the entire driver over */
1270 RtlCopyMemory(NewImageAddress
, DllBase
, LdrEntry
->SizeOfImage
);
1273 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1275 /* Set the image base to the address where the loader put it */
1276 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1277 NtHeader
= RtlImageNtHeader(NewImageAddress
);
1278 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1280 /* Check if we had relocations */
1283 /* Relocate the image */
1284 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1288 STATUS_CONFLICTING_ADDRESSES
,
1289 STATUS_INVALID_IMAGE_FORMAT
);
1290 if (!NT_SUCCESS(Status
))
1292 /* This shouldn't happen */
1293 DPRINT1("Relocations failed!\n");
1298 /* Update the loader entry */
1299 LdrEntry
->DllBase
= NewImageAddress
;
1301 /* Update the thunks */
1302 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1303 MiUpdateThunks(LoaderBlock
,
1306 LdrEntry
->SizeOfImage
);
1308 /* Update the loader entry */
1309 LdrEntry
->Flags
|= 0x01000000;
1310 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1311 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1312 LdrEntry
->SizeOfImage
= LdrEntry
->SizeOfImage
;
1314 /* Free the old copy */
1315 MiFreeBootDriverMemory(DllBase
, LdrEntry
->SizeOfImage
);
1321 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1323 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1324 PLIST_ENTRY ListHead
, NextEntry
;
1327 /* Setup the loaded module list and lock */
1328 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1329 InitializeListHead(&PsLoadedModuleList
);
1331 /* Get loop variables and the kernel entry */
1332 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1333 NextEntry
= ListHead
->Flink
;
1334 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1335 LDR_DATA_TABLE_ENTRY
,
1337 PsNtosImageBase
= (ULONG
)LdrEntry
->DllBase
;
1339 /* Loop the loader block */
1340 while (NextEntry
!= ListHead
)
1342 /* Get the loader entry */
1343 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1344 LDR_DATA_TABLE_ENTRY
,
1347 /* FIXME: ROS HACK. Make sure this is a driver */
1348 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1350 /* Skip this entry */
1351 NextEntry
= NextEntry
->Flink
;
1355 /* Calculate the size we'll need and allocate a copy */
1356 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1357 LdrEntry
->BaseDllName
.MaximumLength
+
1358 sizeof(UNICODE_NULL
);
1359 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1360 if (!NewEntry
) return FALSE
;
1362 /* Copy the entry over */
1363 *NewEntry
= *LdrEntry
;
1365 /* Allocate the name */
1366 NewEntry
->FullDllName
.Buffer
=
1367 ExAllocatePoolWithTag(PagedPool
,
1368 LdrEntry
->FullDllName
.MaximumLength
+
1369 sizeof(UNICODE_NULL
),
1371 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1373 /* Set the base name */
1374 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1376 /* Copy the full and base name */
1377 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1378 LdrEntry
->FullDllName
.Buffer
,
1379 LdrEntry
->FullDllName
.MaximumLength
);
1380 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1381 LdrEntry
->BaseDllName
.Buffer
,
1382 LdrEntry
->BaseDllName
.MaximumLength
);
1384 /* Null-terminate the base name */
1385 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1386 sizeof(WCHAR
)] = UNICODE_NULL
;
1388 /* Insert the entry into the list */
1389 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1390 NextEntry
= NextEntry
->Flink
;
1393 /* Build the import lists for the boot drivers */
1394 //MiBuildImportsForBootDrivers();
1402 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1404 PIMAGE_NT_HEADERS NtHeader
;
1407 /* Get NT Headers */
1408 NtHeader
= RtlImageNtHeader(BaseAddress
);
1411 /* Check if this image is only safe for UP while we have 2+ CPUs */
1412 if ((KeNumberProcessors
> 1) &&
1413 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1420 /* Otherwise, it's safe */
1426 MmCheckSystemImage(IN HANDLE ImageHandle
,
1427 IN BOOLEAN PurgeSection
)
1430 HANDLE SectionHandle
;
1431 PVOID ViewBase
= NULL
;
1432 SIZE_T ViewSize
= 0;
1433 IO_STATUS_BLOCK IoStatusBlock
;
1434 FILE_STANDARD_INFORMATION FileStandardInfo
;
1435 KAPC_STATE ApcState
;
1438 /* Create a section for the DLL */
1439 Status
= ZwCreateSection(&SectionHandle
,
1440 SECTION_MAP_EXECUTE
,
1446 if (!NT_SUCCESS(Status
)) return Status
;
1448 /* Make sure we're in the system process */
1449 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1452 Status
= ZwMapViewOfSection(SectionHandle
,
1462 if (!NT_SUCCESS(Status
))
1464 /* We failed, close the handle and return */
1465 KeUnstackDetachProcess(&ApcState
);
1466 ZwClose(SectionHandle
);
1470 /* Now query image information */
1471 Status
= ZwQueryInformationFile(ImageHandle
,
1474 sizeof(FileStandardInfo
),
1475 FileStandardInformation
);
1476 if ( NT_SUCCESS(Status
) )
1478 /* First, verify the checksum */
1479 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1485 /* Set checksum failure */
1486 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1489 /* Check that it's a valid SMP image if we have more then one CPU */
1490 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1492 /* Otherwise it's not the right image */
1493 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1497 /* Unmap the section, close the handle, and return status */
1498 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1499 KeUnstackDetachProcess(&ApcState
);
1500 ZwClose(SectionHandle
);
1506 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1507 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1508 IN PUNICODE_STRING LoadedName OPTIONAL
,
1510 OUT PVOID
*ModuleObject
,
1511 OUT PVOID
*ImageBaseAddress
)
1513 PVOID ModuleLoadBase
= NULL
;
1515 HANDLE FileHandle
= NULL
;
1516 OBJECT_ATTRIBUTES ObjectAttributes
;
1517 IO_STATUS_BLOCK IoStatusBlock
;
1518 PIMAGE_NT_HEADERS NtHeader
;
1519 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
1520 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1521 ULONG EntrySize
, DriverSize
;
1522 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1523 PCHAR MissingApiName
, Buffer
;
1524 PWCHAR MissingDriverName
;
1525 HANDLE SectionHandle
;
1526 ACCESS_MASK DesiredAccess
;
1527 PVOID Section
= NULL
;
1528 BOOLEAN LockOwned
= FALSE
;
1529 PLIST_ENTRY NextEntry
;
1530 IMAGE_INFO ImageInfo
;
1531 ANSI_STRING AnsiTemp
;
1534 /* Detect session-load */
1538 ASSERT(NamePrefix
== NULL
);
1539 ASSERT(LoadedName
== NULL
);
1541 /* Make sure the process is in session too */
1542 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1545 if (ModuleObject
) *ModuleObject
= NULL
;
1546 if (ImageBaseAddress
) *ImageBaseAddress
= NULL
;
1548 /* Allocate a buffer we'll use for names */
1549 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1550 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1552 /* Check for a separator */
1553 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1558 /* Loop the path until we get to the base name */
1559 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1560 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1562 /* Get the length */
1563 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1564 BaseLength
*= sizeof(WCHAR
);
1566 /* Setup the string */
1567 BaseName
.Length
= (USHORT
)BaseLength
;
1568 BaseName
.Buffer
= p
;
1572 /* Otherwise, we already have a base name */
1573 BaseName
.Length
= FileName
->Length
;
1574 BaseName
.Buffer
= FileName
->Buffer
;
1577 /* Setup the maximum length */
1578 BaseName
.MaximumLength
= BaseName
.Length
;
1580 /* Now compute the base directory */
1581 BaseDirectory
= *FileName
;
1582 BaseDirectory
.Length
-= BaseName
.Length
;
1583 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1585 /* And the prefix, which for now is just the name itself */
1586 PrefixName
= *FileName
;
1588 /* Check if we have a prefix */
1589 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1591 /* Check if we already have a name, use it instead */
1592 if (LoadedName
) BaseName
= *LoadedName
;
1594 /* Acquire the load lock */
1596 ASSERT(LockOwned
== FALSE
);
1598 KeEnterCriticalRegion();
1599 KeWaitForSingleObject(&MmSystemLoadLock
,
1605 /* Scan the module list */
1606 NextEntry
= PsLoadedModuleList
.Flink
;
1607 while (NextEntry
!= &PsLoadedModuleList
)
1609 /* Get the entry and compare the names */
1610 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1611 LDR_DATA_TABLE_ENTRY
,
1613 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1615 /* Found it, break out */
1620 NextEntry
= NextEntry
->Flink
;
1623 /* Check if we found the image */
1624 if (NextEntry
!= &PsLoadedModuleList
)
1626 /* Check if we had already mapped a section */
1629 /* Dereference and clear */
1630 ObDereferenceObject(Section
);
1634 /* Check if this was supposed to be a session load */
1637 /* It wasn't, so just return the data */
1638 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1639 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1640 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1644 /* We don't support session loading yet */
1645 DPRINT1("Unsupported Session-Load!\n");
1654 /* It wasn't loaded, and we didn't have a previous attempt */
1655 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1656 KeLeaveCriticalRegion();
1659 /* Check if KD is enabled */
1660 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1662 /* FIXME: Attempt to get image from KD */
1665 /* We don't have a valid entry */
1668 /* Setup image attributes */
1669 InitializeObjectAttributes(&ObjectAttributes
,
1671 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1675 /* Open the image */
1676 Status
= ZwOpenFile(&FileHandle
,
1680 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1682 if (!NT_SUCCESS(Status
)) goto Quickie
;
1685 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1686 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1687 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1688 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1694 /* Check if this is a session-load */
1697 /* Then we only need read and execute */
1698 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1702 /* Otherwise, we can allow write access */
1703 DesiredAccess
= SECTION_ALL_ACCESS
;
1706 /* Initialize the attributes for the section */
1707 InitializeObjectAttributes(&ObjectAttributes
,
1709 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1713 /* Create the section */
1714 Status
= ZwCreateSection(&SectionHandle
,
1721 if (!NT_SUCCESS(Status
)) goto Quickie
;
1723 /* Now get the section pointer */
1724 Status
= ObReferenceObjectByHandle(SectionHandle
,
1725 SECTION_MAP_EXECUTE
,
1726 MmSectionObjectType
,
1730 ZwClose(SectionHandle
);
1731 if (!NT_SUCCESS(Status
)) goto Quickie
;
1733 /* Check if this was supposed to be a session-load */
1736 /* We don't support session loading yet */
1737 DPRINT1("Unsupported Session-Load!\n");
1741 /* Check the loader list again, we should end up in the path below */
1746 /* We don't have a valid entry */
1750 /* Load the image */
1751 Status
= MiLoadImageSection(&Section
,
1756 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1758 /* Get the size of the driver */
1759 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1761 /* Make sure we're not being loaded into session space */
1764 /* Check for success */
1765 if (NT_SUCCESS(Status
))
1767 /* FIXME: Support large pages for drivers */
1770 /* Dereference the section */
1771 ObDereferenceObject(Section
);
1775 /* Get the NT Header */
1776 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1778 /* Relocate the driver */
1779 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1783 STATUS_CONFLICTING_ADDRESSES
,
1784 STATUS_INVALID_IMAGE_FORMAT
);
1785 if (!NT_SUCCESS(Status
)) goto Quickie
;
1787 /* Calculate the size we'll need for the entry and allocate it */
1788 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1790 sizeof(UNICODE_NULL
);
1792 /* Allocate the entry */
1793 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1797 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1801 /* Setup the entry */
1802 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1803 LdrEntry
->LoadCount
= 1;
1804 LdrEntry
->LoadedImports
= LoadedImports
;
1805 LdrEntry
->PatchInformation
= NULL
;
1807 /* Check the version */
1808 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1809 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1811 /* Mark this image as a native image */
1812 LdrEntry
->Flags
|= 0x80000000;
1815 /* Setup the rest of the entry */
1816 LdrEntry
->DllBase
= ModuleLoadBase
;
1817 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1818 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1819 LdrEntry
->SizeOfImage
= DriverSize
;
1820 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1821 LdrEntry
->SectionPointer
= Section
;
1823 /* Now write the DLL name */
1824 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1825 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1826 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1828 /* Copy and null-terminate it */
1829 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1832 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ 2] = UNICODE_NULL
;
1834 /* Now allocate the full name */
1835 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1837 sizeof(UNICODE_NULL
),
1839 if (!LdrEntry
->FullDllName
.Buffer
)
1841 /* Don't fail, just set it to zero */
1842 LdrEntry
->FullDllName
.Length
= 0;
1843 LdrEntry
->FullDllName
.MaximumLength
= 0;
1848 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1849 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1851 /* Copy and null-terminate */
1852 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1855 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ 2] = UNICODE_NULL
;
1859 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1861 /* Resolve imports */
1862 MissingApiName
= Buffer
;
1863 Status
= MiResolveImageReferences(ModuleLoadBase
,
1869 if (!NT_SUCCESS(Status
))
1872 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1874 /* Check if we need to free the name */
1875 if (LdrEntry
->FullDllName
.Buffer
)
1878 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1881 /* Free the entry itself */
1882 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
1887 /* Update the loader entry */
1888 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
1889 LDRP_ENTRY_PROCESSED
|
1891 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
1892 LdrEntry
->LoadedImports
= LoadedImports
;
1894 /* FIXME: Apply driver verifier */
1896 /* FIXME: Write-protect the system image */
1898 /* Check if notifications are enabled */
1899 if (PsImageNotifyEnabled
)
1901 /* Fill out the notification data */
1902 ImageInfo
.Properties
= 0;
1903 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
1904 ImageInfo
.SystemModeImage
= TRUE
;
1905 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
1906 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
1907 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
1909 /* Send the notification */
1910 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
1913 /* Check if there's symbols */
1915 /* If KDBG is defined, then we always have symbols */
1918 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
1921 /* Check if the system root is present */
1922 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
1923 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
1925 /* Add the system root */
1926 UnicodeTemp
= PrefixName
;
1927 UnicodeTemp
.Buffer
+= 11;
1928 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
1931 &SharedUserData
->NtSystemRoot
[2],
1936 /* Build the name */
1937 sprintf_nt(Buffer
, "%wZ", &BaseName
);
1940 /* Setup the ansi string */
1941 RtlInitString(&AnsiTemp
, Buffer
);
1943 /* Notify the debugger */
1944 DbgLoadImageSymbols(&AnsiTemp
, LdrEntry
->DllBase
, -1);
1945 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
1948 /* FIXME: Page the driver */
1949 ASSERT(Section
== NULL
);
1951 /* Return pointers */
1952 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1953 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1956 /* If we have a file handle, close it */
1957 if (FileHandle
) ZwClose(FileHandle
);
1959 /* Check if we have the lock acquired */
1962 /* Release the lock */
1963 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1964 KeLeaveCriticalRegion();
1968 /* Check if we had a prefix */
1969 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1971 /* Free the name buffer and return status */
1972 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
1981 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
1983 PVOID ProcAddress
= NULL
;
1984 ANSI_STRING AnsiRoutineName
;
1986 PLIST_ENTRY NextEntry
;
1987 extern LIST_ENTRY PsLoadedModuleList
;
1988 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1989 BOOLEAN Found
= FALSE
;
1990 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1991 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1994 /* Convert routine to ansi name */
1995 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
1998 if (!NT_SUCCESS(Status
)) return NULL
;
2001 KeEnterCriticalRegion();
2003 /* Loop the loaded module list */
2004 NextEntry
= PsLoadedModuleList
.Flink
;
2005 while (NextEntry
!= &PsLoadedModuleList
)
2008 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2009 LDR_DATA_TABLE_ENTRY
,
2012 /* Check if it's the kernel or HAL */
2013 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
2019 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
2026 /* Check if we found a valid binary */
2029 /* Find the procedure name */
2030 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
2033 /* Break out if we found it or if we already tried both modules */
2034 if (ProcAddress
) break;
2035 if (Modules
== 2) break;
2039 NextEntry
= NextEntry
->Flink
;
2042 /* Release the lock */
2043 KeLeaveCriticalRegion();
2045 /* Free the string and return */
2046 RtlFreeAnsiString(&AnsiRoutineName
);