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 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
28 /* Check if there's no imports or if we're a boot driver */
29 if ((ImportList
== (PVOID
)-1) || (ImportList
== (PVOID
)-2))
31 /* Then there's nothing to do */
32 return STATUS_SUCCESS
;
35 /* Otherwise, FIXME */
36 DPRINT1("Imports not dereferenced!\n");
37 return STATUS_UNSUCCESSFUL
;
42 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
46 /* Check if there's no imports or we're a boot driver or only one entry */
47 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
48 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
49 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
55 /* Otherwise, free the import list */
56 ExFreePool(LdrEntry
->LoadedImports
);
61 MiLocateExportName(IN PVOID DllBase
,
66 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
67 LONG Low
= 0, Mid
= 0, High
, Ret
;
74 /* Get the export directory */
75 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
77 IMAGE_DIRECTORY_ENTRY_EXPORT
,
79 if (!ExportDirectory
) return NULL
;
81 /* Setup name tables */
82 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
83 ExportDirectory
->AddressOfNames
);
84 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
85 ExportDirectory
->AddressOfNameOrdinals
);
87 /* Do a binary search */
88 High
= ExportDirectory
->NumberOfNames
- 1;
91 /* Get new middle value */
92 Mid
= (Low
+ High
) >> 1;
95 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
113 /* Check if we couldn't find it */
114 if (High
< Low
) return NULL
;
116 /* Otherwise, this is the ordinal */
117 Ordinal
= OrdinalTable
[Mid
];
119 /* Resolve the address and write it */
120 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
121 ExportDirectory
->AddressOfFunctions
);
122 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
124 /* Check if the function is actually a forwarder */
125 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
126 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
138 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
139 IN PLIST_ENTRY ListHead
)
141 PMM_DLL_INITIALIZE DllInit
;
143 /* Try to see if the image exports a DllInitialize routine */
144 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
146 if (!DllInit
) return STATUS_SUCCESS
;
149 DPRINT1("DllInitialize not called!\n");
150 return STATUS_UNSUCCESSFUL
;
155 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
160 /* Acquire the lock */
161 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
163 /* Insert or remove from the list */
164 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
165 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
167 /* Release the lock */
168 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
173 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
178 ULONG_PTR OldBaseTop
, Delta
;
179 PLDR_DATA_TABLE_ENTRY LdrEntry
;
180 PLIST_ENTRY NextEntry
;
182 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
185 /* Calculate the top and delta */
186 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
187 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
189 /* Loop the loader block */
190 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
191 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
192 NextEntry
= NextEntry
->Flink
)
194 /* Get the loader entry */
195 LdrEntry
= CONTAINING_RECORD(NextEntry
,
196 LDR_DATA_TABLE_ENTRY
,
199 /* Get the import table */
200 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
202 IMAGE_DIRECTORY_ENTRY_IMPORT
,
204 if (!ImportDescriptor
) continue;
206 /* Make sure we have an IAT */
207 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
208 while ((ImportDescriptor
->Name
) &&
209 (ImportDescriptor
->OriginalFirstThunk
))
211 /* Get the image thunk */
212 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
213 ImportDescriptor
->FirstThunk
);
216 /* Check if it's within this module */
217 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
220 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
221 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
222 *ImageThunk
+= Delta
;
225 /* Go to the next thunk */
229 /* Go to the next import */
237 MiSnapThunk(IN PVOID DllBase
,
239 IN PIMAGE_THUNK_DATA Name
,
240 IN PIMAGE_THUNK_DATA Address
,
241 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
243 IN BOOLEAN SnapForwarder
,
244 OUT PCHAR
*MissingApi
)
249 PUSHORT OrdinalTable
;
250 PIMAGE_IMPORT_BY_NAME NameImport
;
252 ULONG Low
= 0, Mid
= 0, High
;
255 PCHAR MissingForwarder
;
256 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
259 UNICODE_STRING ForwarderName
;
260 PLIST_ENTRY NextEntry
;
261 PLDR_DATA_TABLE_ENTRY LdrEntry
;
262 ULONG ForwardExportSize
;
263 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
264 PIMAGE_IMPORT_BY_NAME ForwardName
;
266 IMAGE_THUNK_DATA ForwardThunk
;
269 /* Check if this is an ordinal */
270 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
271 if ((IsOrdinal
) && !(SnapForwarder
))
273 /* Get the ordinal number and set it as missing */
274 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
275 ExportDirectory
->Base
);
276 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
280 /* Get the VA if we don't have to snap */
281 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
282 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
284 /* Copy the procedure name */
286 (PCHAR
)&NameImport
->Name
[0],
287 MAXIMUM_FILENAME_LENGTH
- 1);
289 /* Setup name tables */
290 DPRINT("Import name: %s\n", NameImport
->Name
);
291 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
292 ExportDirectory
->AddressOfNames
);
293 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
294 ExportDirectory
->AddressOfNameOrdinals
);
296 /* Get the hint and check if it's valid */
297 Hint
= NameImport
->Hint
;
298 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
299 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
301 /* We have a match, get the ordinal number from here */
302 Ordinal
= OrdinalTable
[Hint
];
306 /* Do a binary search */
307 High
= ExportDirectory
->NumberOfNames
- 1;
310 /* Get new middle value */
311 Mid
= (Low
+ High
) >> 1;
314 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
332 /* Check if we couldn't find it */
333 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
335 /* Otherwise, this is the ordinal */
336 Ordinal
= OrdinalTable
[Mid
];
340 /* Check if the ordinal is invalid */
341 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
344 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
348 /* In case the forwarder is missing */
349 MissingForwarder
= NameBuffer
;
351 /* Resolve the address and write it */
352 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
353 ExportDirectory
->AddressOfFunctions
);
354 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
356 /* Assume success from now on */
357 Status
= STATUS_SUCCESS
;
359 /* Check if the function is actually a forwarder */
360 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
361 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
363 /* Now assume failure in case the forwarder doesn't exist */
364 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
366 /* Build the forwarder name */
367 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
368 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
371 DllName
.MaximumLength
= DllName
.Length
;
374 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
378 /* We failed, just return an error */
382 /* Loop the module list */
383 NextEntry
= PsLoadedModuleList
.Flink
;
384 while (NextEntry
!= &PsLoadedModuleList
)
386 /* Get the loader entry */
387 LdrEntry
= CONTAINING_RECORD(NextEntry
,
388 LDR_DATA_TABLE_ENTRY
,
391 /* Check if it matches */
392 if (RtlPrefixString((PSTRING
)&ForwarderName
,
393 (PSTRING
)&LdrEntry
->BaseDllName
,
396 /* Get the forwarder export directory */
397 ForwardExportDirectory
=
398 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
400 IMAGE_DIRECTORY_ENTRY_EXPORT
,
402 if (!ForwardExportDirectory
) break;
404 /* Allocate a name entry */
405 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
407 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
408 sizeof(*ForwardName
) +
411 if (!ForwardName
) break;
414 RtlCopyMemory(&ForwardName
->Name
[0],
415 DllName
.Buffer
+ DllName
.Length
,
417 ForwardName
->Hint
= 0;
419 /* Set the new address */
420 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
422 /* Snap the forwarder */
423 Status
= MiSnapThunk(LdrEntry
->DllBase
,
427 ForwardExportDirectory
,
432 /* Free the forwarder name and set the thunk */
433 ExFreePool(ForwardName
);
434 Address
->u1
= ForwardThunk
.u1
;
438 /* Go to the next entry */
439 NextEntry
= NextEntry
->Flink
;
443 RtlFreeUnicodeString(&ForwarderName
);
453 MmUnloadSystemImage(IN PVOID ImageHandle
)
455 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
456 PVOID BaseAddress
= LdrEntry
->DllBase
;
458 ANSI_STRING TempName
;
459 BOOLEAN HadEntry
= FALSE
;
461 /* Acquire the loader lock */
462 KeEnterCriticalRegion();
463 KeWaitForSingleObject(&MmSystemLoadLock
,
469 /* Check if this driver was loaded at boot and didn't get imports parsed */
470 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
472 /* We should still be alive */
473 ASSERT(LdrEntry
->LoadCount
!= 0);
474 LdrEntry
->LoadCount
--;
476 /* Check if we're still loaded */
477 if (LdrEntry
->LoadCount
) goto Done
;
479 /* We should cleanup... are symbols loaded */
480 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
482 /* Create the ANSI name */
483 Status
= RtlUnicodeStringToAnsiString(&TempName
,
484 &LdrEntry
->BaseDllName
,
486 if (NT_SUCCESS(Status
))
488 /* Unload the symbols */
489 DbgUnLoadImageSymbols(&TempName
, BaseAddress
, -1);
490 RtlFreeAnsiString(&TempName
);
494 /* FIXME: Free the driver */
495 //MmFreeSection(LdrEntry->DllBase);
497 /* Check if we're linked in */
498 if (LdrEntry
->InLoadOrderLinks
.Flink
)
501 MiProcessLoaderEntry(LdrEntry
, FALSE
);
505 /* Dereference and clear the imports */
506 MiDereferenceImports(LdrEntry
->LoadedImports
);
507 MiClearImports(LdrEntry
);
509 /* Check if the entry needs to go away */
512 /* Check if it had a name */
513 if (LdrEntry
->FullDllName
.Buffer
)
516 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
519 /* Check if we had a section */
520 if (LdrEntry
->SectionPointer
)
523 ObDereferenceObject(LdrEntry
->SectionPointer
);
527 ExFreePool(LdrEntry
);
530 /* Release the system lock and return */
532 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
533 KeLeaveCriticalRegion();
534 return STATUS_SUCCESS
;
539 MiResolveImageReferences(IN PVOID ImageBase
,
540 IN PUNICODE_STRING ImageFileDirectory
,
541 IN PUNICODE_STRING NamePrefix OPTIONAL
,
542 OUT PCHAR
*MissingApi
,
543 OUT PWCHAR
*MissingDriver
,
544 OUT PLOAD_IMPORTS
*LoadImports
)
546 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
547 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
548 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
549 PLOAD_IMPORTS LoadedImports
;
550 ULONG GdiLink
, NormalLink
, i
;
551 BOOLEAN ReferenceNeeded
, Loaded
;
552 ANSI_STRING TempString
;
553 UNICODE_STRING NameString
, DllName
;
554 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
555 PVOID ImportBase
, DllBase
;
556 PLIST_ENTRY NextEntry
;
557 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
559 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
561 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
562 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
564 /* Assume no imports */
565 *LoadImports
= (PVOID
)-2;
567 /* Get the import descriptor */
568 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
570 IMAGE_DIRECTORY_ENTRY_IMPORT
,
572 if (!ImportDescriptor
) return STATUS_SUCCESS
;
574 /* Loop all imports to count them */
575 for (CurrentImport
= ImportDescriptor
;
576 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
583 /* Make sure we have non-zero imports */
586 /* Calculate and allocate the list we'll need */
587 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
588 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
593 /* Zero it and set the count */
594 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
595 LoadedImports
->Count
= ImportCount
;
601 LoadedImports
= NULL
;
604 /* Reset the import count and loop descriptors again */
605 ImportCount
= GdiLink
= NormalLink
= 0;
606 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
609 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
611 /* Check if this is a GDI driver */
613 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
615 /* We can also allow dxapi */
616 NormalLink
= NormalLink
|
617 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
618 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
620 /* Check if this is a valid GDI driver */
621 if ((GdiLink
) && (NormalLink
))
623 /* It's not, it's importing stuff it shouldn't be! */
624 MiDereferenceImports(LoadedImports
);
625 if (LoadedImports
) ExFreePool(LoadedImports
);
626 return STATUS_PROCEDURE_NOT_FOUND
;
629 /* Check if this is a "core" import, which doesn't get referenced */
630 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
631 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
632 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
634 /* Don't reference this */
635 ReferenceNeeded
= FALSE
;
639 /* Reference these modules */
640 ReferenceNeeded
= TRUE
;
643 /* Now setup a unicode string for the import */
644 RtlInitAnsiString(&TempString
, ImportName
);
645 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
646 if (!NT_SUCCESS(Status
))
649 MiDereferenceImports(LoadedImports
);
650 if (LoadedImports
) ExFreePool(LoadedImports
);
654 /* We don't support name prefixes yet */
655 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
657 /* Remember that we haven't loaded the import at this point */
662 /* Loop the driver list */
663 NextEntry
= PsLoadedModuleList
.Flink
;
664 while (NextEntry
!= &PsLoadedModuleList
)
666 /* Get the loader entry and compare the name */
667 LdrEntry
= CONTAINING_RECORD(NextEntry
,
668 LDR_DATA_TABLE_ENTRY
,
670 if (RtlEqualUnicodeString(&NameString
,
671 &LdrEntry
->BaseDllName
,
674 /* Get the base address */
675 ImportBase
= LdrEntry
->DllBase
;
677 /* Check if we haven't loaded yet, and we need references */
678 if (!(Loaded
) && (ReferenceNeeded
))
680 /* Make sure we're not already loading */
681 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
683 /* Increase the load count */
684 LdrEntry
->LoadCount
++;
688 /* Done, break out */
692 /* Go to the next entry */
693 NextEntry
= NextEntry
->Flink
;
696 /* Check if we haven't loaded the import yet */
699 /* Setup the import DLL name */
700 DllName
.MaximumLength
= NameString
.Length
+
701 ImageFileDirectory
->Length
+
702 sizeof(UNICODE_NULL
);
703 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
704 DllName
.MaximumLength
,
708 /* Setup the base length and copy it */
709 DllName
.Length
= ImageFileDirectory
->Length
;
710 RtlCopyMemory(DllName
.Buffer
,
711 ImageFileDirectory
->Buffer
,
712 ImageFileDirectory
->Length
);
714 /* Now add the import name and null-terminate it */
715 RtlAppendStringToString((PSTRING
)&DllName
,
716 (PSTRING
)&NameString
);
717 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
720 Status
= MmLoadSystemImage(&DllName
,
726 if (NT_SUCCESS(Status
))
728 /* We can free the DLL Name */
729 ExFreePool(DllName
.Buffer
);
733 /* Fill out the information for the error */
734 *MissingDriver
= DllName
.Buffer
;
735 *(PULONG
)MissingDriver
|= 1;
741 /* We're out of resources */
742 Status
= STATUS_INSUFFICIENT_RESOURCES
;
745 /* Check if we're OK until now */
746 if (NT_SUCCESS(Status
))
748 /* We're now loaded */
752 ASSERT(DllBase
= DllEntry
->DllBase
);
754 /* Call the initialization routines */
755 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
756 if (!NT_SUCCESS(Status
))
758 /* We failed, unload the image */
759 MmUnloadSystemImage(DllEntry
);
765 /* Check if we failed by here */
766 if (!NT_SUCCESS(Status
))
768 /* Cleanup and return */
769 RtlFreeUnicodeString(&NameString
);
770 MiDereferenceImports(LoadedImports
);
771 if (LoadedImports
) ExFreePool(LoadedImports
);
775 /* Loop again to make sure that everything is OK */
779 /* Check if we're support to reference this import */
780 if ((ReferenceNeeded
) && (LoadedImports
))
782 /* Make sure we're not already loading */
783 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
786 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
791 /* Free the import name */
792 RtlFreeUnicodeString(&NameString
);
794 /* Set the missing driver name and get the export directory */
795 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
796 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
798 IMAGE_DIRECTORY_ENTRY_EXPORT
,
800 if (!ExportDirectory
)
802 /* Cleanup and return */
803 MiDereferenceImports(LoadedImports
);
804 if (LoadedImports
) ExFreePool(LoadedImports
);
805 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
808 /* Make sure we have an IAT */
809 if (ImportDescriptor
->OriginalFirstThunk
)
811 /* Get the first thunks */
812 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
813 ImportDescriptor
->OriginalFirstThunk
);
814 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
815 ImportDescriptor
->FirstThunk
);
818 while (OrigThunk
->u1
.AddressOfData
)
821 Status
= MiSnapThunk(ImportBase
,
829 if (!NT_SUCCESS(Status
))
831 /* Cleanup and return */
832 MiDereferenceImports(LoadedImports
);
833 if (LoadedImports
) ExFreePool(LoadedImports
);
837 /* Reset the buffer */
838 *MissingApi
= MissingApiBuffer
;
842 /* Go to the next import */
846 /* Check if we have an import list */
849 /* Reset the count again, and loop entries*/
851 for (i
= 0; i
< LoadedImports
->Count
; i
++)
853 if (LoadedImports
->Entry
[i
])
855 /* Got an entry, OR it with 1 in case it's the single entry */
856 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
861 /* Check if we had no imports */
864 /* Free the list and set it to no imports */
865 ExFreePool(LoadedImports
);
866 LoadedImports
= (PVOID
)-2;
868 else if (ImportCount
== 1)
870 /* Just one entry, we can free the table and only use our entry */
871 ExFreePool(LoadedImports
);
872 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
874 else if (ImportCount
!= LoadedImports
->Count
)
876 /* FIXME: Can this happen? */
877 DPRINT1("Unhandled scenario\n");
881 /* Return the list */
882 *LoadImports
= LoadedImports
;
886 return STATUS_SUCCESS
;
891 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
893 PLIST_ENTRY NextEntry
;
895 PIMAGE_NT_HEADERS NtHeader
;
896 PLDR_DATA_TABLE_ENTRY LdrEntry
;
897 PIMAGE_FILE_HEADER FileHeader
;
899 PIMAGE_DATA_DIRECTORY DataDirectory
;
900 PVOID DllBase
, NewImageAddress
;
902 ULONG DriverSize
= 0, Size
;
903 PIMAGE_SECTION_HEADER Section
;
905 /* Loop driver list */
906 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
907 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
908 NextEntry
= NextEntry
->Flink
)
910 /* Get the loader entry and NT header */
911 LdrEntry
= CONTAINING_RECORD(NextEntry
,
912 LDR_DATA_TABLE_ENTRY
,
914 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
917 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
919 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
920 &LdrEntry
->FullDllName
);
922 /* Skip kernel and HAL */
923 /* ROS HACK: Skip BOOTVID/KDCOM too */
925 if (i
<= 4) continue;
927 /* Skip non-drivers */
928 if (!NtHeader
) continue;
930 #if 1 // Disable for FreeLDR 2.5
931 /* Get header pointers */
932 Section
= IMAGE_FIRST_SECTION(NtHeader
);
934 /* Determine the size of the module */
935 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
937 /* Skip this section if we're not supposed to load it */
938 if (!(Section
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
940 /* Add the size of this section into the total size */
941 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
942 DriverSize
= max(DriverSize
, Size
);
946 /* Round up the driver size to section alignment */
947 DriverSize
= ROUND_UP(DriverSize
, NtHeader
->OptionalHeader
.SectionAlignment
);
950 /* Get the file header and make sure we can relocate */
951 FileHeader
= &NtHeader
->FileHeader
;
952 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
953 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
954 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
956 /* Everything made sense until now, check the relocation section too */
957 DataDirectory
= &NtHeader
->OptionalHeader
.
958 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
959 if (!DataDirectory
->VirtualAddress
)
961 /* We don't really have relocations */
966 /* Make sure the size is valid */
967 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
968 LdrEntry
->SizeOfImage
)
970 /* They're not, skip */
974 /* We have relocations */
978 /* Remember the original address */
979 DllBase
= LdrEntry
->DllBase
;
981 /* Allocate a virtual section for the module */
982 NewImageAddress
= MmAllocateSection(DriverSize
, NULL
);
983 if (!NewImageAddress
)
985 /* Shouldn't happen */
986 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
991 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
992 ASSERT(ExpInitializationPhase
== 0);
994 #if 0 // Enable for FreeLDR 2.5
995 /* Now copy the entire driver over */
996 RtlCopyMemory(NewImageAddress
, DllBase
, DriverSize
);
998 /* Copy headers over */
999 RtlCopyMemory(NewImageAddress
,
1001 NtHeader
->OptionalHeader
.SizeOfHeaders
);
1003 /* Copy image sections into virtual section */
1004 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1006 /* Get the size of this section and check if it's valid and on-disk */
1007 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
1008 if ((Size
<= DriverSize
) && (Section
[i
].SizeOfRawData
))
1010 /* Copy the data from the disk to the image */
1011 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewImageAddress
+
1012 Section
[i
].VirtualAddress
),
1013 (PVOID
)((ULONG_PTR
)DllBase
+
1014 Section
[i
].PointerToRawData
),
1015 Section
[i
].Misc
.VirtualSize
>
1016 Section
[i
].SizeOfRawData
?
1017 Section
[i
].SizeOfRawData
:
1018 Section
[i
].Misc
.VirtualSize
);
1024 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1026 /* Set the image base to the old address */
1027 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1029 /* Check if we had relocations */
1032 /* Relocate the image */
1033 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1037 STATUS_CONFLICTING_ADDRESSES
,
1038 STATUS_INVALID_IMAGE_FORMAT
);
1039 if (!NT_SUCCESS(Status
))
1041 /* This shouldn't happen */
1042 DPRINT1("Relocations failed!\n");
1047 /* Update the loader entry */
1048 LdrEntry
->DllBase
= NewImageAddress
;
1050 /* Update the thunks */
1051 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1052 MiUpdateThunks(LoaderBlock
,
1055 LdrEntry
->SizeOfImage
);
1057 /* Update the loader entry */
1058 LdrEntry
->Flags
|= 0x01000000;
1059 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1060 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1061 LdrEntry
->SizeOfImage
= DriverSize
;
1067 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1069 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1070 PLIST_ENTRY ListHead
, NextEntry
;
1073 /* Setup the loaded module list and lock */
1074 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1075 InitializeListHead(&PsLoadedModuleList
);
1077 /* Get loop variables and the kernel entry */
1078 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1079 NextEntry
= ListHead
->Flink
;
1080 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1081 LDR_DATA_TABLE_ENTRY
,
1083 PsNtosImageBase
= LdrEntry
->DllBase
;
1085 /* Loop the loader block */
1086 while (NextEntry
!= ListHead
)
1088 /* Get the loader entry */
1089 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1090 LDR_DATA_TABLE_ENTRY
,
1093 /* FIXME: ROS HACK. Make sure this is a driver */
1094 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1096 /* Skip this entry */
1097 NextEntry
= NextEntry
->Flink
;
1101 /* Calculate the size we'll need and allocate a copy */
1102 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1103 LdrEntry
->BaseDllName
.MaximumLength
+
1104 sizeof(UNICODE_NULL
);
1105 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1106 if (!NewEntry
) return FALSE
;
1108 /* Copy the entry over */
1109 *NewEntry
= *LdrEntry
;
1111 /* Allocate the name */
1112 NewEntry
->FullDllName
.Buffer
=
1113 ExAllocatePoolWithTag(PagedPool
,
1114 LdrEntry
->FullDllName
.MaximumLength
+
1115 sizeof(UNICODE_NULL
),
1117 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1119 /* Set the base name */
1120 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1122 /* Copy the full and base name */
1123 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1124 LdrEntry
->FullDllName
.Buffer
,
1125 LdrEntry
->FullDllName
.MaximumLength
);
1126 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1127 LdrEntry
->BaseDllName
.Buffer
,
1128 LdrEntry
->BaseDllName
.MaximumLength
);
1130 /* Null-terminate the base name */
1131 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1132 sizeof(WCHAR
)] = UNICODE_NULL
;
1134 /* Insert the entry into the list */
1135 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1136 NextEntry
= NextEntry
->Flink
;
1139 /* Build the import lists for the boot drivers */
1140 //MiBuildImportsForBootDrivers();
1148 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1150 PIMAGE_NT_HEADERS NtHeader
;
1153 /* Get NT Headers */
1154 NtHeader
= RtlImageNtHeader(BaseAddress
);
1157 /* Check if this image is only safe for UP while we have 2+ CPUs */
1158 if ((KeNumberProcessors
> 1) &&
1159 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1166 /* Otherwise, it's safe */
1172 MmCheckSystemImage(IN HANDLE ImageHandle
,
1173 IN BOOLEAN PurgeSection
)
1176 HANDLE SectionHandle
;
1177 PVOID ViewBase
= NULL
;
1178 SIZE_T ViewSize
= 0;
1179 IO_STATUS_BLOCK IoStatusBlock
;
1180 FILE_STANDARD_INFORMATION FileStandardInfo
;
1181 KAPC_STATE ApcState
;
1184 /* Create a section for the DLL */
1185 Status
= ZwCreateSection(&SectionHandle
,
1186 SECTION_MAP_EXECUTE
,
1192 if (!NT_SUCCESS(Status
)) return Status
;
1194 /* Make sure we're in the system process */
1195 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1198 Status
= ZwMapViewOfSection(SectionHandle
,
1208 if (!NT_SUCCESS(Status
))
1210 /* We failed, close the handle and return */
1211 KeUnstackDetachProcess(&ApcState
);
1212 ZwClose(SectionHandle
);
1216 /* Now query image information */
1217 Status
= ZwQueryInformationFile(ImageHandle
,
1220 sizeof(FileStandardInfo
),
1221 FileStandardInformation
);
1222 if ( NT_SUCCESS(Status
) )
1224 /* First, verify the checksum */
1225 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1231 /* Set checksum failure */
1232 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1235 /* Check that it's a valid SMP image if we have more then one CPU */
1236 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1238 /* Otherwise it's not the right image */
1239 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1243 /* Unmap the section, close the handle, and return status */
1244 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1245 KeUnstackDetachProcess(&ApcState
);
1246 ZwClose(SectionHandle
);
1252 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1253 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1254 IN PUNICODE_STRING LoadedName OPTIONAL
,
1256 OUT PVOID
*ModuleObject
,
1257 OUT PVOID
*ImageBaseAddress
)
1259 PVOID ModuleLoadBase
= NULL
;
1261 HANDLE FileHandle
= NULL
;
1262 OBJECT_ATTRIBUTES ObjectAttributes
;
1263 FILE_STANDARD_INFORMATION FileStdInfo
;
1264 IO_STATUS_BLOCK IoStatusBlock
;
1265 ULONG DriverSize
= 0, Size
, i
;
1267 PIMAGE_SECTION_HEADER SectionHeaders
;
1268 PIMAGE_NT_HEADERS NtHeader
;
1269 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
;
1270 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1272 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1273 PCHAR MissingApiName
, Buffer
;
1274 PWCHAR MissingDriverName
;
1275 HANDLE SectionHandle
;
1276 ACCESS_MASK DesiredAccess
;
1277 PVOID Section
= NULL
;
1278 BOOLEAN LockOwned
= FALSE
;
1279 PLIST_ENTRY NextEntry
;
1282 /* Detect session-load */
1286 ASSERT(NamePrefix
== NULL
);
1287 ASSERT(LoadedName
== NULL
);
1289 /* Make sure the process is in session too */
1290 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1293 if (ModuleObject
) *ModuleObject
= NULL
;
1294 if (ImageBaseAddress
) *ImageBaseAddress
= NULL
;
1296 /* Allocate a buffer we'll use for names */
1297 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1298 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1300 /* Check for a separator */
1301 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1306 /* Loop the path until we get to the base name */
1307 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1308 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1310 /* Get the length */
1311 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1312 BaseLength
*= sizeof(WCHAR
);
1314 /* Setup the string */
1315 BaseName
.Length
= (USHORT
)BaseLength
;
1316 BaseName
.Buffer
= p
;
1320 /* Otherwise, we already have a base name */
1321 BaseName
.Length
= FileName
->Length
;
1322 BaseName
.Buffer
= FileName
->Buffer
;
1325 /* Setup the maximum length */
1326 BaseName
.MaximumLength
= BaseName
.Length
;
1328 /* Now compute the base directory */
1329 BaseDirectory
= *FileName
;
1330 BaseDirectory
.Length
-= BaseName
.Length
;
1331 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1333 /* And the prefix, which for now is just the name itself */
1334 PrefixName
= *FileName
;
1336 /* Check if we have a prefix */
1337 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1339 /* Check if we already have a name, use it instead */
1340 if (LoadedName
) BaseName
= *LoadedName
;
1342 /* Acquire the load lock */
1344 ASSERT(LockOwned
== FALSE
);
1346 KeEnterCriticalRegion();
1347 KeWaitForSingleObject(&MmSystemLoadLock
,
1353 /* Scan the module list */
1354 NextEntry
= PsLoadedModuleList
.Flink
;
1355 while (NextEntry
!= &PsLoadedModuleList
)
1357 /* Get the entry and compare the names */
1358 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1359 LDR_DATA_TABLE_ENTRY
,
1361 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1363 /* Found it, break out */
1368 NextEntry
= NextEntry
->Flink
;
1371 /* Check if we found the image */
1372 if (NextEntry
!= &PsLoadedModuleList
)
1374 /* Check if we had already mapped a section */
1377 /* Dereference and clear */
1378 ObDereferenceObject(Section
);
1382 /* Check if this was supposed to be a session load */
1385 /* It wasn't, so just return the data */
1386 *ModuleObject
= LdrEntry
;
1387 *ImageBaseAddress
= LdrEntry
->DllBase
;
1388 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1392 /* We don't support session loading yet */
1393 DPRINT1("Unsupported Session-Load!\n");
1402 /* It wasn't loaded, and we didn't have a previous attempt */
1403 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1404 KeLeaveCriticalRegion();
1407 /* Check if KD is enabled */
1408 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1410 /* FIXME: Attempt to get image from KD */
1413 /* We don't have a valid entry */
1416 /* Setup image attributes */
1417 InitializeObjectAttributes(&ObjectAttributes
,
1419 OBJ_CASE_INSENSITIVE
,
1423 /* Open the image */
1424 Status
= ZwOpenFile(&FileHandle
,
1428 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1429 FILE_SYNCHRONOUS_IO_NONALERT
);
1430 if (!NT_SUCCESS(Status
)) goto Quickie
;
1433 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1434 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1435 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1436 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1442 /* Get image size */
1443 Status
= ZwQueryInformationFile(FileHandle
,
1446 sizeof(FileStdInfo
),
1447 FileStandardInformation
);
1448 if (!NT_SUCCESS(Status
)) goto Quickie
;
1450 /* Allocate memory for image */
1451 ModuleLoadBase
= ExAllocatePoolWithTag(NonPagedPool
,
1452 FileStdInfo
.EndOfFile
.u
.LowPart
,
1455 /* Read the image */
1456 Status
= ZwReadFile(FileHandle
,
1462 FileStdInfo
.EndOfFile
.u
.LowPart
,
1465 if (!NT_SUCCESS(Status
)) goto Quickie
;
1467 /* Check if this is a session-load */
1470 /* Then we only need read and execute */
1471 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1475 /* Otherwise, we can allow write access */
1476 DesiredAccess
= SECTION_ALL_ACCESS
;
1479 /* Initialize the attributes for the section */
1480 InitializeObjectAttributes(&ObjectAttributes
,
1482 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1486 /* Create the section */
1487 Status
= ZwCreateSection(&SectionHandle
,
1494 if (!NT_SUCCESS(Status
)) goto Quickie
;
1496 /* Now get the section pointer */
1497 Status
= ObReferenceObjectByHandle(SectionHandle
,
1498 SECTION_MAP_EXECUTE
,
1499 MmSectionObjectType
,
1503 ZwClose(SectionHandle
);
1504 if (!NT_SUCCESS(Status
)) goto Quickie
;
1506 /* Check if this was supposed to be a session-load */
1509 /* We don't support session loading yet */
1510 DPRINT1("Unsupported Session-Load!\n");
1514 /* Check the loader list again, we should end up in the path below */
1519 /* We don't have a valid entry */
1523 /* We should have a valid module base */
1524 ASSERT(ModuleLoadBase
!= NULL
);
1526 /* Get header pointers */
1527 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1529 /* Get header pointers */
1530 SectionHeaders
= IMAGE_FIRST_SECTION(NtHeader
);
1532 /* Determine the size of the module */
1533 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1535 /* Skip this section if we're not supposed to load it */
1536 if (!(SectionHeaders
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
1538 /* Add the size of this section into the total size */
1539 Size
= SectionHeaders
[i
].VirtualAddress
+
1540 SectionHeaders
[i
].Misc
.VirtualSize
;
1541 DriverSize
= max(DriverSize
, Size
);
1545 /* Round up the driver size to section alignment */
1546 DriverSize
= ROUND_UP(DriverSize
, NtHeader
->OptionalHeader
.SectionAlignment
);
1548 /* Allocate a virtual section for the module */
1549 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
1551 /* Copy headers over */
1552 RtlCopyMemory(DriverBase
,
1554 NtHeader
->OptionalHeader
.SizeOfHeaders
);
1556 /* Copy image sections into virtual section */
1557 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1559 /* Get the size of this section and check if it's valid and on-disk */
1560 Size
= SectionHeaders
[i
].VirtualAddress
+
1561 SectionHeaders
[i
].Misc
.VirtualSize
;
1562 if ((Size
<= DriverSize
) && (SectionHeaders
[i
].SizeOfRawData
))
1564 /* Copy the data from the disk to the image */
1565 RtlCopyMemory((PVOID
)((ULONG_PTR
)DriverBase
+
1566 SectionHeaders
[i
].VirtualAddress
),
1567 (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1568 SectionHeaders
[i
].PointerToRawData
),
1569 SectionHeaders
[i
].Misc
.VirtualSize
>
1570 SectionHeaders
[i
].SizeOfRawData
?
1571 SectionHeaders
[i
].SizeOfRawData
:
1572 SectionHeaders
[i
].Misc
.VirtualSize
);
1576 /* Relocate the driver */
1577 Status
= LdrRelocateImageWithBias(DriverBase
,
1581 STATUS_CONFLICTING_ADDRESSES
,
1582 STATUS_INVALID_IMAGE_FORMAT
);
1583 if (!NT_SUCCESS(Status
)) goto Quickie
;
1585 /* Calculate the size we'll need for the entry and allocate it */
1586 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1588 sizeof(UNICODE_NULL
);
1590 /* Allocate the entry */
1591 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1595 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1599 /* Setup the entry */
1600 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1601 LdrEntry
->LoadCount
= 1;
1602 LdrEntry
->LoadedImports
= LoadedImports
;
1603 LdrEntry
->PatchInformation
= NULL
;
1605 /* Check the version */
1606 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1607 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1609 /* Mark this image as a native image */
1610 LdrEntry
->Flags
|= 0x80000000;
1613 /* Setup the rest of the entry */
1614 LdrEntry
->DllBase
= DriverBase
;
1615 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)DriverBase
+
1616 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1617 LdrEntry
->SizeOfImage
= DriverSize
;
1618 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1619 LdrEntry
->SectionPointer
= LdrEntry
;
1621 /* Now write the DLL name */
1622 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1623 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1624 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1626 /* Copy and null-terminate it */
1627 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1630 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ 2] = UNICODE_NULL
;
1632 /* Now allocate the full name */
1633 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1635 sizeof(UNICODE_NULL
),
1637 if (!LdrEntry
->FullDllName
.Buffer
)
1639 /* Don't fail, just set it to zero */
1640 LdrEntry
->FullDllName
.Length
= 0;
1641 LdrEntry
->FullDllName
.MaximumLength
= 0;
1646 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1647 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1649 /* Copy and null-terminate */
1650 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1653 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ 2] = UNICODE_NULL
;
1657 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1659 /* Resolve imports */
1660 MissingApiName
= Buffer
;
1661 Status
= MiResolveImageReferences(DriverBase
,
1667 if (!NT_SUCCESS(Status
))
1670 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1672 /* Check if we need to free the name */
1673 if (LdrEntry
->FullDllName
.Buffer
)
1676 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1679 /* Free the entry itself */
1680 ExFreePool(LdrEntry
);
1685 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1686 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1688 /* Hook for KDB on loading a driver. */
1689 KDB_LOADDRIVER_HOOK(FileName
, LdrEntry
);
1692 /* If we have a file handle, close it */
1693 if (FileHandle
) ZwClose(FileHandle
);
1696 if (ModuleLoadBase
) ExFreePool(ModuleLoadBase
);
1698 /* Check if we have the lock acquired */
1701 /* Release the lock */
1702 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1703 KeLeaveCriticalRegion();
1707 /* Check if we had a prefix */
1708 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1710 /* Free the name buffer and return status */