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 */
17 sprintf_nt(IN PCHAR Buffer
,
23 vsprintf(Buffer
, Format
, ap
);
27 /* GLOBALS *******************************************************************/
29 LIST_ENTRY PsLoadedModuleList
;
30 KSPIN_LOCK PsLoadedModuleSpinLock
;
31 ULONG PsNtosImageBase
;
32 KMUTANT MmSystemLoadLock
;
33 extern ULONG NtGlobalFlag
;
35 /* FUNCTIONS *****************************************************************/
39 MiCacheImageSymbols(IN PVOID BaseAddress
)
42 PVOID DebugDirectory
= NULL
;
45 /* Make sure it's safe to access the image */
48 /* Get the debug directory */
49 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
51 IMAGE_DIRECTORY_ENTRY_DEBUG
,
54 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
60 /* Return the directory */
61 return DebugDirectory
;
66 MiFreeBootDriverMemory(PVOID BaseAddress
,
72 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
75 MmDeleteVirtualMapping(NULL
,
76 (PVOID
)((ULONG_PTR
)BaseAddress
+ i
* PAGE_SIZE
),
85 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
87 IN PUNICODE_STRING FileName
,
88 IN BOOLEAN SessionLoad
,
89 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
91 PROS_SECTION_OBJECT Section
= *SectionPtr
;
97 LARGE_INTEGER SectionOffset
= {{0, 0}};
98 BOOLEAN LoadSymbols
= FALSE
;
103 /* Detect session load */
107 DPRINT1("Session loading not yet supported!\n");
111 /* Not session load, shouldn't have an entry */
112 ASSERT(LdrEntry
== NULL
);
114 /* Attach to the system process */
115 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
117 /* Check if we need to load symbols */
118 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
122 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
126 Process
= PsGetCurrentProcess();
127 Status
= MmMapViewOfSection(Section
,
138 /* Re-enable the flag */
139 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
141 /* Check if we failed with distinguished status code */
142 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
144 /* Change it to something more generic */
145 Status
= STATUS_INVALID_IMAGE_FORMAT
;
148 /* Now check if we failed */
149 if (!NT_SUCCESS(Status
))
151 /* Detach and return */
152 KeUnstackDetachProcess(&ApcState
);
156 /* Get the driver size */
157 DriverSize
= Section
->ImageSection
->ImageSize
;
159 /* Allocate a virtual section for the module */
160 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
161 *ImageBase
= DriverBase
;
164 RtlCopyMemory(DriverBase
, Base
, DriverSize
);
166 /* Now unmap the view */
167 Status
= MmUnmapViewOfSection(Process
, Base
);
168 ASSERT(NT_SUCCESS(Status
));
170 /* Detach and return status */
171 KeUnstackDetachProcess(&ApcState
);
177 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
181 /* Check if there's no imports or if we're a boot driver */
182 if ((ImportList
== (PVOID
)-1) ||
183 (ImportList
== (PVOID
)-2) ||
184 (ImportList
->Count
== 0))
186 /* Then there's nothing to do */
187 return STATUS_SUCCESS
;
190 /* Otherwise, FIXME */
191 DPRINT1("%u imports not dereferenced!\n", ImportList
->Count
);
192 for (i
= 0; i
< ImportList
->Count
; i
++)
194 DPRINT1("%wZ <%wZ>\n", &ImportList
->Entry
[i
]->FullDllName
, &ImportList
->Entry
[i
]->BaseDllName
);
196 return STATUS_UNSUCCESSFUL
;
201 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
205 /* Check if there's no imports or we're a boot driver or only one entry */
206 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
207 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
208 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
214 /* Otherwise, free the import list */
215 ExFreePool(LdrEntry
->LoadedImports
);
220 MiFindExportedRoutineByName(IN PVOID DllBase
,
221 IN PANSI_STRING ExportName
)
224 PUSHORT OrdinalTable
;
225 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
226 LONG Low
= 0, Mid
= 0, High
, Ret
;
233 /* Get the export directory */
234 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
236 IMAGE_DIRECTORY_ENTRY_EXPORT
,
238 if (!ExportDirectory
) return NULL
;
240 /* Setup name tables */
241 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
242 ExportDirectory
->AddressOfNames
);
243 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
244 ExportDirectory
->AddressOfNameOrdinals
);
246 /* Do a binary search */
247 High
= ExportDirectory
->NumberOfNames
- 1;
250 /* Get new middle value */
251 Mid
= (Low
+ High
) >> 1;
254 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
272 /* Check if we couldn't find it */
273 if (High
< Low
) return NULL
;
275 /* Otherwise, this is the ordinal */
276 Ordinal
= OrdinalTable
[Mid
];
278 /* Resolve the address and write it */
279 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
280 ExportDirectory
->AddressOfFunctions
);
281 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
284 ASSERT((Function
> (PVOID
)ExportDirectory
) &&
285 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
291 MiLocateExportName(IN PVOID DllBase
,
295 PUSHORT OrdinalTable
;
296 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
297 LONG Low
= 0, Mid
= 0, High
, Ret
;
304 /* Get the export directory */
305 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
307 IMAGE_DIRECTORY_ENTRY_EXPORT
,
309 if (!ExportDirectory
) return NULL
;
311 /* Setup name tables */
312 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
313 ExportDirectory
->AddressOfNames
);
314 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
315 ExportDirectory
->AddressOfNameOrdinals
);
317 /* Do a binary search */
318 High
= ExportDirectory
->NumberOfNames
- 1;
321 /* Get new middle value */
322 Mid
= (Low
+ High
) >> 1;
325 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
343 /* Check if we couldn't find it */
344 if (High
< Low
) return NULL
;
346 /* Otherwise, this is the ordinal */
347 Ordinal
= OrdinalTable
[Mid
];
349 /* Resolve the address and write it */
350 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
351 ExportDirectory
->AddressOfFunctions
);
352 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
354 /* Check if the function is actually a forwarder */
355 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
356 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
368 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
369 IN PLIST_ENTRY ListHead
)
371 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
372 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
373 PMM_DLL_INITIALIZE DllInit
;
374 UNICODE_STRING RegPath
, ImportName
;
377 /* Try to see if the image exports a DllInitialize routine */
378 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
380 if (!DllInit
) return STATUS_SUCCESS
;
382 /* Do a temporary copy of BaseDllName called ImportName
383 * because we'll alter the length of the string
385 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
386 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
387 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
389 /* Obtain the path to this dll's service in the registry */
390 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
391 ImportName
.Length
+ sizeof(UNICODE_NULL
);
392 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
393 RegPath
.MaximumLength
,
396 /* Check if this allocation was unsuccessful */
397 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
399 /* Build and append the service name itself */
400 RegPath
.Length
= ServicesKeyName
.Length
;
401 RtlCopyMemory(RegPath
.Buffer
,
402 ServicesKeyName
.Buffer
,
403 ServicesKeyName
.Length
);
405 /* Check if there is a dot in the filename */
406 if (wcschr(ImportName
.Buffer
, L
'.'))
408 /* Remove the extension */
409 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
410 ImportName
.Buffer
) * sizeof(WCHAR
);
413 /* Append service name (the basename without extension) */
414 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
416 /* Now call the DllInit func */
417 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
418 Status
= DllInit(&RegPath
);
421 ExFreePool(RegPath
.Buffer
);
423 /* Return status value which DllInitialize returned */
429 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
434 /* Acquire the lock */
435 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
437 /* Insert or remove from the list */
438 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
439 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
441 /* Release the lock */
442 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
447 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
452 ULONG_PTR OldBaseTop
, Delta
;
453 PLDR_DATA_TABLE_ENTRY LdrEntry
;
454 PLIST_ENTRY NextEntry
;
456 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
459 /* Calculate the top and delta */
460 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
461 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
463 /* Loop the loader block */
464 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
465 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
466 NextEntry
= NextEntry
->Flink
)
468 /* Get the loader entry */
469 LdrEntry
= CONTAINING_RECORD(NextEntry
,
470 LDR_DATA_TABLE_ENTRY
,
473 /* Get the import table */
474 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
476 IMAGE_DIRECTORY_ENTRY_IMPORT
,
478 if (!ImportDescriptor
) continue;
480 /* Make sure we have an IAT */
481 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
482 while ((ImportDescriptor
->Name
) &&
483 (ImportDescriptor
->OriginalFirstThunk
))
485 /* Get the image thunk */
486 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
487 ImportDescriptor
->FirstThunk
);
490 /* Check if it's within this module */
491 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
494 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
495 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
496 *ImageThunk
+= Delta
;
499 /* Go to the next thunk */
503 /* Go to the next import */
511 MiSnapThunk(IN PVOID DllBase
,
513 IN PIMAGE_THUNK_DATA Name
,
514 IN PIMAGE_THUNK_DATA Address
,
515 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
517 IN BOOLEAN SnapForwarder
,
518 OUT PCHAR
*MissingApi
)
523 PUSHORT OrdinalTable
;
524 PIMAGE_IMPORT_BY_NAME NameImport
;
526 ULONG Low
= 0, Mid
= 0, High
;
529 PCHAR MissingForwarder
;
530 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
533 UNICODE_STRING ForwarderName
;
534 PLIST_ENTRY NextEntry
;
535 PLDR_DATA_TABLE_ENTRY LdrEntry
;
536 ULONG ForwardExportSize
;
537 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
538 PIMAGE_IMPORT_BY_NAME ForwardName
;
540 IMAGE_THUNK_DATA ForwardThunk
;
543 /* Check if this is an ordinal */
544 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
545 if ((IsOrdinal
) && !(SnapForwarder
))
547 /* Get the ordinal number and set it as missing */
548 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
549 ExportDirectory
->Base
);
550 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
554 /* Get the VA if we don't have to snap */
555 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
556 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
558 /* Copy the procedure name */
560 (PCHAR
)&NameImport
->Name
[0],
561 MAXIMUM_FILENAME_LENGTH
- 1);
563 /* Setup name tables */
564 DPRINT("Import name: %s\n", NameImport
->Name
);
565 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
566 ExportDirectory
->AddressOfNames
);
567 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
568 ExportDirectory
->AddressOfNameOrdinals
);
570 /* Get the hint and check if it's valid */
571 Hint
= NameImport
->Hint
;
572 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
573 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
575 /* We have a match, get the ordinal number from here */
576 Ordinal
= OrdinalTable
[Hint
];
580 /* Do a binary search */
581 High
= ExportDirectory
->NumberOfNames
- 1;
584 /* Get new middle value */
585 Mid
= (Low
+ High
) >> 1;
588 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
606 /* Check if we couldn't find it */
607 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
609 /* Otherwise, this is the ordinal */
610 Ordinal
= OrdinalTable
[Mid
];
614 /* Check if the ordinal is invalid */
615 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
618 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
622 /* In case the forwarder is missing */
623 MissingForwarder
= NameBuffer
;
625 /* Resolve the address and write it */
626 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
627 ExportDirectory
->AddressOfFunctions
);
628 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
630 /* Assume success from now on */
631 Status
= STATUS_SUCCESS
;
633 /* Check if the function is actually a forwarder */
634 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
635 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
637 /* Now assume failure in case the forwarder doesn't exist */
638 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
640 /* Build the forwarder name */
641 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
642 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
645 DllName
.MaximumLength
= DllName
.Length
;
648 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
652 /* We failed, just return an error */
656 /* Loop the module list */
657 NextEntry
= PsLoadedModuleList
.Flink
;
658 while (NextEntry
!= &PsLoadedModuleList
)
660 /* Get the loader entry */
661 LdrEntry
= CONTAINING_RECORD(NextEntry
,
662 LDR_DATA_TABLE_ENTRY
,
665 /* Check if it matches */
666 if (RtlPrefixString((PSTRING
)&ForwarderName
,
667 (PSTRING
)&LdrEntry
->BaseDllName
,
670 /* Get the forwarder export directory */
671 ForwardExportDirectory
=
672 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
674 IMAGE_DIRECTORY_ENTRY_EXPORT
,
676 if (!ForwardExportDirectory
) break;
678 /* Allocate a name entry */
679 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
681 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
682 sizeof(*ForwardName
) +
685 if (!ForwardName
) break;
688 RtlCopyMemory(&ForwardName
->Name
[0],
689 DllName
.Buffer
+ DllName
.Length
,
691 ForwardName
->Hint
= 0;
693 /* Set the new address */
694 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
696 /* Snap the forwarder */
697 Status
= MiSnapThunk(LdrEntry
->DllBase
,
701 ForwardExportDirectory
,
706 /* Free the forwarder name and set the thunk */
707 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
708 Address
->u1
= ForwardThunk
.u1
;
712 /* Go to the next entry */
713 NextEntry
= NextEntry
->Flink
;
717 RtlFreeUnicodeString(&ForwarderName
);
727 MmUnloadSystemImage(IN PVOID ImageHandle
)
729 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
730 PVOID BaseAddress
= LdrEntry
->DllBase
;
732 ANSI_STRING TempName
;
733 BOOLEAN HadEntry
= FALSE
;
735 /* Acquire the loader lock */
736 KeEnterCriticalRegion();
737 KeWaitForSingleObject(&MmSystemLoadLock
,
743 /* Check if this driver was loaded at boot and didn't get imports parsed */
744 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
746 /* We should still be alive */
747 ASSERT(LdrEntry
->LoadCount
!= 0);
748 LdrEntry
->LoadCount
--;
750 /* Check if we're still loaded */
751 if (LdrEntry
->LoadCount
) goto Done
;
753 /* We should cleanup... are symbols loaded */
754 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
756 /* Create the ANSI name */
757 Status
= RtlUnicodeStringToAnsiString(&TempName
,
758 &LdrEntry
->BaseDllName
,
760 if (NT_SUCCESS(Status
))
762 /* Unload the symbols */
763 DbgUnLoadImageSymbols(&TempName
, BaseAddress
, -1);
764 RtlFreeAnsiString(&TempName
);
768 /* FIXME: Free the driver */
769 //MmFreeSection(LdrEntry->DllBase);
771 /* Check if we're linked in */
772 if (LdrEntry
->InLoadOrderLinks
.Flink
)
775 MiProcessLoaderEntry(LdrEntry
, FALSE
);
779 /* Dereference and clear the imports */
780 MiDereferenceImports(LdrEntry
->LoadedImports
);
781 MiClearImports(LdrEntry
);
783 /* Check if the entry needs to go away */
786 /* Check if it had a name */
787 if (LdrEntry
->FullDllName
.Buffer
)
790 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
793 /* Check if we had a section */
794 if (LdrEntry
->SectionPointer
)
797 ObDereferenceObject(LdrEntry
->SectionPointer
);
801 ExFreePool(LdrEntry
);
804 /* Release the system lock and return */
806 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
807 KeLeaveCriticalRegion();
808 return STATUS_SUCCESS
;
813 MiResolveImageReferences(IN PVOID ImageBase
,
814 IN PUNICODE_STRING ImageFileDirectory
,
815 IN PUNICODE_STRING NamePrefix OPTIONAL
,
816 OUT PCHAR
*MissingApi
,
817 OUT PWCHAR
*MissingDriver
,
818 OUT PLOAD_IMPORTS
*LoadImports
)
820 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
821 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
822 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
823 PLOAD_IMPORTS LoadedImports
, NewImports
;
824 ULONG GdiLink
, NormalLink
, i
;
825 BOOLEAN ReferenceNeeded
, Loaded
;
826 ANSI_STRING TempString
;
827 UNICODE_STRING NameString
, DllName
;
828 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
829 PVOID ImportBase
, DllBase
;
830 PLIST_ENTRY NextEntry
;
831 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
833 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
835 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
836 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
838 /* Assume no imports */
839 *LoadImports
= (PVOID
)-2;
841 /* Get the import descriptor */
842 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
844 IMAGE_DIRECTORY_ENTRY_IMPORT
,
846 if (!ImportDescriptor
) return STATUS_SUCCESS
;
848 /* Loop all imports to count them */
849 for (CurrentImport
= ImportDescriptor
;
850 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
857 /* Make sure we have non-zero imports */
860 /* Calculate and allocate the list we'll need */
861 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
862 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
868 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
874 LoadedImports
= NULL
;
877 /* Reset the import count and loop descriptors again */
878 ImportCount
= GdiLink
= NormalLink
= 0;
879 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
882 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
884 /* Check if this is a GDI driver */
886 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
888 /* We can also allow dxapi */
889 NormalLink
= NormalLink
|
890 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
891 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
893 /* Check if this is a valid GDI driver */
894 if ((GdiLink
) && (NormalLink
))
896 /* It's not, it's importing stuff it shouldn't be! */
897 MiDereferenceImports(LoadedImports
);
898 if (LoadedImports
) ExFreePool(LoadedImports
);
899 return STATUS_PROCEDURE_NOT_FOUND
;
902 /* Check if this is a "core" import, which doesn't get referenced */
903 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
904 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
905 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
907 /* Don't reference this */
908 ReferenceNeeded
= FALSE
;
912 /* Reference these modules */
913 ReferenceNeeded
= TRUE
;
916 /* Now setup a unicode string for the import */
917 RtlInitAnsiString(&TempString
, ImportName
);
918 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
919 if (!NT_SUCCESS(Status
))
922 MiDereferenceImports(LoadedImports
);
923 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
927 /* We don't support name prefixes yet */
928 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
930 /* Remember that we haven't loaded the import at this point */
935 /* Loop the driver list */
936 NextEntry
= PsLoadedModuleList
.Flink
;
937 while (NextEntry
!= &PsLoadedModuleList
)
939 /* Get the loader entry and compare the name */
940 LdrEntry
= CONTAINING_RECORD(NextEntry
,
941 LDR_DATA_TABLE_ENTRY
,
943 if (RtlEqualUnicodeString(&NameString
,
944 &LdrEntry
->BaseDllName
,
947 /* Get the base address */
948 ImportBase
= LdrEntry
->DllBase
;
950 /* Check if we haven't loaded yet, and we need references */
951 if (!(Loaded
) && (ReferenceNeeded
))
953 /* Make sure we're not already loading */
954 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
956 /* Increase the load count */
957 LdrEntry
->LoadCount
++;
961 /* Done, break out */
965 /* Go to the next entry */
966 NextEntry
= NextEntry
->Flink
;
969 /* Check if we haven't loaded the import yet */
972 /* Setup the import DLL name */
973 DllName
.MaximumLength
= NameString
.Length
+
974 ImageFileDirectory
->Length
+
975 sizeof(UNICODE_NULL
);
976 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
977 DllName
.MaximumLength
,
981 /* Setup the base length and copy it */
982 DllName
.Length
= ImageFileDirectory
->Length
;
983 RtlCopyMemory(DllName
.Buffer
,
984 ImageFileDirectory
->Buffer
,
985 ImageFileDirectory
->Length
);
987 /* Now add the import name and null-terminate it */
988 RtlAppendStringToString((PSTRING
)&DllName
,
989 (PSTRING
)&NameString
);
990 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
993 Status
= MmLoadSystemImage(&DllName
,
999 if (NT_SUCCESS(Status
))
1001 /* We can free the DLL Name */
1002 ExFreePool(DllName
.Buffer
);
1006 /* Fill out the information for the error */
1007 *MissingDriver
= DllName
.Buffer
;
1008 *(PULONG
)MissingDriver
|= 1;
1014 /* We're out of resources */
1015 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1018 /* Check if we're OK until now */
1019 if (NT_SUCCESS(Status
))
1021 /* We're now loaded */
1025 ASSERT(DllBase
= DllEntry
->DllBase
);
1027 /* Call the initialization routines */
1028 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1029 if (!NT_SUCCESS(Status
))
1031 /* We failed, unload the image */
1032 MmUnloadSystemImage(DllEntry
);
1038 /* Check if we failed by here */
1039 if (!NT_SUCCESS(Status
))
1041 /* Cleanup and return */
1042 RtlFreeUnicodeString(&NameString
);
1043 MiDereferenceImports(LoadedImports
);
1044 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1048 /* Loop again to make sure that everything is OK */
1052 /* Check if we're support to reference this import */
1053 if ((ReferenceNeeded
) && (LoadedImports
))
1055 /* Make sure we're not already loading */
1056 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1059 LoadedImports
->Entry
[LoadedImports
->Count
] = LdrEntry
;
1060 LoadedImports
->Count
++;
1064 /* Free the import name */
1065 RtlFreeUnicodeString(&NameString
);
1067 /* Set the missing driver name and get the export directory */
1068 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1069 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1071 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1073 if (!ExportDirectory
)
1075 /* Cleanup and return */
1076 MiDereferenceImports(LoadedImports
);
1077 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1078 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1081 /* Make sure we have an IAT */
1082 if (ImportDescriptor
->OriginalFirstThunk
)
1084 /* Get the first thunks */
1085 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1086 ImportDescriptor
->OriginalFirstThunk
);
1087 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1088 ImportDescriptor
->FirstThunk
);
1091 while (OrigThunk
->u1
.AddressOfData
)
1094 Status
= MiSnapThunk(ImportBase
,
1102 if (!NT_SUCCESS(Status
))
1104 /* Cleanup and return */
1105 MiDereferenceImports(LoadedImports
);
1106 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1110 /* Reset the buffer */
1111 *MissingApi
= MissingApiBuffer
;
1115 /* Go to the next import */
1119 /* Check if we have an import list */
1122 /* Reset the count again, and loop entries*/
1124 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1126 if (LoadedImports
->Entry
[i
])
1128 /* Got an entry, OR it with 1 in case it's the single entry */
1129 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1134 /* Check if we had no imports */
1137 /* Free the list and set it to no imports */
1138 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1139 LoadedImports
= (PVOID
)-2;
1141 else if (ImportCount
== 1)
1143 /* Just one entry, we can free the table and only use our entry */
1144 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1145 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1147 else if (ImportCount
!= LoadedImports
->Count
)
1149 /* Allocate a new list */
1150 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1151 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1157 NewImports
->Count
= 0;
1159 /* Loop all the imports */
1160 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1162 /* Make sure it's valid */
1163 if (LoadedImports
->Entry
[i
])
1166 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1167 NewImports
->Count
++;
1171 /* Free the old copy */
1172 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1173 LoadedImports
= NewImports
;
1177 /* Return the list */
1178 *LoadImports
= LoadedImports
;
1181 /* Return success */
1182 return STATUS_SUCCESS
;
1187 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1189 PLIST_ENTRY NextEntry
;
1191 PIMAGE_NT_HEADERS NtHeader
;
1192 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1193 PIMAGE_FILE_HEADER FileHeader
;
1194 BOOLEAN ValidRelocs
;
1195 PIMAGE_DATA_DIRECTORY DataDirectory
;
1196 PVOID DllBase
, NewImageAddress
;
1199 /* Loop driver list */
1200 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1201 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1202 NextEntry
= NextEntry
->Flink
)
1204 /* Get the loader entry and NT header */
1205 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1206 LDR_DATA_TABLE_ENTRY
,
1208 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1211 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1213 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1214 &LdrEntry
->FullDllName
);
1216 /* Skip kernel and HAL */
1217 /* ROS HACK: Skip BOOTVID/KDCOM too */
1219 if (i
<= 4) continue;
1221 /* Skip non-drivers */
1222 if (!NtHeader
) continue;
1224 /* Get the file header and make sure we can relocate */
1225 FileHeader
= &NtHeader
->FileHeader
;
1226 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1227 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1228 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1230 /* Everything made sense until now, check the relocation section too */
1231 DataDirectory
= &NtHeader
->OptionalHeader
.
1232 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1233 if (!DataDirectory
->VirtualAddress
)
1235 /* We don't really have relocations */
1236 ValidRelocs
= FALSE
;
1240 /* Make sure the size is valid */
1241 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1242 LdrEntry
->SizeOfImage
)
1244 /* They're not, skip */
1248 /* We have relocations */
1252 /* Remember the original address */
1253 DllBase
= LdrEntry
->DllBase
;
1255 /* Allocate a virtual section for the module */
1256 NewImageAddress
= MmAllocateSection(LdrEntry
->SizeOfImage
, NULL
);
1257 if (!NewImageAddress
)
1259 /* Shouldn't happen */
1260 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1265 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1266 ASSERT(ExpInitializationPhase
== 0);
1268 /* Now copy the entire driver over */
1269 RtlCopyMemory(NewImageAddress
, DllBase
, LdrEntry
->SizeOfImage
);
1272 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1274 /* Set the image base to the address where the loader put it */
1275 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1276 NtHeader
= RtlImageNtHeader(NewImageAddress
);
1277 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1279 /* Check if we had relocations */
1282 /* Relocate the image */
1283 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1287 STATUS_CONFLICTING_ADDRESSES
,
1288 STATUS_INVALID_IMAGE_FORMAT
);
1289 if (!NT_SUCCESS(Status
))
1291 /* This shouldn't happen */
1292 DPRINT1("Relocations failed!\n");
1297 /* Update the loader entry */
1298 LdrEntry
->DllBase
= NewImageAddress
;
1300 /* Update the thunks */
1301 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1302 MiUpdateThunks(LoaderBlock
,
1305 LdrEntry
->SizeOfImage
);
1307 /* Update the loader entry */
1308 LdrEntry
->Flags
|= 0x01000000;
1309 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1310 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1311 LdrEntry
->SizeOfImage
= LdrEntry
->SizeOfImage
;
1313 /* Free the old copy */
1314 MiFreeBootDriverMemory(DllBase
, LdrEntry
->SizeOfImage
);
1320 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1322 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1323 PLIST_ENTRY ListHead
, NextEntry
;
1326 /* Setup the loaded module list and lock */
1327 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1328 InitializeListHead(&PsLoadedModuleList
);
1330 /* Get loop variables and the kernel entry */
1331 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1332 NextEntry
= ListHead
->Flink
;
1333 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1334 LDR_DATA_TABLE_ENTRY
,
1336 PsNtosImageBase
= (ULONG
)LdrEntry
->DllBase
;
1338 /* Loop the loader block */
1339 while (NextEntry
!= ListHead
)
1341 /* Get the loader entry */
1342 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1343 LDR_DATA_TABLE_ENTRY
,
1346 /* FIXME: ROS HACK. Make sure this is a driver */
1347 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1349 /* Skip this entry */
1350 NextEntry
= NextEntry
->Flink
;
1354 /* Calculate the size we'll need and allocate a copy */
1355 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1356 LdrEntry
->BaseDllName
.MaximumLength
+
1357 sizeof(UNICODE_NULL
);
1358 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1359 if (!NewEntry
) return FALSE
;
1361 /* Copy the entry over */
1362 *NewEntry
= *LdrEntry
;
1364 /* Allocate the name */
1365 NewEntry
->FullDllName
.Buffer
=
1366 ExAllocatePoolWithTag(PagedPool
,
1367 LdrEntry
->FullDllName
.MaximumLength
+
1368 sizeof(UNICODE_NULL
),
1370 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1372 /* Set the base name */
1373 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1375 /* Copy the full and base name */
1376 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1377 LdrEntry
->FullDllName
.Buffer
,
1378 LdrEntry
->FullDllName
.MaximumLength
);
1379 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1380 LdrEntry
->BaseDllName
.Buffer
,
1381 LdrEntry
->BaseDllName
.MaximumLength
);
1383 /* Null-terminate the base name */
1384 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1385 sizeof(WCHAR
)] = UNICODE_NULL
;
1387 /* Insert the entry into the list */
1388 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1389 NextEntry
= NextEntry
->Flink
;
1392 /* Build the import lists for the boot drivers */
1393 //MiBuildImportsForBootDrivers();
1401 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1403 PIMAGE_NT_HEADERS NtHeader
;
1406 /* Get NT Headers */
1407 NtHeader
= RtlImageNtHeader(BaseAddress
);
1410 /* Check if this image is only safe for UP while we have 2+ CPUs */
1411 if ((KeNumberProcessors
> 1) &&
1412 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1419 /* Otherwise, it's safe */
1425 MmCheckSystemImage(IN HANDLE ImageHandle
,
1426 IN BOOLEAN PurgeSection
)
1429 HANDLE SectionHandle
;
1430 PVOID ViewBase
= NULL
;
1431 SIZE_T ViewSize
= 0;
1432 IO_STATUS_BLOCK IoStatusBlock
;
1433 FILE_STANDARD_INFORMATION FileStandardInfo
;
1434 KAPC_STATE ApcState
;
1437 /* Create a section for the DLL */
1438 Status
= ZwCreateSection(&SectionHandle
,
1439 SECTION_MAP_EXECUTE
,
1445 if (!NT_SUCCESS(Status
)) return Status
;
1447 /* Make sure we're in the system process */
1448 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1451 Status
= ZwMapViewOfSection(SectionHandle
,
1461 if (!NT_SUCCESS(Status
))
1463 /* We failed, close the handle and return */
1464 KeUnstackDetachProcess(&ApcState
);
1465 ZwClose(SectionHandle
);
1469 /* Now query image information */
1470 Status
= ZwQueryInformationFile(ImageHandle
,
1473 sizeof(FileStandardInfo
),
1474 FileStandardInformation
);
1475 if ( NT_SUCCESS(Status
) )
1477 /* First, verify the checksum */
1478 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1484 /* Set checksum failure */
1485 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1488 /* Check that it's a valid SMP image if we have more then one CPU */
1489 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1491 /* Otherwise it's not the right image */
1492 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1496 /* Unmap the section, close the handle, and return status */
1497 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1498 KeUnstackDetachProcess(&ApcState
);
1499 ZwClose(SectionHandle
);
1505 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1506 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1507 IN PUNICODE_STRING LoadedName OPTIONAL
,
1509 OUT PVOID
*ModuleObject
,
1510 OUT PVOID
*ImageBaseAddress
)
1512 PVOID ModuleLoadBase
= NULL
;
1514 HANDLE FileHandle
= NULL
;
1515 OBJECT_ATTRIBUTES ObjectAttributes
;
1516 IO_STATUS_BLOCK IoStatusBlock
;
1517 PIMAGE_NT_HEADERS NtHeader
;
1518 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
1519 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1520 ULONG EntrySize
, DriverSize
;
1521 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1522 PCHAR MissingApiName
, Buffer
;
1523 PWCHAR MissingDriverName
;
1524 HANDLE SectionHandle
;
1525 ACCESS_MASK DesiredAccess
;
1526 PVOID Section
= NULL
;
1527 BOOLEAN LockOwned
= FALSE
;
1528 PLIST_ENTRY NextEntry
;
1529 IMAGE_INFO ImageInfo
;
1530 ANSI_STRING AnsiTemp
;
1533 /* Detect session-load */
1537 ASSERT(NamePrefix
== NULL
);
1538 ASSERT(LoadedName
== NULL
);
1540 /* Make sure the process is in session too */
1541 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1544 if (ModuleObject
) *ModuleObject
= NULL
;
1545 if (ImageBaseAddress
) *ImageBaseAddress
= NULL
;
1547 /* Allocate a buffer we'll use for names */
1548 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1549 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1551 /* Check for a separator */
1552 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1557 /* Loop the path until we get to the base name */
1558 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1559 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1561 /* Get the length */
1562 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1563 BaseLength
*= sizeof(WCHAR
);
1565 /* Setup the string */
1566 BaseName
.Length
= (USHORT
)BaseLength
;
1567 BaseName
.Buffer
= p
;
1571 /* Otherwise, we already have a base name */
1572 BaseName
.Length
= FileName
->Length
;
1573 BaseName
.Buffer
= FileName
->Buffer
;
1576 /* Setup the maximum length */
1577 BaseName
.MaximumLength
= BaseName
.Length
;
1579 /* Now compute the base directory */
1580 BaseDirectory
= *FileName
;
1581 BaseDirectory
.Length
-= BaseName
.Length
;
1582 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1584 /* And the prefix, which for now is just the name itself */
1585 PrefixName
= *FileName
;
1587 /* Check if we have a prefix */
1588 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1590 /* Check if we already have a name, use it instead */
1591 if (LoadedName
) BaseName
= *LoadedName
;
1593 /* Acquire the load lock */
1595 ASSERT(LockOwned
== FALSE
);
1597 KeEnterCriticalRegion();
1598 KeWaitForSingleObject(&MmSystemLoadLock
,
1604 /* Scan the module list */
1605 NextEntry
= PsLoadedModuleList
.Flink
;
1606 while (NextEntry
!= &PsLoadedModuleList
)
1608 /* Get the entry and compare the names */
1609 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1610 LDR_DATA_TABLE_ENTRY
,
1612 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1614 /* Found it, break out */
1619 NextEntry
= NextEntry
->Flink
;
1622 /* Check if we found the image */
1623 if (NextEntry
!= &PsLoadedModuleList
)
1625 /* Check if we had already mapped a section */
1628 /* Dereference and clear */
1629 ObDereferenceObject(Section
);
1633 /* Check if this was supposed to be a session load */
1636 /* It wasn't, so just return the data */
1637 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1638 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1639 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1643 /* We don't support session loading yet */
1644 DPRINT1("Unsupported Session-Load!\n");
1653 /* It wasn't loaded, and we didn't have a previous attempt */
1654 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1655 KeLeaveCriticalRegion();
1658 /* Check if KD is enabled */
1659 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1661 /* FIXME: Attempt to get image from KD */
1664 /* We don't have a valid entry */
1667 /* Setup image attributes */
1668 InitializeObjectAttributes(&ObjectAttributes
,
1670 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1674 /* Open the image */
1675 Status
= ZwOpenFile(&FileHandle
,
1679 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1681 if (!NT_SUCCESS(Status
)) goto Quickie
;
1684 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1685 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1686 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1687 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1693 /* Check if this is a session-load */
1696 /* Then we only need read and execute */
1697 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1701 /* Otherwise, we can allow write access */
1702 DesiredAccess
= SECTION_ALL_ACCESS
;
1705 /* Initialize the attributes for the section */
1706 InitializeObjectAttributes(&ObjectAttributes
,
1708 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1712 /* Create the section */
1713 Status
= ZwCreateSection(&SectionHandle
,
1720 if (!NT_SUCCESS(Status
)) goto Quickie
;
1722 /* Now get the section pointer */
1723 Status
= ObReferenceObjectByHandle(SectionHandle
,
1724 SECTION_MAP_EXECUTE
,
1725 MmSectionObjectType
,
1729 ZwClose(SectionHandle
);
1730 if (!NT_SUCCESS(Status
)) goto Quickie
;
1732 /* Check if this was supposed to be a session-load */
1735 /* We don't support session loading yet */
1736 DPRINT1("Unsupported Session-Load!\n");
1740 /* Check the loader list again, we should end up in the path below */
1745 /* We don't have a valid entry */
1749 /* Load the image */
1750 Status
= MiLoadImageSection(&Section
,
1755 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1757 /* Get the size of the driver */
1758 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1760 /* Make sure we're not being loaded into session space */
1763 /* Check for success */
1764 if (NT_SUCCESS(Status
))
1766 /* FIXME: Support large pages for drivers */
1769 /* Dereference the section */
1770 ObDereferenceObject(Section
);
1774 /* Get the NT Header */
1775 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1777 /* Relocate the driver */
1778 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1782 STATUS_CONFLICTING_ADDRESSES
,
1783 STATUS_INVALID_IMAGE_FORMAT
);
1784 if (!NT_SUCCESS(Status
)) goto Quickie
;
1786 /* Calculate the size we'll need for the entry and allocate it */
1787 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1789 sizeof(UNICODE_NULL
);
1791 /* Allocate the entry */
1792 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1796 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1800 /* Setup the entry */
1801 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1802 LdrEntry
->LoadCount
= 1;
1803 LdrEntry
->LoadedImports
= LoadedImports
;
1804 LdrEntry
->PatchInformation
= NULL
;
1806 /* Check the version */
1807 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1808 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1810 /* Mark this image as a native image */
1811 LdrEntry
->Flags
|= 0x80000000;
1814 /* Setup the rest of the entry */
1815 LdrEntry
->DllBase
= ModuleLoadBase
;
1816 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1817 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1818 LdrEntry
->SizeOfImage
= DriverSize
;
1819 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1820 LdrEntry
->SectionPointer
= Section
;
1822 /* Now write the DLL name */
1823 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1824 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1825 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1827 /* Copy and null-terminate it */
1828 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1831 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ 2] = UNICODE_NULL
;
1833 /* Now allocate the full name */
1834 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1836 sizeof(UNICODE_NULL
),
1838 if (!LdrEntry
->FullDllName
.Buffer
)
1840 /* Don't fail, just set it to zero */
1841 LdrEntry
->FullDllName
.Length
= 0;
1842 LdrEntry
->FullDllName
.MaximumLength
= 0;
1847 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1848 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1850 /* Copy and null-terminate */
1851 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1854 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ 2] = UNICODE_NULL
;
1858 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1860 /* Resolve imports */
1861 MissingApiName
= Buffer
;
1862 Status
= MiResolveImageReferences(ModuleLoadBase
,
1868 if (!NT_SUCCESS(Status
))
1871 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1873 /* Check if we need to free the name */
1874 if (LdrEntry
->FullDllName
.Buffer
)
1877 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1880 /* Free the entry itself */
1881 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
1886 /* Update the loader entry */
1887 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
1888 LDRP_ENTRY_PROCESSED
|
1890 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
1891 LdrEntry
->LoadedImports
= LoadedImports
;
1893 /* FIXME: Apply driver verifier */
1895 /* FIXME: Write-protect the system image */
1897 /* Check if notifications are enabled */
1898 if (PsImageNotifyEnabled
)
1900 /* Fill out the notification data */
1901 ImageInfo
.Properties
= 0;
1902 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
1903 ImageInfo
.SystemModeImage
= TRUE
;
1904 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
1905 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
1906 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
1908 /* Send the notification */
1909 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
1912 /* Check if there's symbols */
1914 /* If KDBG is defined, then we always have symbols */
1917 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
1920 /* Check if the system root is present */
1921 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
1922 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
1924 /* Add the system root */
1925 UnicodeTemp
= PrefixName
;
1926 UnicodeTemp
.Buffer
+= 11;
1927 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
1930 &SharedUserData
->NtSystemRoot
[2],
1935 /* Build the name */
1936 sprintf_nt(Buffer
, "%wZ", &BaseName
);
1939 /* Setup the ansi string */
1940 RtlInitString(&AnsiTemp
, Buffer
);
1942 /* Notify the debugger */
1943 DbgLoadImageSymbols(&AnsiTemp
, LdrEntry
->DllBase
, -1);
1944 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
1947 /* FIXME: Page the driver */
1948 ASSERT(Section
== NULL
);
1950 /* Return pointers */
1951 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1952 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1955 /* If we have a file handle, close it */
1956 if (FileHandle
) ZwClose(FileHandle
);
1958 /* Check if we have the lock acquired */
1961 /* Release the lock */
1962 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1963 KeLeaveCriticalRegion();
1967 /* Check if we had a prefix */
1968 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1970 /* Free the name buffer and return status */
1971 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
1980 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
1982 PVOID ProcAddress
= NULL
;
1983 ANSI_STRING AnsiRoutineName
;
1985 PLIST_ENTRY NextEntry
;
1986 extern LIST_ENTRY PsLoadedModuleList
;
1987 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1988 BOOLEAN Found
= FALSE
;
1989 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1990 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1993 /* Convert routine to ansi name */
1994 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
1997 if (!NT_SUCCESS(Status
)) return NULL
;
2000 KeEnterCriticalRegion();
2002 /* Loop the loaded module list */
2003 NextEntry
= PsLoadedModuleList
.Flink
;
2004 while (NextEntry
!= &PsLoadedModuleList
)
2007 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2008 LDR_DATA_TABLE_ENTRY
,
2011 /* Check if it's the kernel or HAL */
2012 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
2018 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
2025 /* Check if we found a valid binary */
2028 /* Find the procedure name */
2029 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
2032 /* Break out if we found it or if we already tried both modules */
2033 if (ProcAddress
) break;
2034 if (Modules
== 2) break;
2038 NextEntry
= NextEntry
->Flink
;
2041 /* Release the lock */
2042 KeLeaveCriticalRegion();
2044 /* Free the string and return */
2045 RtlFreeAnsiString(&AnsiRoutineName
);