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 /* FUNCTIONS ******************************************************************/
51 MiCacheImageSymbols(IN PVOID BaseAddress
)
54 PVOID DebugDirectory
= NULL
;
57 /* Make sure it's safe to access the image */
60 /* Get the debug directory */
61 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
63 IMAGE_DIRECTORY_ENTRY_DEBUG
,
66 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
72 /* Return the directory */
73 return DebugDirectory
;
78 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
80 IN PUNICODE_STRING FileName
,
81 IN BOOLEAN SessionLoad
,
82 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
84 PROS_SECTION_OBJECT Section
= *SectionPtr
;
90 LARGE_INTEGER SectionOffset
= {{0, 0}};
91 BOOLEAN LoadSymbols
= FALSE
;
93 PMMPTE PointerPte
, LastPte
;
98 /* Detect session load */
102 DPRINT1("Session loading not yet supported!\n");
106 /* Not session load, shouldn't have an entry */
107 ASSERT(LdrEntry
== NULL
);
109 /* Attach to the system process */
110 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
112 /* Check if we need to load symbols */
113 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
117 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
121 Process
= PsGetCurrentProcess();
122 Status
= MmMapViewOfSection(Section
,
133 /* Re-enable the flag */
134 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
136 /* Check if we failed with distinguished status code */
137 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
139 /* Change it to something more generic */
140 Status
= STATUS_INVALID_IMAGE_FORMAT
;
143 /* Now check if we failed */
144 if (!NT_SUCCESS(Status
))
146 /* Detach and return */
147 KeUnstackDetachProcess(&ApcState
);
151 /* Reserve system PTEs needed */
152 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
153 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
154 if (!PointerPte
) return STATUS_INSUFFICIENT_RESOURCES
;
156 /* New driver base */
157 LastPte
= PointerPte
+ PteCount
;
158 DriverBase
= MiPteToAddress(PointerPte
);
160 /* The driver is here */
161 *ImageBase
= DriverBase
;
163 /* Loop the new driver PTEs */
164 TempPte
= ValidKernelPte
;
165 while (PointerPte
< LastPte
)
167 /* Allocate a page */
168 TempPte
.u
.Hard
.PageFrameNumber
= MmAllocPage(MC_NPPOOL
);
171 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
172 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
173 *PointerPte
= TempPte
;
180 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
182 /* Now unmap the view */
183 Status
= MmUnmapViewOfSection(Process
, Base
);
184 ASSERT(NT_SUCCESS(Status
));
186 /* Detach and return status */
187 KeUnstackDetachProcess(&ApcState
);
193 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
197 /* Check if there's no imports or if we're a boot driver */
198 if ((ImportList
== (PVOID
)-1) ||
199 (ImportList
== (PVOID
)-2) ||
200 (ImportList
->Count
== 0))
202 /* Then there's nothing to do */
203 return STATUS_SUCCESS
;
206 /* Otherwise, FIXME */
207 DPRINT1("%u imports not dereferenced!\n", ImportList
->Count
);
208 for (i
= 0; i
< ImportList
->Count
; i
++)
210 DPRINT1("%wZ <%wZ>\n", &ImportList
->Entry
[i
]->FullDllName
, &ImportList
->Entry
[i
]->BaseDllName
);
212 return STATUS_UNSUCCESSFUL
;
217 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
221 /* Check if there's no imports or we're a boot driver or only one entry */
222 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
223 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
224 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
230 /* Otherwise, free the import list */
231 ExFreePool(LdrEntry
->LoadedImports
);
236 MiFindExportedRoutineByName(IN PVOID DllBase
,
237 IN PANSI_STRING ExportName
)
240 PUSHORT OrdinalTable
;
241 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
242 LONG Low
= 0, Mid
= 0, High
, Ret
;
249 /* Get the export directory */
250 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
252 IMAGE_DIRECTORY_ENTRY_EXPORT
,
254 if (!ExportDirectory
) return NULL
;
256 /* Setup name tables */
257 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
258 ExportDirectory
->AddressOfNames
);
259 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
260 ExportDirectory
->AddressOfNameOrdinals
);
262 /* Do a binary search */
263 High
= ExportDirectory
->NumberOfNames
- 1;
266 /* Get new middle value */
267 Mid
= (Low
+ High
) >> 1;
270 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
288 /* Check if we couldn't find it */
289 if (High
< Low
) return NULL
;
291 /* Otherwise, this is the ordinal */
292 Ordinal
= OrdinalTable
[Mid
];
294 /* Resolve the address and write it */
295 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
296 ExportDirectory
->AddressOfFunctions
);
297 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
300 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
301 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
307 MiLocateExportName(IN PVOID DllBase
,
311 PUSHORT OrdinalTable
;
312 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
313 LONG Low
= 0, Mid
= 0, High
, Ret
;
320 /* Get the export directory */
321 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
323 IMAGE_DIRECTORY_ENTRY_EXPORT
,
325 if (!ExportDirectory
) return NULL
;
327 /* Setup name tables */
328 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
329 ExportDirectory
->AddressOfNames
);
330 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
331 ExportDirectory
->AddressOfNameOrdinals
);
333 /* Do a binary search */
334 High
= ExportDirectory
->NumberOfNames
- 1;
337 /* Get new middle value */
338 Mid
= (Low
+ High
) >> 1;
341 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
359 /* Check if we couldn't find it */
360 if (High
< Low
) return NULL
;
362 /* Otherwise, this is the ordinal */
363 Ordinal
= OrdinalTable
[Mid
];
365 /* Resolve the address and write it */
366 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
367 ExportDirectory
->AddressOfFunctions
);
368 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
370 /* Check if the function is actually a forwarder */
371 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
372 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
384 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
385 IN PLIST_ENTRY ListHead
)
387 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
388 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
389 PMM_DLL_INITIALIZE DllInit
;
390 UNICODE_STRING RegPath
, ImportName
;
393 /* Try to see if the image exports a DllInitialize routine */
394 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
396 if (!DllInit
) return STATUS_SUCCESS
;
398 /* Do a temporary copy of BaseDllName called ImportName
399 * because we'll alter the length of the string
401 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
402 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
403 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
405 /* Obtain the path to this dll's service in the registry */
406 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
407 ImportName
.Length
+ sizeof(UNICODE_NULL
);
408 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
409 RegPath
.MaximumLength
,
412 /* Check if this allocation was unsuccessful */
413 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
415 /* Build and append the service name itself */
416 RegPath
.Length
= ServicesKeyName
.Length
;
417 RtlCopyMemory(RegPath
.Buffer
,
418 ServicesKeyName
.Buffer
,
419 ServicesKeyName
.Length
);
421 /* Check if there is a dot in the filename */
422 if (wcschr(ImportName
.Buffer
, L
'.'))
424 /* Remove the extension */
425 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
426 ImportName
.Buffer
) * sizeof(WCHAR
);
429 /* Append service name (the basename without extension) */
430 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
432 /* Now call the DllInit func */
433 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
434 Status
= DllInit(&RegPath
);
437 ExFreePool(RegPath
.Buffer
);
439 /* Return status value which DllInitialize returned */
445 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
450 /* Acquire module list lock */
451 KeEnterCriticalRegion();
452 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
454 /* Acquire the spinlock too as we will insert or remove the entry */
455 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
457 /* Insert or remove from the list */
458 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
459 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
462 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
463 ExReleaseResourceLite(&PsLoadedModuleResource
);
464 KeLeaveCriticalRegion();
469 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
474 ULONG_PTR OldBaseTop
, Delta
;
475 PLDR_DATA_TABLE_ENTRY LdrEntry
;
476 PLIST_ENTRY NextEntry
;
478 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
481 /* Calculate the top and delta */
482 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
483 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
485 /* Loop the loader block */
486 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
487 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
488 NextEntry
= NextEntry
->Flink
)
490 /* Get the loader entry */
491 LdrEntry
= CONTAINING_RECORD(NextEntry
,
492 LDR_DATA_TABLE_ENTRY
,
495 /* Get the import table */
496 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
498 IMAGE_DIRECTORY_ENTRY_IMPORT
,
500 if (!ImportDescriptor
) continue;
502 /* Make sure we have an IAT */
503 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
504 while ((ImportDescriptor
->Name
) &&
505 (ImportDescriptor
->OriginalFirstThunk
))
507 /* Get the image thunk */
508 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
509 ImportDescriptor
->FirstThunk
);
512 /* Check if it's within this module */
513 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
516 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
517 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
518 *ImageThunk
+= Delta
;
521 /* Go to the next thunk */
525 /* Go to the next import */
533 MiSnapThunk(IN PVOID DllBase
,
535 IN PIMAGE_THUNK_DATA Name
,
536 IN PIMAGE_THUNK_DATA Address
,
537 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
539 IN BOOLEAN SnapForwarder
,
540 OUT PCHAR
*MissingApi
)
545 PUSHORT OrdinalTable
;
546 PIMAGE_IMPORT_BY_NAME NameImport
;
548 ULONG Low
= 0, Mid
= 0, High
;
551 PCHAR MissingForwarder
;
552 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
555 UNICODE_STRING ForwarderName
;
556 PLIST_ENTRY NextEntry
;
557 PLDR_DATA_TABLE_ENTRY LdrEntry
;
558 ULONG ForwardExportSize
;
559 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
560 PIMAGE_IMPORT_BY_NAME ForwardName
;
562 IMAGE_THUNK_DATA ForwardThunk
;
565 /* Check if this is an ordinal */
566 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
567 if ((IsOrdinal
) && !(SnapForwarder
))
569 /* Get the ordinal number and set it as missing */
570 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
571 ExportDirectory
->Base
);
572 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
576 /* Get the VA if we don't have to snap */
577 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
578 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
580 /* Copy the procedure name */
582 (PCHAR
)&NameImport
->Name
[0],
583 MAXIMUM_FILENAME_LENGTH
- 1);
585 /* Setup name tables */
586 DPRINT("Import name: %s\n", NameImport
->Name
);
587 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
588 ExportDirectory
->AddressOfNames
);
589 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
590 ExportDirectory
->AddressOfNameOrdinals
);
592 /* Get the hint and check if it's valid */
593 Hint
= NameImport
->Hint
;
594 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
595 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
597 /* We have a match, get the ordinal number from here */
598 Ordinal
= OrdinalTable
[Hint
];
602 /* Do a binary search */
603 High
= ExportDirectory
->NumberOfNames
- 1;
606 /* Get new middle value */
607 Mid
= (Low
+ High
) >> 1;
610 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
628 /* Check if we couldn't find it */
629 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
631 /* Otherwise, this is the ordinal */
632 Ordinal
= OrdinalTable
[Mid
];
636 /* Check if the ordinal is invalid */
637 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
640 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
644 /* In case the forwarder is missing */
645 MissingForwarder
= NameBuffer
;
647 /* Resolve the address and write it */
648 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
649 ExportDirectory
->AddressOfFunctions
);
650 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
652 /* Assume success from now on */
653 Status
= STATUS_SUCCESS
;
655 /* Check if the function is actually a forwarder */
656 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
657 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
659 /* Now assume failure in case the forwarder doesn't exist */
660 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
662 /* Build the forwarder name */
663 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
664 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
667 DllName
.MaximumLength
= DllName
.Length
;
670 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
674 /* We failed, just return an error */
678 /* Loop the module list */
679 NextEntry
= PsLoadedModuleList
.Flink
;
680 while (NextEntry
!= &PsLoadedModuleList
)
682 /* Get the loader entry */
683 LdrEntry
= CONTAINING_RECORD(NextEntry
,
684 LDR_DATA_TABLE_ENTRY
,
687 /* Check if it matches */
688 if (RtlPrefixString((PSTRING
)&ForwarderName
,
689 (PSTRING
)&LdrEntry
->BaseDllName
,
692 /* Get the forwarder export directory */
693 ForwardExportDirectory
=
694 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
696 IMAGE_DIRECTORY_ENTRY_EXPORT
,
698 if (!ForwardExportDirectory
) break;
700 /* Allocate a name entry */
701 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
703 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
704 sizeof(*ForwardName
) +
707 if (!ForwardName
) break;
710 RtlCopyMemory(&ForwardName
->Name
[0],
711 DllName
.Buffer
+ DllName
.Length
,
713 ForwardName
->Hint
= 0;
715 /* Set the new address */
716 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
718 /* Snap the forwarder */
719 Status
= MiSnapThunk(LdrEntry
->DllBase
,
723 ForwardExportDirectory
,
728 /* Free the forwarder name and set the thunk */
729 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
730 Address
->u1
= ForwardThunk
.u1
;
734 /* Go to the next entry */
735 NextEntry
= NextEntry
->Flink
;
739 RtlFreeUnicodeString(&ForwarderName
);
749 MmUnloadSystemImage(IN PVOID ImageHandle
)
751 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
752 PVOID BaseAddress
= LdrEntry
->DllBase
;
755 BOOLEAN HadEntry
= FALSE
;
757 /* Acquire the loader lock */
758 KeEnterCriticalRegion();
759 KeWaitForSingleObject(&MmSystemLoadLock
,
765 /* Check if this driver was loaded at boot and didn't get imports parsed */
766 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
768 /* We should still be alive */
769 ASSERT(LdrEntry
->LoadCount
!= 0);
770 LdrEntry
->LoadCount
--;
772 /* Check if we're still loaded */
773 if (LdrEntry
->LoadCount
) goto Done
;
775 /* We should cleanup... are symbols loaded */
776 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
778 /* Create the ANSI name */
779 Status
= RtlUnicodeStringToAnsiString(&TempName
,
780 &LdrEntry
->BaseDllName
,
782 if (NT_SUCCESS(Status
))
784 /* Unload the symbols */
785 DbgUnLoadImageSymbols(&TempName
,
787 (ULONG_PTR
)ZwCurrentProcess());
788 RtlFreeAnsiString(&TempName
);
792 /* FIXME: Free the driver */
793 //MmFreeSection(LdrEntry->DllBase);
795 /* Check if we're linked in */
796 if (LdrEntry
->InLoadOrderLinks
.Flink
)
799 MiProcessLoaderEntry(LdrEntry
, FALSE
);
803 /* Dereference and clear the imports */
804 MiDereferenceImports(LdrEntry
->LoadedImports
);
805 MiClearImports(LdrEntry
);
807 /* Check if the entry needs to go away */
810 /* Check if it had a name */
811 if (LdrEntry
->FullDllName
.Buffer
)
814 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
817 /* Check if we had a section */
818 if (LdrEntry
->SectionPointer
)
821 ObDereferenceObject(LdrEntry
->SectionPointer
);
825 ExFreePool(LdrEntry
);
828 /* Release the system lock and return */
830 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
831 KeLeaveCriticalRegion();
832 return STATUS_SUCCESS
;
837 MiResolveImageReferences(IN PVOID ImageBase
,
838 IN PUNICODE_STRING ImageFileDirectory
,
839 IN PUNICODE_STRING NamePrefix OPTIONAL
,
840 OUT PCHAR
*MissingApi
,
841 OUT PWCHAR
*MissingDriver
,
842 OUT PLOAD_IMPORTS
*LoadImports
)
844 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
845 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
846 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
847 PLOAD_IMPORTS LoadedImports
, NewImports
;
848 ULONG GdiLink
, NormalLink
, i
;
849 BOOLEAN ReferenceNeeded
, Loaded
;
850 ANSI_STRING TempString
;
851 UNICODE_STRING NameString
, DllName
;
852 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
853 PVOID ImportBase
, DllBase
;
854 PLIST_ENTRY NextEntry
;
855 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
857 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
859 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
860 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
862 /* Assume no imports */
863 *LoadImports
= (PVOID
)-2;
865 /* Get the import descriptor */
866 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
868 IMAGE_DIRECTORY_ENTRY_IMPORT
,
870 if (!ImportDescriptor
) return STATUS_SUCCESS
;
872 /* Loop all imports to count them */
873 for (CurrentImport
= ImportDescriptor
;
874 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
881 /* Make sure we have non-zero imports */
884 /* Calculate and allocate the list we'll need */
885 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
886 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
892 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
898 LoadedImports
= NULL
;
901 /* Reset the import count and loop descriptors again */
902 ImportCount
= GdiLink
= NormalLink
= 0;
903 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
906 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
908 /* Check if this is a GDI driver */
910 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
912 /* We can also allow dxapi */
913 NormalLink
= NormalLink
|
914 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
915 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
917 /* Check if this is a valid GDI driver */
918 if ((GdiLink
) && (NormalLink
))
920 /* It's not, it's importing stuff it shouldn't be! */
921 MiDereferenceImports(LoadedImports
);
922 if (LoadedImports
) ExFreePool(LoadedImports
);
923 return STATUS_PROCEDURE_NOT_FOUND
;
926 /* Check if this is a "core" import, which doesn't get referenced */
927 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
928 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
929 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
931 /* Don't reference this */
932 ReferenceNeeded
= FALSE
;
936 /* Reference these modules */
937 ReferenceNeeded
= TRUE
;
940 /* Now setup a unicode string for the import */
941 RtlInitAnsiString(&TempString
, ImportName
);
942 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
943 if (!NT_SUCCESS(Status
))
946 MiDereferenceImports(LoadedImports
);
947 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
951 /* We don't support name prefixes yet */
952 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
954 /* Remember that we haven't loaded the import at this point */
959 /* Loop the driver list */
960 NextEntry
= PsLoadedModuleList
.Flink
;
961 while (NextEntry
!= &PsLoadedModuleList
)
963 /* Get the loader entry and compare the name */
964 LdrEntry
= CONTAINING_RECORD(NextEntry
,
965 LDR_DATA_TABLE_ENTRY
,
967 if (RtlEqualUnicodeString(&NameString
,
968 &LdrEntry
->BaseDllName
,
971 /* Get the base address */
972 ImportBase
= LdrEntry
->DllBase
;
974 /* Check if we haven't loaded yet, and we need references */
975 if (!(Loaded
) && (ReferenceNeeded
))
977 /* Make sure we're not already loading */
978 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
980 /* Increase the load count */
981 LdrEntry
->LoadCount
++;
985 /* Done, break out */
989 /* Go to the next entry */
990 NextEntry
= NextEntry
->Flink
;
993 /* Check if we haven't loaded the import yet */
996 /* Setup the import DLL name */
997 DllName
.MaximumLength
= NameString
.Length
+
998 ImageFileDirectory
->Length
+
999 sizeof(UNICODE_NULL
);
1000 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1001 DllName
.MaximumLength
,
1005 /* Setup the base length and copy it */
1006 DllName
.Length
= ImageFileDirectory
->Length
;
1007 RtlCopyMemory(DllName
.Buffer
,
1008 ImageFileDirectory
->Buffer
,
1009 ImageFileDirectory
->Length
);
1011 /* Now add the import name and null-terminate it */
1012 RtlAppendStringToString((PSTRING
)&DllName
,
1013 (PSTRING
)&NameString
);
1014 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / sizeof(WCHAR
)] = UNICODE_NULL
;
1016 /* Load the image */
1017 Status
= MmLoadSystemImage(&DllName
,
1023 if (NT_SUCCESS(Status
))
1025 /* We can free the DLL Name */
1026 ExFreePool(DllName
.Buffer
);
1030 /* Fill out the information for the error */
1031 *MissingDriver
= DllName
.Buffer
;
1032 *(PULONG
)MissingDriver
|= 1;
1038 /* We're out of resources */
1039 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1042 /* Check if we're OK until now */
1043 if (NT_SUCCESS(Status
))
1045 /* We're now loaded */
1049 ASSERT(DllBase
= DllEntry
->DllBase
);
1051 /* Call the initialization routines */
1052 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1053 if (!NT_SUCCESS(Status
))
1055 /* We failed, unload the image */
1056 MmUnloadSystemImage(DllEntry
);
1062 /* Check if we failed by here */
1063 if (!NT_SUCCESS(Status
))
1065 /* Cleanup and return */
1066 RtlFreeUnicodeString(&NameString
);
1067 MiDereferenceImports(LoadedImports
);
1068 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1072 /* Loop again to make sure that everything is OK */
1076 /* Check if we're support to reference this import */
1077 if ((ReferenceNeeded
) && (LoadedImports
))
1079 /* Make sure we're not already loading */
1080 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1083 LoadedImports
->Entry
[LoadedImports
->Count
] = LdrEntry
;
1084 LoadedImports
->Count
++;
1088 /* Free the import name */
1089 RtlFreeUnicodeString(&NameString
);
1091 /* Set the missing driver name and get the export directory */
1092 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1093 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1095 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1097 if (!ExportDirectory
)
1099 /* Cleanup and return */
1100 MiDereferenceImports(LoadedImports
);
1101 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1102 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1105 /* Make sure we have an IAT */
1106 if (ImportDescriptor
->OriginalFirstThunk
)
1108 /* Get the first thunks */
1109 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1110 ImportDescriptor
->OriginalFirstThunk
);
1111 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1112 ImportDescriptor
->FirstThunk
);
1115 while (OrigThunk
->u1
.AddressOfData
)
1118 Status
= MiSnapThunk(ImportBase
,
1126 if (!NT_SUCCESS(Status
))
1128 /* Cleanup and return */
1129 MiDereferenceImports(LoadedImports
);
1130 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1134 /* Reset the buffer */
1135 *MissingApi
= MissingApiBuffer
;
1139 /* Go to the next import */
1143 /* Check if we have an import list */
1146 /* Reset the count again, and loop entries*/
1148 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1150 if (LoadedImports
->Entry
[i
])
1152 /* Got an entry, OR it with 1 in case it's the single entry */
1153 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1158 /* Check if we had no imports */
1161 /* Free the list and set it to no imports */
1162 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1163 LoadedImports
= (PVOID
)-2;
1165 else if (ImportCount
== 1)
1167 /* Just one entry, we can free the table and only use our entry */
1168 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1169 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1171 else if (ImportCount
!= LoadedImports
->Count
)
1173 /* Allocate a new list */
1174 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1175 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1181 NewImports
->Count
= 0;
1183 /* Loop all the imports */
1184 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1186 /* Make sure it's valid */
1187 if (LoadedImports
->Entry
[i
])
1190 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1191 NewImports
->Count
++;
1195 /* Free the old copy */
1196 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1197 LoadedImports
= NewImports
;
1201 /* Return the list */
1202 *LoadImports
= LoadedImports
;
1205 /* Return success */
1206 return STATUS_SUCCESS
;
1211 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1213 PLIST_ENTRY NextEntry
;
1215 PIMAGE_NT_HEADERS NtHeader
;
1216 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1217 PIMAGE_FILE_HEADER FileHeader
;
1218 BOOLEAN ValidRelocs
;
1219 PIMAGE_DATA_DIRECTORY DataDirectory
;
1220 PVOID DllBase
, NewImageAddress
;
1222 PMMPTE PointerPte
, StartPte
, LastPte
;
1223 PFN_NUMBER PteCount
;
1225 MMPTE TempPte
, OldPte
;
1227 /* Loop driver list */
1228 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1229 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1230 NextEntry
= NextEntry
->Flink
)
1232 /* Get the loader entry and NT header */
1233 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1234 LDR_DATA_TABLE_ENTRY
,
1236 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1239 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1241 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1242 &LdrEntry
->FullDllName
);
1244 /* Skip kernel and HAL */
1245 /* ROS HACK: Skip BOOTVID/KDCOM too */
1247 if (i
<= 4) continue;
1249 /* Skip non-drivers */
1250 if (!NtHeader
) continue;
1252 /* Get the file header and make sure we can relocate */
1253 FileHeader
= &NtHeader
->FileHeader
;
1254 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1255 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1256 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1258 /* Everything made sense until now, check the relocation section too */
1259 DataDirectory
= &NtHeader
->OptionalHeader
.
1260 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1261 if (!DataDirectory
->VirtualAddress
)
1263 /* We don't really have relocations */
1264 ValidRelocs
= FALSE
;
1268 /* Make sure the size is valid */
1269 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1270 LdrEntry
->SizeOfImage
)
1272 /* They're not, skip */
1276 /* We have relocations */
1280 /* Remember the original address */
1281 DllBase
= LdrEntry
->DllBase
;
1283 /* Get the first PTE and the number of PTEs we'll need */
1284 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1285 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1286 LastPte
= StartPte
+ PteCount
;
1289 while (PointerPte
< LastPte
)
1291 /* Mark the page modified in the PFN database */
1292 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1293 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1294 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1295 Pfn1
->u3
.e1
.Modified
= TRUE
;
1301 /* Now reserve system PTEs for the image */
1302 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1305 /* Shouldn't happen */
1306 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1310 /* This is the new virtual address for the module */
1311 LastPte
= PointerPte
+ PteCount
;
1312 NewImageAddress
= MiPteToAddress(PointerPte
);
1315 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1316 ASSERT(ExpInitializationPhase
== 0);
1318 /* Loop the new driver PTEs */
1319 TempPte
= ValidKernelPte
;
1320 while (PointerPte
< LastPte
)
1322 /* Copy the old data */
1324 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1326 /* Set page number from the loader's memory */
1327 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1330 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1331 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
1332 *PointerPte
= TempPte
;
1339 /* Update position */
1340 PointerPte
-= PteCount
;
1343 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1345 /* Set the image base to the address where the loader put it */
1346 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1348 /* Check if we had relocations */
1351 /* Relocate the image */
1352 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1356 STATUS_CONFLICTING_ADDRESSES
,
1357 STATUS_INVALID_IMAGE_FORMAT
);
1358 if (!NT_SUCCESS(Status
))
1360 /* This shouldn't happen */
1361 DPRINT1("Relocations failed!\n");
1366 /* Update the loader entry */
1367 LdrEntry
->DllBase
= NewImageAddress
;
1369 /* Update the thunks */
1370 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1371 MiUpdateThunks(LoaderBlock
,
1374 LdrEntry
->SizeOfImage
);
1376 /* Update the loader entry */
1377 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1378 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1379 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1380 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1382 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1388 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1390 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1391 PLIST_ENTRY ListHead
, NextEntry
;
1394 /* Setup the loaded module list and locks */
1395 ExInitializeResourceLite(&PsLoadedModuleResource
);
1396 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1397 InitializeListHead(&PsLoadedModuleList
);
1399 /* Get loop variables and the kernel entry */
1400 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1401 NextEntry
= ListHead
->Flink
;
1402 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1403 LDR_DATA_TABLE_ENTRY
,
1405 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1407 /* Loop the loader block */
1408 while (NextEntry
!= ListHead
)
1410 /* Get the loader entry */
1411 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1412 LDR_DATA_TABLE_ENTRY
,
1415 /* FIXME: ROS HACK. Make sure this is a driver */
1416 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1418 /* Skip this entry */
1419 NextEntry
= NextEntry
->Flink
;
1423 /* Calculate the size we'll need and allocate a copy */
1424 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1425 LdrEntry
->BaseDllName
.MaximumLength
+
1426 sizeof(UNICODE_NULL
);
1427 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1428 if (!NewEntry
) return FALSE
;
1430 /* Copy the entry over */
1431 *NewEntry
= *LdrEntry
;
1433 /* Allocate the name */
1434 NewEntry
->FullDllName
.Buffer
=
1435 ExAllocatePoolWithTag(PagedPool
,
1436 LdrEntry
->FullDllName
.MaximumLength
+
1437 sizeof(UNICODE_NULL
),
1439 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1441 /* Set the base name */
1442 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1444 /* Copy the full and base name */
1445 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1446 LdrEntry
->FullDllName
.Buffer
,
1447 LdrEntry
->FullDllName
.MaximumLength
);
1448 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1449 LdrEntry
->BaseDllName
.Buffer
,
1450 LdrEntry
->BaseDllName
.MaximumLength
);
1452 /* Null-terminate the base name */
1453 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1454 sizeof(WCHAR
)] = UNICODE_NULL
;
1456 /* Insert the entry into the list */
1457 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1458 NextEntry
= NextEntry
->Flink
;
1461 /* Build the import lists for the boot drivers */
1462 //MiBuildImportsForBootDrivers();
1470 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1472 PIMAGE_NT_HEADERS NtHeader
;
1475 /* Get NT Headers */
1476 NtHeader
= RtlImageNtHeader(BaseAddress
);
1479 /* Check if this image is only safe for UP while we have 2+ CPUs */
1480 if ((KeNumberProcessors
> 1) &&
1481 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1488 /* Otherwise, it's safe */
1494 MmCheckSystemImage(IN HANDLE ImageHandle
,
1495 IN BOOLEAN PurgeSection
)
1498 HANDLE SectionHandle
;
1499 PVOID ViewBase
= NULL
;
1500 SIZE_T ViewSize
= 0;
1501 IO_STATUS_BLOCK IoStatusBlock
;
1502 FILE_STANDARD_INFORMATION FileStandardInfo
;
1503 KAPC_STATE ApcState
;
1506 /* Create a section for the DLL */
1507 Status
= ZwCreateSection(&SectionHandle
,
1508 SECTION_MAP_EXECUTE
,
1514 if (!NT_SUCCESS(Status
)) return Status
;
1516 /* Make sure we're in the system process */
1517 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1520 Status
= ZwMapViewOfSection(SectionHandle
,
1530 if (!NT_SUCCESS(Status
))
1532 /* We failed, close the handle and return */
1533 KeUnstackDetachProcess(&ApcState
);
1534 ZwClose(SectionHandle
);
1538 /* Now query image information */
1539 Status
= ZwQueryInformationFile(ImageHandle
,
1542 sizeof(FileStandardInfo
),
1543 FileStandardInformation
);
1544 if ( NT_SUCCESS(Status
) )
1546 /* First, verify the checksum */
1547 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1553 /* Set checksum failure */
1554 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1557 /* Check that it's a valid SMP image if we have more then one CPU */
1558 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1560 /* Otherwise it's not the right image */
1561 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1565 /* Unmap the section, close the handle, and return status */
1566 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1567 KeUnstackDetachProcess(&ApcState
);
1568 ZwClose(SectionHandle
);
1574 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1575 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1576 IN PUNICODE_STRING LoadedName OPTIONAL
,
1578 OUT PVOID
*ModuleObject
,
1579 OUT PVOID
*ImageBaseAddress
)
1581 PVOID ModuleLoadBase
= NULL
;
1583 HANDLE FileHandle
= NULL
;
1584 OBJECT_ATTRIBUTES ObjectAttributes
;
1585 IO_STATUS_BLOCK IoStatusBlock
;
1586 PIMAGE_NT_HEADERS NtHeader
;
1587 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
1588 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1589 ULONG EntrySize
, DriverSize
;
1590 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1591 PCHAR MissingApiName
, Buffer
;
1592 PWCHAR MissingDriverName
;
1593 HANDLE SectionHandle
;
1594 ACCESS_MASK DesiredAccess
;
1595 PVOID Section
= NULL
;
1596 BOOLEAN LockOwned
= FALSE
;
1597 PLIST_ENTRY NextEntry
;
1598 IMAGE_INFO ImageInfo
;
1602 /* Detect session-load */
1606 ASSERT(NamePrefix
== NULL
);
1607 ASSERT(LoadedName
== NULL
);
1609 /* Make sure the process is in session too */
1610 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1613 /* Allocate a buffer we'll use for names */
1614 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1615 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1617 /* Check for a separator */
1618 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1623 /* Loop the path until we get to the base name */
1624 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1625 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1627 /* Get the length */
1628 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1629 BaseLength
*= sizeof(WCHAR
);
1631 /* Setup the string */
1632 BaseName
.Length
= (USHORT
)BaseLength
;
1633 BaseName
.Buffer
= p
;
1637 /* Otherwise, we already have a base name */
1638 BaseName
.Length
= FileName
->Length
;
1639 BaseName
.Buffer
= FileName
->Buffer
;
1642 /* Setup the maximum length */
1643 BaseName
.MaximumLength
= BaseName
.Length
;
1645 /* Now compute the base directory */
1646 BaseDirectory
= *FileName
;
1647 BaseDirectory
.Length
-= BaseName
.Length
;
1648 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1650 /* And the prefix, which for now is just the name itself */
1651 PrefixName
= *FileName
;
1653 /* Check if we have a prefix */
1654 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1656 /* Check if we already have a name, use it instead */
1657 if (LoadedName
) BaseName
= *LoadedName
;
1659 /* Acquire the load lock */
1661 ASSERT(LockOwned
== FALSE
);
1663 KeEnterCriticalRegion();
1664 KeWaitForSingleObject(&MmSystemLoadLock
,
1670 /* Scan the module list */
1671 NextEntry
= PsLoadedModuleList
.Flink
;
1672 while (NextEntry
!= &PsLoadedModuleList
)
1674 /* Get the entry and compare the names */
1675 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1676 LDR_DATA_TABLE_ENTRY
,
1678 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1680 /* Found it, break out */
1685 NextEntry
= NextEntry
->Flink
;
1688 /* Check if we found the image */
1689 if (NextEntry
!= &PsLoadedModuleList
)
1691 /* Check if we had already mapped a section */
1694 /* Dereference and clear */
1695 ObDereferenceObject(Section
);
1699 /* Check if this was supposed to be a session load */
1702 /* It wasn't, so just return the data */
1703 *ModuleObject
= LdrEntry
;
1704 *ImageBaseAddress
= LdrEntry
->DllBase
;
1705 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1709 /* We don't support session loading yet */
1710 DPRINT1("Unsupported Session-Load!\n");
1719 /* It wasn't loaded, and we didn't have a previous attempt */
1720 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1721 KeLeaveCriticalRegion();
1724 /* Check if KD is enabled */
1725 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1727 /* FIXME: Attempt to get image from KD */
1730 /* We don't have a valid entry */
1733 /* Setup image attributes */
1734 InitializeObjectAttributes(&ObjectAttributes
,
1736 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1740 /* Open the image */
1741 Status
= ZwOpenFile(&FileHandle
,
1745 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1747 if (!NT_SUCCESS(Status
)) goto Quickie
;
1750 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1751 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1752 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1753 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1759 /* Check if this is a session-load */
1762 /* Then we only need read and execute */
1763 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1767 /* Otherwise, we can allow write access */
1768 DesiredAccess
= SECTION_ALL_ACCESS
;
1771 /* Initialize the attributes for the section */
1772 InitializeObjectAttributes(&ObjectAttributes
,
1774 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1778 /* Create the section */
1779 Status
= ZwCreateSection(&SectionHandle
,
1786 if (!NT_SUCCESS(Status
)) goto Quickie
;
1788 /* Now get the section pointer */
1789 Status
= ObReferenceObjectByHandle(SectionHandle
,
1790 SECTION_MAP_EXECUTE
,
1791 MmSectionObjectType
,
1795 ZwClose(SectionHandle
);
1796 if (!NT_SUCCESS(Status
)) goto Quickie
;
1798 /* Check if this was supposed to be a session-load */
1801 /* We don't support session loading yet */
1802 DPRINT1("Unsupported Session-Load!\n");
1806 /* Check the loader list again, we should end up in the path below */
1811 /* We don't have a valid entry */
1815 /* Load the image */
1816 Status
= MiLoadImageSection(&Section
,
1821 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1823 /* Get the size of the driver */
1824 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1826 /* Make sure we're not being loaded into session space */
1829 /* Check for success */
1830 if (NT_SUCCESS(Status
))
1832 /* FIXME: Support large pages for drivers */
1835 /* Dereference the section */
1836 ObDereferenceObject(Section
);
1840 /* Get the NT Header */
1841 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1843 /* Relocate the driver */
1844 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1848 STATUS_CONFLICTING_ADDRESSES
,
1849 STATUS_INVALID_IMAGE_FORMAT
);
1850 if (!NT_SUCCESS(Status
)) goto Quickie
;
1852 /* Calculate the size we'll need for the entry and allocate it */
1853 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1855 sizeof(UNICODE_NULL
);
1857 /* Allocate the entry */
1858 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1862 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1866 /* Setup the entry */
1867 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1868 LdrEntry
->LoadCount
= 1;
1869 LdrEntry
->LoadedImports
= LoadedImports
;
1870 LdrEntry
->PatchInformation
= NULL
;
1872 /* Check the version */
1873 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1874 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1876 /* Mark this image as a native image */
1877 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
1880 /* Setup the rest of the entry */
1881 LdrEntry
->DllBase
= ModuleLoadBase
;
1882 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1883 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1884 LdrEntry
->SizeOfImage
= DriverSize
;
1885 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1886 LdrEntry
->SectionPointer
= Section
;
1888 /* Now write the DLL name */
1889 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1890 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1891 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1893 /* Copy and null-terminate it */
1894 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1897 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1899 /* Now allocate the full name */
1900 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1902 sizeof(UNICODE_NULL
),
1904 if (!LdrEntry
->FullDllName
.Buffer
)
1906 /* Don't fail, just set it to zero */
1907 LdrEntry
->FullDllName
.Length
= 0;
1908 LdrEntry
->FullDllName
.MaximumLength
= 0;
1913 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1914 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1916 /* Copy and null-terminate */
1917 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1920 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1924 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1926 /* Resolve imports */
1927 MissingApiName
= Buffer
;
1928 Status
= MiResolveImageReferences(ModuleLoadBase
,
1934 if (!NT_SUCCESS(Status
))
1937 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1939 /* Check if we need to free the name */
1940 if (LdrEntry
->FullDllName
.Buffer
)
1943 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1946 /* Free the entry itself */
1947 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
1952 /* Update the loader entry */
1953 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
1954 LDRP_ENTRY_PROCESSED
|
1956 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
1957 LdrEntry
->LoadedImports
= LoadedImports
;
1959 /* FIXME: Apply driver verifier */
1961 /* FIXME: Write-protect the system image */
1963 /* Check if notifications are enabled */
1964 if (PsImageNotifyEnabled
)
1966 /* Fill out the notification data */
1967 ImageInfo
.Properties
= 0;
1968 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
1969 ImageInfo
.SystemModeImage
= TRUE
;
1970 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
1971 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
1972 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
1974 /* Send the notification */
1975 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
1978 #if defined(KDBG) || defined(_WINKD_)
1979 /* MiCacheImageSymbols doesn't detect rossym */
1982 /* Check if there's symbols */
1983 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
1986 /* Check if the system root is present */
1987 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
1988 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
1990 /* Add the system root */
1991 UnicodeTemp
= PrefixName
;
1992 UnicodeTemp
.Buffer
+= 11;
1993 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
1996 &SharedUserData
->NtSystemRoot
[2],
2001 /* Build the name */
2002 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2005 /* Setup the ansi string */
2006 RtlInitString(&AnsiTemp
, Buffer
);
2008 /* Notify the debugger */
2009 DbgLoadImageSymbols(&AnsiTemp
,
2011 (ULONG_PTR
)ZwCurrentProcess());
2012 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
2015 /* FIXME: Page the driver */
2016 ASSERT(Section
== NULL
);
2018 /* Return pointers */
2019 *ModuleObject
= LdrEntry
;
2020 *ImageBaseAddress
= LdrEntry
->DllBase
;
2023 /* If we have a file handle, close it */
2024 if (FileHandle
) ZwClose(FileHandle
);
2026 /* Check if we have the lock acquired */
2029 /* Release the lock */
2030 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2031 KeLeaveCriticalRegion();
2035 /* Check if we had a prefix */
2036 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
2038 /* Free the name buffer and return status */
2039 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
2048 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
2050 PVOID ProcAddress
= NULL
;
2051 ANSI_STRING AnsiRoutineName
;
2053 PLIST_ENTRY NextEntry
;
2054 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2055 BOOLEAN Found
= FALSE
;
2056 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
2057 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
2060 /* Convert routine to ansi name */
2061 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
2064 if (!NT_SUCCESS(Status
)) return NULL
;
2067 KeEnterCriticalRegion();
2068 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
2070 /* Loop the loaded module list */
2071 NextEntry
= PsLoadedModuleList
.Flink
;
2072 while (NextEntry
!= &PsLoadedModuleList
)
2075 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2076 LDR_DATA_TABLE_ENTRY
,
2079 /* Check if it's the kernel or HAL */
2080 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
2086 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
2093 /* Check if we found a valid binary */
2096 /* Find the procedure name */
2097 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
2100 /* Break out if we found it or if we already tried both modules */
2101 if (ProcAddress
) break;
2102 if (Modules
== 2) break;
2106 NextEntry
= NextEntry
->Flink
;
2109 /* Release the lock */
2110 ExReleaseResourceLite(&PsLoadedModuleResource
);
2111 KeLeaveCriticalRegion();
2113 /* Free the string and return */
2114 RtlFreeAnsiString(&AnsiRoutineName
);