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)
7 * ReactOS Portable Systems Group
10 /* INCLUDES *******************************************************************/
16 #line 16 "ARMĀ³::LOADER"
17 #define MODULE_INVOLVED_IN_ARM3
18 #include "./ARM3/miarm.h"
20 /* GCC's incompetence strikes again */
23 sprintf_nt(IN PCHAR Buffer
,
29 vsprintf(Buffer
, Format
, ap
);
33 /* GLOBALS ********************************************************************/
35 LIST_ENTRY PsLoadedModuleList
;
36 LIST_ENTRY MmLoadedUserImageList
;
37 KSPIN_LOCK PsLoadedModuleSpinLock
;
38 ERESOURCE PsLoadedModuleResource
;
39 ULONG_PTR PsNtosImageBase
;
40 KMUTANT MmSystemLoadLock
;
42 PVOID MmUnloadedDrivers
;
43 PVOID MmLastUnloadedDrivers
;
44 PVOID MmTriageActionTaken
;
47 BOOLEAN MmMakeLowMemory
;
48 BOOLEAN MmEnforceWriteProtection
= TRUE
;
50 /* FUNCTIONS ******************************************************************/
54 MiCacheImageSymbols(IN PVOID BaseAddress
)
57 PVOID DebugDirectory
= NULL
;
60 /* Make sure it's safe to access the image */
63 /* Get the debug directory */
64 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
66 IMAGE_DIRECTORY_ENTRY_DEBUG
,
69 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
75 /* Return the directory */
76 return DebugDirectory
;
81 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
83 IN PUNICODE_STRING FileName
,
84 IN BOOLEAN SessionLoad
,
85 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
87 PROS_SECTION_OBJECT Section
= *SectionPtr
;
93 LARGE_INTEGER SectionOffset
= {{0, 0}};
94 BOOLEAN LoadSymbols
= FALSE
;
96 PMMPTE PointerPte
, LastPte
;
101 /* Detect session load */
105 DPRINT1("Session loading not yet supported!\n");
109 /* Not session load, shouldn't have an entry */
110 ASSERT(LdrEntry
== NULL
);
112 /* Attach to the system process */
113 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
115 /* Check if we need to load symbols */
116 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
120 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
124 Process
= PsGetCurrentProcess();
125 Status
= MmMapViewOfSection(Section
,
136 /* Re-enable the flag */
137 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
139 /* Check if we failed with distinguished status code */
140 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
142 /* Change it to something more generic */
143 Status
= STATUS_INVALID_IMAGE_FORMAT
;
146 /* Now check if we failed */
147 if (!NT_SUCCESS(Status
))
149 /* Detach and return */
150 KeUnstackDetachProcess(&ApcState
);
154 /* Reserve system PTEs needed */
155 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
156 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
157 if (!PointerPte
) return STATUS_INSUFFICIENT_RESOURCES
;
159 /* New driver base */
160 LastPte
= PointerPte
+ PteCount
;
161 DriverBase
= MiPteToAddress(PointerPte
);
163 /* The driver is here */
164 *ImageBase
= DriverBase
;
166 /* Loop the new driver PTEs */
167 TempPte
= ValidKernelPte
;
168 while (PointerPte
< LastPte
)
170 /* Allocate a page */
171 TempPte
.u
.Hard
.PageFrameNumber
= MmAllocPage(MC_NPPOOL
);
174 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
175 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
176 *PointerPte
= TempPte
;
183 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
185 /* Now unmap the view */
186 Status
= MmUnmapViewOfSection(Process
, Base
);
187 ASSERT(NT_SUCCESS(Status
));
189 /* Detach and return status */
190 KeUnstackDetachProcess(&ApcState
);
196 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
200 /* Check if there's no imports or if we're a boot driver */
201 if ((ImportList
== (PVOID
)-1) ||
202 (ImportList
== (PVOID
)-2) ||
203 (ImportList
->Count
== 0))
205 /* Then there's nothing to do */
206 return STATUS_SUCCESS
;
209 /* Otherwise, FIXME */
210 DPRINT1("%u imports not dereferenced!\n", ImportList
->Count
);
211 for (i
= 0; i
< ImportList
->Count
; i
++)
213 DPRINT1("%wZ <%wZ>\n", &ImportList
->Entry
[i
]->FullDllName
, &ImportList
->Entry
[i
]->BaseDllName
);
215 return STATUS_UNSUCCESSFUL
;
220 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
224 /* Check if there's no imports or we're a boot driver or only one entry */
225 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
226 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
227 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
233 /* Otherwise, free the import list */
234 ExFreePool(LdrEntry
->LoadedImports
);
239 MiFindExportedRoutineByName(IN PVOID DllBase
,
240 IN PANSI_STRING ExportName
)
243 PUSHORT OrdinalTable
;
244 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
245 LONG Low
= 0, Mid
= 0, High
, Ret
;
252 /* Get the export directory */
253 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
255 IMAGE_DIRECTORY_ENTRY_EXPORT
,
257 if (!ExportDirectory
) return NULL
;
259 /* Setup name tables */
260 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
261 ExportDirectory
->AddressOfNames
);
262 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
263 ExportDirectory
->AddressOfNameOrdinals
);
265 /* Do a binary search */
266 High
= ExportDirectory
->NumberOfNames
- 1;
269 /* Get new middle value */
270 Mid
= (Low
+ High
) >> 1;
273 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
291 /* Check if we couldn't find it */
292 if (High
< Low
) return NULL
;
294 /* Otherwise, this is the ordinal */
295 Ordinal
= OrdinalTable
[Mid
];
297 /* Resolve the address and write it */
298 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
299 ExportDirectory
->AddressOfFunctions
);
300 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
303 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
304 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
310 MiLocateExportName(IN PVOID DllBase
,
314 PUSHORT OrdinalTable
;
315 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
316 LONG Low
= 0, Mid
= 0, High
, Ret
;
323 /* Get the export directory */
324 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
326 IMAGE_DIRECTORY_ENTRY_EXPORT
,
328 if (!ExportDirectory
) return NULL
;
330 /* Setup name tables */
331 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
332 ExportDirectory
->AddressOfNames
);
333 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
334 ExportDirectory
->AddressOfNameOrdinals
);
336 /* Do a binary search */
337 High
= ExportDirectory
->NumberOfNames
- 1;
340 /* Get new middle value */
341 Mid
= (Low
+ High
) >> 1;
344 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
362 /* Check if we couldn't find it */
363 if (High
< Low
) return NULL
;
365 /* Otherwise, this is the ordinal */
366 Ordinal
= OrdinalTable
[Mid
];
368 /* Resolve the address and write it */
369 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
370 ExportDirectory
->AddressOfFunctions
);
371 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
373 /* Check if the function is actually a forwarder */
374 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
375 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
387 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
388 IN PLIST_ENTRY ListHead
)
390 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
391 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
392 PMM_DLL_INITIALIZE DllInit
;
393 UNICODE_STRING RegPath
, ImportName
;
396 /* Try to see if the image exports a DllInitialize routine */
397 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
399 if (!DllInit
) return STATUS_SUCCESS
;
401 /* Do a temporary copy of BaseDllName called ImportName
402 * because we'll alter the length of the string
404 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
405 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
406 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
408 /* Obtain the path to this dll's service in the registry */
409 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
410 ImportName
.Length
+ sizeof(UNICODE_NULL
);
411 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
412 RegPath
.MaximumLength
,
415 /* Check if this allocation was unsuccessful */
416 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
418 /* Build and append the service name itself */
419 RegPath
.Length
= ServicesKeyName
.Length
;
420 RtlCopyMemory(RegPath
.Buffer
,
421 ServicesKeyName
.Buffer
,
422 ServicesKeyName
.Length
);
424 /* Check if there is a dot in the filename */
425 if (wcschr(ImportName
.Buffer
, L
'.'))
427 /* Remove the extension */
428 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
429 ImportName
.Buffer
) * sizeof(WCHAR
);
432 /* Append service name (the basename without extension) */
433 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
435 /* Now call the DllInit func */
436 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
437 Status
= DllInit(&RegPath
);
440 ExFreePool(RegPath
.Buffer
);
442 /* Return status value which DllInitialize returned */
448 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
453 /* Acquire module list lock */
454 KeEnterCriticalRegion();
455 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
457 /* Acquire the spinlock too as we will insert or remove the entry */
458 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
460 /* Insert or remove from the list */
461 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
462 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
465 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
466 ExReleaseResourceLite(&PsLoadedModuleResource
);
467 KeLeaveCriticalRegion();
472 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
477 ULONG_PTR OldBaseTop
, Delta
;
478 PLDR_DATA_TABLE_ENTRY LdrEntry
;
479 PLIST_ENTRY NextEntry
;
481 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
484 /* Calculate the top and delta */
485 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
486 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
488 /* Loop the loader block */
489 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
490 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
491 NextEntry
= NextEntry
->Flink
)
493 /* Get the loader entry */
494 LdrEntry
= CONTAINING_RECORD(NextEntry
,
495 LDR_DATA_TABLE_ENTRY
,
498 /* Get the import table */
499 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
501 IMAGE_DIRECTORY_ENTRY_IMPORT
,
503 if (!ImportDescriptor
) continue;
505 /* Make sure we have an IAT */
506 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
507 while ((ImportDescriptor
->Name
) &&
508 (ImportDescriptor
->OriginalFirstThunk
))
510 /* Get the image thunk */
511 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
512 ImportDescriptor
->FirstThunk
);
515 /* Check if it's within this module */
516 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
519 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
520 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
521 *ImageThunk
+= Delta
;
524 /* Go to the next thunk */
528 /* Go to the next import */
536 MiSnapThunk(IN PVOID DllBase
,
538 IN PIMAGE_THUNK_DATA Name
,
539 IN PIMAGE_THUNK_DATA Address
,
540 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
542 IN BOOLEAN SnapForwarder
,
543 OUT PCHAR
*MissingApi
)
548 PUSHORT OrdinalTable
;
549 PIMAGE_IMPORT_BY_NAME NameImport
;
551 ULONG Low
= 0, Mid
= 0, High
;
554 PCHAR MissingForwarder
;
555 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
558 UNICODE_STRING ForwarderName
;
559 PLIST_ENTRY NextEntry
;
560 PLDR_DATA_TABLE_ENTRY LdrEntry
;
561 ULONG ForwardExportSize
;
562 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
563 PIMAGE_IMPORT_BY_NAME ForwardName
;
565 IMAGE_THUNK_DATA ForwardThunk
;
568 /* Check if this is an ordinal */
569 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
570 if ((IsOrdinal
) && !(SnapForwarder
))
572 /* Get the ordinal number and set it as missing */
573 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
574 ExportDirectory
->Base
);
575 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
579 /* Get the VA if we don't have to snap */
580 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
581 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
583 /* Copy the procedure name */
585 (PCHAR
)&NameImport
->Name
[0],
586 MAXIMUM_FILENAME_LENGTH
- 1);
588 /* Setup name tables */
589 DPRINT("Import name: %s\n", NameImport
->Name
);
590 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
591 ExportDirectory
->AddressOfNames
);
592 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
593 ExportDirectory
->AddressOfNameOrdinals
);
595 /* Get the hint and check if it's valid */
596 Hint
= NameImport
->Hint
;
597 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
598 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
600 /* We have a match, get the ordinal number from here */
601 Ordinal
= OrdinalTable
[Hint
];
605 /* Do a binary search */
606 High
= ExportDirectory
->NumberOfNames
- 1;
609 /* Get new middle value */
610 Mid
= (Low
+ High
) >> 1;
613 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
631 /* Check if we couldn't find it */
632 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
634 /* Otherwise, this is the ordinal */
635 Ordinal
= OrdinalTable
[Mid
];
639 /* Check if the ordinal is invalid */
640 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
643 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
647 /* In case the forwarder is missing */
648 MissingForwarder
= NameBuffer
;
650 /* Resolve the address and write it */
651 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
652 ExportDirectory
->AddressOfFunctions
);
653 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
655 /* Assume success from now on */
656 Status
= STATUS_SUCCESS
;
658 /* Check if the function is actually a forwarder */
659 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
660 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
662 /* Now assume failure in case the forwarder doesn't exist */
663 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
665 /* Build the forwarder name */
666 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
667 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
670 DllName
.MaximumLength
= DllName
.Length
;
673 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
677 /* We failed, just return an error */
681 /* Loop the module list */
682 NextEntry
= PsLoadedModuleList
.Flink
;
683 while (NextEntry
!= &PsLoadedModuleList
)
685 /* Get the loader entry */
686 LdrEntry
= CONTAINING_RECORD(NextEntry
,
687 LDR_DATA_TABLE_ENTRY
,
690 /* Check if it matches */
691 if (RtlPrefixString((PSTRING
)&ForwarderName
,
692 (PSTRING
)&LdrEntry
->BaseDllName
,
695 /* Get the forwarder export directory */
696 ForwardExportDirectory
=
697 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
699 IMAGE_DIRECTORY_ENTRY_EXPORT
,
701 if (!ForwardExportDirectory
) break;
703 /* Allocate a name entry */
704 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
706 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
707 sizeof(*ForwardName
) +
710 if (!ForwardName
) break;
713 RtlCopyMemory(&ForwardName
->Name
[0],
714 DllName
.Buffer
+ DllName
.Length
,
716 ForwardName
->Hint
= 0;
718 /* Set the new address */
719 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
721 /* Snap the forwarder */
722 Status
= MiSnapThunk(LdrEntry
->DllBase
,
726 ForwardExportDirectory
,
731 /* Free the forwarder name and set the thunk */
732 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
733 Address
->u1
= ForwardThunk
.u1
;
737 /* Go to the next entry */
738 NextEntry
= NextEntry
->Flink
;
742 RtlFreeUnicodeString(&ForwarderName
);
752 MmUnloadSystemImage(IN PVOID ImageHandle
)
754 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
755 PVOID BaseAddress
= LdrEntry
->DllBase
;
758 BOOLEAN HadEntry
= FALSE
;
760 /* Acquire the loader lock */
761 KeEnterCriticalRegion();
762 KeWaitForSingleObject(&MmSystemLoadLock
,
768 /* Check if this driver was loaded at boot and didn't get imports parsed */
769 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
771 /* We should still be alive */
772 ASSERT(LdrEntry
->LoadCount
!= 0);
773 LdrEntry
->LoadCount
--;
775 /* Check if we're still loaded */
776 if (LdrEntry
->LoadCount
) goto Done
;
778 /* We should cleanup... are symbols loaded */
779 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
781 /* Create the ANSI name */
782 Status
= RtlUnicodeStringToAnsiString(&TempName
,
783 &LdrEntry
->BaseDllName
,
785 if (NT_SUCCESS(Status
))
787 /* Unload the symbols */
788 DbgUnLoadImageSymbols(&TempName
,
790 (ULONG_PTR
)ZwCurrentProcess());
791 RtlFreeAnsiString(&TempName
);
795 /* FIXME: Free the driver */
796 //MmFreeSection(LdrEntry->DllBase);
798 /* Check if we're linked in */
799 if (LdrEntry
->InLoadOrderLinks
.Flink
)
802 MiProcessLoaderEntry(LdrEntry
, FALSE
);
806 /* Dereference and clear the imports */
807 MiDereferenceImports(LdrEntry
->LoadedImports
);
808 MiClearImports(LdrEntry
);
810 /* Check if the entry needs to go away */
813 /* Check if it had a name */
814 if (LdrEntry
->FullDllName
.Buffer
)
817 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
820 /* Check if we had a section */
821 if (LdrEntry
->SectionPointer
)
824 ObDereferenceObject(LdrEntry
->SectionPointer
);
828 ExFreePool(LdrEntry
);
831 /* Release the system lock and return */
833 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
834 KeLeaveCriticalRegion();
835 return STATUS_SUCCESS
;
840 MiResolveImageReferences(IN PVOID ImageBase
,
841 IN PUNICODE_STRING ImageFileDirectory
,
842 IN PUNICODE_STRING NamePrefix OPTIONAL
,
843 OUT PCHAR
*MissingApi
,
844 OUT PWCHAR
*MissingDriver
,
845 OUT PLOAD_IMPORTS
*LoadImports
)
847 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
848 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
849 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
850 PLOAD_IMPORTS LoadedImports
, NewImports
;
851 ULONG GdiLink
, NormalLink
, i
;
852 BOOLEAN ReferenceNeeded
, Loaded
;
853 ANSI_STRING TempString
;
854 UNICODE_STRING NameString
, DllName
;
855 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
856 PVOID ImportBase
, DllBase
;
857 PLIST_ENTRY NextEntry
;
858 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
860 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
862 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
863 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
865 /* Assume no imports */
866 *LoadImports
= (PVOID
)-2;
868 /* Get the import descriptor */
869 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
871 IMAGE_DIRECTORY_ENTRY_IMPORT
,
873 if (!ImportDescriptor
) return STATUS_SUCCESS
;
875 /* Loop all imports to count them */
876 for (CurrentImport
= ImportDescriptor
;
877 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
884 /* Make sure we have non-zero imports */
887 /* Calculate and allocate the list we'll need */
888 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
889 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
895 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
901 LoadedImports
= NULL
;
904 /* Reset the import count and loop descriptors again */
905 ImportCount
= GdiLink
= NormalLink
= 0;
906 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
909 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
911 /* Check if this is a GDI driver */
913 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
915 /* We can also allow dxapi */
916 NormalLink
= NormalLink
|
917 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
918 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
920 /* Check if this is a valid GDI driver */
921 if ((GdiLink
) && (NormalLink
))
923 /* It's not, it's importing stuff it shouldn't be! */
924 MiDereferenceImports(LoadedImports
);
925 if (LoadedImports
) ExFreePool(LoadedImports
);
926 return STATUS_PROCEDURE_NOT_FOUND
;
929 /* Check if this is a "core" import, which doesn't get referenced */
930 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
931 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
932 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
934 /* Don't reference this */
935 ReferenceNeeded
= FALSE
;
939 /* Reference these modules */
940 ReferenceNeeded
= TRUE
;
943 /* Now setup a unicode string for the import */
944 RtlInitAnsiString(&TempString
, ImportName
);
945 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
946 if (!NT_SUCCESS(Status
))
949 MiDereferenceImports(LoadedImports
);
950 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
954 /* We don't support name prefixes yet */
955 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
957 /* Remember that we haven't loaded the import at this point */
962 /* Loop the driver list */
963 NextEntry
= PsLoadedModuleList
.Flink
;
964 while (NextEntry
!= &PsLoadedModuleList
)
966 /* Get the loader entry and compare the name */
967 LdrEntry
= CONTAINING_RECORD(NextEntry
,
968 LDR_DATA_TABLE_ENTRY
,
970 if (RtlEqualUnicodeString(&NameString
,
971 &LdrEntry
->BaseDllName
,
974 /* Get the base address */
975 ImportBase
= LdrEntry
->DllBase
;
977 /* Check if we haven't loaded yet, and we need references */
978 if (!(Loaded
) && (ReferenceNeeded
))
980 /* Make sure we're not already loading */
981 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
983 /* Increase the load count */
984 LdrEntry
->LoadCount
++;
988 /* Done, break out */
992 /* Go to the next entry */
993 NextEntry
= NextEntry
->Flink
;
996 /* Check if we haven't loaded the import yet */
999 /* Setup the import DLL name */
1000 DllName
.MaximumLength
= NameString
.Length
+
1001 ImageFileDirectory
->Length
+
1002 sizeof(UNICODE_NULL
);
1003 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1004 DllName
.MaximumLength
,
1008 /* Setup the base length and copy it */
1009 DllName
.Length
= ImageFileDirectory
->Length
;
1010 RtlCopyMemory(DllName
.Buffer
,
1011 ImageFileDirectory
->Buffer
,
1012 ImageFileDirectory
->Length
);
1014 /* Now add the import name and null-terminate it */
1015 RtlAppendStringToString((PSTRING
)&DllName
,
1016 (PSTRING
)&NameString
);
1017 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / sizeof(WCHAR
)] = UNICODE_NULL
;
1019 /* Load the image */
1020 Status
= MmLoadSystemImage(&DllName
,
1026 if (NT_SUCCESS(Status
))
1028 /* We can free the DLL Name */
1029 ExFreePool(DllName
.Buffer
);
1033 /* Fill out the information for the error */
1034 *MissingDriver
= DllName
.Buffer
;
1035 *(PULONG
)MissingDriver
|= 1;
1041 /* We're out of resources */
1042 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1045 /* Check if we're OK until now */
1046 if (NT_SUCCESS(Status
))
1048 /* We're now loaded */
1052 ASSERT(DllBase
= DllEntry
->DllBase
);
1054 /* Call the initialization routines */
1055 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1056 if (!NT_SUCCESS(Status
))
1058 /* We failed, unload the image */
1059 MmUnloadSystemImage(DllEntry
);
1065 /* Check if we failed by here */
1066 if (!NT_SUCCESS(Status
))
1068 /* Cleanup and return */
1069 RtlFreeUnicodeString(&NameString
);
1070 MiDereferenceImports(LoadedImports
);
1071 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1075 /* Loop again to make sure that everything is OK */
1079 /* Check if we're support to reference this import */
1080 if ((ReferenceNeeded
) && (LoadedImports
))
1082 /* Make sure we're not already loading */
1083 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1086 LoadedImports
->Entry
[LoadedImports
->Count
] = LdrEntry
;
1087 LoadedImports
->Count
++;
1091 /* Free the import name */
1092 RtlFreeUnicodeString(&NameString
);
1094 /* Set the missing driver name and get the export directory */
1095 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1096 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1098 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1100 if (!ExportDirectory
)
1102 /* Cleanup and return */
1103 MiDereferenceImports(LoadedImports
);
1104 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1105 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1108 /* Make sure we have an IAT */
1109 if (ImportDescriptor
->OriginalFirstThunk
)
1111 /* Get the first thunks */
1112 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1113 ImportDescriptor
->OriginalFirstThunk
);
1114 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1115 ImportDescriptor
->FirstThunk
);
1118 while (OrigThunk
->u1
.AddressOfData
)
1121 Status
= MiSnapThunk(ImportBase
,
1129 if (!NT_SUCCESS(Status
))
1131 /* Cleanup and return */
1132 MiDereferenceImports(LoadedImports
);
1133 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1137 /* Reset the buffer */
1138 *MissingApi
= MissingApiBuffer
;
1142 /* Go to the next import */
1146 /* Check if we have an import list */
1149 /* Reset the count again, and loop entries*/
1151 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1153 if (LoadedImports
->Entry
[i
])
1155 /* Got an entry, OR it with 1 in case it's the single entry */
1156 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1161 /* Check if we had no imports */
1164 /* Free the list and set it to no imports */
1165 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1166 LoadedImports
= (PVOID
)-2;
1168 else if (ImportCount
== 1)
1170 /* Just one entry, we can free the table and only use our entry */
1171 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1172 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1174 else if (ImportCount
!= LoadedImports
->Count
)
1176 /* Allocate a new list */
1177 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1178 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1184 NewImports
->Count
= 0;
1186 /* Loop all the imports */
1187 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1189 /* Make sure it's valid */
1190 if (LoadedImports
->Entry
[i
])
1193 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1194 NewImports
->Count
++;
1198 /* Free the old copy */
1199 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1200 LoadedImports
= NewImports
;
1204 /* Return the list */
1205 *LoadImports
= LoadedImports
;
1208 /* Return success */
1209 return STATUS_SUCCESS
;
1214 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1216 PLIST_ENTRY NextEntry
;
1218 PIMAGE_NT_HEADERS NtHeader
;
1219 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1220 PIMAGE_FILE_HEADER FileHeader
;
1221 BOOLEAN ValidRelocs
;
1222 PIMAGE_DATA_DIRECTORY DataDirectory
;
1223 PVOID DllBase
, NewImageAddress
;
1225 PMMPTE PointerPte
, StartPte
, LastPte
;
1226 PFN_NUMBER PteCount
;
1228 MMPTE TempPte
, OldPte
;
1230 /* Loop driver list */
1231 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1232 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1233 NextEntry
= NextEntry
->Flink
)
1235 /* Get the loader entry and NT header */
1236 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1237 LDR_DATA_TABLE_ENTRY
,
1239 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1242 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1244 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1245 &LdrEntry
->FullDllName
);
1247 /* Skip kernel and HAL */
1248 /* ROS HACK: Skip BOOTVID/KDCOM too */
1250 if (i
<= 4) continue;
1252 /* Skip non-drivers */
1253 if (!NtHeader
) continue;
1255 /* Get the file header and make sure we can relocate */
1256 FileHeader
= &NtHeader
->FileHeader
;
1257 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1258 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1259 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1261 /* Everything made sense until now, check the relocation section too */
1262 DataDirectory
= &NtHeader
->OptionalHeader
.
1263 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1264 if (!DataDirectory
->VirtualAddress
)
1266 /* We don't really have relocations */
1267 ValidRelocs
= FALSE
;
1271 /* Make sure the size is valid */
1272 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1273 LdrEntry
->SizeOfImage
)
1275 /* They're not, skip */
1279 /* We have relocations */
1283 /* Remember the original address */
1284 DllBase
= LdrEntry
->DllBase
;
1286 /* Get the first PTE and the number of PTEs we'll need */
1287 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1288 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1289 LastPte
= StartPte
+ PteCount
;
1292 while (PointerPte
< LastPte
)
1294 /* Mark the page modified in the PFN database */
1295 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1296 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1297 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1298 Pfn1
->u3
.e1
.Modified
= TRUE
;
1304 /* Now reserve system PTEs for the image */
1305 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1308 /* Shouldn't happen */
1309 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1313 /* This is the new virtual address for the module */
1314 LastPte
= PointerPte
+ PteCount
;
1315 NewImageAddress
= MiPteToAddress(PointerPte
);
1318 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1319 ASSERT(ExpInitializationPhase
== 0);
1321 /* Loop the new driver PTEs */
1322 TempPte
= ValidKernelPte
;
1323 while (PointerPte
< LastPte
)
1325 /* Copy the old data */
1327 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1329 /* Set page number from the loader's memory */
1330 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1333 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1334 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
1335 *PointerPte
= TempPte
;
1342 /* Update position */
1343 PointerPte
-= PteCount
;
1346 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1348 /* Set the image base to the address where the loader put it */
1349 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1351 /* Check if we had relocations */
1354 /* Relocate the image */
1355 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1359 STATUS_CONFLICTING_ADDRESSES
,
1360 STATUS_INVALID_IMAGE_FORMAT
);
1361 if (!NT_SUCCESS(Status
))
1363 /* This shouldn't happen */
1364 DPRINT1("Relocations failed!\n");
1369 /* Update the loader entry */
1370 LdrEntry
->DllBase
= NewImageAddress
;
1372 /* Update the thunks */
1373 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1374 MiUpdateThunks(LoaderBlock
,
1377 LdrEntry
->SizeOfImage
);
1379 /* Update the loader entry */
1380 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1381 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1382 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1383 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1385 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1391 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1393 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1394 PLIST_ENTRY ListHead
, NextEntry
;
1397 /* Setup the loaded module list and locks */
1398 ExInitializeResourceLite(&PsLoadedModuleResource
);
1399 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1400 InitializeListHead(&PsLoadedModuleList
);
1402 /* Get loop variables and the kernel entry */
1403 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1404 NextEntry
= ListHead
->Flink
;
1405 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1406 LDR_DATA_TABLE_ENTRY
,
1408 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1410 /* Loop the loader block */
1411 while (NextEntry
!= ListHead
)
1413 /* Get the loader entry */
1414 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1415 LDR_DATA_TABLE_ENTRY
,
1418 /* FIXME: ROS HACK. Make sure this is a driver */
1419 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1421 /* Skip this entry */
1422 NextEntry
= NextEntry
->Flink
;
1426 /* Calculate the size we'll need and allocate a copy */
1427 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1428 LdrEntry
->BaseDllName
.MaximumLength
+
1429 sizeof(UNICODE_NULL
);
1430 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1431 if (!NewEntry
) return FALSE
;
1433 /* Copy the entry over */
1434 *NewEntry
= *LdrEntry
;
1436 /* Allocate the name */
1437 NewEntry
->FullDllName
.Buffer
=
1438 ExAllocatePoolWithTag(PagedPool
,
1439 LdrEntry
->FullDllName
.MaximumLength
+
1440 sizeof(UNICODE_NULL
),
1442 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1444 /* Set the base name */
1445 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1447 /* Copy the full and base name */
1448 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1449 LdrEntry
->FullDllName
.Buffer
,
1450 LdrEntry
->FullDllName
.MaximumLength
);
1451 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1452 LdrEntry
->BaseDllName
.Buffer
,
1453 LdrEntry
->BaseDllName
.MaximumLength
);
1455 /* Null-terminate the base name */
1456 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1457 sizeof(WCHAR
)] = UNICODE_NULL
;
1459 /* Insert the entry into the list */
1460 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1461 NextEntry
= NextEntry
->Flink
;
1464 /* Build the import lists for the boot drivers */
1465 //MiBuildImportsForBootDrivers();
1473 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1475 PIMAGE_NT_HEADERS NtHeader
;
1478 /* Get NT Headers */
1479 NtHeader
= RtlImageNtHeader(BaseAddress
);
1482 /* Check if this image is only safe for UP while we have 2+ CPUs */
1483 if ((KeNumberProcessors
> 1) &&
1484 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1491 /* Otherwise, it's safe */
1497 MmCheckSystemImage(IN HANDLE ImageHandle
,
1498 IN BOOLEAN PurgeSection
)
1501 HANDLE SectionHandle
;
1502 PVOID ViewBase
= NULL
;
1503 SIZE_T ViewSize
= 0;
1504 IO_STATUS_BLOCK IoStatusBlock
;
1505 FILE_STANDARD_INFORMATION FileStandardInfo
;
1506 KAPC_STATE ApcState
;
1509 /* Create a section for the DLL */
1510 Status
= ZwCreateSection(&SectionHandle
,
1511 SECTION_MAP_EXECUTE
,
1517 if (!NT_SUCCESS(Status
)) return Status
;
1519 /* Make sure we're in the system process */
1520 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1523 Status
= ZwMapViewOfSection(SectionHandle
,
1533 if (!NT_SUCCESS(Status
))
1535 /* We failed, close the handle and return */
1536 KeUnstackDetachProcess(&ApcState
);
1537 ZwClose(SectionHandle
);
1541 /* Now query image information */
1542 Status
= ZwQueryInformationFile(ImageHandle
,
1545 sizeof(FileStandardInfo
),
1546 FileStandardInformation
);
1547 if ( NT_SUCCESS(Status
) )
1549 /* First, verify the checksum */
1550 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1556 /* Set checksum failure */
1557 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1560 /* Check that it's a valid SMP image if we have more then one CPU */
1561 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1563 /* Otherwise it's not the right image */
1564 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1568 /* Unmap the section, close the handle, and return status */
1569 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1570 KeUnstackDetachProcess(&ApcState
);
1571 ZwClose(SectionHandle
);
1577 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1578 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1579 IN PUNICODE_STRING LoadedName OPTIONAL
,
1581 OUT PVOID
*ModuleObject
,
1582 OUT PVOID
*ImageBaseAddress
)
1584 PVOID ModuleLoadBase
= NULL
;
1586 HANDLE FileHandle
= NULL
;
1587 OBJECT_ATTRIBUTES ObjectAttributes
;
1588 IO_STATUS_BLOCK IoStatusBlock
;
1589 PIMAGE_NT_HEADERS NtHeader
;
1590 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
1591 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1592 ULONG EntrySize
, DriverSize
;
1593 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1594 PCHAR MissingApiName
, Buffer
;
1595 PWCHAR MissingDriverName
;
1596 HANDLE SectionHandle
;
1597 ACCESS_MASK DesiredAccess
;
1598 PVOID Section
= NULL
;
1599 BOOLEAN LockOwned
= FALSE
;
1600 PLIST_ENTRY NextEntry
;
1601 IMAGE_INFO ImageInfo
;
1605 /* Detect session-load */
1609 ASSERT(NamePrefix
== NULL
);
1610 ASSERT(LoadedName
== NULL
);
1612 /* Make sure the process is in session too */
1613 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1616 /* Allocate a buffer we'll use for names */
1617 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1618 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1620 /* Check for a separator */
1621 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1626 /* Loop the path until we get to the base name */
1627 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1628 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1630 /* Get the length */
1631 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1632 BaseLength
*= sizeof(WCHAR
);
1634 /* Setup the string */
1635 BaseName
.Length
= (USHORT
)BaseLength
;
1636 BaseName
.Buffer
= p
;
1640 /* Otherwise, we already have a base name */
1641 BaseName
.Length
= FileName
->Length
;
1642 BaseName
.Buffer
= FileName
->Buffer
;
1645 /* Setup the maximum length */
1646 BaseName
.MaximumLength
= BaseName
.Length
;
1648 /* Now compute the base directory */
1649 BaseDirectory
= *FileName
;
1650 BaseDirectory
.Length
-= BaseName
.Length
;
1651 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1653 /* And the prefix, which for now is just the name itself */
1654 PrefixName
= *FileName
;
1656 /* Check if we have a prefix */
1657 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1659 /* Check if we already have a name, use it instead */
1660 if (LoadedName
) BaseName
= *LoadedName
;
1662 /* Acquire the load lock */
1664 ASSERT(LockOwned
== FALSE
);
1666 KeEnterCriticalRegion();
1667 KeWaitForSingleObject(&MmSystemLoadLock
,
1673 /* Scan the module list */
1674 NextEntry
= PsLoadedModuleList
.Flink
;
1675 while (NextEntry
!= &PsLoadedModuleList
)
1677 /* Get the entry and compare the names */
1678 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1679 LDR_DATA_TABLE_ENTRY
,
1681 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1683 /* Found it, break out */
1688 NextEntry
= NextEntry
->Flink
;
1691 /* Check if we found the image */
1692 if (NextEntry
!= &PsLoadedModuleList
)
1694 /* Check if we had already mapped a section */
1697 /* Dereference and clear */
1698 ObDereferenceObject(Section
);
1702 /* Check if this was supposed to be a session load */
1705 /* It wasn't, so just return the data */
1706 *ModuleObject
= LdrEntry
;
1707 *ImageBaseAddress
= LdrEntry
->DllBase
;
1708 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1712 /* We don't support session loading yet */
1713 DPRINT1("Unsupported Session-Load!\n");
1722 /* It wasn't loaded, and we didn't have a previous attempt */
1723 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1724 KeLeaveCriticalRegion();
1727 /* Check if KD is enabled */
1728 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1730 /* FIXME: Attempt to get image from KD */
1733 /* We don't have a valid entry */
1736 /* Setup image attributes */
1737 InitializeObjectAttributes(&ObjectAttributes
,
1739 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1743 /* Open the image */
1744 Status
= ZwOpenFile(&FileHandle
,
1748 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1750 if (!NT_SUCCESS(Status
)) goto Quickie
;
1753 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1754 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1755 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1756 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1762 /* Check if this is a session-load */
1765 /* Then we only need read and execute */
1766 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1770 /* Otherwise, we can allow write access */
1771 DesiredAccess
= SECTION_ALL_ACCESS
;
1774 /* Initialize the attributes for the section */
1775 InitializeObjectAttributes(&ObjectAttributes
,
1777 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1781 /* Create the section */
1782 Status
= ZwCreateSection(&SectionHandle
,
1789 if (!NT_SUCCESS(Status
)) goto Quickie
;
1791 /* Now get the section pointer */
1792 Status
= ObReferenceObjectByHandle(SectionHandle
,
1793 SECTION_MAP_EXECUTE
,
1794 MmSectionObjectType
,
1798 ZwClose(SectionHandle
);
1799 if (!NT_SUCCESS(Status
)) goto Quickie
;
1801 /* Check if this was supposed to be a session-load */
1804 /* We don't support session loading yet */
1805 DPRINT1("Unsupported Session-Load!\n");
1809 /* Check the loader list again, we should end up in the path below */
1814 /* We don't have a valid entry */
1818 /* Load the image */
1819 Status
= MiLoadImageSection(&Section
,
1824 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1826 /* Get the size of the driver */
1827 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1829 /* Make sure we're not being loaded into session space */
1832 /* Check for success */
1833 if (NT_SUCCESS(Status
))
1835 /* FIXME: Support large pages for drivers */
1838 /* Dereference the section */
1839 ObDereferenceObject(Section
);
1843 /* Get the NT Header */
1844 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1846 /* Relocate the driver */
1847 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1851 STATUS_CONFLICTING_ADDRESSES
,
1852 STATUS_INVALID_IMAGE_FORMAT
);
1853 if (!NT_SUCCESS(Status
)) goto Quickie
;
1855 /* Calculate the size we'll need for the entry and allocate it */
1856 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1858 sizeof(UNICODE_NULL
);
1860 /* Allocate the entry */
1861 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1865 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1869 /* Setup the entry */
1870 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1871 LdrEntry
->LoadCount
= 1;
1872 LdrEntry
->LoadedImports
= LoadedImports
;
1873 LdrEntry
->PatchInformation
= NULL
;
1875 /* Check the version */
1876 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1877 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1879 /* Mark this image as a native image */
1880 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
1883 /* Setup the rest of the entry */
1884 LdrEntry
->DllBase
= ModuleLoadBase
;
1885 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1886 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1887 LdrEntry
->SizeOfImage
= DriverSize
;
1888 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1889 LdrEntry
->SectionPointer
= Section
;
1891 /* Now write the DLL name */
1892 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1893 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1894 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1896 /* Copy and null-terminate it */
1897 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1900 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1902 /* Now allocate the full name */
1903 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1905 sizeof(UNICODE_NULL
),
1907 if (!LdrEntry
->FullDllName
.Buffer
)
1909 /* Don't fail, just set it to zero */
1910 LdrEntry
->FullDllName
.Length
= 0;
1911 LdrEntry
->FullDllName
.MaximumLength
= 0;
1916 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1917 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1919 /* Copy and null-terminate */
1920 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1923 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1927 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1929 /* Resolve imports */
1930 MissingApiName
= Buffer
;
1931 Status
= MiResolveImageReferences(ModuleLoadBase
,
1937 if (!NT_SUCCESS(Status
))
1940 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1942 /* Check if we need to free the name */
1943 if (LdrEntry
->FullDllName
.Buffer
)
1946 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1949 /* Free the entry itself */
1950 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
1955 /* Update the loader entry */
1956 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
1957 LDRP_ENTRY_PROCESSED
|
1959 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
1960 LdrEntry
->LoadedImports
= LoadedImports
;
1962 /* FIXME: Apply driver verifier */
1964 /* FIXME: Write-protect the system image */
1966 /* Check if notifications are enabled */
1967 if (PsImageNotifyEnabled
)
1969 /* Fill out the notification data */
1970 ImageInfo
.Properties
= 0;
1971 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
1972 ImageInfo
.SystemModeImage
= TRUE
;
1973 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
1974 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
1975 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
1977 /* Send the notification */
1978 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
1981 #if defined(KDBG) || defined(_WINKD_)
1982 /* MiCacheImageSymbols doesn't detect rossym */
1985 /* Check if there's symbols */
1986 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
1989 /* Check if the system root is present */
1990 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
1991 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
1993 /* Add the system root */
1994 UnicodeTemp
= PrefixName
;
1995 UnicodeTemp
.Buffer
+= 11;
1996 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
1999 &SharedUserData
->NtSystemRoot
[2],
2004 /* Build the name */
2005 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2008 /* Setup the ansi string */
2009 RtlInitString(&AnsiTemp
, Buffer
);
2011 /* Notify the debugger */
2012 DbgLoadImageSymbols(&AnsiTemp
,
2014 (ULONG_PTR
)ZwCurrentProcess());
2015 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
2018 /* FIXME: Page the driver */
2019 ASSERT(Section
== NULL
);
2021 /* Return pointers */
2022 *ModuleObject
= LdrEntry
;
2023 *ImageBaseAddress
= LdrEntry
->DllBase
;
2026 /* If we have a file handle, close it */
2027 if (FileHandle
) ZwClose(FileHandle
);
2029 /* Check if we have the lock acquired */
2032 /* Release the lock */
2033 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2034 KeLeaveCriticalRegion();
2038 /* Check if we had a prefix */
2039 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
2041 /* Free the name buffer and return status */
2042 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
2046 PLDR_DATA_TABLE_ENTRY
2048 MiLookupDataTableEntry(IN PVOID Address
)
2050 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
2051 PLIST_ENTRY NextEntry
;
2055 NextEntry
= PsLoadedModuleList
.Flink
;
2058 /* Get the loader entry */
2059 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2060 LDR_DATA_TABLE_ENTRY
,
2063 /* Check if the address matches */
2064 if ((Address
>= LdrEntry
->DllBase
) &&
2065 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
2066 LdrEntry
->SizeOfImage
)))
2069 FoundEntry
= LdrEntry
;
2074 NextEntry
= NextEntry
->Flink
;
2075 } while(NextEntry
!= &PsLoadedModuleList
);
2077 /* Return the entry */
2086 MmPageEntireDriver(IN PVOID AddressWithinSection
)
2088 PMMPTE StartPte
, EndPte
;
2089 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2092 /* Get the loader entry */
2093 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
2094 if (!LdrEntry
) return NULL
;
2096 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
2097 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
2099 /* Don't do anything, just return the base address */
2100 return LdrEntry
->DllBase
;
2103 /* Wait for active DPCs to finish before we page out the driver */
2104 KeFlushQueuedDpcs();
2106 /* Get the PTE range for the whole driver image */
2107 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
2108 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
2110 /* Enable paging for the PTE range */
2111 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
2112 MiSetPagingOfDriver(StartPte
, EndPte
);
2114 /* Return the base address */
2115 return LdrEntry
->DllBase
;
2123 MmResetDriverPaging(IN PVOID AddressWithinSection
)
2132 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
2134 PVOID ProcAddress
= NULL
;
2135 ANSI_STRING AnsiRoutineName
;
2137 PLIST_ENTRY NextEntry
;
2138 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2139 BOOLEAN Found
= FALSE
;
2140 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
2141 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
2144 /* Convert routine to ansi name */
2145 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
2148 if (!NT_SUCCESS(Status
)) return NULL
;
2151 KeEnterCriticalRegion();
2152 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
2154 /* Loop the loaded module list */
2155 NextEntry
= PsLoadedModuleList
.Flink
;
2156 while (NextEntry
!= &PsLoadedModuleList
)
2159 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2160 LDR_DATA_TABLE_ENTRY
,
2163 /* Check if it's the kernel or HAL */
2164 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
2170 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
2177 /* Check if we found a valid binary */
2180 /* Find the procedure name */
2181 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
2184 /* Break out if we found it or if we already tried both modules */
2185 if (ProcAddress
) break;
2186 if (Modules
== 2) break;
2190 NextEntry
= NextEntry
->Flink
;
2193 /* Release the lock */
2194 ExReleaseResourceLite(&PsLoadedModuleResource
);
2195 KeLeaveCriticalRegion();
2197 /* Free the string and return */
2198 RtlFreeAnsiString(&AnsiRoutineName
);