3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ldr/loader.c
6 * PURPOSE: Loaders for PE executables
8 * PROGRAMMERS: Jean Michault
9 * Rex Jolliff (rex@lvcablemodem.com)
10 * Jason Filby (jasonfilby@yahoo.com)
11 * Casper S. Hornstrup (chorns@users.sourceforge.net)
15 /* INCLUDES *****************************************************************/
20 #include <internal/ntosdbg.h>
31 #define ps(args...) DPRINT1(args)
35 #include <internal/debug.h>
37 #if defined (ALLOC_PRAGMA)
38 #pragma alloc_text(INIT, LdrInit1)
39 #pragma alloc_text(INIT, LdrInitModuleManagement)
40 #pragma alloc_text(INIT, LdrSafePEProcessModule)
43 /* GLOBALS *******************************************************************/
45 LIST_ENTRY PsLoadedModuleList
;
46 ULONG PsNtosImageBase
= 0x80100000;
47 KSPIN_LOCK ModuleListLock
;
48 LDR_DATA_TABLE_ENTRY NtoskrnlModuleObject
;
49 LDR_DATA_TABLE_ENTRY HalModuleObject
;
51 /* FORWARD DECLARATIONS ******************************************************/
56 PUNICODE_STRING ModuleName
,
57 PLDR_DATA_TABLE_ENTRY
*ModuleObject
);
60 LdrpBuildModuleBaseName (
61 PUNICODE_STRING BaseName
,
62 PUNICODE_STRING FullName
);
65 LdrpCompareModuleNames (
66 IN PUNICODE_STRING String1
,
67 IN PUNICODE_STRING String2
);
70 /* PE Driver load support */
74 PUNICODE_STRING FileName
,
75 PLDR_DATA_TABLE_ENTRY
*ModuleObject
);
78 LdrPEGetExportByName (
84 LdrPEFixupForward ( PCHAR ForwardName
);
87 LdrPEFixupImports ( IN PVOID DllBase
, IN PWCHAR DllName
);
89 /* FUNCTIONS *****************************************************************/
93 LdrInitDebug ( PLOADER_MODULE Module
, PWCH Name
)
102 PLDR_DATA_TABLE_ENTRY HalModuleObject
, NtoskrnlModuleObject
, LdrEntry
;
104 /* Initialize the module list and spinlock */
105 InitializeListHead(&PsLoadedModuleList
);
106 KeInitializeSpinLock(&ModuleListLock
);
108 /* Get the NTOSKRNL Entry from the loader */
109 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
111 /* Initialize ModuleObject for NTOSKRNL */
112 NtoskrnlModuleObject
= ExAllocatePoolWithTag(PagedPool
,
113 sizeof(LDR_DATA_TABLE_ENTRY
),
114 TAG('M', 'm', 'L', 'd'));
115 NtoskrnlModuleObject
->DllBase
= LdrEntry
->DllBase
;
116 PsNtosImageBase
= PtrToUlong(LdrEntry
->DllBase
);
117 RtlInitUnicodeString(&NtoskrnlModuleObject
->FullDllName
, KERNEL_MODULE_NAME
);
118 LdrpBuildModuleBaseName(&NtoskrnlModuleObject
->BaseDllName
, &NtoskrnlModuleObject
->FullDllName
);
119 NtoskrnlModuleObject
->EntryPoint
= LdrEntry
->EntryPoint
;
120 NtoskrnlModuleObject
->SizeOfImage
= LdrEntry
->SizeOfImage
;
122 /* Insert it into the list */
123 InsertTailList(&PsLoadedModuleList
, &NtoskrnlModuleObject
->InLoadOrderLinks
);
125 /* Get the HAL Entry from the loader */
126 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
->Flink
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
128 /* Initialize ModuleObject for HAL */
129 HalModuleObject
= ExAllocatePoolWithTag(PagedPool
,
130 sizeof(LDR_DATA_TABLE_ENTRY
),
131 TAG('M', 'm', 'L', 'd'));
132 HalModuleObject
->DllBase
= LdrEntry
->DllBase
;
133 RtlInitUnicodeString(&HalModuleObject
->FullDllName
, HAL_MODULE_NAME
);
134 LdrpBuildModuleBaseName(&HalModuleObject
->BaseDllName
, &HalModuleObject
->FullDllName
);
135 HalModuleObject
->EntryPoint
= LdrEntry
->EntryPoint
;
136 HalModuleObject
->SizeOfImage
= LdrEntry
->SizeOfImage
;
138 /* Insert it into the list */
139 InsertTailList(&PsLoadedModuleList
, &HalModuleObject
->InLoadOrderLinks
);
145 PUNICODE_STRING DriverName
,
147 PVOID
*SectionPointer
,
149 PVOID
*ExportSectionPointer
)
151 PLDR_DATA_TABLE_ENTRY ModuleObject
;
154 ModuleObject
= LdrGetModuleObject(DriverName
);
155 if (ModuleObject
== NULL
)
157 Status
= LdrLoadModule(DriverName
, &ModuleObject
);
158 if (!NT_SUCCESS(Status
))
165 *ModuleBase
= ModuleObject
->DllBase
;
168 *SectionPointer
= ModuleObject
;
171 *EntryPoint
= ModuleObject
->EntryPoint
;
173 //if (ExportSectionPointer)
174 // *ExportSectionPointer = ModuleObject->
176 return(STATUS_SUCCESS
);
182 LdrpUnloadImage ( PVOID ModuleBase
)
184 return(STATUS_NOT_IMPLEMENTED
);
190 LdrpLoadAndCallImage ( PUNICODE_STRING ModuleName
)
192 PDRIVER_INITIALIZE DriverEntry
;
193 PLDR_DATA_TABLE_ENTRY ModuleObject
;
194 DRIVER_OBJECT DriverObject
;
197 ModuleObject
= LdrGetModuleObject(ModuleName
);
198 if (ModuleObject
!= NULL
)
200 return(STATUS_IMAGE_ALREADY_LOADED
);
203 Status
= LdrLoadModule(ModuleName
, &ModuleObject
);
204 if (!NT_SUCCESS(Status
))
209 DriverEntry
= (PDRIVER_INITIALIZE
)ModuleObject
->EntryPoint
;
211 RtlZeroMemory(&DriverObject
, sizeof(DriverObject
));
212 // DriverObject.DriverStart = ModuleObject->DllBase;
214 Status
= DriverEntry(&DriverObject
, NULL
);
215 if (!NT_SUCCESS(Status
))
217 LdrUnloadModule(ModuleObject
);
227 PUNICODE_STRING Filename
,
228 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
230 PVOID ModuleLoadBase
;
233 OBJECT_ATTRIBUTES ObjectAttributes
;
234 PLDR_DATA_TABLE_ENTRY Module
;
235 FILE_STANDARD_INFORMATION FileStdInfo
;
236 IO_STATUS_BLOCK IoStatusBlock
;
238 *ModuleObject
= NULL
;
240 DPRINT("Loading Module %wZ...\n", Filename
);
242 /* Open the Module */
243 InitializeObjectAttributes(&ObjectAttributes
,
245 OBJ_CASE_INSENSITIVE
,
249 Status
= ZwOpenFile(&FileHandle
,
254 FILE_SYNCHRONOUS_IO_NONALERT
);
256 if (!NT_SUCCESS(Status
))
258 CPRINT("Could not open module file: %wZ (Status 0x%08lx)\n", Filename
, Status
);
263 /* Get the size of the file */
264 Status
= ZwQueryInformationFile(FileHandle
,
268 FileStandardInformation
);
269 if (!NT_SUCCESS(Status
))
271 CPRINT("Could not get file size\n");
277 /* Allocate nonpageable memory for driver */
278 ModuleLoadBase
= ExAllocatePoolWithTag(NonPagedPool
,
279 FileStdInfo
.EndOfFile
.u
.LowPart
,
281 if (ModuleLoadBase
== NULL
)
283 CPRINT("Could not allocate memory for module");
285 return(STATUS_INSUFFICIENT_RESOURCES
);
289 /* Load driver into memory chunk */
290 Status
= ZwReadFile(FileHandle
,
294 FileStdInfo
.EndOfFile
.u
.LowPart
,
296 if (!NT_SUCCESS(Status
))
298 CPRINT("Could not read module file into memory");
299 ExFreePool(ModuleLoadBase
);
307 Status
= LdrProcessModule(ModuleLoadBase
,
310 if (!NT_SUCCESS(Status
))
312 CPRINT("Could not process module\n");
313 ExFreePool(ModuleLoadBase
);
318 ExFreePool(ModuleLoadBase
);
320 *ModuleObject
= Module
;
322 return(STATUS_SUCCESS
);
328 LdrUnloadModule ( PLDR_DATA_TABLE_ENTRY ModuleObject
)
332 /* Remove the module from the module list */
333 KeAcquireSpinLock(&ModuleListLock
,&Irql
);
334 RemoveEntryList(&ModuleObject
->InLoadOrderLinks
);
335 KeReleaseSpinLock(&ModuleListLock
, Irql
);
337 /* Free module section */
338 // MmFreeSection(ModuleObject->DllBase);
340 ExFreePool(ModuleObject
->FullDllName
.Buffer
);
341 ExFreePool(ModuleObject
);
343 return(STATUS_SUCCESS
);
349 PVOID ModuleLoadBase
,
350 PUNICODE_STRING ModuleName
,
351 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
353 PIMAGE_DOS_HEADER PEDosHeader
;
355 /* If MZ header exists */
356 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
357 if (PEDosHeader
->e_magic
== IMAGE_DOS_SIGNATURE
&& PEDosHeader
->e_lfanew
!= 0L)
359 return LdrPEProcessModule(ModuleLoadBase
,
364 CPRINT("Module wasn't PE\n");
365 return STATUS_UNSUCCESSFUL
;
370 LdrpQueryModuleInformation (
375 PLIST_ENTRY current_entry
;
376 PLDR_DATA_TABLE_ENTRY current
;
377 ULONG ModuleCount
= 0;
378 PRTL_PROCESS_MODULES Smi
;
379 ANSI_STRING AnsiName
;
382 PUNICODE_STRING UnicodeName
;
383 ULONG tmpBufferSize
= 0;
384 PWCHAR tmpNameBuffer
;
386 KeAcquireSpinLock(&ModuleListLock
,&Irql
);
388 /* calculate required size */
389 current_entry
= PsLoadedModuleList
.Flink
;
390 while (current_entry
!= (&PsLoadedModuleList
))
393 current
= CONTAINING_RECORD(current_entry
,LDR_DATA_TABLE_ENTRY
,InLoadOrderLinks
);
394 tmpBufferSize
+= current
->FullDllName
.Length
+ sizeof(WCHAR
) + sizeof(UNICODE_STRING
);
395 current_entry
= current_entry
->Flink
;
398 *ReqSize
= sizeof(RTL_PROCESS_MODULES
)+
399 (ModuleCount
- 1) * sizeof(RTL_PROCESS_MODULE_INFORMATION
);
403 KeReleaseSpinLock(&ModuleListLock
, Irql
);
404 return(STATUS_INFO_LENGTH_MISMATCH
);
407 /* allocate a temp buffer to store the module names */
408 UnicodeName
= ExAllocatePool(NonPagedPool
, tmpBufferSize
);
409 if (UnicodeName
== NULL
)
411 KeReleaseSpinLock(&ModuleListLock
, Irql
);
412 return STATUS_INSUFFICIENT_RESOURCES
;
414 tmpNameBuffer
= (PWCHAR
)((ULONG_PTR
)UnicodeName
+ ModuleCount
* sizeof(UNICODE_STRING
));
416 /* fill the buffer */
417 memset(Buffer
, '=', Size
);
419 Smi
= (PRTL_PROCESS_MODULES
)Buffer
;
420 Smi
->NumberOfModules
= ModuleCount
;
423 current_entry
= PsLoadedModuleList
.Flink
;
424 while (current_entry
!= (&PsLoadedModuleList
))
426 current
= CONTAINING_RECORD(current_entry
,LDR_DATA_TABLE_ENTRY
,InLoadOrderLinks
);
428 Smi
->Modules
[ModuleCount
].Section
= 0; /* Always 0 */
429 Smi
->Modules
[ModuleCount
].MappedBase
= 0; /* Always 0 */
430 Smi
->Modules
[ModuleCount
].ImageBase
= current
->DllBase
;
431 Smi
->Modules
[ModuleCount
].ImageSize
= current
->SizeOfImage
;
432 Smi
->Modules
[ModuleCount
].Flags
= 0; /* Flags ??? (GN) */
433 Smi
->Modules
[ModuleCount
].LoadOrderIndex
= (USHORT
)ModuleCount
;
434 Smi
->Modules
[ModuleCount
].InitOrderIndex
= 0;
435 Smi
->Modules
[ModuleCount
].LoadCount
= 0; /* FIXME */
436 UnicodeName
[ModuleCount
].Buffer
= tmpNameBuffer
;
437 UnicodeName
[ModuleCount
].MaximumLength
= current
->FullDllName
.Length
+ sizeof(WCHAR
);
438 tmpNameBuffer
+= UnicodeName
[ModuleCount
].MaximumLength
/ sizeof(WCHAR
);
439 RtlCopyUnicodeString(&UnicodeName
[ModuleCount
], ¤t
->FullDllName
);
442 current_entry
= current_entry
->Flink
;
445 KeReleaseSpinLock(&ModuleListLock
, Irql
);
447 for (ModuleCount
= 0; ModuleCount
< Smi
->NumberOfModules
; ModuleCount
++)
450 AnsiName
.MaximumLength
= 255;
451 AnsiName
.Buffer
= Smi
->Modules
[ModuleCount
].FullPathName
;
452 RtlUnicodeStringToAnsiString(&AnsiName
, &UnicodeName
[ModuleCount
], FALSE
);
453 AnsiName
.Buffer
[AnsiName
.Length
] = 0;
454 Smi
->Modules
[ModuleCount
].InitOrderIndex
= AnsiName
.Length
;
456 p
= strrchr(AnsiName
.Buffer
, '\\');
459 Smi
->Modules
[ModuleCount
].OffsetToFileName
= 0;
464 Smi
->Modules
[ModuleCount
].OffsetToFileName
= p
- AnsiName
.Buffer
;
468 ExFreePool(UnicodeName
);
470 return(STATUS_SUCCESS
);
475 LdrpBuildModuleBaseName (
476 PUNICODE_STRING BaseName
,
477 PUNICODE_STRING FullName
)
481 DPRINT("LdrpBuildModuleBaseName()\n");
482 DPRINT("FullName %wZ\n", FullName
);
484 p
= wcsrchr(FullName
->Buffer
, L
'\\');
487 p
= FullName
->Buffer
;
496 RtlInitUnicodeString(BaseName
, p
);
501 LdrpCompareModuleNames (
502 IN PUNICODE_STRING String1
,
503 IN PUNICODE_STRING String2
)
509 if (String1
&& String2
)
511 /* Search String1 for last path component */
512 len1
= String1
->Length
/ sizeof(WCHAR
);
513 s1
= String1
->Buffer
;
514 for (i
= 0, p
= String1
->Buffer
; i
< String1
->Length
; i
= i
+ sizeof(WCHAR
), p
++)
518 if (i
== String1
->Length
- sizeof(WCHAR
))
526 len1
= (String1
->Length
- i
) / sizeof(WCHAR
);
531 /* Search String2 for last path component */
532 len2
= String2
->Length
/ sizeof(WCHAR
);
533 s2
= String2
->Buffer
;
534 for (i
= 0, p
= String2
->Buffer
; i
< String2
->Length
; i
= i
+ sizeof(WCHAR
), p
++)
538 if (i
== String2
->Length
- sizeof(WCHAR
))
546 len2
= (String2
->Length
- i
) / sizeof(WCHAR
);
551 /* Compare last path components */
556 c1
= len1
-- ? RtlUpcaseUnicodeChar (*s1
++) : 0;
557 c2
= len2
-- ? RtlUpcaseUnicodeChar (*s2
++) : 0;
558 if ((c1
== 0 && c2
== L
'.') || (c1
== L
'.' && c2
== 0))
560 if (!c1
|| !c2
|| c1
!= c2
)
569 PLDR_DATA_TABLE_ENTRY
571 LdrGetModuleObject ( PUNICODE_STRING ModuleName
)
573 PLDR_DATA_TABLE_ENTRY Module
;
577 DPRINT("LdrGetModuleObject(%wZ) called\n", ModuleName
);
579 KeAcquireSpinLock(&ModuleListLock
,&Irql
);
581 Entry
= PsLoadedModuleList
.Flink
;
582 while (Entry
!= &PsLoadedModuleList
)
584 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
586 DPRINT("Comparing %wZ and %wZ\n",
587 &Module
->BaseDllName
,
590 if (!LdrpCompareModuleNames(&Module
->BaseDllName
, ModuleName
))
592 DPRINT("Module %wZ\n", &Module
->BaseDllName
);
593 KeReleaseSpinLock(&ModuleListLock
, Irql
);
597 Entry
= Entry
->Flink
;
600 KeReleaseSpinLock(&ModuleListLock
, Irql
);
602 DPRINT("Could not find module '%wZ'\n", ModuleName
);
608 /* ---------------------------------------------- PE Module support */
611 LdrLookupPageProtection (
614 PIMAGE_FILE_HEADER PEFileHeader
,
615 PIMAGE_SECTION_HEADER PESectionHeaders
)
617 BOOLEAN Write
= FALSE
;
618 BOOLEAN Execute
= FALSE
;
619 ULONG Characteristics
;
624 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
&& (!Write
|| !Execute
); Idx
++)
626 Characteristics
= PESectionHeaders
[Idx
].Characteristics
;
627 if (!(Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
629 Length
= max(PESectionHeaders
[Idx
].Misc
.VirtualSize
, PESectionHeaders
[Idx
].SizeOfRawData
);
630 BaseAddress
= PESectionHeaders
[Idx
].VirtualAddress
+ (char*)DriverBase
;
631 if (BaseAddress
< (PVOID
)((ULONG_PTR
)PageStart
+ PAGE_SIZE
) &&
632 PageStart
< (PVOID
)((ULONG_PTR
)BaseAddress
+ Length
))
634 if (Characteristics
& IMAGE_SCN_CNT_CODE
)
638 if (Characteristics
& (IMAGE_SCN_MEM_WRITE
|IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
645 if (Write
&& Execute
)
647 return PAGE_EXECUTE_READWRITE
;
651 return PAGE_EXECUTE_READ
;
655 return PAGE_READWRITE
;
659 return PAGE_READONLY
;
665 PVOID ModuleLoadBase
,
666 PUNICODE_STRING FileName
,
667 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
669 unsigned int DriverSize
, Idx
;
672 PIMAGE_DOS_HEADER PEDosHeader
;
673 PIMAGE_NT_HEADERS PENtHeaders
;
674 PIMAGE_SECTION_HEADER PESectionHeaders
;
675 PLDR_DATA_TABLE_ENTRY CreatedModuleObject
;
679 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase
);
681 /* Get header pointers */
682 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
683 PENtHeaders
= RtlImageNtHeader(ModuleLoadBase
);
684 PESectionHeaders
= IMAGE_FIRST_SECTION(PENtHeaders
);
687 /* Check file magic numbers */
688 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
690 CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader
->e_magic
);
691 return STATUS_UNSUCCESSFUL
;
693 if (PEDosHeader
->e_lfanew
== 0)
695 CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader
->e_lfanew
);
696 return STATUS_UNSUCCESSFUL
;
698 if (PENtHeaders
->Signature
!= IMAGE_NT_SIGNATURE
)
700 CPRINT("Incorrect PE magic: %08x\n", PENtHeaders
->Signature
);
701 return STATUS_UNSUCCESSFUL
;
703 if (PENtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_I386
)
705 CPRINT("Incorrect Architechture: %04x\n", PENtHeaders
->FileHeader
.Machine
);
706 return STATUS_UNSUCCESSFUL
;
710 /* FIXME: if image is fixed-address load, then fail */
712 /* FIXME: check/verify OS version number */
714 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
715 PENtHeaders
->OptionalHeader
.Magic
,
716 PENtHeaders
->OptionalHeader
.MajorLinkerVersion
,
717 PENtHeaders
->OptionalHeader
.MinorLinkerVersion
);
718 DPRINT("Entry Point:%08lx\n", PENtHeaders
->OptionalHeader
.AddressOfEntryPoint
);
720 /* Determine the size of the module */
722 for (Idx
= 0; Idx
< PENtHeaders
->FileHeader
.NumberOfSections
; Idx
++)
724 if (!(PESectionHeaders
[Idx
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
726 CurrentSize
= PESectionHeaders
[Idx
].VirtualAddress
+ PESectionHeaders
[Idx
].Misc
.VirtualSize
;
727 DriverSize
= max(DriverSize
, CurrentSize
);
730 DriverSize
= ROUND_UP(DriverSize
, PENtHeaders
->OptionalHeader
.SectionAlignment
);
731 DPRINT("DriverSize %x, SizeOfImage %x\n",DriverSize
, PENtHeaders
->OptionalHeader
.SizeOfImage
);
733 /* Allocate a virtual section for the module */
735 DriverBase
= MmAllocateSection(DriverSize
, DriverBase
);
738 CPRINT("Failed to allocate a virtual section for driver\n");
739 return STATUS_UNSUCCESSFUL
;
741 DPRINT("DriverBase for %wZ: %x\n", FileName
, DriverBase
);
743 /* Copy headers over */
744 memcpy(DriverBase
, ModuleLoadBase
, PENtHeaders
->OptionalHeader
.SizeOfHeaders
);
746 /* Copy image sections into virtual section */
747 for (Idx
= 0; Idx
< PENtHeaders
->FileHeader
.NumberOfSections
; Idx
++)
749 CurrentSize
= PESectionHeaders
[Idx
].VirtualAddress
+ PESectionHeaders
[Idx
].Misc
.VirtualSize
;
750 /* Copy current section into current offset of virtual section */
751 if (CurrentSize
<= DriverSize
&&
752 PESectionHeaders
[Idx
].SizeOfRawData
)
754 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
755 PESectionHeaders
[Idx
].VirtualAddress
+ (ULONG_PTR
)DriverBase
);
756 memcpy((PVOID
)((ULONG_PTR
)DriverBase
+ PESectionHeaders
[Idx
].VirtualAddress
),
757 (PVOID
)((ULONG_PTR
)ModuleLoadBase
+ PESectionHeaders
[Idx
].PointerToRawData
),
758 PESectionHeaders
[Idx
].Misc
.VirtualSize
> PESectionHeaders
[Idx
].SizeOfRawData
759 ? PESectionHeaders
[Idx
].SizeOfRawData
: PESectionHeaders
[Idx
].Misc
.VirtualSize
);
763 /* Perform relocation fixups */
764 Status
= LdrRelocateImageWithBias(DriverBase
, 0, "", STATUS_SUCCESS
,
765 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
766 if (!NT_SUCCESS(Status
))
768 // MmFreeSection(DriverBase);
772 /* Create the module */
773 CreatedModuleObject
= ExAllocatePoolWithTag (
774 NonPagedPool
, sizeof(LDR_DATA_TABLE_ENTRY
), TAG_MODULE_OBJECT
);
775 if (CreatedModuleObject
== NULL
)
777 // MmFreeSection(DriverBase);
778 return STATUS_INSUFFICIENT_RESOURCES
;
781 RtlZeroMemory(CreatedModuleObject
, sizeof(LDR_DATA_TABLE_ENTRY
));
783 /* Initialize ModuleObject data */
784 CreatedModuleObject
->DllBase
= DriverBase
;
786 CreatedModuleObject
->FullDllName
.Length
= 0;
787 CreatedModuleObject
->FullDllName
.MaximumLength
= FileName
->Length
+ sizeof(UNICODE_NULL
);
788 CreatedModuleObject
->FullDllName
.Buffer
=
789 ExAllocatePoolWithTag(PagedPool
, CreatedModuleObject
->FullDllName
.MaximumLength
, TAG_LDR_WSTR
);
790 if (CreatedModuleObject
->FullDllName
.Buffer
== NULL
)
792 ExFreePool(CreatedModuleObject
);
793 // MmFreeSection(DriverBase);
794 return STATUS_INSUFFICIENT_RESOURCES
;
797 RtlCopyUnicodeString(&CreatedModuleObject
->FullDllName
, FileName
);
798 CreatedModuleObject
->FullDllName
.Buffer
[FileName
->Length
/ sizeof(WCHAR
)] = 0;
799 LdrpBuildModuleBaseName(&CreatedModuleObject
->BaseDllName
,
800 &CreatedModuleObject
->FullDllName
);
802 CreatedModuleObject
->EntryPoint
=
803 (PVOID
)((ULONG_PTR
)DriverBase
+
804 PENtHeaders
->OptionalHeader
.AddressOfEntryPoint
);
805 CreatedModuleObject
->SizeOfImage
= DriverSize
;
806 DPRINT("EntryPoint at %x\n", CreatedModuleObject
->EntryPoint
);
808 /* Perform import fixups */
809 Status
= LdrPEFixupImports(CreatedModuleObject
->DllBase
,
810 CreatedModuleObject
->FullDllName
.Buffer
);
811 if (!NT_SUCCESS(Status
))
813 // MmFreeSection(DriverBase);
814 ExFreePool(CreatedModuleObject
->FullDllName
.Buffer
);
815 ExFreePool(CreatedModuleObject
);
819 MmSetPageProtect(NULL
, DriverBase
, PAGE_READONLY
);
820 /* Set the protections for the various parts of the driver */
821 for (Idx
= 0; Idx
< PENtHeaders
->FileHeader
.NumberOfSections
; Idx
++)
823 ULONG Characteristics
= PESectionHeaders
[Idx
].Characteristics
;
828 Length
= PESectionHeaders
[Idx
].Misc
.VirtualSize
;
829 BaseAddress
= PESectionHeaders
[Idx
].VirtualAddress
+ (char*)DriverBase
;
830 PageAddress
= (PVOID
)PAGE_ROUND_DOWN(BaseAddress
);
832 Protect
= LdrLookupPageProtection(PageAddress
, DriverBase
, &PENtHeaders
->FileHeader
, PESectionHeaders
);
833 if (PageAddress
< RVA(DriverBase
, DriverSize
))
835 MmSetPageProtect(NULL
, PageAddress
, Protect
);
838 if (Characteristics
& IMAGE_SCN_CNT_CODE
)
840 if (Characteristics
& IMAGE_SCN_MEM_WRITE
)
842 Protect
= PAGE_EXECUTE_READWRITE
;
846 Protect
= PAGE_EXECUTE_READ
;
849 else if (Characteristics
& (IMAGE_SCN_MEM_WRITE
|IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
851 Protect
= PAGE_READWRITE
;
855 Protect
= PAGE_READONLY
;
857 PageAddress
= (PVOID
)((ULONG_PTR
)PageAddress
+ PAGE_SIZE
);
858 while ((ULONG_PTR
)PageAddress
+ PAGE_SIZE
< (ULONG_PTR
)BaseAddress
+ Length
)
860 if (PageAddress
< RVA(DriverBase
, DriverSize
))
862 MmSetPageProtect(NULL
, PageAddress
, Protect
);
864 PageAddress
= (PVOID
)((ULONG_PTR
)PageAddress
+ PAGE_SIZE
);
866 if (PageAddress
< (PVOID
)((ULONG_PTR
)BaseAddress
+ Length
) &&
867 PageAddress
< RVA(DriverBase
, DriverSize
))
869 Protect
= LdrLookupPageProtection(PageAddress
, DriverBase
, &PENtHeaders
->FileHeader
, PESectionHeaders
);
870 MmSetPageProtect(NULL
, PageAddress
, Protect
);
875 KeAcquireSpinLock(&ModuleListLock
, &Irql
);
876 InsertTailList(&PsLoadedModuleList
,
877 &CreatedModuleObject
->InLoadOrderLinks
);
878 KeReleaseSpinLock(&ModuleListLock
, Irql
);
880 *ModuleObject
= CreatedModuleObject
;
882 DPRINT("Loading Module %wZ...\n", FileName
);
884 DPRINT("Module %wZ loaded at 0x%.08x.\n",
885 FileName
, CreatedModuleObject
->DllBase
);
887 return STATUS_SUCCESS
;
891 LdrPEFixupForward ( PCHAR ForwardName
)
893 CHAR NameBuffer
[128];
894 UNICODE_STRING ModuleName
;
896 PLDR_DATA_TABLE_ENTRY ModuleObject
;
898 DPRINT("LdrPEFixupForward (%s)\n", ForwardName
);
900 strcpy(NameBuffer
, ForwardName
);
901 p
= strchr(NameBuffer
, '.');
909 DPRINT("Driver: %s Function: %s\n", NameBuffer
, p
+1);
911 RtlCreateUnicodeStringFromAsciiz(&ModuleName
,
913 ModuleObject
= LdrGetModuleObject(&ModuleName
);
914 RtlFreeUnicodeString(&ModuleName
);
916 DPRINT("ModuleObject: %p\n", ModuleObject
);
918 if (ModuleObject
== NULL
)
920 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer
);
923 return LdrPEGetExportByName(ModuleObject
->DllBase
, (PUCHAR
)(p
+1), 0xffff);
931 LdrPEGetOrLoadModule (
934 PLDR_DATA_TABLE_ENTRY
* ImportedModule
)
936 UNICODE_STRING DriverName
;
937 UNICODE_STRING NameString
;
938 WCHAR NameBuffer
[PATH_MAX
];
939 NTSTATUS Status
= STATUS_SUCCESS
;
941 RtlCreateUnicodeStringFromAsciiz (&DriverName
, ImportedName
);
942 DPRINT("Import module: %wZ\n", &DriverName
);
944 *ImportedModule
= LdrGetModuleObject(&DriverName
);
945 if (*ImportedModule
== NULL
)
950 PathEnd
= wcsrchr(ModuleName
, L
'\\');
953 PathLength
= (PathEnd
- ModuleName
+ 1) * sizeof(WCHAR
);
954 RtlCopyMemory(NameBuffer
, ModuleName
, PathLength
);
955 RtlCopyMemory(NameBuffer
+ (PathLength
/ sizeof(WCHAR
)), DriverName
.Buffer
, DriverName
.Length
);
956 NameString
.Buffer
= NameBuffer
;
957 NameString
.MaximumLength
= NameString
.Length
= (USHORT
)PathLength
+ DriverName
.Length
;
960 NameString
.MaximumLength
+= sizeof(WCHAR
);
961 NameBuffer
[NameString
.Length
/ sizeof(WCHAR
)] = 0;
963 Status
= LdrLoadModule(&NameString
, ImportedModule
);
967 DPRINT("Module '%wZ' not loaded yet\n", &DriverName
);
968 wcscpy(NameBuffer
, L
"\\SystemRoot\\system32\\drivers\\");
969 wcsncat(NameBuffer
, DriverName
.Buffer
, DriverName
.Length
/ sizeof(WCHAR
));
970 RtlInitUnicodeString(&NameString
, NameBuffer
);
971 Status
= LdrLoadModule(&NameString
, ImportedModule
);
973 if (!NT_SUCCESS(Status
))
975 wcscpy(NameBuffer
, L
"\\SystemRoot\\system32\\");
976 wcsncat(NameBuffer
, DriverName
.Buffer
, DriverName
.Length
/ sizeof(WCHAR
));
977 RtlInitUnicodeString(&NameString
, NameBuffer
);
978 Status
= LdrLoadModule(&NameString
, ImportedModule
);
979 if (!NT_SUCCESS(Status
))
981 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &DriverName
, Status
);
985 RtlFreeUnicodeString(&DriverName
);
990 LdrPEGetExportByName (
995 PIMAGE_EXPORT_DIRECTORY ExportDir
;
996 PULONG
* ExFunctions
;
1002 LONG minn
, maxn
, mid
, res
;
1003 ULONG ExportDirSize
;
1005 DPRINT("LdrPEGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1007 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)RtlImageDirectoryEntryToData(BaseAddress
,
1009 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1011 if (ExportDir
== NULL
)
1013 DPRINT1("LdrPEGetExportByName(): no export directory!\n");
1018 /* The symbol names may be missing entirely */
1019 if (ExportDir
->AddressOfNames
== 0)
1021 DPRINT("LdrPEGetExportByName(): symbol names missing entirely\n");
1026 * Get header pointers
1028 ExNames
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfNames
);
1029 ExOrdinals
= (USHORT
*)RVA(BaseAddress
, ExportDir
->AddressOfNameOrdinals
);
1030 ExFunctions
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfFunctions
);
1033 * Check the hint first
1035 if (Hint
< ExportDir
->NumberOfNames
)
1037 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1038 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1040 Ordinal
= ExOrdinals
[Hint
];
1041 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1042 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
1043 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
1045 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1046 Function
= LdrPEFixupForward((PCHAR
)Function
);
1047 if (Function
== NULL
)
1049 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName
);
1053 if (Function
!= NULL
)
1064 maxn
= ExportDir
->NumberOfNames
- 1;
1065 while (minn
<= maxn
)
1067 mid
= (minn
+ maxn
) / 2;
1069 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1070 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
1073 Ordinal
= ExOrdinals
[mid
];
1074 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1075 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
1076 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
1078 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1079 Function
= LdrPEFixupForward((PCHAR
)Function
);
1080 if (Function
== NULL
)
1082 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName
);
1086 if (Function
!= NULL
)
1101 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1102 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName
);
1107 LdrPEGetExportByOrdinal (
1111 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1112 ULONG ExportDirSize
;
1113 PULONG
* ExFunctions
;
1116 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)RtlImageDirectoryEntryToData (
1119 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1122 ExFunctions
= (PULONG
*)RVA(BaseAddress
,
1123 ExportDir
->AddressOfFunctions
);
1124 DPRINT("LdrPEGetExportByOrdinal(Ordinal %d) = %x\n",
1126 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
]));
1128 Function
= 0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1129 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1132 if (((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
) &&
1133 ((ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
))
1135 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1136 Function
= LdrPEFixupForward((PCHAR
)Function
);
1143 LdrPEProcessImportDirectoryEntry(
1145 PLDR_DATA_TABLE_ENTRY ImportedModule
,
1146 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
)
1148 PVOID
* ImportAddressList
;
1149 PULONG FunctionNameList
;
1152 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->Name
== 0)
1154 return STATUS_UNSUCCESSFUL
;
1157 /* Get the import address list. */
1158 ImportAddressList
= (PVOID
*)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
1160 /* Get the list of functions to import. */
1161 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
1163 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->OriginalFirstThunk
);
1167 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
1170 /* Walk through function list and fixup addresses. */
1171 while (*FunctionNameList
!= 0L)
1173 if ((*FunctionNameList
) & 0x80000000)
1175 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1176 *ImportAddressList
= LdrPEGetExportByOrdinal(ImportedModule
->DllBase
, Ordinal
);
1177 if ((*ImportAddressList
) == NULL
)
1179 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1180 return STATUS_UNSUCCESSFUL
;
1185 IMAGE_IMPORT_BY_NAME
*pe_name
;
1186 pe_name
= RVA(DriverBase
, *FunctionNameList
);
1187 *ImportAddressList
= LdrPEGetExportByName(ImportedModule
->DllBase
, pe_name
->Name
, pe_name
->Hint
);
1188 if ((*ImportAddressList
) == NULL
)
1190 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1191 return STATUS_UNSUCCESSFUL
;
1194 ImportAddressList
++;
1197 return STATUS_SUCCESS
;
1201 LdrPEFixupImports (IN PVOID DllBase
,
1204 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1206 PLDR_DATA_TABLE_ENTRY ImportedModule
;
1210 /* Process each import module */
1211 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1212 RtlImageDirectoryEntryToData(DllBase
,
1214 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1216 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
1217 while (ImportModuleDirectory
->Name
)
1219 /* Check to make sure that import lib is kernel */
1220 ImportedName
= (PCHAR
) DllBase
+ ImportModuleDirectory
->Name
;
1222 Status
= LdrPEGetOrLoadModule(DllName
, ImportedName
, &ImportedModule
);
1223 if (!NT_SUCCESS(Status
))
1228 Status
= LdrPEProcessImportDirectoryEntry(DllBase
, ImportedModule
, ImportModuleDirectory
);
1229 if (!NT_SUCCESS(Status
))
1235 ImportModuleDirectory
++;
1237 return STATUS_SUCCESS
;