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 /* GLOBALS *******************************************************************/
17 LIST_ENTRY PsLoadedModuleList
;
18 KSPIN_LOCK PsLoadedModuleSpinLock
;
19 PVOID PsNtosImageBase
;
20 KMUTANT MmSystemLoadLock
;
21 extern ULONG NtGlobalFlag
;
23 /* FUNCTIONS *****************************************************************/
27 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
29 IN PUNICODE_STRING FileName
,
30 IN BOOLEAN SessionLoad
,
31 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
33 PROS_SECTION_OBJECT Section
= *SectionPtr
;
39 LARGE_INTEGER SectionOffset
= {{0}};
40 BOOLEAN LoadSymbols
= FALSE
;
45 /* Detect session load */
49 DPRINT1("Session loading not yet supported!\n");
53 /* Not session load, shouldn't have an entry */
54 ASSERT(LdrEntry
== NULL
);
56 /* Attach to the system process */
57 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
59 /* Check if we need to load symbols */
60 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
64 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
68 Process
= PsGetCurrentProcess();
69 Status
= MmMapViewOfSection(Section
,
80 /* Re-enable the flag */
81 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
83 /* Check if we failed with distinguished status code */
84 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
86 /* Change it to something more generic */
87 Status
= STATUS_INVALID_IMAGE_FORMAT
;
90 /* Now check if we failed */
91 if (!NT_SUCCESS(Status
))
93 /* Detach and return */
94 KeUnstackDetachProcess(&ApcState
);
98 /* Get the driver size */
99 DriverSize
= Section
->ImageSection
->ImageSize
;
101 /* Allocate a virtual section for the module */
102 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
103 *ImageBase
= DriverBase
;
106 RtlCopyMemory(DriverBase
, Base
, DriverSize
);
108 /* Now unmap the view */
109 Status
= MmUnmapViewOfSection(Process
, Base
);
110 ASSERT(NT_SUCCESS(Status
));
112 /* Detach and return status */
113 KeUnstackDetachProcess(&ApcState
);
119 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
121 /* Check if there's no imports or if we're a boot driver */
122 if ((ImportList
== (PVOID
)-1) || (ImportList
== (PVOID
)-2))
124 /* Then there's nothing to do */
125 return STATUS_SUCCESS
;
128 /* Otherwise, FIXME */
129 DPRINT1("Imports not dereferenced!\n");
130 return STATUS_UNSUCCESSFUL
;
135 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
139 /* Check if there's no imports or we're a boot driver or only one entry */
140 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
141 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
142 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
148 /* Otherwise, free the import list */
149 ExFreePool(LdrEntry
->LoadedImports
);
154 MiFindExportedRoutineByName(IN PVOID DllBase
,
155 IN PANSI_STRING ExportName
)
158 PUSHORT OrdinalTable
;
159 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
160 LONG Low
= 0, Mid
= 0, High
, Ret
;
167 /* Get the export directory */
168 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
170 IMAGE_DIRECTORY_ENTRY_EXPORT
,
172 if (!ExportDirectory
) return NULL
;
174 /* Setup name tables */
175 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
176 ExportDirectory
->AddressOfNames
);
177 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
178 ExportDirectory
->AddressOfNameOrdinals
);
180 /* Do a binary search */
181 High
= ExportDirectory
->NumberOfNames
- 1;
184 /* Get new middle value */
185 Mid
= (Low
+ High
) >> 1;
188 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
206 /* Check if we couldn't find it */
207 if (High
< Low
) return NULL
;
209 /* Otherwise, this is the ordinal */
210 Ordinal
= OrdinalTable
[Mid
];
212 /* Resolve the address and write it */
213 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
214 ExportDirectory
->AddressOfFunctions
);
215 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
218 ASSERT((Function
> (PVOID
)ExportDirectory
) &&
219 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
225 MiLocateExportName(IN PVOID DllBase
,
229 PUSHORT OrdinalTable
;
230 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
231 LONG Low
= 0, Mid
= 0, High
, Ret
;
238 /* Get the export directory */
239 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
241 IMAGE_DIRECTORY_ENTRY_EXPORT
,
243 if (!ExportDirectory
) return NULL
;
245 /* Setup name tables */
246 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
247 ExportDirectory
->AddressOfNames
);
248 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
249 ExportDirectory
->AddressOfNameOrdinals
);
251 /* Do a binary search */
252 High
= ExportDirectory
->NumberOfNames
- 1;
255 /* Get new middle value */
256 Mid
= (Low
+ High
) >> 1;
259 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
277 /* Check if we couldn't find it */
278 if (High
< Low
) return NULL
;
280 /* Otherwise, this is the ordinal */
281 Ordinal
= OrdinalTable
[Mid
];
283 /* Resolve the address and write it */
284 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
285 ExportDirectory
->AddressOfFunctions
);
286 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
288 /* Check if the function is actually a forwarder */
289 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
290 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
302 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
303 IN PLIST_ENTRY ListHead
)
305 PMM_DLL_INITIALIZE DllInit
;
307 /* Try to see if the image exports a DllInitialize routine */
308 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
310 if (!DllInit
) return STATUS_SUCCESS
;
313 DPRINT1("DllInitialize not called!\n");
314 return STATUS_UNSUCCESSFUL
;
319 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
324 /* Acquire the lock */
325 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
327 /* Insert or remove from the list */
328 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
329 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
331 /* Release the lock */
332 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
337 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
342 ULONG_PTR OldBaseTop
, Delta
;
343 PLDR_DATA_TABLE_ENTRY LdrEntry
;
344 PLIST_ENTRY NextEntry
;
346 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
349 /* Calculate the top and delta */
350 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
351 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
353 /* Loop the loader block */
354 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
355 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
356 NextEntry
= NextEntry
->Flink
)
358 /* Get the loader entry */
359 LdrEntry
= CONTAINING_RECORD(NextEntry
,
360 LDR_DATA_TABLE_ENTRY
,
363 /* Get the import table */
364 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
366 IMAGE_DIRECTORY_ENTRY_IMPORT
,
368 if (!ImportDescriptor
) continue;
370 /* Make sure we have an IAT */
371 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
372 while ((ImportDescriptor
->Name
) &&
373 (ImportDescriptor
->OriginalFirstThunk
))
375 /* Get the image thunk */
376 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
377 ImportDescriptor
->FirstThunk
);
380 /* Check if it's within this module */
381 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
384 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
385 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
386 *ImageThunk
+= Delta
;
389 /* Go to the next thunk */
393 /* Go to the next import */
401 MiSnapThunk(IN PVOID DllBase
,
403 IN PIMAGE_THUNK_DATA Name
,
404 IN PIMAGE_THUNK_DATA Address
,
405 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
407 IN BOOLEAN SnapForwarder
,
408 OUT PCHAR
*MissingApi
)
413 PUSHORT OrdinalTable
;
414 PIMAGE_IMPORT_BY_NAME NameImport
;
416 ULONG Low
= 0, Mid
= 0, High
;
419 PCHAR MissingForwarder
;
420 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
423 UNICODE_STRING ForwarderName
;
424 PLIST_ENTRY NextEntry
;
425 PLDR_DATA_TABLE_ENTRY LdrEntry
;
426 ULONG ForwardExportSize
;
427 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
428 PIMAGE_IMPORT_BY_NAME ForwardName
;
430 IMAGE_THUNK_DATA ForwardThunk
;
433 /* Check if this is an ordinal */
434 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
435 if ((IsOrdinal
) && !(SnapForwarder
))
437 /* Get the ordinal number and set it as missing */
438 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
439 ExportDirectory
->Base
);
440 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
444 /* Get the VA if we don't have to snap */
445 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
446 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
448 /* Copy the procedure name */
450 (PCHAR
)&NameImport
->Name
[0],
451 MAXIMUM_FILENAME_LENGTH
- 1);
453 /* Setup name tables */
454 DPRINT("Import name: %s\n", NameImport
->Name
);
455 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
456 ExportDirectory
->AddressOfNames
);
457 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
458 ExportDirectory
->AddressOfNameOrdinals
);
460 /* Get the hint and check if it's valid */
461 Hint
= NameImport
->Hint
;
462 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
463 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
465 /* We have a match, get the ordinal number from here */
466 Ordinal
= OrdinalTable
[Hint
];
470 /* Do a binary search */
471 High
= ExportDirectory
->NumberOfNames
- 1;
474 /* Get new middle value */
475 Mid
= (Low
+ High
) >> 1;
478 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
496 /* Check if we couldn't find it */
497 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
499 /* Otherwise, this is the ordinal */
500 Ordinal
= OrdinalTable
[Mid
];
504 /* Check if the ordinal is invalid */
505 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
508 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
512 /* In case the forwarder is missing */
513 MissingForwarder
= NameBuffer
;
515 /* Resolve the address and write it */
516 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
517 ExportDirectory
->AddressOfFunctions
);
518 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
520 /* Assume success from now on */
521 Status
= STATUS_SUCCESS
;
523 /* Check if the function is actually a forwarder */
524 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
525 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
527 /* Now assume failure in case the forwarder doesn't exist */
528 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
530 /* Build the forwarder name */
531 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
532 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
535 DllName
.MaximumLength
= DllName
.Length
;
538 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
542 /* We failed, just return an error */
546 /* Loop the module list */
547 NextEntry
= PsLoadedModuleList
.Flink
;
548 while (NextEntry
!= &PsLoadedModuleList
)
550 /* Get the loader entry */
551 LdrEntry
= CONTAINING_RECORD(NextEntry
,
552 LDR_DATA_TABLE_ENTRY
,
555 /* Check if it matches */
556 if (RtlPrefixString((PSTRING
)&ForwarderName
,
557 (PSTRING
)&LdrEntry
->BaseDllName
,
560 /* Get the forwarder export directory */
561 ForwardExportDirectory
=
562 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
564 IMAGE_DIRECTORY_ENTRY_EXPORT
,
566 if (!ForwardExportDirectory
) break;
568 /* Allocate a name entry */
569 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
571 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
572 sizeof(*ForwardName
) +
575 if (!ForwardName
) break;
578 RtlCopyMemory(&ForwardName
->Name
[0],
579 DllName
.Buffer
+ DllName
.Length
,
581 ForwardName
->Hint
= 0;
583 /* Set the new address */
584 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
586 /* Snap the forwarder */
587 Status
= MiSnapThunk(LdrEntry
->DllBase
,
591 ForwardExportDirectory
,
596 /* Free the forwarder name and set the thunk */
597 ExFreePool(ForwardName
);
598 Address
->u1
= ForwardThunk
.u1
;
602 /* Go to the next entry */
603 NextEntry
= NextEntry
->Flink
;
607 RtlFreeUnicodeString(&ForwarderName
);
617 MmUnloadSystemImage(IN PVOID ImageHandle
)
619 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
620 PVOID BaseAddress
= LdrEntry
->DllBase
;
622 ANSI_STRING TempName
;
623 BOOLEAN HadEntry
= FALSE
;
625 /* Acquire the loader lock */
626 KeEnterCriticalRegion();
627 KeWaitForSingleObject(&MmSystemLoadLock
,
633 /* Check if this driver was loaded at boot and didn't get imports parsed */
634 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
636 /* We should still be alive */
637 ASSERT(LdrEntry
->LoadCount
!= 0);
638 LdrEntry
->LoadCount
--;
640 /* Check if we're still loaded */
641 if (LdrEntry
->LoadCount
) goto Done
;
643 /* We should cleanup... are symbols loaded */
644 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
646 /* Create the ANSI name */
647 Status
= RtlUnicodeStringToAnsiString(&TempName
,
648 &LdrEntry
->BaseDllName
,
650 if (NT_SUCCESS(Status
))
652 /* Unload the symbols */
653 DbgUnLoadImageSymbols(&TempName
, BaseAddress
, -1);
654 RtlFreeAnsiString(&TempName
);
658 /* FIXME: Free the driver */
659 //MmFreeSection(LdrEntry->DllBase);
661 /* Check if we're linked in */
662 if (LdrEntry
->InLoadOrderLinks
.Flink
)
665 MiProcessLoaderEntry(LdrEntry
, FALSE
);
669 /* Dereference and clear the imports */
670 MiDereferenceImports(LdrEntry
->LoadedImports
);
671 MiClearImports(LdrEntry
);
673 /* Check if the entry needs to go away */
676 /* Check if it had a name */
677 if (LdrEntry
->FullDllName
.Buffer
)
680 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
683 /* Check if we had a section */
684 if (LdrEntry
->SectionPointer
)
687 ObDereferenceObject(LdrEntry
->SectionPointer
);
691 ExFreePool(LdrEntry
);
694 /* Release the system lock and return */
696 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
697 KeLeaveCriticalRegion();
698 return STATUS_SUCCESS
;
703 MiResolveImageReferences(IN PVOID ImageBase
,
704 IN PUNICODE_STRING ImageFileDirectory
,
705 IN PUNICODE_STRING NamePrefix OPTIONAL
,
706 OUT PCHAR
*MissingApi
,
707 OUT PWCHAR
*MissingDriver
,
708 OUT PLOAD_IMPORTS
*LoadImports
)
710 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
711 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
712 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
713 PLOAD_IMPORTS LoadedImports
;
714 ULONG GdiLink
, NormalLink
, i
;
715 BOOLEAN ReferenceNeeded
, Loaded
;
716 ANSI_STRING TempString
;
717 UNICODE_STRING NameString
, DllName
;
718 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
719 PVOID ImportBase
, DllBase
;
720 PLIST_ENTRY NextEntry
;
721 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
723 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
725 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
726 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
728 /* Assume no imports */
729 *LoadImports
= (PVOID
)-2;
731 /* Get the import descriptor */
732 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
734 IMAGE_DIRECTORY_ENTRY_IMPORT
,
736 if (!ImportDescriptor
) return STATUS_SUCCESS
;
738 /* Loop all imports to count them */
739 for (CurrentImport
= ImportDescriptor
;
740 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
747 /* Make sure we have non-zero imports */
750 /* Calculate and allocate the list we'll need */
751 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
752 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
757 /* Zero it and set the count */
758 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
759 LoadedImports
->Count
= ImportCount
;
765 LoadedImports
= NULL
;
768 /* Reset the import count and loop descriptors again */
769 ImportCount
= GdiLink
= NormalLink
= 0;
770 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
773 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
775 /* Check if this is a GDI driver */
777 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
779 /* We can also allow dxapi */
780 NormalLink
= NormalLink
|
781 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
782 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
784 /* Check if this is a valid GDI driver */
785 if ((GdiLink
) && (NormalLink
))
787 /* It's not, it's importing stuff it shouldn't be! */
788 MiDereferenceImports(LoadedImports
);
789 if (LoadedImports
) ExFreePool(LoadedImports
);
790 return STATUS_PROCEDURE_NOT_FOUND
;
793 /* Check if this is a "core" import, which doesn't get referenced */
794 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
795 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
796 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
798 /* Don't reference this */
799 ReferenceNeeded
= FALSE
;
803 /* Reference these modules */
804 ReferenceNeeded
= TRUE
;
807 /* Now setup a unicode string for the import */
808 RtlInitAnsiString(&TempString
, ImportName
);
809 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
810 if (!NT_SUCCESS(Status
))
813 MiDereferenceImports(LoadedImports
);
814 if (LoadedImports
) ExFreePool(LoadedImports
);
818 /* We don't support name prefixes yet */
819 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
821 /* Remember that we haven't loaded the import at this point */
826 /* Loop the driver list */
827 NextEntry
= PsLoadedModuleList
.Flink
;
828 while (NextEntry
!= &PsLoadedModuleList
)
830 /* Get the loader entry and compare the name */
831 LdrEntry
= CONTAINING_RECORD(NextEntry
,
832 LDR_DATA_TABLE_ENTRY
,
834 if (RtlEqualUnicodeString(&NameString
,
835 &LdrEntry
->BaseDllName
,
838 /* Get the base address */
839 ImportBase
= LdrEntry
->DllBase
;
841 /* Check if we haven't loaded yet, and we need references */
842 if (!(Loaded
) && (ReferenceNeeded
))
844 /* Make sure we're not already loading */
845 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
847 /* Increase the load count */
848 LdrEntry
->LoadCount
++;
852 /* Done, break out */
856 /* Go to the next entry */
857 NextEntry
= NextEntry
->Flink
;
860 /* Check if we haven't loaded the import yet */
863 /* Setup the import DLL name */
864 DllName
.MaximumLength
= NameString
.Length
+
865 ImageFileDirectory
->Length
+
866 sizeof(UNICODE_NULL
);
867 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
868 DllName
.MaximumLength
,
872 /* Setup the base length and copy it */
873 DllName
.Length
= ImageFileDirectory
->Length
;
874 RtlCopyMemory(DllName
.Buffer
,
875 ImageFileDirectory
->Buffer
,
876 ImageFileDirectory
->Length
);
878 /* Now add the import name and null-terminate it */
879 RtlAppendStringToString((PSTRING
)&DllName
,
880 (PSTRING
)&NameString
);
881 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
884 Status
= MmLoadSystemImage(&DllName
,
890 if (NT_SUCCESS(Status
))
892 /* We can free the DLL Name */
893 ExFreePool(DllName
.Buffer
);
897 /* Fill out the information for the error */
898 *MissingDriver
= DllName
.Buffer
;
899 *(PULONG
)MissingDriver
|= 1;
905 /* We're out of resources */
906 Status
= STATUS_INSUFFICIENT_RESOURCES
;
909 /* Check if we're OK until now */
910 if (NT_SUCCESS(Status
))
912 /* We're now loaded */
916 ASSERT(DllBase
= DllEntry
->DllBase
);
918 /* Call the initialization routines */
919 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
920 if (!NT_SUCCESS(Status
))
922 /* We failed, unload the image */
923 MmUnloadSystemImage(DllEntry
);
929 /* Check if we failed by here */
930 if (!NT_SUCCESS(Status
))
932 /* Cleanup and return */
933 RtlFreeUnicodeString(&NameString
);
934 MiDereferenceImports(LoadedImports
);
935 if (LoadedImports
) ExFreePool(LoadedImports
);
939 /* Loop again to make sure that everything is OK */
943 /* Check if we're support to reference this import */
944 if ((ReferenceNeeded
) && (LoadedImports
))
946 /* Make sure we're not already loading */
947 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
950 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
955 /* Free the import name */
956 RtlFreeUnicodeString(&NameString
);
958 /* Set the missing driver name and get the export directory */
959 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
960 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
962 IMAGE_DIRECTORY_ENTRY_EXPORT
,
964 if (!ExportDirectory
)
966 /* Cleanup and return */
967 MiDereferenceImports(LoadedImports
);
968 if (LoadedImports
) ExFreePool(LoadedImports
);
969 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
972 /* Make sure we have an IAT */
973 if (ImportDescriptor
->OriginalFirstThunk
)
975 /* Get the first thunks */
976 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
977 ImportDescriptor
->OriginalFirstThunk
);
978 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
979 ImportDescriptor
->FirstThunk
);
982 while (OrigThunk
->u1
.AddressOfData
)
985 Status
= MiSnapThunk(ImportBase
,
993 if (!NT_SUCCESS(Status
))
995 /* Cleanup and return */
996 MiDereferenceImports(LoadedImports
);
997 if (LoadedImports
) ExFreePool(LoadedImports
);
1001 /* Reset the buffer */
1002 *MissingApi
= MissingApiBuffer
;
1006 /* Go to the next import */
1010 /* Check if we have an import list */
1013 /* Reset the count again, and loop entries*/
1015 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1017 if (LoadedImports
->Entry
[i
])
1019 /* Got an entry, OR it with 1 in case it's the single entry */
1020 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1025 /* Check if we had no imports */
1028 /* Free the list and set it to no imports */
1029 ExFreePool(LoadedImports
);
1030 LoadedImports
= (PVOID
)-2;
1032 else if (ImportCount
== 1)
1034 /* Just one entry, we can free the table and only use our entry */
1035 ExFreePool(LoadedImports
);
1036 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1038 else if (ImportCount
!= LoadedImports
->Count
)
1040 /* FIXME: Can this happen? */
1041 DPRINT1("Unhandled scenario\n");
1045 /* Return the list */
1046 *LoadImports
= LoadedImports
;
1049 /* Return success */
1050 return STATUS_SUCCESS
;
1055 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1057 PLIST_ENTRY NextEntry
;
1059 PIMAGE_NT_HEADERS NtHeader
;
1060 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1061 PIMAGE_FILE_HEADER FileHeader
;
1062 BOOLEAN ValidRelocs
;
1063 PIMAGE_DATA_DIRECTORY DataDirectory
;
1064 PVOID DllBase
, NewImageAddress
;
1067 /* Loop driver list */
1068 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1069 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1070 NextEntry
= NextEntry
->Flink
)
1072 /* Get the loader entry and NT header */
1073 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1074 LDR_DATA_TABLE_ENTRY
,
1076 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1079 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1081 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1082 &LdrEntry
->FullDllName
);
1084 /* Skip kernel and HAL */
1085 /* ROS HACK: Skip BOOTVID/KDCOM too */
1087 if (i
<= 4) continue;
1089 /* Skip non-drivers */
1090 if (!NtHeader
) continue;
1092 /* Get the file header and make sure we can relocate */
1093 FileHeader
= &NtHeader
->FileHeader
;
1094 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1095 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1096 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1098 /* Everything made sense until now, check the relocation section too */
1099 DataDirectory
= &NtHeader
->OptionalHeader
.
1100 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1101 if (!DataDirectory
->VirtualAddress
)
1103 /* We don't really have relocations */
1104 ValidRelocs
= FALSE
;
1108 /* Make sure the size is valid */
1109 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1110 LdrEntry
->SizeOfImage
)
1112 /* They're not, skip */
1116 /* We have relocations */
1120 /* Remember the original address */
1121 DllBase
= LdrEntry
->DllBase
;
1123 /* Allocate a virtual section for the module */
1124 NewImageAddress
= MmAllocateSection(LdrEntry
->SizeOfImage
, NULL
);
1125 if (!NewImageAddress
)
1127 /* Shouldn't happen */
1128 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1133 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1134 ASSERT(ExpInitializationPhase
== 0);
1136 /* Now copy the entire driver over */
1137 RtlCopyMemory(NewImageAddress
, DllBase
, LdrEntry
->SizeOfImage
);
1140 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1142 /* Set the image base to the old address */
1143 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1145 /* Check if we had relocations */
1148 /* Relocate the image */
1149 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1153 STATUS_CONFLICTING_ADDRESSES
,
1154 STATUS_INVALID_IMAGE_FORMAT
);
1155 if (!NT_SUCCESS(Status
))
1157 /* This shouldn't happen */
1158 DPRINT1("Relocations failed!\n");
1163 /* Update the loader entry */
1164 LdrEntry
->DllBase
= NewImageAddress
;
1166 /* Update the thunks */
1167 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1168 MiUpdateThunks(LoaderBlock
,
1171 LdrEntry
->SizeOfImage
);
1173 /* Update the loader entry */
1174 LdrEntry
->Flags
|= 0x01000000;
1175 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1176 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1177 LdrEntry
->SizeOfImage
= LdrEntry
->SizeOfImage
;
1183 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1185 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1186 PLIST_ENTRY ListHead
, NextEntry
;
1189 /* Setup the loaded module list and lock */
1190 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1191 InitializeListHead(&PsLoadedModuleList
);
1193 /* Get loop variables and the kernel entry */
1194 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1195 NextEntry
= ListHead
->Flink
;
1196 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1197 LDR_DATA_TABLE_ENTRY
,
1199 PsNtosImageBase
= LdrEntry
->DllBase
;
1201 /* Loop the loader block */
1202 while (NextEntry
!= ListHead
)
1204 /* Get the loader entry */
1205 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1206 LDR_DATA_TABLE_ENTRY
,
1209 /* FIXME: ROS HACK. Make sure this is a driver */
1210 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1212 /* Skip this entry */
1213 NextEntry
= NextEntry
->Flink
;
1217 /* Calculate the size we'll need and allocate a copy */
1218 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1219 LdrEntry
->BaseDllName
.MaximumLength
+
1220 sizeof(UNICODE_NULL
);
1221 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1222 if (!NewEntry
) return FALSE
;
1224 /* Copy the entry over */
1225 *NewEntry
= *LdrEntry
;
1227 /* Allocate the name */
1228 NewEntry
->FullDllName
.Buffer
=
1229 ExAllocatePoolWithTag(PagedPool
,
1230 LdrEntry
->FullDllName
.MaximumLength
+
1231 sizeof(UNICODE_NULL
),
1233 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1235 /* Set the base name */
1236 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1238 /* Copy the full and base name */
1239 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1240 LdrEntry
->FullDllName
.Buffer
,
1241 LdrEntry
->FullDllName
.MaximumLength
);
1242 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1243 LdrEntry
->BaseDllName
.Buffer
,
1244 LdrEntry
->BaseDllName
.MaximumLength
);
1246 /* Null-terminate the base name */
1247 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1248 sizeof(WCHAR
)] = UNICODE_NULL
;
1250 /* Insert the entry into the list */
1251 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1252 NextEntry
= NextEntry
->Flink
;
1255 /* Build the import lists for the boot drivers */
1256 //MiBuildImportsForBootDrivers();
1264 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1266 PIMAGE_NT_HEADERS NtHeader
;
1269 /* Get NT Headers */
1270 NtHeader
= RtlImageNtHeader(BaseAddress
);
1273 /* Check if this image is only safe for UP while we have 2+ CPUs */
1274 if ((KeNumberProcessors
> 1) &&
1275 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1282 /* Otherwise, it's safe */
1288 MmCheckSystemImage(IN HANDLE ImageHandle
,
1289 IN BOOLEAN PurgeSection
)
1292 HANDLE SectionHandle
;
1293 PVOID ViewBase
= NULL
;
1294 SIZE_T ViewSize
= 0;
1295 IO_STATUS_BLOCK IoStatusBlock
;
1296 FILE_STANDARD_INFORMATION FileStandardInfo
;
1297 KAPC_STATE ApcState
;
1300 /* Create a section for the DLL */
1301 Status
= ZwCreateSection(&SectionHandle
,
1302 SECTION_MAP_EXECUTE
,
1308 if (!NT_SUCCESS(Status
)) return Status
;
1310 /* Make sure we're in the system process */
1311 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1314 Status
= ZwMapViewOfSection(SectionHandle
,
1324 if (!NT_SUCCESS(Status
))
1326 /* We failed, close the handle and return */
1327 KeUnstackDetachProcess(&ApcState
);
1328 ZwClose(SectionHandle
);
1332 /* Now query image information */
1333 Status
= ZwQueryInformationFile(ImageHandle
,
1336 sizeof(FileStandardInfo
),
1337 FileStandardInformation
);
1338 if ( NT_SUCCESS(Status
) )
1340 /* First, verify the checksum */
1341 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1347 /* Set checksum failure */
1348 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1351 /* Check that it's a valid SMP image if we have more then one CPU */
1352 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1354 /* Otherwise it's not the right image */
1355 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1359 /* Unmap the section, close the handle, and return status */
1360 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1361 KeUnstackDetachProcess(&ApcState
);
1362 ZwClose(SectionHandle
);
1368 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1369 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1370 IN PUNICODE_STRING LoadedName OPTIONAL
,
1372 OUT PVOID
*ModuleObject
,
1373 OUT PVOID
*ImageBaseAddress
)
1375 PVOID ModuleLoadBase
= NULL
;
1377 HANDLE FileHandle
= NULL
;
1378 OBJECT_ATTRIBUTES ObjectAttributes
;
1379 IO_STATUS_BLOCK IoStatusBlock
;
1380 PIMAGE_NT_HEADERS NtHeader
;
1381 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
;
1382 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1384 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1385 PCHAR MissingApiName
, Buffer
;
1386 PWCHAR MissingDriverName
;
1387 HANDLE SectionHandle
;
1388 ACCESS_MASK DesiredAccess
;
1389 PVOID Section
= NULL
;
1390 BOOLEAN LockOwned
= FALSE
;
1391 PLIST_ENTRY NextEntry
;
1394 /* Detect session-load */
1398 ASSERT(NamePrefix
== NULL
);
1399 ASSERT(LoadedName
== NULL
);
1401 /* Make sure the process is in session too */
1402 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1405 if (ModuleObject
) *ModuleObject
= NULL
;
1406 if (ImageBaseAddress
) *ImageBaseAddress
= NULL
;
1408 /* Allocate a buffer we'll use for names */
1409 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1410 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1412 /* Check for a separator */
1413 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1418 /* Loop the path until we get to the base name */
1419 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1420 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1422 /* Get the length */
1423 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1424 BaseLength
*= sizeof(WCHAR
);
1426 /* Setup the string */
1427 BaseName
.Length
= (USHORT
)BaseLength
;
1428 BaseName
.Buffer
= p
;
1432 /* Otherwise, we already have a base name */
1433 BaseName
.Length
= FileName
->Length
;
1434 BaseName
.Buffer
= FileName
->Buffer
;
1437 /* Setup the maximum length */
1438 BaseName
.MaximumLength
= BaseName
.Length
;
1440 /* Now compute the base directory */
1441 BaseDirectory
= *FileName
;
1442 BaseDirectory
.Length
-= BaseName
.Length
;
1443 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1445 /* And the prefix, which for now is just the name itself */
1446 PrefixName
= *FileName
;
1448 /* Check if we have a prefix */
1449 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1451 /* Check if we already have a name, use it instead */
1452 if (LoadedName
) BaseName
= *LoadedName
;
1454 /* Acquire the load lock */
1456 ASSERT(LockOwned
== FALSE
);
1458 KeEnterCriticalRegion();
1459 KeWaitForSingleObject(&MmSystemLoadLock
,
1465 /* Scan the module list */
1466 NextEntry
= PsLoadedModuleList
.Flink
;
1467 while (NextEntry
!= &PsLoadedModuleList
)
1469 /* Get the entry and compare the names */
1470 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1471 LDR_DATA_TABLE_ENTRY
,
1473 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1475 /* Found it, break out */
1480 NextEntry
= NextEntry
->Flink
;
1483 /* Check if we found the image */
1484 if (NextEntry
!= &PsLoadedModuleList
)
1486 /* Check if we had already mapped a section */
1489 /* Dereference and clear */
1490 ObDereferenceObject(Section
);
1494 /* Check if this was supposed to be a session load */
1497 /* It wasn't, so just return the data */
1498 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1499 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1500 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1504 /* We don't support session loading yet */
1505 DPRINT1("Unsupported Session-Load!\n");
1514 /* It wasn't loaded, and we didn't have a previous attempt */
1515 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1516 KeLeaveCriticalRegion();
1519 /* Check if KD is enabled */
1520 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1522 /* FIXME: Attempt to get image from KD */
1525 /* We don't have a valid entry */
1528 /* Setup image attributes */
1529 InitializeObjectAttributes(&ObjectAttributes
,
1531 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1535 /* Open the image */
1536 Status
= ZwOpenFile(&FileHandle
,
1540 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1542 if (!NT_SUCCESS(Status
)) goto Quickie
;
1545 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1546 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1547 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1548 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1554 /* Check if this is a session-load */
1557 /* Then we only need read and execute */
1558 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1562 /* Otherwise, we can allow write access */
1563 DesiredAccess
= SECTION_ALL_ACCESS
;
1566 /* Initialize the attributes for the section */
1567 InitializeObjectAttributes(&ObjectAttributes
,
1569 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1573 /* Create the section */
1574 Status
= ZwCreateSection(&SectionHandle
,
1581 if (!NT_SUCCESS(Status
)) goto Quickie
;
1583 /* Now get the section pointer */
1584 Status
= ObReferenceObjectByHandle(SectionHandle
,
1585 SECTION_MAP_EXECUTE
,
1586 MmSectionObjectType
,
1590 ZwClose(SectionHandle
);
1591 if (!NT_SUCCESS(Status
)) goto Quickie
;
1593 /* Check if this was supposed to be a session-load */
1596 /* We don't support session loading yet */
1597 DPRINT1("Unsupported Session-Load!\n");
1601 /* Check the loader list again, we should end up in the path below */
1606 /* We don't have a valid entry */
1610 /* Load the image */
1611 Status
= MiLoadImageSection(&Section
,
1616 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1618 /* Get the NT Header */
1619 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1621 /* Relocate the driver */
1622 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1626 STATUS_CONFLICTING_ADDRESSES
,
1627 STATUS_INVALID_IMAGE_FORMAT
);
1628 if (!NT_SUCCESS(Status
)) goto Quickie
;
1630 /* Calculate the size we'll need for the entry and allocate it */
1631 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1633 sizeof(UNICODE_NULL
);
1635 /* Allocate the entry */
1636 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1640 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1644 /* Setup the entry */
1645 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1646 LdrEntry
->LoadCount
= 1;
1647 LdrEntry
->LoadedImports
= LoadedImports
;
1648 LdrEntry
->PatchInformation
= NULL
;
1650 /* Check the version */
1651 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1652 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1654 /* Mark this image as a native image */
1655 LdrEntry
->Flags
|= 0x80000000;
1658 /* Setup the rest of the entry */
1659 LdrEntry
->DllBase
= ModuleLoadBase
;
1660 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1661 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1662 LdrEntry
->SizeOfImage
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1663 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1664 LdrEntry
->SectionPointer
= LdrEntry
;
1666 /* Now write the DLL name */
1667 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1668 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1669 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1671 /* Copy and null-terminate it */
1672 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1675 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ 2] = UNICODE_NULL
;
1677 /* Now allocate the full name */
1678 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1680 sizeof(UNICODE_NULL
),
1682 if (!LdrEntry
->FullDllName
.Buffer
)
1684 /* Don't fail, just set it to zero */
1685 LdrEntry
->FullDllName
.Length
= 0;
1686 LdrEntry
->FullDllName
.MaximumLength
= 0;
1691 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1692 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1694 /* Copy and null-terminate */
1695 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1698 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ 2] = UNICODE_NULL
;
1702 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1704 /* Resolve imports */
1705 MissingApiName
= Buffer
;
1706 Status
= MiResolveImageReferences(ModuleLoadBase
,
1712 if (!NT_SUCCESS(Status
))
1715 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1717 /* Check if we need to free the name */
1718 if (LdrEntry
->FullDllName
.Buffer
)
1721 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1724 /* Free the entry itself */
1725 ExFreePool(LdrEntry
);
1730 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1731 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1733 /* Hook for KDB on loading a driver. */
1734 KDB_LOADDRIVER_HOOK(FileName
, LdrEntry
);
1737 /* If we have a file handle, close it */
1738 if (FileHandle
) ZwClose(FileHandle
);
1740 /* Check if we have the lock acquired */
1743 /* Release the lock */
1744 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1745 KeLeaveCriticalRegion();
1749 /* Check if we had a prefix */
1750 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1752 /* Free the name buffer and return status */
1762 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
1764 PVOID ProcAddress
= NULL
;
1765 ANSI_STRING AnsiRoutineName
;
1767 PLIST_ENTRY NextEntry
;
1768 extern LIST_ENTRY PsLoadedModuleList
;
1769 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1770 BOOLEAN Found
= FALSE
;
1771 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1772 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1775 /* Convert routine to ansi name */
1776 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
1779 if (!NT_SUCCESS(Status
)) return NULL
;
1782 KeEnterCriticalRegion();
1784 /* Loop the loaded module list */
1785 NextEntry
= PsLoadedModuleList
.Flink
;
1786 while (NextEntry
!= &PsLoadedModuleList
)
1789 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1790 LDR_DATA_TABLE_ENTRY
,
1793 /* Check if it's the kernel or HAL */
1794 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1800 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1807 /* Check if we found a valid binary */
1810 /* Find the procedure name */
1811 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
1814 /* Break out if we found it or if we already tried both modules */
1815 if (ProcAddress
) break;
1816 if (Modules
== 2) break;
1820 NextEntry
= NextEntry
->Flink
;
1823 /* Release the lock */
1824 KeLeaveCriticalRegion();
1826 /* Free the string and return */
1827 RtlFreeAnsiString(&AnsiRoutineName
);