2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 LIST_ENTRY PsLoadedModuleList
;
18 KSPIN_LOCK PsLoadedModuleSpinLock
;
19 PVOID PsNtosImageBase
;
20 KMUTANT MmSystemLoadLock
;
22 /* FUNCTIONS *****************************************************************/
26 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
31 ULONG_PTR OldBaseTop
, Delta
;
32 PLDR_DATA_TABLE_ENTRY LdrEntry
;
33 PLIST_ENTRY NextEntry
;
35 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
38 /* Calculate the top and delta */
39 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
40 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
42 /* Loop the loader block */
43 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
44 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
45 NextEntry
= NextEntry
->Flink
)
47 /* Get the loader entry */
48 LdrEntry
= CONTAINING_RECORD(NextEntry
,
52 /* Get the import table */
53 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
55 IMAGE_DIRECTORY_ENTRY_IMPORT
,
57 if (!ImportDescriptor
) continue;
59 /* Make sure we have an IAT */
60 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
61 while ((ImportDescriptor
->Name
) &&
62 (ImportDescriptor
->OriginalFirstThunk
))
64 /* Get the image thunk */
65 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
66 ImportDescriptor
->FirstThunk
);
69 /* Check if it's within this module */
70 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
73 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
74 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
78 /* Go to the next thunk */
82 /* Go to the next import */
90 MiSnapThunk(IN PVOID DllBase
,
92 IN PIMAGE_THUNK_DATA Name
,
93 IN PIMAGE_THUNK_DATA Address
,
94 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
96 IN BOOLEAN SnapForwarder
,
97 OUT PCHAR
*MissingApi
)
102 PUSHORT OrdinalTable
;
103 PIMAGE_IMPORT_BY_NAME NameImport
;
105 ULONG Low
= 0, Mid
= 0, High
;
108 PCHAR MissingForwarder
;
109 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
112 UNICODE_STRING ForwarderName
;
113 PLIST_ENTRY NextEntry
;
114 PLDR_DATA_TABLE_ENTRY LdrEntry
;
115 ULONG ForwardExportSize
;
116 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
117 PIMAGE_IMPORT_BY_NAME ForwardName
;
119 IMAGE_THUNK_DATA ForwardThunk
;
122 /* Check if this is an ordinal */
123 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
124 if ((IsOrdinal
) && !(SnapForwarder
))
126 /* Get the ordinal number and set it as missing */
127 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
128 ExportDirectory
->Base
);
129 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
133 /* Get the VA if we don't have to snap */
134 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
135 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
137 /* Copy the procedure name */
139 (PCHAR
)&NameImport
->Name
[0],
140 MAXIMUM_FILENAME_LENGTH
- 1);
142 /* Setup name tables */
143 DPRINT("Import name: %s\n", NameImport
->Name
);
144 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
145 ExportDirectory
->AddressOfNames
);
146 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
147 ExportDirectory
->AddressOfNameOrdinals
);
149 /* Get the hint and check if it's valid */
150 Hint
= NameImport
->Hint
;
151 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
152 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
154 /* We have a match, get the ordinal number from here */
155 Ordinal
= OrdinalTable
[Hint
];
159 /* Do a binary search */
160 High
= ExportDirectory
->NumberOfNames
- 1;
163 /* Get new middle value */
164 Mid
= (Low
+ High
) >> 1;
167 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
185 /* Check if we couldn't find it */
186 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
188 /* Otherwise, this is the ordinal */
189 Ordinal
= OrdinalTable
[Mid
];
193 /* Check if the ordinal is invalid */
194 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
197 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
201 /* In case the forwarder is missing */
202 MissingForwarder
= NameBuffer
;
204 /* Resolve the address and write it */
205 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
206 ExportDirectory
->AddressOfFunctions
);
207 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
209 /* Assume success from now on */
210 Status
= STATUS_SUCCESS
;
212 /* Check if the function is actually a forwarder */
213 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
214 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
216 /* Now assume failure in case the forwarder doesn't exist */
217 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
219 /* Build the forwarder name */
220 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
221 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
224 DllName
.MaximumLength
= DllName
.Length
;
227 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
231 /* We failed, just return an error */
235 /* Loop the module list */
236 NextEntry
= PsLoadedModuleList
.Flink
;
237 while (NextEntry
!= &PsLoadedModuleList
)
239 /* Get the loader entry */
240 LdrEntry
= CONTAINING_RECORD(NextEntry
,
241 LDR_DATA_TABLE_ENTRY
,
244 /* Check if it matches */
245 if (RtlPrefixString((PSTRING
)&ForwarderName
,
246 (PSTRING
)&LdrEntry
->BaseDllName
,
249 /* Get the forwarder export directory */
250 ForwardExportDirectory
=
251 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
253 IMAGE_DIRECTORY_ENTRY_EXPORT
,
255 if (!ForwardExportDirectory
) break;
257 /* Allocate a name entry */
258 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
260 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
261 sizeof(*ForwardName
) +
264 if (!ForwardName
) break;
267 RtlCopyMemory(&ForwardName
->Name
[0],
268 DllName
.Buffer
+ DllName
.Length
,
270 ForwardName
->Hint
= 0;
272 /* Set the new address */
273 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
275 /* Snap the forwarder */
276 Status
= MiSnapThunk(LdrEntry
->DllBase
,
280 ForwardExportDirectory
,
285 /* Free the forwarder name and set the thunk */
286 ExFreePool(ForwardName
);
287 Address
->u1
= ForwardThunk
.u1
;
291 /* Go to the next entry */
292 NextEntry
= NextEntry
->Flink
;
296 RtlFreeUnicodeString(&ForwarderName
);
306 MiResolveImageReferences(IN PVOID ImageBase
,
307 IN PUNICODE_STRING ImageFileDirectory
,
308 IN PUNICODE_STRING NamePrefix OPTIONAL
,
309 OUT PCHAR
*MissingApi
,
310 OUT PWCHAR
*MissingDriver
,
311 OUT PLOAD_IMPORTS
*LoadImports
)
313 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
314 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
315 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
316 PLOAD_IMPORTS LoadedImports
;
317 ULONG GdiLink
, NormalLink
, i
;
318 BOOLEAN ReferenceNeeded
, Loaded
;
319 ANSI_STRING TempString
;
320 UNICODE_STRING NameString
, DllName
;
321 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
322 PVOID ImportBase
, DllBase
;
323 PLIST_ENTRY NextEntry
;
324 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
326 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
328 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
329 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
331 /* Assume no imports */
332 *LoadImports
= (PVOID
)-2;
334 /* Get the import descriptor */
335 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
337 IMAGE_DIRECTORY_ENTRY_IMPORT
,
339 if (!ImportDescriptor
) return STATUS_SUCCESS
;
341 /* Loop all imports to count them */
342 for (CurrentImport
= ImportDescriptor
;
343 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
350 /* Make sure we have non-zero imports */
353 /* Calculate and allocate the list we'll need */
354 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
355 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
360 /* Zero it and set the count */
361 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
362 LoadedImports
->Count
= ImportCount
;
368 LoadedImports
= NULL
;
371 /* Reset the import count and loop descriptors again */
372 ImportCount
= GdiLink
= NormalLink
= 0;
373 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
376 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
378 /* Check if this is a GDI driver */
380 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
382 /* We can also allow dxapi */
383 NormalLink
= NormalLink
|
384 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
385 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
387 /* Check if this is a valid GDI driver */
388 if ((GdiLink
) && (NormalLink
))
390 /* It's not, it's importing stuff it shouldn't be! */
391 DPRINT1("Invalid driver!\n");
392 //MiDereferenceImports(LoadedImports);
393 if (LoadedImports
) ExFreePool(LoadedImports
);
394 return STATUS_PROCEDURE_NOT_FOUND
;
397 /* Check if this is a "core" import, which doesn't get referenced */
398 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
399 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
400 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
402 /* Don't reference this */
403 ReferenceNeeded
= FALSE
;
407 /* Reference these modules */
408 ReferenceNeeded
= TRUE
;
411 /* Now setup a unicode string for the import */
412 RtlInitAnsiString(&TempString
, ImportName
);
413 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
414 if (!NT_SUCCESS(Status
))
417 //MiDereferenceImports(LoadedImports);
418 if (LoadedImports
) ExFreePool(LoadedImports
);
422 /* We don't support name prefixes yet */
423 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
425 /* Remember that we haven't loaded the import at this point */
430 /* Loop the driver list */
431 NextEntry
= PsLoadedModuleList
.Flink
;
432 while (NextEntry
!= &PsLoadedModuleList
)
434 /* Get the loader entry and compare the name */
435 LdrEntry
= CONTAINING_RECORD(NextEntry
,
436 LDR_DATA_TABLE_ENTRY
,
438 if (RtlEqualUnicodeString(&NameString
,
439 &LdrEntry
->BaseDllName
,
442 /* Get the base address */
443 ImportBase
= LdrEntry
->DllBase
;
445 /* Check if we haven't loaded yet, and we need references */
446 if (!(Loaded
) && (ReferenceNeeded
))
448 /* Make sure we're not already loading */
449 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
451 /* Increase the load count */
452 LdrEntry
->LoadCount
++;
456 /* Done, break out */
460 /* Go to the next entry */
461 NextEntry
= NextEntry
->Flink
;
464 /* Check if we haven't loaded the import yet */
467 /* Setup the import DLL name */
468 DllName
.MaximumLength
= NameString
.Length
+
469 ImageFileDirectory
->Length
+
470 sizeof(UNICODE_NULL
);
471 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
472 DllName
.MaximumLength
,
476 /* Setup the base length and copy it */
477 DllName
.Length
= ImageFileDirectory
->Length
;
478 RtlCopyMemory(DllName
.Buffer
,
479 ImageFileDirectory
->Buffer
,
480 ImageFileDirectory
->Length
);
482 /* Now add the import name and null-terminate it */
483 RtlAppendStringToString((PSTRING
)&DllName
,
484 (PSTRING
)&NameString
);
485 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
488 Status
= MmLoadSystemImage(&DllName
,
494 if (NT_SUCCESS(Status
))
496 /* We can free the DLL Name */
497 ExFreePool(DllName
.Buffer
);
501 /* Fill out the information for the error */
502 DPRINT1("Failed to import: %S\n", DllName
.Buffer
);
503 *MissingDriver
= DllName
.Buffer
;
504 *(PULONG
)MissingDriver
|= 1;
510 /* We're out of resources */
511 Status
= STATUS_INSUFFICIENT_RESOURCES
;
514 /* Check if we're OK until now */
515 if (NT_SUCCESS(Status
))
517 /* We're now loaded */
521 ASSERT(DllBase
= DllEntry
->DllBase
);
523 /* Call the initialization routines */
525 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
526 if (!NT_SUCCESS(Status
))
528 /* We failed, unload the image */
529 MmUnloadSystemImage(DllEntry
);
536 /* Check if we failed by here */
537 if (!NT_SUCCESS(Status
))
539 /* Cleanup and return */
540 DPRINT1("Failed loading import\n");
541 RtlFreeUnicodeString(&NameString
);
542 //MiDereferenceImports(LoadedImports);
543 if (LoadedImports
) ExFreePool(LoadedImports
);
547 /* Loop again to make sure that everything is OK */
551 /* Check if we're support to reference this import */
552 if ((ReferenceNeeded
) && (LoadedImports
))
554 /* Make sure we're not already loading */
555 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
558 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
563 /* Free the import name */
564 RtlFreeUnicodeString(&NameString
);
566 /* Set the missing driver name and get the export directory */
567 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
568 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
570 IMAGE_DIRECTORY_ENTRY_EXPORT
,
572 if (!ExportDirectory
)
574 /* Cleanup and return */
575 DPRINT1("Invalid driver: %wZ\n", &LdrEntry
->BaseDllName
);
576 //MiDereferenceImports(LoadedImports);
577 if (LoadedImports
) ExFreePool(LoadedImports
);
578 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
581 /* Make sure we have an IAT */
582 if (ImportDescriptor
->OriginalFirstThunk
)
584 /* Get the first thunks */
585 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
586 ImportDescriptor
->OriginalFirstThunk
);
587 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
588 ImportDescriptor
->FirstThunk
);
591 while (OrigThunk
->u1
.AddressOfData
)
594 Status
= MiSnapThunk(ImportBase
,
602 if (!NT_SUCCESS(Status
))
604 /* Cleanup and return */
605 //MiDereferenceImports(LoadedImports);
606 if (LoadedImports
) ExFreePool(LoadedImports
);
610 /* Reset the buffer */
611 *MissingApi
= MissingApiBuffer
;
615 /* Go to the next import */
619 /* Check if we have an import list */
622 /* Reset the count again, and loop entries*/
624 for (i
= 0; i
< LoadedImports
->Count
; i
++)
626 if (LoadedImports
->Entry
[i
])
628 /* Got an entry, OR it with 1 in case it's the single entry */
629 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
634 /* Check if we had no imports */
637 /* Free the list and set it to no imports */
638 ExFreePool(LoadedImports
);
639 LoadedImports
= (PVOID
)-2;
641 else if (ImportCount
== 1)
643 /* Just one entry, we can free the table and only use our entry */
644 ExFreePool(LoadedImports
);
645 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
647 else if (ImportCount
!= LoadedImports
->Count
)
649 /* FIXME: Can this happen? */
650 DPRINT1("Unhandled scenario\n");
654 /* Return the list */
655 *LoadImports
= LoadedImports
;
659 return STATUS_SUCCESS
;
664 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
666 PLIST_ENTRY NextEntry
;
668 PIMAGE_NT_HEADERS NtHeader
;
669 PLDR_DATA_TABLE_ENTRY LdrEntry
;
670 PIMAGE_FILE_HEADER FileHeader
;
672 PIMAGE_DATA_DIRECTORY DataDirectory
;
673 PVOID DllBase
, NewImageAddress
;
675 ULONG DriverSize
= 0, Size
;
676 PIMAGE_SECTION_HEADER Section
;
678 /* Loop driver list */
679 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
680 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
681 NextEntry
= NextEntry
->Flink
)
683 /* Get the loader entry and NT header */
684 LdrEntry
= CONTAINING_RECORD(NextEntry
,
685 LDR_DATA_TABLE_ENTRY
,
687 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
690 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
692 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
693 &LdrEntry
->FullDllName
);
695 /* Skip kernel and HAL */
696 /* ROS HACK: Skip BOOTVID/KDCOM too */
698 if (i
<= 4) continue;
700 /* Skip non-drivers */
701 if (!NtHeader
) continue;
703 #if 1 // Disable for FreeLDR 2.5
704 /* Get header pointers */
705 Section
= IMAGE_FIRST_SECTION(NtHeader
);
707 /* Determine the size of the module */
708 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
710 /* Skip this section if we're not supposed to load it */
711 if (!(Section
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
713 /* Add the size of this section into the total size */
714 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
715 DriverSize
= max(DriverSize
, Size
);
719 /* Round up the driver size to section alignment */
720 DriverSize
= ROUND_UP(DriverSize
, NtHeader
->OptionalHeader
.SectionAlignment
);
723 /* Get the file header and make sure we can relocate */
724 FileHeader
= &NtHeader
->FileHeader
;
725 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
726 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
727 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
729 /* Everything made sense until now, check the relocation section too */
730 DataDirectory
= &NtHeader
->OptionalHeader
.
731 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
732 if (!DataDirectory
->VirtualAddress
)
734 /* We don't really have relocations */
739 /* Make sure the size is valid */
740 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
741 LdrEntry
->SizeOfImage
)
743 /* They're not, skip */
747 /* We have relocations */
751 /* Remember the original address */
752 DllBase
= LdrEntry
->DllBase
;
754 /* Allocate a virtual section for the module */
755 NewImageAddress
= MmAllocateSection(DriverSize
, NULL
);
756 if (!NewImageAddress
)
758 /* Shouldn't happen */
759 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
764 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
765 ASSERT(ExpInitializationPhase
== 0);
767 #if 0 // Enable for FreeLDR 2.5
768 /* Now copy the entire driver over */
769 RtlCopyMemory(NewImageAddress
, DllBase
, DriverSize
);
771 /* Copy headers over */
772 RtlCopyMemory(NewImageAddress
,
774 NtHeader
->OptionalHeader
.SizeOfHeaders
);
776 /* Copy image sections into virtual section */
777 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
779 /* Get the size of this section and check if it's valid and on-disk */
780 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
781 if ((Size
<= DriverSize
) && (Section
[i
].SizeOfRawData
))
783 /* Copy the data from the disk to the image */
784 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewImageAddress
+
785 Section
[i
].VirtualAddress
),
786 (PVOID
)((ULONG_PTR
)DllBase
+
787 Section
[i
].PointerToRawData
),
788 Section
[i
].Misc
.VirtualSize
>
789 Section
[i
].SizeOfRawData
?
790 Section
[i
].SizeOfRawData
:
791 Section
[i
].Misc
.VirtualSize
);
797 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
799 /* Set the image base to the old address */
800 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
802 /* Check if we had relocations */
805 /* Relocate the image */
806 Status
= LdrRelocateImageWithBias(NewImageAddress
,
810 STATUS_CONFLICTING_ADDRESSES
,
811 STATUS_INVALID_IMAGE_FORMAT
);
812 if (!NT_SUCCESS(Status
))
814 /* This shouldn't happen */
815 DPRINT1("Relocations failed!\n");
820 /* Update the loader entry */
821 LdrEntry
->DllBase
= NewImageAddress
;
823 /* Update the thunks */
824 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
825 MiUpdateThunks(LoaderBlock
,
828 LdrEntry
->SizeOfImage
);
830 /* Update the loader entry */
831 LdrEntry
->Flags
|= 0x01000000;
832 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
833 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
834 LdrEntry
->SizeOfImage
= DriverSize
;
840 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
842 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
843 PLIST_ENTRY ListHead
, NextEntry
;
846 /* Setup the loaded module list and lock */
847 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
848 InitializeListHead(&PsLoadedModuleList
);
850 /* Get loop variables and the kernel entry */
851 ListHead
= &LoaderBlock
->LoadOrderListHead
;
852 NextEntry
= ListHead
->Flink
;
853 LdrEntry
= CONTAINING_RECORD(NextEntry
,
854 LDR_DATA_TABLE_ENTRY
,
856 PsNtosImageBase
= LdrEntry
->DllBase
;
858 /* Loop the loader block */
859 while (NextEntry
!= ListHead
)
861 /* Get the loader entry */
862 LdrEntry
= CONTAINING_RECORD(NextEntry
,
863 LDR_DATA_TABLE_ENTRY
,
866 /* FIXME: ROS HACK. Make sure this is a driver */
867 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
869 /* Skip this entry */
870 NextEntry
= NextEntry
->Flink
;
874 /* Calculate the size we'll need and allocate a copy */
875 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
876 LdrEntry
->BaseDllName
.MaximumLength
+
877 sizeof(UNICODE_NULL
);
878 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
879 if (!NewEntry
) return FALSE
;
881 /* Copy the entry over */
882 *NewEntry
= *LdrEntry
;
884 /* Allocate the name */
885 NewEntry
->FullDllName
.Buffer
=
886 ExAllocatePoolWithTag(PagedPool
,
887 LdrEntry
->FullDllName
.MaximumLength
+
888 sizeof(UNICODE_NULL
),
890 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
892 /* Set the base name */
893 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
895 /* Copy the full and base name */
896 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
897 LdrEntry
->FullDllName
.Buffer
,
898 LdrEntry
->FullDllName
.MaximumLength
);
899 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
900 LdrEntry
->BaseDllName
.Buffer
,
901 LdrEntry
->BaseDllName
.MaximumLength
);
903 /* Null-terminate the base name */
904 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
905 sizeof(WCHAR
)] = UNICODE_NULL
;
907 /* Insert the entry into the list */
908 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
909 NextEntry
= NextEntry
->Flink
;
912 /* Build the import lists for the boot drivers */
913 //MiBuildImportsForBootDrivers();
921 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
923 PIMAGE_NT_HEADERS NtHeader
;
927 NtHeader
= RtlImageNtHeader(BaseAddress
);
930 /* Check if this image is only safe for UP while we have 2+ CPUs */
931 if ((KeNumberProcessors
> 1) &&
932 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
939 /* Otherwise, it's safe */
945 MmCheckSystemImage(IN HANDLE ImageHandle
,
946 IN BOOLEAN PurgeSection
)
949 HANDLE SectionHandle
;
950 PVOID ViewBase
= NULL
;
952 IO_STATUS_BLOCK IoStatusBlock
;
953 FILE_STANDARD_INFORMATION FileStandardInfo
;
957 /* Create a section for the DLL */
958 Status
= ZwCreateSection(&SectionHandle
,
965 if (!NT_SUCCESS(Status
)) return Status
;
967 /* Make sure we're in the system process */
968 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
971 Status
= ZwMapViewOfSection(SectionHandle
,
981 if (!NT_SUCCESS(Status
))
983 /* We failed, close the handle and return */
984 KeUnstackDetachProcess(&ApcState
);
985 ZwClose(SectionHandle
);
989 /* Now query image information */
990 Status
= ZwQueryInformationFile(ImageHandle
,
993 sizeof(FileStandardInfo
),
994 FileStandardInformation
);
995 if ( NT_SUCCESS(Status
) )
997 /* First, verify the checksum */
998 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1004 /* Set checksum failure */
1005 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1008 /* Check that it's a valid SMP image if we have more then one CPU */
1009 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1011 /* Otherwise it's not the right image */
1012 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1016 /* Unmap the section, close the handle, and return status */
1017 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1018 KeUnstackDetachProcess(&ApcState
);
1019 ZwClose(SectionHandle
);