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 MiFreeBootDriverMemory(PVOID BaseAddress
,
33 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
36 MmDeleteVirtualMapping(NULL
,
37 (PVOID
)((ULONG_PTR
)BaseAddress
+ i
* PAGE_SIZE
),
46 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
48 IN PUNICODE_STRING FileName
,
49 IN BOOLEAN SessionLoad
,
50 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
52 PROS_SECTION_OBJECT Section
= *SectionPtr
;
58 LARGE_INTEGER SectionOffset
= {{0}};
59 BOOLEAN LoadSymbols
= FALSE
;
64 /* Detect session load */
68 DPRINT1("Session loading not yet supported!\n");
72 /* Not session load, shouldn't have an entry */
73 ASSERT(LdrEntry
== NULL
);
75 /* Attach to the system process */
76 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
78 /* Check if we need to load symbols */
79 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
83 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
87 Process
= PsGetCurrentProcess();
88 Status
= MmMapViewOfSection(Section
,
99 /* Re-enable the flag */
100 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
102 /* Check if we failed with distinguished status code */
103 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
105 /* Change it to something more generic */
106 Status
= STATUS_INVALID_IMAGE_FORMAT
;
109 /* Now check if we failed */
110 if (!NT_SUCCESS(Status
))
112 /* Detach and return */
113 KeUnstackDetachProcess(&ApcState
);
117 /* Get the driver size */
118 DriverSize
= Section
->ImageSection
->ImageSize
;
120 /* Allocate a virtual section for the module */
121 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
122 *ImageBase
= DriverBase
;
125 RtlCopyMemory(DriverBase
, Base
, DriverSize
);
127 /* Now unmap the view */
128 Status
= MmUnmapViewOfSection(Process
, Base
);
129 ASSERT(NT_SUCCESS(Status
));
131 /* Detach and return status */
132 KeUnstackDetachProcess(&ApcState
);
138 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
140 /* Check if there's no imports or if we're a boot driver */
141 if ((ImportList
== (PVOID
)-1) || (ImportList
== (PVOID
)-2))
143 /* Then there's nothing to do */
144 return STATUS_SUCCESS
;
147 /* Otherwise, FIXME */
148 DPRINT1("Imports not dereferenced!\n");
149 return STATUS_UNSUCCESSFUL
;
154 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
158 /* Check if there's no imports or we're a boot driver or only one entry */
159 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
160 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
161 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
167 /* Otherwise, free the import list */
168 ExFreePool(LdrEntry
->LoadedImports
);
173 MiFindExportedRoutineByName(IN PVOID DllBase
,
174 IN PANSI_STRING ExportName
)
177 PUSHORT OrdinalTable
;
178 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
179 LONG Low
= 0, Mid
= 0, High
, Ret
;
186 /* Get the export directory */
187 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
189 IMAGE_DIRECTORY_ENTRY_EXPORT
,
191 if (!ExportDirectory
) return NULL
;
193 /* Setup name tables */
194 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
195 ExportDirectory
->AddressOfNames
);
196 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
197 ExportDirectory
->AddressOfNameOrdinals
);
199 /* Do a binary search */
200 High
= ExportDirectory
->NumberOfNames
- 1;
203 /* Get new middle value */
204 Mid
= (Low
+ High
) >> 1;
207 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
225 /* Check if we couldn't find it */
226 if (High
< Low
) return NULL
;
228 /* Otherwise, this is the ordinal */
229 Ordinal
= OrdinalTable
[Mid
];
231 /* Resolve the address and write it */
232 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
233 ExportDirectory
->AddressOfFunctions
);
234 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
237 ASSERT((Function
> (PVOID
)ExportDirectory
) &&
238 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
244 MiLocateExportName(IN PVOID DllBase
,
248 PUSHORT OrdinalTable
;
249 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
250 LONG Low
= 0, Mid
= 0, High
, Ret
;
257 /* Get the export directory */
258 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
260 IMAGE_DIRECTORY_ENTRY_EXPORT
,
262 if (!ExportDirectory
) return NULL
;
264 /* Setup name tables */
265 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
266 ExportDirectory
->AddressOfNames
);
267 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
268 ExportDirectory
->AddressOfNameOrdinals
);
270 /* Do a binary search */
271 High
= ExportDirectory
->NumberOfNames
- 1;
274 /* Get new middle value */
275 Mid
= (Low
+ High
) >> 1;
278 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
296 /* Check if we couldn't find it */
297 if (High
< Low
) return NULL
;
299 /* Otherwise, this is the ordinal */
300 Ordinal
= OrdinalTable
[Mid
];
302 /* Resolve the address and write it */
303 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
304 ExportDirectory
->AddressOfFunctions
);
305 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
307 /* Check if the function is actually a forwarder */
308 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
309 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
321 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
322 IN PLIST_ENTRY ListHead
)
324 PMM_DLL_INITIALIZE DllInit
;
326 /* Try to see if the image exports a DllInitialize routine */
327 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
329 if (!DllInit
) return STATUS_SUCCESS
;
332 DPRINT1("DllInitialize not called!\n");
333 return STATUS_UNSUCCESSFUL
;
338 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
343 /* Acquire the lock */
344 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
346 /* Insert or remove from the list */
347 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
348 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
350 /* Release the lock */
351 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
356 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
361 ULONG_PTR OldBaseTop
, Delta
;
362 PLDR_DATA_TABLE_ENTRY LdrEntry
;
363 PLIST_ENTRY NextEntry
;
365 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
368 /* Calculate the top and delta */
369 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
370 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
372 /* Loop the loader block */
373 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
374 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
375 NextEntry
= NextEntry
->Flink
)
377 /* Get the loader entry */
378 LdrEntry
= CONTAINING_RECORD(NextEntry
,
379 LDR_DATA_TABLE_ENTRY
,
382 /* Get the import table */
383 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
385 IMAGE_DIRECTORY_ENTRY_IMPORT
,
387 if (!ImportDescriptor
) continue;
389 /* Make sure we have an IAT */
390 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
391 while ((ImportDescriptor
->Name
) &&
392 (ImportDescriptor
->OriginalFirstThunk
))
394 /* Get the image thunk */
395 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
396 ImportDescriptor
->FirstThunk
);
399 /* Check if it's within this module */
400 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
403 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
404 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
405 *ImageThunk
+= Delta
;
408 /* Go to the next thunk */
412 /* Go to the next import */
420 MiSnapThunk(IN PVOID DllBase
,
422 IN PIMAGE_THUNK_DATA Name
,
423 IN PIMAGE_THUNK_DATA Address
,
424 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
426 IN BOOLEAN SnapForwarder
,
427 OUT PCHAR
*MissingApi
)
432 PUSHORT OrdinalTable
;
433 PIMAGE_IMPORT_BY_NAME NameImport
;
435 ULONG Low
= 0, Mid
= 0, High
;
438 PCHAR MissingForwarder
;
439 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
442 UNICODE_STRING ForwarderName
;
443 PLIST_ENTRY NextEntry
;
444 PLDR_DATA_TABLE_ENTRY LdrEntry
;
445 ULONG ForwardExportSize
;
446 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
447 PIMAGE_IMPORT_BY_NAME ForwardName
;
449 IMAGE_THUNK_DATA ForwardThunk
;
452 /* Check if this is an ordinal */
453 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
454 if ((IsOrdinal
) && !(SnapForwarder
))
456 /* Get the ordinal number and set it as missing */
457 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
458 ExportDirectory
->Base
);
459 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
463 /* Get the VA if we don't have to snap */
464 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
465 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
467 /* Copy the procedure name */
469 (PCHAR
)&NameImport
->Name
[0],
470 MAXIMUM_FILENAME_LENGTH
- 1);
472 /* Setup name tables */
473 DPRINT("Import name: %s\n", NameImport
->Name
);
474 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
475 ExportDirectory
->AddressOfNames
);
476 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
477 ExportDirectory
->AddressOfNameOrdinals
);
479 /* Get the hint and check if it's valid */
480 Hint
= NameImport
->Hint
;
481 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
482 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
484 /* We have a match, get the ordinal number from here */
485 Ordinal
= OrdinalTable
[Hint
];
489 /* Do a binary search */
490 High
= ExportDirectory
->NumberOfNames
- 1;
493 /* Get new middle value */
494 Mid
= (Low
+ High
) >> 1;
497 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
515 /* Check if we couldn't find it */
516 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
518 /* Otherwise, this is the ordinal */
519 Ordinal
= OrdinalTable
[Mid
];
523 /* Check if the ordinal is invalid */
524 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
527 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
531 /* In case the forwarder is missing */
532 MissingForwarder
= NameBuffer
;
534 /* Resolve the address and write it */
535 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
536 ExportDirectory
->AddressOfFunctions
);
537 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
539 /* Assume success from now on */
540 Status
= STATUS_SUCCESS
;
542 /* Check if the function is actually a forwarder */
543 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
544 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
546 /* Now assume failure in case the forwarder doesn't exist */
547 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
549 /* Build the forwarder name */
550 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
551 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
554 DllName
.MaximumLength
= DllName
.Length
;
557 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
561 /* We failed, just return an error */
565 /* Loop the module list */
566 NextEntry
= PsLoadedModuleList
.Flink
;
567 while (NextEntry
!= &PsLoadedModuleList
)
569 /* Get the loader entry */
570 LdrEntry
= CONTAINING_RECORD(NextEntry
,
571 LDR_DATA_TABLE_ENTRY
,
574 /* Check if it matches */
575 if (RtlPrefixString((PSTRING
)&ForwarderName
,
576 (PSTRING
)&LdrEntry
->BaseDllName
,
579 /* Get the forwarder export directory */
580 ForwardExportDirectory
=
581 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
583 IMAGE_DIRECTORY_ENTRY_EXPORT
,
585 if (!ForwardExportDirectory
) break;
587 /* Allocate a name entry */
588 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
590 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
591 sizeof(*ForwardName
) +
594 if (!ForwardName
) break;
597 RtlCopyMemory(&ForwardName
->Name
[0],
598 DllName
.Buffer
+ DllName
.Length
,
600 ForwardName
->Hint
= 0;
602 /* Set the new address */
603 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
605 /* Snap the forwarder */
606 Status
= MiSnapThunk(LdrEntry
->DllBase
,
610 ForwardExportDirectory
,
615 /* Free the forwarder name and set the thunk */
616 ExFreePool(ForwardName
);
617 Address
->u1
= ForwardThunk
.u1
;
621 /* Go to the next entry */
622 NextEntry
= NextEntry
->Flink
;
626 RtlFreeUnicodeString(&ForwarderName
);
636 MmUnloadSystemImage(IN PVOID ImageHandle
)
638 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
639 PVOID BaseAddress
= LdrEntry
->DllBase
;
641 ANSI_STRING TempName
;
642 BOOLEAN HadEntry
= FALSE
;
644 /* Acquire the loader lock */
645 KeEnterCriticalRegion();
646 KeWaitForSingleObject(&MmSystemLoadLock
,
652 /* Check if this driver was loaded at boot and didn't get imports parsed */
653 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
655 /* We should still be alive */
656 ASSERT(LdrEntry
->LoadCount
!= 0);
657 LdrEntry
->LoadCount
--;
659 /* Check if we're still loaded */
660 if (LdrEntry
->LoadCount
) goto Done
;
662 /* We should cleanup... are symbols loaded */
663 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
665 /* Create the ANSI name */
666 Status
= RtlUnicodeStringToAnsiString(&TempName
,
667 &LdrEntry
->BaseDllName
,
669 if (NT_SUCCESS(Status
))
671 /* Unload the symbols */
672 DbgUnLoadImageSymbols(&TempName
, BaseAddress
, -1);
673 RtlFreeAnsiString(&TempName
);
677 /* FIXME: Free the driver */
678 //MmFreeSection(LdrEntry->DllBase);
680 /* Check if we're linked in */
681 if (LdrEntry
->InLoadOrderLinks
.Flink
)
684 MiProcessLoaderEntry(LdrEntry
, FALSE
);
688 /* Dereference and clear the imports */
689 MiDereferenceImports(LdrEntry
->LoadedImports
);
690 MiClearImports(LdrEntry
);
692 /* Check if the entry needs to go away */
695 /* Check if it had a name */
696 if (LdrEntry
->FullDllName
.Buffer
)
699 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
702 /* Check if we had a section */
703 if (LdrEntry
->SectionPointer
)
706 ObDereferenceObject(LdrEntry
->SectionPointer
);
710 ExFreePool(LdrEntry
);
713 /* Release the system lock and return */
715 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
716 KeLeaveCriticalRegion();
717 return STATUS_SUCCESS
;
722 MiResolveImageReferences(IN PVOID ImageBase
,
723 IN PUNICODE_STRING ImageFileDirectory
,
724 IN PUNICODE_STRING NamePrefix OPTIONAL
,
725 OUT PCHAR
*MissingApi
,
726 OUT PWCHAR
*MissingDriver
,
727 OUT PLOAD_IMPORTS
*LoadImports
)
729 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
730 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
731 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
732 PLOAD_IMPORTS LoadedImports
;
733 ULONG GdiLink
, NormalLink
, i
;
734 BOOLEAN ReferenceNeeded
, Loaded
;
735 ANSI_STRING TempString
;
736 UNICODE_STRING NameString
, DllName
;
737 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
738 PVOID ImportBase
, DllBase
;
739 PLIST_ENTRY NextEntry
;
740 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
742 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
744 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
745 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
747 /* Assume no imports */
748 *LoadImports
= (PVOID
)-2;
750 /* Get the import descriptor */
751 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
753 IMAGE_DIRECTORY_ENTRY_IMPORT
,
755 if (!ImportDescriptor
) return STATUS_SUCCESS
;
757 /* Loop all imports to count them */
758 for (CurrentImport
= ImportDescriptor
;
759 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
766 /* Make sure we have non-zero imports */
769 /* Calculate and allocate the list we'll need */
770 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
771 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
776 /* Zero it and set the count */
777 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
778 LoadedImports
->Count
= ImportCount
;
784 LoadedImports
= NULL
;
787 /* Reset the import count and loop descriptors again */
788 ImportCount
= GdiLink
= NormalLink
= 0;
789 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
792 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
794 /* Check if this is a GDI driver */
796 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
798 /* We can also allow dxapi */
799 NormalLink
= NormalLink
|
800 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
801 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
803 /* Check if this is a valid GDI driver */
804 if ((GdiLink
) && (NormalLink
))
806 /* It's not, it's importing stuff it shouldn't be! */
807 MiDereferenceImports(LoadedImports
);
808 if (LoadedImports
) ExFreePool(LoadedImports
);
809 return STATUS_PROCEDURE_NOT_FOUND
;
812 /* Check if this is a "core" import, which doesn't get referenced */
813 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
814 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
815 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
817 /* Don't reference this */
818 ReferenceNeeded
= FALSE
;
822 /* Reference these modules */
823 ReferenceNeeded
= TRUE
;
826 /* Now setup a unicode string for the import */
827 RtlInitAnsiString(&TempString
, ImportName
);
828 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
829 if (!NT_SUCCESS(Status
))
832 MiDereferenceImports(LoadedImports
);
833 if (LoadedImports
) ExFreePool(LoadedImports
);
837 /* We don't support name prefixes yet */
838 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
840 /* Remember that we haven't loaded the import at this point */
845 /* Loop the driver list */
846 NextEntry
= PsLoadedModuleList
.Flink
;
847 while (NextEntry
!= &PsLoadedModuleList
)
849 /* Get the loader entry and compare the name */
850 LdrEntry
= CONTAINING_RECORD(NextEntry
,
851 LDR_DATA_TABLE_ENTRY
,
853 if (RtlEqualUnicodeString(&NameString
,
854 &LdrEntry
->BaseDllName
,
857 /* Get the base address */
858 ImportBase
= LdrEntry
->DllBase
;
860 /* Check if we haven't loaded yet, and we need references */
861 if (!(Loaded
) && (ReferenceNeeded
))
863 /* Make sure we're not already loading */
864 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
866 /* Increase the load count */
867 LdrEntry
->LoadCount
++;
871 /* Done, break out */
875 /* Go to the next entry */
876 NextEntry
= NextEntry
->Flink
;
879 /* Check if we haven't loaded the import yet */
882 /* Setup the import DLL name */
883 DllName
.MaximumLength
= NameString
.Length
+
884 ImageFileDirectory
->Length
+
885 sizeof(UNICODE_NULL
);
886 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
887 DllName
.MaximumLength
,
891 /* Setup the base length and copy it */
892 DllName
.Length
= ImageFileDirectory
->Length
;
893 RtlCopyMemory(DllName
.Buffer
,
894 ImageFileDirectory
->Buffer
,
895 ImageFileDirectory
->Length
);
897 /* Now add the import name and null-terminate it */
898 RtlAppendStringToString((PSTRING
)&DllName
,
899 (PSTRING
)&NameString
);
900 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
903 Status
= MmLoadSystemImage(&DllName
,
909 if (NT_SUCCESS(Status
))
911 /* We can free the DLL Name */
912 ExFreePool(DllName
.Buffer
);
916 /* Fill out the information for the error */
917 *MissingDriver
= DllName
.Buffer
;
918 *(PULONG
)MissingDriver
|= 1;
924 /* We're out of resources */
925 Status
= STATUS_INSUFFICIENT_RESOURCES
;
928 /* Check if we're OK until now */
929 if (NT_SUCCESS(Status
))
931 /* We're now loaded */
935 ASSERT(DllBase
= DllEntry
->DllBase
);
937 /* Call the initialization routines */
938 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
939 if (!NT_SUCCESS(Status
))
941 /* We failed, unload the image */
942 MmUnloadSystemImage(DllEntry
);
948 /* Check if we failed by here */
949 if (!NT_SUCCESS(Status
))
951 /* Cleanup and return */
952 RtlFreeUnicodeString(&NameString
);
953 MiDereferenceImports(LoadedImports
);
954 if (LoadedImports
) ExFreePool(LoadedImports
);
958 /* Loop again to make sure that everything is OK */
962 /* Check if we're support to reference this import */
963 if ((ReferenceNeeded
) && (LoadedImports
))
965 /* Make sure we're not already loading */
966 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
969 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
974 /* Free the import name */
975 RtlFreeUnicodeString(&NameString
);
977 /* Set the missing driver name and get the export directory */
978 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
979 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
981 IMAGE_DIRECTORY_ENTRY_EXPORT
,
983 if (!ExportDirectory
)
985 /* Cleanup and return */
986 MiDereferenceImports(LoadedImports
);
987 if (LoadedImports
) ExFreePool(LoadedImports
);
988 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
991 /* Make sure we have an IAT */
992 if (ImportDescriptor
->OriginalFirstThunk
)
994 /* Get the first thunks */
995 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
996 ImportDescriptor
->OriginalFirstThunk
);
997 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
998 ImportDescriptor
->FirstThunk
);
1001 while (OrigThunk
->u1
.AddressOfData
)
1004 Status
= MiSnapThunk(ImportBase
,
1012 if (!NT_SUCCESS(Status
))
1014 /* Cleanup and return */
1015 MiDereferenceImports(LoadedImports
);
1016 if (LoadedImports
) ExFreePool(LoadedImports
);
1020 /* Reset the buffer */
1021 *MissingApi
= MissingApiBuffer
;
1025 /* Go to the next import */
1029 /* Check if we have an import list */
1032 /* Reset the count again, and loop entries*/
1034 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1036 if (LoadedImports
->Entry
[i
])
1038 /* Got an entry, OR it with 1 in case it's the single entry */
1039 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1044 /* Check if we had no imports */
1047 /* Free the list and set it to no imports */
1048 ExFreePool(LoadedImports
);
1049 LoadedImports
= (PVOID
)-2;
1051 else if (ImportCount
== 1)
1053 /* Just one entry, we can free the table and only use our entry */
1054 ExFreePool(LoadedImports
);
1055 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1057 else if (ImportCount
!= LoadedImports
->Count
)
1059 /* FIXME: Can this happen? */
1060 DPRINT1("Unhandled scenario\n");
1064 /* Return the list */
1065 *LoadImports
= LoadedImports
;
1068 /* Return success */
1069 return STATUS_SUCCESS
;
1074 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1076 PLIST_ENTRY NextEntry
;
1078 PIMAGE_NT_HEADERS NtHeader
;
1079 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1080 PIMAGE_FILE_HEADER FileHeader
;
1081 BOOLEAN ValidRelocs
;
1082 PIMAGE_DATA_DIRECTORY DataDirectory
;
1083 PVOID DllBase
, NewImageAddress
;
1086 /* Loop driver list */
1087 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1088 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1089 NextEntry
= NextEntry
->Flink
)
1091 /* Get the loader entry and NT header */
1092 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1093 LDR_DATA_TABLE_ENTRY
,
1095 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1098 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1100 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1101 &LdrEntry
->FullDllName
);
1103 /* Skip kernel and HAL */
1104 /* ROS HACK: Skip BOOTVID/KDCOM too */
1106 if (i
<= 4) continue;
1108 /* Skip non-drivers */
1109 if (!NtHeader
) continue;
1111 /* Get the file header and make sure we can relocate */
1112 FileHeader
= &NtHeader
->FileHeader
;
1113 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1114 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1115 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1117 /* Everything made sense until now, check the relocation section too */
1118 DataDirectory
= &NtHeader
->OptionalHeader
.
1119 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1120 if (!DataDirectory
->VirtualAddress
)
1122 /* We don't really have relocations */
1123 ValidRelocs
= FALSE
;
1127 /* Make sure the size is valid */
1128 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1129 LdrEntry
->SizeOfImage
)
1131 /* They're not, skip */
1135 /* We have relocations */
1139 /* Remember the original address */
1140 DllBase
= LdrEntry
->DllBase
;
1142 /* Allocate a virtual section for the module */
1143 NewImageAddress
= MmAllocateSection(LdrEntry
->SizeOfImage
, NULL
);
1144 if (!NewImageAddress
)
1146 /* Shouldn't happen */
1147 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1152 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1153 ASSERT(ExpInitializationPhase
== 0);
1155 /* Now copy the entire driver over */
1156 RtlCopyMemory(NewImageAddress
, DllBase
, LdrEntry
->SizeOfImage
);
1159 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1161 /* Set the image base to the old address */
1162 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1164 /* Check if we had relocations */
1167 /* Relocate the image */
1168 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1172 STATUS_CONFLICTING_ADDRESSES
,
1173 STATUS_INVALID_IMAGE_FORMAT
);
1174 if (!NT_SUCCESS(Status
))
1176 /* This shouldn't happen */
1177 DPRINT1("Relocations failed!\n");
1182 /* Update the loader entry */
1183 LdrEntry
->DllBase
= NewImageAddress
;
1185 /* Update the thunks */
1186 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1187 MiUpdateThunks(LoaderBlock
,
1190 LdrEntry
->SizeOfImage
);
1192 /* Update the loader entry */
1193 LdrEntry
->Flags
|= 0x01000000;
1194 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1195 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1196 LdrEntry
->SizeOfImage
= LdrEntry
->SizeOfImage
;
1198 /* Free the old copy */
1199 MiFreeBootDriverMemory(DllBase
, LdrEntry
->SizeOfImage
);
1205 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1207 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1208 PLIST_ENTRY ListHead
, NextEntry
;
1211 /* Setup the loaded module list and lock */
1212 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1213 InitializeListHead(&PsLoadedModuleList
);
1215 /* Get loop variables and the kernel entry */
1216 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1217 NextEntry
= ListHead
->Flink
;
1218 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1219 LDR_DATA_TABLE_ENTRY
,
1221 PsNtosImageBase
= LdrEntry
->DllBase
;
1223 /* Loop the loader block */
1224 while (NextEntry
!= ListHead
)
1226 /* Get the loader entry */
1227 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1228 LDR_DATA_TABLE_ENTRY
,
1231 /* FIXME: ROS HACK. Make sure this is a driver */
1232 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1234 /* Skip this entry */
1235 NextEntry
= NextEntry
->Flink
;
1239 /* Calculate the size we'll need and allocate a copy */
1240 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1241 LdrEntry
->BaseDllName
.MaximumLength
+
1242 sizeof(UNICODE_NULL
);
1243 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1244 if (!NewEntry
) return FALSE
;
1246 /* Copy the entry over */
1247 *NewEntry
= *LdrEntry
;
1249 /* Allocate the name */
1250 NewEntry
->FullDllName
.Buffer
=
1251 ExAllocatePoolWithTag(PagedPool
,
1252 LdrEntry
->FullDllName
.MaximumLength
+
1253 sizeof(UNICODE_NULL
),
1255 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1257 /* Set the base name */
1258 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1260 /* Copy the full and base name */
1261 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1262 LdrEntry
->FullDllName
.Buffer
,
1263 LdrEntry
->FullDllName
.MaximumLength
);
1264 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1265 LdrEntry
->BaseDllName
.Buffer
,
1266 LdrEntry
->BaseDllName
.MaximumLength
);
1268 /* Null-terminate the base name */
1269 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1270 sizeof(WCHAR
)] = UNICODE_NULL
;
1272 /* Insert the entry into the list */
1273 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1274 NextEntry
= NextEntry
->Flink
;
1277 /* Build the import lists for the boot drivers */
1278 //MiBuildImportsForBootDrivers();
1286 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1288 PIMAGE_NT_HEADERS NtHeader
;
1291 /* Get NT Headers */
1292 NtHeader
= RtlImageNtHeader(BaseAddress
);
1295 /* Check if this image is only safe for UP while we have 2+ CPUs */
1296 if ((KeNumberProcessors
> 1) &&
1297 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1304 /* Otherwise, it's safe */
1310 MmCheckSystemImage(IN HANDLE ImageHandle
,
1311 IN BOOLEAN PurgeSection
)
1314 HANDLE SectionHandle
;
1315 PVOID ViewBase
= NULL
;
1316 SIZE_T ViewSize
= 0;
1317 IO_STATUS_BLOCK IoStatusBlock
;
1318 FILE_STANDARD_INFORMATION FileStandardInfo
;
1319 KAPC_STATE ApcState
;
1322 /* Create a section for the DLL */
1323 Status
= ZwCreateSection(&SectionHandle
,
1324 SECTION_MAP_EXECUTE
,
1330 if (!NT_SUCCESS(Status
)) return Status
;
1332 /* Make sure we're in the system process */
1333 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1336 Status
= ZwMapViewOfSection(SectionHandle
,
1346 if (!NT_SUCCESS(Status
))
1348 /* We failed, close the handle and return */
1349 KeUnstackDetachProcess(&ApcState
);
1350 ZwClose(SectionHandle
);
1354 /* Now query image information */
1355 Status
= ZwQueryInformationFile(ImageHandle
,
1358 sizeof(FileStandardInfo
),
1359 FileStandardInformation
);
1360 if ( NT_SUCCESS(Status
) )
1362 /* First, verify the checksum */
1363 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1369 /* Set checksum failure */
1370 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1373 /* Check that it's a valid SMP image if we have more then one CPU */
1374 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1376 /* Otherwise it's not the right image */
1377 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1381 /* Unmap the section, close the handle, and return status */
1382 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1383 KeUnstackDetachProcess(&ApcState
);
1384 ZwClose(SectionHandle
);
1390 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1391 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1392 IN PUNICODE_STRING LoadedName OPTIONAL
,
1394 OUT PVOID
*ModuleObject
,
1395 OUT PVOID
*ImageBaseAddress
)
1397 PVOID ModuleLoadBase
= NULL
;
1399 HANDLE FileHandle
= NULL
;
1400 OBJECT_ATTRIBUTES ObjectAttributes
;
1401 IO_STATUS_BLOCK IoStatusBlock
;
1402 PIMAGE_NT_HEADERS NtHeader
;
1403 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
;
1404 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1406 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1407 PCHAR MissingApiName
, Buffer
;
1408 PWCHAR MissingDriverName
;
1409 HANDLE SectionHandle
;
1410 ACCESS_MASK DesiredAccess
;
1411 PVOID Section
= NULL
;
1412 BOOLEAN LockOwned
= FALSE
;
1413 PLIST_ENTRY NextEntry
;
1416 /* Detect session-load */
1420 ASSERT(NamePrefix
== NULL
);
1421 ASSERT(LoadedName
== NULL
);
1423 /* Make sure the process is in session too */
1424 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1427 if (ModuleObject
) *ModuleObject
= NULL
;
1428 if (ImageBaseAddress
) *ImageBaseAddress
= NULL
;
1430 /* Allocate a buffer we'll use for names */
1431 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1432 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1434 /* Check for a separator */
1435 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1440 /* Loop the path until we get to the base name */
1441 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1442 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1444 /* Get the length */
1445 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1446 BaseLength
*= sizeof(WCHAR
);
1448 /* Setup the string */
1449 BaseName
.Length
= (USHORT
)BaseLength
;
1450 BaseName
.Buffer
= p
;
1454 /* Otherwise, we already have a base name */
1455 BaseName
.Length
= FileName
->Length
;
1456 BaseName
.Buffer
= FileName
->Buffer
;
1459 /* Setup the maximum length */
1460 BaseName
.MaximumLength
= BaseName
.Length
;
1462 /* Now compute the base directory */
1463 BaseDirectory
= *FileName
;
1464 BaseDirectory
.Length
-= BaseName
.Length
;
1465 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1467 /* And the prefix, which for now is just the name itself */
1468 PrefixName
= *FileName
;
1470 /* Check if we have a prefix */
1471 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1473 /* Check if we already have a name, use it instead */
1474 if (LoadedName
) BaseName
= *LoadedName
;
1476 /* Acquire the load lock */
1478 ASSERT(LockOwned
== FALSE
);
1480 KeEnterCriticalRegion();
1481 KeWaitForSingleObject(&MmSystemLoadLock
,
1487 /* Scan the module list */
1488 NextEntry
= PsLoadedModuleList
.Flink
;
1489 while (NextEntry
!= &PsLoadedModuleList
)
1491 /* Get the entry and compare the names */
1492 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1493 LDR_DATA_TABLE_ENTRY
,
1495 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1497 /* Found it, break out */
1502 NextEntry
= NextEntry
->Flink
;
1505 /* Check if we found the image */
1506 if (NextEntry
!= &PsLoadedModuleList
)
1508 /* Check if we had already mapped a section */
1511 /* Dereference and clear */
1512 ObDereferenceObject(Section
);
1516 /* Check if this was supposed to be a session load */
1519 /* It wasn't, so just return the data */
1520 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1521 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1522 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1526 /* We don't support session loading yet */
1527 DPRINT1("Unsupported Session-Load!\n");
1536 /* It wasn't loaded, and we didn't have a previous attempt */
1537 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1538 KeLeaveCriticalRegion();
1541 /* Check if KD is enabled */
1542 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1544 /* FIXME: Attempt to get image from KD */
1547 /* We don't have a valid entry */
1550 /* Setup image attributes */
1551 InitializeObjectAttributes(&ObjectAttributes
,
1553 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1557 /* Open the image */
1558 Status
= ZwOpenFile(&FileHandle
,
1562 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1564 if (!NT_SUCCESS(Status
)) goto Quickie
;
1567 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1568 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1569 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1570 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1576 /* Check if this is a session-load */
1579 /* Then we only need read and execute */
1580 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1584 /* Otherwise, we can allow write access */
1585 DesiredAccess
= SECTION_ALL_ACCESS
;
1588 /* Initialize the attributes for the section */
1589 InitializeObjectAttributes(&ObjectAttributes
,
1591 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1595 /* Create the section */
1596 Status
= ZwCreateSection(&SectionHandle
,
1603 if (!NT_SUCCESS(Status
)) goto Quickie
;
1605 /* Now get the section pointer */
1606 Status
= ObReferenceObjectByHandle(SectionHandle
,
1607 SECTION_MAP_EXECUTE
,
1608 MmSectionObjectType
,
1612 ZwClose(SectionHandle
);
1613 if (!NT_SUCCESS(Status
)) goto Quickie
;
1615 /* Check if this was supposed to be a session-load */
1618 /* We don't support session loading yet */
1619 DPRINT1("Unsupported Session-Load!\n");
1623 /* Check the loader list again, we should end up in the path below */
1628 /* We don't have a valid entry */
1632 /* Load the image */
1633 Status
= MiLoadImageSection(&Section
,
1638 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1640 /* Get the NT Header */
1641 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1643 /* Relocate the driver */
1644 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1648 STATUS_CONFLICTING_ADDRESSES
,
1649 STATUS_INVALID_IMAGE_FORMAT
);
1650 if (!NT_SUCCESS(Status
)) goto Quickie
;
1652 /* Calculate the size we'll need for the entry and allocate it */
1653 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1655 sizeof(UNICODE_NULL
);
1657 /* Allocate the entry */
1658 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1662 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1666 /* Setup the entry */
1667 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1668 LdrEntry
->LoadCount
= 1;
1669 LdrEntry
->LoadedImports
= LoadedImports
;
1670 LdrEntry
->PatchInformation
= NULL
;
1672 /* Check the version */
1673 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1674 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1676 /* Mark this image as a native image */
1677 LdrEntry
->Flags
|= 0x80000000;
1680 /* Setup the rest of the entry */
1681 LdrEntry
->DllBase
= ModuleLoadBase
;
1682 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1683 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1684 LdrEntry
->SizeOfImage
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1685 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1686 LdrEntry
->SectionPointer
= LdrEntry
;
1688 /* Now write the DLL name */
1689 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1690 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1691 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1693 /* Copy and null-terminate it */
1694 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1697 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ 2] = UNICODE_NULL
;
1699 /* Now allocate the full name */
1700 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1702 sizeof(UNICODE_NULL
),
1704 if (!LdrEntry
->FullDllName
.Buffer
)
1706 /* Don't fail, just set it to zero */
1707 LdrEntry
->FullDllName
.Length
= 0;
1708 LdrEntry
->FullDllName
.MaximumLength
= 0;
1713 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1714 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1716 /* Copy and null-terminate */
1717 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1720 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ 2] = UNICODE_NULL
;
1724 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1726 /* Resolve imports */
1727 MissingApiName
= Buffer
;
1728 Status
= MiResolveImageReferences(ModuleLoadBase
,
1734 if (!NT_SUCCESS(Status
))
1737 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1739 /* Check if we need to free the name */
1740 if (LdrEntry
->FullDllName
.Buffer
)
1743 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1746 /* Free the entry itself */
1747 ExFreePool(LdrEntry
);
1752 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1753 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1755 /* Hook for KDB on loading a driver. */
1756 KDB_LOADDRIVER_HOOK(FileName
, LdrEntry
);
1759 /* If we have a file handle, close it */
1760 if (FileHandle
) ZwClose(FileHandle
);
1762 /* Check if we have the lock acquired */
1765 /* Release the lock */
1766 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1767 KeLeaveCriticalRegion();
1771 /* Check if we had a prefix */
1772 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1774 /* Free the name buffer and return status */
1784 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
1786 PVOID ProcAddress
= NULL
;
1787 ANSI_STRING AnsiRoutineName
;
1789 PLIST_ENTRY NextEntry
;
1790 extern LIST_ENTRY PsLoadedModuleList
;
1791 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1792 BOOLEAN Found
= FALSE
;
1793 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1794 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1797 /* Convert routine to ansi name */
1798 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
1801 if (!NT_SUCCESS(Status
)) return NULL
;
1804 KeEnterCriticalRegion();
1806 /* Loop the loaded module list */
1807 NextEntry
= PsLoadedModuleList
.Flink
;
1808 while (NextEntry
!= &PsLoadedModuleList
)
1811 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1812 LDR_DATA_TABLE_ENTRY
,
1815 /* Check if it's the kernel or HAL */
1816 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1822 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1829 /* Check if we found a valid binary */
1832 /* Find the procedure name */
1833 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
1836 /* Break out if we found it or if we already tried both modules */
1837 if (ProcAddress
) break;
1838 if (Modules
== 2) break;
1842 NextEntry
= NextEntry
->Flink
;
1845 /* Release the lock */
1846 KeLeaveCriticalRegion();
1848 /* Free the string and return */
1849 RtlFreeAnsiString(&AnsiRoutineName
);