- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /* $Id$
2 *
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
7 *
8 * PROGRAMMERS: Jean Michault
9 * Rex Jolliff (rex@lvcablemodem.com)
10 * Jason Filby (jasonfilby@yahoo.com)
11 * Casper S. Hornstrup (chorns@users.sourceforge.net)
12 */
13
14
15 /* INCLUDES *****************************************************************/
16
17 #include <ntoskrnl.h>
18
19 #ifdef HALDBG
20 #include <internal/ntosdbg.h>
21 #else
22 #ifdef __GNUC__
23 #define ps(args...)
24 #else
25 #define ps
26 #endif /* __GNUC__ */
27 #endif
28
29 #if 0
30 #undef ps
31 #define ps(args...) DPRINT1(args)
32 #endif
33
34 #define NDEBUG
35 #include <internal/debug.h>
36
37 #if defined (ALLOC_PRAGMA)
38 #pragma alloc_text(INIT, LdrInit1)
39 #pragma alloc_text(INIT, LdrInitModuleManagement)
40 #pragma alloc_text(INIT, LdrSafePEProcessModule)
41 #endif
42
43 /* GLOBALS *******************************************************************/
44
45 LIST_ENTRY PsLoadedModuleList;
46 ULONG PsNtosImageBase = 0x80100000;
47 KSPIN_LOCK ModuleListLock;
48 LDR_DATA_TABLE_ENTRY NtoskrnlModuleObject;
49 LDR_DATA_TABLE_ENTRY HalModuleObject;
50
51 /* FORWARD DECLARATIONS ******************************************************/
52
53 NTSTATUS
54 LdrProcessModule (
55 PVOID ModuleLoadBase,
56 PUNICODE_STRING ModuleName,
57 PLDR_DATA_TABLE_ENTRY *ModuleObject );
58
59 static VOID
60 LdrpBuildModuleBaseName (
61 PUNICODE_STRING BaseName,
62 PUNICODE_STRING FullName );
63
64 static LONG
65 LdrpCompareModuleNames (
66 IN PUNICODE_STRING String1,
67 IN PUNICODE_STRING String2 );
68
69
70 /* PE Driver load support */
71 static NTSTATUS
72 LdrPEProcessModule (
73 PVOID ModuleLoadBase,
74 PUNICODE_STRING FileName,
75 PLDR_DATA_TABLE_ENTRY *ModuleObject );
76
77 static PVOID
78 LdrPEGetExportByName (
79 PVOID BaseAddress,
80 PUCHAR SymbolName,
81 USHORT Hint );
82
83 static PVOID
84 LdrPEFixupForward ( PCHAR ForwardName );
85
86 static NTSTATUS
87 LdrPEFixupImports ( IN PVOID DllBase, IN PWCHAR DllName);
88
89 /* FUNCTIONS *****************************************************************/
90
91 VOID
92 NTAPI
93 LdrInitDebug ( PLOADER_MODULE Module, PWCH Name )
94 {
95 }
96
97 VOID
98 INIT_FUNCTION
99 NTAPI
100 LdrInit1(VOID)
101 {
102 PLDR_DATA_TABLE_ENTRY HalModuleObject, NtoskrnlModuleObject, LdrEntry;
103
104 /* Initialize the module list and spinlock */
105 InitializeListHead(&PsLoadedModuleList);
106 KeInitializeSpinLock(&ModuleListLock);
107
108 /* Get the NTOSKRNL Entry from the loader */
109 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
110
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;
121
122 /* Insert it into the list */
123 InsertTailList(&PsLoadedModuleList, &NtoskrnlModuleObject->InLoadOrderLinks);
124
125 /* Get the HAL Entry from the loader */
126 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink->Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
127
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;
137
138 /* Insert it into the list */
139 InsertTailList(&PsLoadedModuleList, &HalModuleObject->InLoadOrderLinks);
140 }
141
142 NTSTATUS
143 NTAPI
144 LdrpLoadImage (
145 PUNICODE_STRING DriverName,
146 PVOID *ModuleBase,
147 PVOID *SectionPointer,
148 PVOID *EntryPoint,
149 PVOID *ExportSectionPointer )
150 {
151 PLDR_DATA_TABLE_ENTRY ModuleObject;
152 NTSTATUS Status;
153
154 ModuleObject = LdrGetModuleObject(DriverName);
155 if (ModuleObject == NULL)
156 {
157 Status = LdrLoadModule(DriverName, &ModuleObject);
158 if (!NT_SUCCESS(Status))
159 {
160 return(Status);
161 }
162 }
163
164 if (ModuleBase)
165 *ModuleBase = ModuleObject->DllBase;
166
167 if (SectionPointer)
168 *SectionPointer = ModuleObject;
169
170 if (EntryPoint)
171 *EntryPoint = ModuleObject->EntryPoint;
172
173 //if (ExportSectionPointer)
174 // *ExportSectionPointer = ModuleObject->
175
176 return(STATUS_SUCCESS);
177 }
178
179
180 NTSTATUS
181 NTAPI
182 LdrpUnloadImage ( PVOID ModuleBase )
183 {
184 return(STATUS_NOT_IMPLEMENTED);
185 }
186
187
188 NTSTATUS
189 NTAPI
190 LdrpLoadAndCallImage ( PUNICODE_STRING ModuleName )
191 {
192 PDRIVER_INITIALIZE DriverEntry;
193 PLDR_DATA_TABLE_ENTRY ModuleObject;
194 DRIVER_OBJECT DriverObject;
195 NTSTATUS Status;
196
197 ModuleObject = LdrGetModuleObject(ModuleName);
198 if (ModuleObject != NULL)
199 {
200 return(STATUS_IMAGE_ALREADY_LOADED);
201 }
202
203 Status = LdrLoadModule(ModuleName, &ModuleObject);
204 if (!NT_SUCCESS(Status))
205 {
206 return(Status);
207 }
208
209 DriverEntry = (PDRIVER_INITIALIZE)ModuleObject->EntryPoint;
210
211 RtlZeroMemory(&DriverObject, sizeof(DriverObject));
212 // DriverObject.DriverStart = ModuleObject->DllBase;
213
214 Status = DriverEntry(&DriverObject, NULL);
215 if (!NT_SUCCESS(Status))
216 {
217 LdrUnloadModule(ModuleObject);
218 }
219
220 return(Status);
221 }
222
223
224 NTSTATUS
225 NTAPI
226 LdrLoadModule(
227 PUNICODE_STRING Filename,
228 PLDR_DATA_TABLE_ENTRY *ModuleObject )
229 {
230 PVOID ModuleLoadBase;
231 NTSTATUS Status;
232 HANDLE FileHandle;
233 OBJECT_ATTRIBUTES ObjectAttributes;
234 PLDR_DATA_TABLE_ENTRY Module;
235 FILE_STANDARD_INFORMATION FileStdInfo;
236 IO_STATUS_BLOCK IoStatusBlock;
237
238 *ModuleObject = NULL;
239
240 DPRINT("Loading Module %wZ...\n", Filename);
241
242 /* Open the Module */
243 InitializeObjectAttributes(&ObjectAttributes,
244 Filename,
245 OBJ_CASE_INSENSITIVE,
246 NULL,
247 NULL);
248 CHECKPOINT;
249 Status = ZwOpenFile(&FileHandle,
250 GENERIC_READ,
251 &ObjectAttributes,
252 &IoStatusBlock,
253 FILE_SHARE_READ,
254 FILE_SYNCHRONOUS_IO_NONALERT);
255 CHECKPOINT;
256 if (!NT_SUCCESS(Status))
257 {
258 CPRINT("Could not open module file: %wZ (Status 0x%08lx)\n", Filename, Status);
259 return(Status);
260 }
261 CHECKPOINT;
262
263 /* Get the size of the file */
264 Status = ZwQueryInformationFile(FileHandle,
265 &IoStatusBlock,
266 &FileStdInfo,
267 sizeof(FileStdInfo),
268 FileStandardInformation);
269 if (!NT_SUCCESS(Status))
270 {
271 CPRINT("Could not get file size\n");
272 NtClose(FileHandle);
273 return(Status);
274 }
275 CHECKPOINT;
276
277 /* Allocate nonpageable memory for driver */
278 ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
279 FileStdInfo.EndOfFile.u.LowPart,
280 TAG_DRIVER_MEM);
281 if (ModuleLoadBase == NULL)
282 {
283 CPRINT("Could not allocate memory for module");
284 NtClose(FileHandle);
285 return(STATUS_INSUFFICIENT_RESOURCES);
286 }
287 CHECKPOINT;
288
289 /* Load driver into memory chunk */
290 Status = ZwReadFile(FileHandle,
291 0, 0, 0,
292 &IoStatusBlock,
293 ModuleLoadBase,
294 FileStdInfo.EndOfFile.u.LowPart,
295 0, 0);
296 if (!NT_SUCCESS(Status))
297 {
298 CPRINT("Could not read module file into memory");
299 ExFreePool(ModuleLoadBase);
300 NtClose(FileHandle);
301 return(Status);
302 }
303 CHECKPOINT;
304
305 ZwClose(FileHandle);
306
307 Status = LdrProcessModule(ModuleLoadBase,
308 Filename,
309 &Module);
310 if (!NT_SUCCESS(Status))
311 {
312 CPRINT("Could not process module\n");
313 ExFreePool(ModuleLoadBase);
314 return(Status);
315 }
316
317 /* Cleanup */
318 ExFreePool(ModuleLoadBase);
319
320 *ModuleObject = Module;
321
322 return(STATUS_SUCCESS);
323 }
324
325
326 NTSTATUS
327 NTAPI
328 LdrUnloadModule ( PLDR_DATA_TABLE_ENTRY ModuleObject )
329 {
330 KIRQL Irql;
331
332 /* Remove the module from the module list */
333 KeAcquireSpinLock(&ModuleListLock,&Irql);
334 RemoveEntryList(&ModuleObject->InLoadOrderLinks);
335 KeReleaseSpinLock(&ModuleListLock, Irql);
336
337 /* Free module section */
338 // MmFreeSection(ModuleObject->DllBase);
339
340 ExFreePool(ModuleObject->FullDllName.Buffer);
341 ExFreePool(ModuleObject);
342
343 return(STATUS_SUCCESS);
344 }
345
346
347 NTSTATUS
348 LdrProcessModule(
349 PVOID ModuleLoadBase,
350 PUNICODE_STRING ModuleName,
351 PLDR_DATA_TABLE_ENTRY *ModuleObject )
352 {
353 PIMAGE_DOS_HEADER PEDosHeader;
354
355 /* If MZ header exists */
356 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
357 if (PEDosHeader->e_magic == IMAGE_DOS_SIGNATURE && PEDosHeader->e_lfanew != 0L)
358 {
359 return LdrPEProcessModule(ModuleLoadBase,
360 ModuleName,
361 ModuleObject);
362 }
363
364 CPRINT("Module wasn't PE\n");
365 return STATUS_UNSUCCESSFUL;
366 }
367
368 NTSTATUS
369 NTAPI
370 LdrpQueryModuleInformation (
371 PVOID Buffer,
372 ULONG Size,
373 PULONG ReqSize )
374 {
375 PLIST_ENTRY current_entry;
376 PLDR_DATA_TABLE_ENTRY current;
377 ULONG ModuleCount = 0;
378 PRTL_PROCESS_MODULES Smi;
379 ANSI_STRING AnsiName;
380 PCHAR p;
381 KIRQL Irql;
382 PUNICODE_STRING UnicodeName;
383 ULONG tmpBufferSize = 0;
384 PWCHAR tmpNameBuffer;
385
386 KeAcquireSpinLock(&ModuleListLock,&Irql);
387
388 /* calculate required size */
389 current_entry = PsLoadedModuleList.Flink;
390 while (current_entry != (&PsLoadedModuleList))
391 {
392 ModuleCount++;
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;
396 }
397
398 *ReqSize = sizeof(RTL_PROCESS_MODULES)+
399 (ModuleCount - 1) * sizeof(RTL_PROCESS_MODULE_INFORMATION);
400
401 if (Size < *ReqSize)
402 {
403 KeReleaseSpinLock(&ModuleListLock, Irql);
404 return(STATUS_INFO_LENGTH_MISMATCH);
405 }
406
407 /* allocate a temp buffer to store the module names */
408 UnicodeName = ExAllocatePool(NonPagedPool, tmpBufferSize);
409 if (UnicodeName == NULL)
410 {
411 KeReleaseSpinLock(&ModuleListLock, Irql);
412 return STATUS_INSUFFICIENT_RESOURCES;
413 }
414 tmpNameBuffer = (PWCHAR)((ULONG_PTR)UnicodeName + ModuleCount * sizeof(UNICODE_STRING));
415
416 /* fill the buffer */
417 memset(Buffer, '=', Size);
418
419 Smi = (PRTL_PROCESS_MODULES)Buffer;
420 Smi->NumberOfModules = ModuleCount;
421
422 ModuleCount = 0;
423 current_entry = PsLoadedModuleList.Flink;
424 while (current_entry != (&PsLoadedModuleList))
425 {
426 current = CONTAINING_RECORD(current_entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
427
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], &current->FullDllName);
440
441 ModuleCount++;
442 current_entry = current_entry->Flink;
443 }
444
445 KeReleaseSpinLock(&ModuleListLock, Irql);
446
447 for (ModuleCount = 0; ModuleCount < Smi->NumberOfModules; ModuleCount++)
448 {
449 AnsiName.Length = 0;
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;
455
456 p = strrchr(AnsiName.Buffer, '\\');
457 if (p == NULL)
458 {
459 Smi->Modules[ModuleCount].OffsetToFileName = 0;
460 }
461 else
462 {
463 p++;
464 Smi->Modules[ModuleCount].OffsetToFileName = p - AnsiName.Buffer;
465 }
466 }
467
468 ExFreePool(UnicodeName);
469
470 return(STATUS_SUCCESS);
471 }
472
473
474 static VOID
475 LdrpBuildModuleBaseName (
476 PUNICODE_STRING BaseName,
477 PUNICODE_STRING FullName )
478 {
479 PWCHAR p;
480
481 DPRINT("LdrpBuildModuleBaseName()\n");
482 DPRINT("FullName %wZ\n", FullName);
483
484 p = wcsrchr(FullName->Buffer, L'\\');
485 if (p == NULL)
486 {
487 p = FullName->Buffer;
488 }
489 else
490 {
491 p++;
492 }
493
494 DPRINT("p %S\n", p);
495
496 RtlInitUnicodeString(BaseName, p);
497 }
498
499
500 static LONG
501 LdrpCompareModuleNames (
502 IN PUNICODE_STRING String1,
503 IN PUNICODE_STRING String2 )
504 {
505 ULONG len1, len2, i;
506 PWCHAR s1, s2, p;
507 WCHAR c1, c2;
508
509 if (String1 && String2)
510 {
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++)
515 {
516 if (*p == L'\\')
517 {
518 if (i == String1->Length - sizeof(WCHAR))
519 {
520 s1 = NULL;
521 len1 = 0;
522 }
523 else
524 {
525 s1 = p + 1;
526 len1 = (String1->Length - i) / sizeof(WCHAR);
527 }
528 }
529 }
530
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++)
535 {
536 if (*p == L'\\')
537 {
538 if (i == String2->Length - sizeof(WCHAR))
539 {
540 s2 = NULL;
541 len2 = 0;
542 }
543 else
544 {
545 s2 = p + 1;
546 len2 = (String2->Length - i) / sizeof(WCHAR);
547 }
548 }
549 }
550
551 /* Compare last path components */
552 if (s1 && s2)
553 {
554 while (1)
555 {
556 c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
557 c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
558 if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
559 return(0);
560 if (!c1 || !c2 || c1 != c2)
561 return(c1 - c2);
562 }
563 }
564 }
565
566 return(0);
567 }
568
569 PLDR_DATA_TABLE_ENTRY
570 NTAPI
571 LdrGetModuleObject ( PUNICODE_STRING ModuleName )
572 {
573 PLDR_DATA_TABLE_ENTRY Module;
574 PLIST_ENTRY Entry;
575 KIRQL Irql;
576
577 DPRINT("LdrGetModuleObject(%wZ) called\n", ModuleName);
578
579 KeAcquireSpinLock(&ModuleListLock,&Irql);
580
581 Entry = PsLoadedModuleList.Flink;
582 while (Entry != &PsLoadedModuleList)
583 {
584 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
585
586 DPRINT("Comparing %wZ and %wZ\n",
587 &Module->BaseDllName,
588 ModuleName);
589
590 if (!LdrpCompareModuleNames(&Module->BaseDllName, ModuleName))
591 {
592 DPRINT("Module %wZ\n", &Module->BaseDllName);
593 KeReleaseSpinLock(&ModuleListLock, Irql);
594 return(Module);
595 }
596
597 Entry = Entry->Flink;
598 }
599
600 KeReleaseSpinLock(&ModuleListLock, Irql);
601
602 DPRINT("Could not find module '%wZ'\n", ModuleName);
603
604 return(NULL);
605 }
606
607
608 /* ---------------------------------------------- PE Module support */
609
610 static ULONG
611 LdrLookupPageProtection (
612 PVOID PageStart,
613 PVOID DriverBase,
614 PIMAGE_FILE_HEADER PEFileHeader,
615 PIMAGE_SECTION_HEADER PESectionHeaders )
616 {
617 BOOLEAN Write = FALSE;
618 BOOLEAN Execute = FALSE;
619 ULONG Characteristics;
620 ULONG Idx;
621 ULONG Length;
622 PVOID BaseAddress;
623
624 for (Idx = 0; Idx < PEFileHeader->NumberOfSections && (!Write || !Execute); Idx++)
625 {
626 Characteristics = PESectionHeaders[Idx].Characteristics;
627 if (!(Characteristics & IMAGE_SCN_TYPE_NOLOAD))
628 {
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))
633 {
634 if (Characteristics & IMAGE_SCN_CNT_CODE)
635 {
636 Execute = TRUE;
637 }
638 if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
639 {
640 Write = TRUE;
641 }
642 }
643 }
644 }
645 if (Write && Execute)
646 {
647 return PAGE_EXECUTE_READWRITE;
648 }
649 else if (Execute)
650 {
651 return PAGE_EXECUTE_READ;
652 }
653 else if (Write)
654 {
655 return PAGE_READWRITE;
656 }
657 else
658 {
659 return PAGE_READONLY;
660 }
661 }
662
663 static NTSTATUS
664 LdrPEProcessModule(
665 PVOID ModuleLoadBase,
666 PUNICODE_STRING FileName,
667 PLDR_DATA_TABLE_ENTRY *ModuleObject )
668 {
669 unsigned int DriverSize, Idx;
670 ULONG CurrentSize;
671 PVOID DriverBase;
672 PIMAGE_DOS_HEADER PEDosHeader;
673 PIMAGE_NT_HEADERS PENtHeaders;
674 PIMAGE_SECTION_HEADER PESectionHeaders;
675 PLDR_DATA_TABLE_ENTRY CreatedModuleObject;
676 NTSTATUS Status;
677 KIRQL Irql;
678
679 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
680
681 /* Get header pointers */
682 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
683 PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
684 PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
685 CHECKPOINT;
686
687 /* Check file magic numbers */
688 if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
689 {
690 CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
691 return STATUS_UNSUCCESSFUL;
692 }
693 if (PEDosHeader->e_lfanew == 0)
694 {
695 CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
696 return STATUS_UNSUCCESSFUL;
697 }
698 if (PENtHeaders->Signature != IMAGE_NT_SIGNATURE)
699 {
700 CPRINT("Incorrect PE magic: %08x\n", PENtHeaders->Signature);
701 return STATUS_UNSUCCESSFUL;
702 }
703 if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
704 {
705 CPRINT("Incorrect Architechture: %04x\n", PENtHeaders->FileHeader.Machine);
706 return STATUS_UNSUCCESSFUL;
707 }
708 CHECKPOINT;
709
710 /* FIXME: if image is fixed-address load, then fail */
711
712 /* FIXME: check/verify OS version number */
713
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);
719
720 /* Determine the size of the module */
721 DriverSize = 0;
722 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
723 {
724 if (!(PESectionHeaders[Idx].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
725 {
726 CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
727 DriverSize = max(DriverSize, CurrentSize);
728 }
729 }
730 DriverSize = ROUND_UP(DriverSize, PENtHeaders->OptionalHeader.SectionAlignment);
731 DPRINT("DriverSize %x, SizeOfImage %x\n",DriverSize, PENtHeaders->OptionalHeader.SizeOfImage);
732
733 /* Allocate a virtual section for the module */
734 DriverBase = NULL;
735 DriverBase = MmAllocateSection(DriverSize, DriverBase);
736 if (DriverBase == 0)
737 {
738 CPRINT("Failed to allocate a virtual section for driver\n");
739 return STATUS_UNSUCCESSFUL;
740 }
741 DPRINT("DriverBase for %wZ: %x\n", FileName, DriverBase);
742
743 /* Copy headers over */
744 memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
745
746 /* Copy image sections into virtual section */
747 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
748 {
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)
753 {
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 );
760 }
761 }
762
763 /* Perform relocation fixups */
764 Status = LdrRelocateImageWithBias(DriverBase, 0, "", STATUS_SUCCESS,
765 STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT);
766 if (!NT_SUCCESS(Status))
767 {
768 // MmFreeSection(DriverBase);
769 return Status;
770 }
771
772 /* Create the module */
773 CreatedModuleObject = ExAllocatePoolWithTag (
774 NonPagedPool, sizeof(LDR_DATA_TABLE_ENTRY), TAG_MODULE_OBJECT );
775 if (CreatedModuleObject == NULL)
776 {
777 // MmFreeSection(DriverBase);
778 return STATUS_INSUFFICIENT_RESOURCES;
779 }
780
781 RtlZeroMemory(CreatedModuleObject, sizeof(LDR_DATA_TABLE_ENTRY));
782
783 /* Initialize ModuleObject data */
784 CreatedModuleObject->DllBase = DriverBase;
785
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)
791 {
792 ExFreePool(CreatedModuleObject);
793 // MmFreeSection(DriverBase);
794 return STATUS_INSUFFICIENT_RESOURCES;
795 }
796
797 RtlCopyUnicodeString(&CreatedModuleObject->FullDllName, FileName);
798 CreatedModuleObject->FullDllName.Buffer[FileName->Length / sizeof(WCHAR)] = 0;
799 LdrpBuildModuleBaseName(&CreatedModuleObject->BaseDllName,
800 &CreatedModuleObject->FullDllName);
801
802 CreatedModuleObject->EntryPoint =
803 (PVOID)((ULONG_PTR)DriverBase +
804 PENtHeaders->OptionalHeader.AddressOfEntryPoint);
805 CreatedModuleObject->SizeOfImage = DriverSize;
806 DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
807
808 /* Perform import fixups */
809 Status = LdrPEFixupImports(CreatedModuleObject->DllBase,
810 CreatedModuleObject->FullDllName.Buffer);
811 if (!NT_SUCCESS(Status))
812 {
813 // MmFreeSection(DriverBase);
814 ExFreePool(CreatedModuleObject->FullDllName.Buffer);
815 ExFreePool(CreatedModuleObject);
816 return Status;
817 }
818
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++)
822 {
823 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
824 ULONG Length;
825 PVOID BaseAddress;
826 PVOID PageAddress;
827 ULONG Protect;
828 Length = PESectionHeaders[Idx].Misc.VirtualSize;
829 BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
830 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
831
832 Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
833 if (PageAddress < RVA(DriverBase, DriverSize))
834 {
835 MmSetPageProtect(NULL, PageAddress, Protect);
836 }
837
838 if (Characteristics & IMAGE_SCN_CNT_CODE)
839 {
840 if (Characteristics & IMAGE_SCN_MEM_WRITE)
841 {
842 Protect = PAGE_EXECUTE_READWRITE;
843 }
844 else
845 {
846 Protect = PAGE_EXECUTE_READ;
847 }
848 }
849 else if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
850 {
851 Protect = PAGE_READWRITE;
852 }
853 else
854 {
855 Protect = PAGE_READONLY;
856 }
857 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
858 while ((ULONG_PTR)PageAddress + PAGE_SIZE < (ULONG_PTR)BaseAddress + Length)
859 {
860 if (PageAddress < RVA(DriverBase, DriverSize))
861 {
862 MmSetPageProtect(NULL, PageAddress, Protect);
863 }
864 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
865 }
866 if (PageAddress < (PVOID)((ULONG_PTR)BaseAddress + Length) &&
867 PageAddress < RVA(DriverBase, DriverSize))
868 {
869 Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
870 MmSetPageProtect(NULL, PageAddress, Protect);
871 }
872 }
873
874 /* Insert module */
875 KeAcquireSpinLock(&ModuleListLock, &Irql);
876 InsertTailList(&PsLoadedModuleList,
877 &CreatedModuleObject->InLoadOrderLinks);
878 KeReleaseSpinLock(&ModuleListLock, Irql);
879
880 *ModuleObject = CreatedModuleObject;
881
882 DPRINT("Loading Module %wZ...\n", FileName);
883
884 DPRINT("Module %wZ loaded at 0x%.08x.\n",
885 FileName, CreatedModuleObject->DllBase);
886
887 return STATUS_SUCCESS;
888 }
889
890 static PVOID
891 LdrPEFixupForward ( PCHAR ForwardName )
892 {
893 CHAR NameBuffer[128];
894 UNICODE_STRING ModuleName;
895 PCHAR p;
896 PLDR_DATA_TABLE_ENTRY ModuleObject;
897
898 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
899
900 strcpy(NameBuffer, ForwardName);
901 p = strchr(NameBuffer, '.');
902 if (p == NULL)
903 {
904 return NULL;
905 }
906
907 *p = 0;
908
909 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
910
911 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
912 NameBuffer);
913 ModuleObject = LdrGetModuleObject(&ModuleName);
914 RtlFreeUnicodeString(&ModuleName);
915
916 DPRINT("ModuleObject: %p\n", ModuleObject);
917
918 if (ModuleObject == NULL)
919 {
920 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
921 return NULL;
922 }
923 return LdrPEGetExportByName(ModuleObject->DllBase, (PUCHAR)(p+1), 0xffff);
924 }
925
926 #ifndef PATH_MAX
927 #define PATH_MAX 260
928 #endif
929
930 static NTSTATUS
931 LdrPEGetOrLoadModule (
932 PWCHAR ModuleName,
933 PCHAR ImportedName,
934 PLDR_DATA_TABLE_ENTRY* ImportedModule)
935 {
936 UNICODE_STRING DriverName;
937 UNICODE_STRING NameString;
938 WCHAR NameBuffer[PATH_MAX];
939 NTSTATUS Status = STATUS_SUCCESS;
940
941 RtlCreateUnicodeStringFromAsciiz (&DriverName, ImportedName);
942 DPRINT("Import module: %wZ\n", &DriverName);
943
944 *ImportedModule = LdrGetModuleObject(&DriverName);
945 if (*ImportedModule == NULL)
946 {
947 PWCHAR PathEnd;
948 ULONG PathLength;
949
950 PathEnd = wcsrchr(ModuleName, L'\\');
951 if (NULL != PathEnd)
952 {
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;
958
959 /* NULL-terminate */
960 NameString.MaximumLength += sizeof(WCHAR);
961 NameBuffer[NameString.Length / sizeof(WCHAR)] = 0;
962
963 Status = LdrLoadModule(&NameString, ImportedModule);
964 }
965 else
966 {
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);
972 }
973 if (!NT_SUCCESS(Status))
974 {
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))
980 {
981 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &DriverName, Status);
982 }
983 }
984 }
985 RtlFreeUnicodeString(&DriverName);
986 return Status;
987 }
988
989 static PVOID
990 LdrPEGetExportByName (
991 PVOID BaseAddress,
992 PUCHAR SymbolName,
993 USHORT Hint )
994 {
995 PIMAGE_EXPORT_DIRECTORY ExportDir;
996 PULONG * ExFunctions;
997 PULONG * ExNames;
998 USHORT * ExOrdinals;
999 PVOID ExName;
1000 ULONG Ordinal;
1001 PVOID Function;
1002 LONG minn, maxn, mid, res;
1003 ULONG ExportDirSize;
1004
1005 DPRINT("LdrPEGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
1006
1007 ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(BaseAddress,
1008 TRUE,
1009 IMAGE_DIRECTORY_ENTRY_EXPORT,
1010 &ExportDirSize);
1011 if (ExportDir == NULL)
1012 {
1013 DPRINT1("LdrPEGetExportByName(): no export directory!\n");
1014 return NULL;
1015 }
1016
1017
1018 /* The symbol names may be missing entirely */
1019 if (ExportDir->AddressOfNames == 0)
1020 {
1021 DPRINT("LdrPEGetExportByName(): symbol names missing entirely\n");
1022 return NULL;
1023 }
1024
1025 /*
1026 * Get header pointers
1027 */
1028 ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
1029 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
1030 ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
1031
1032 /*
1033 * Check the hint first
1034 */
1035 if (Hint < ExportDir->NumberOfNames)
1036 {
1037 ExName = RVA(BaseAddress, ExNames[Hint]);
1038 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
1039 {
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)
1044 {
1045 DPRINT("Forward: %s\n", (PCHAR)Function);
1046 Function = LdrPEFixupForward((PCHAR)Function);
1047 if (Function == NULL)
1048 {
1049 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1050 }
1051 return Function;
1052 }
1053 if (Function != NULL)
1054 {
1055 return Function;
1056 }
1057 }
1058 }
1059
1060 /*
1061 * Binary search
1062 */
1063 minn = 0;
1064 maxn = ExportDir->NumberOfNames - 1;
1065 while (minn <= maxn)
1066 {
1067 mid = (minn + maxn) / 2;
1068
1069 ExName = RVA(BaseAddress, ExNames[mid]);
1070 res = strcmp(ExName, (PCHAR)SymbolName);
1071 if (res == 0)
1072 {
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)
1077 {
1078 DPRINT("Forward: %s\n", (PCHAR)Function);
1079 Function = LdrPEFixupForward((PCHAR)Function);
1080 if (Function == NULL)
1081 {
1082 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1083 }
1084 return Function;
1085 }
1086 if (Function != NULL)
1087 {
1088 return Function;
1089 }
1090 }
1091 else if (res > 0)
1092 {
1093 maxn = mid - 1;
1094 }
1095 else
1096 {
1097 minn = mid + 1;
1098 }
1099 }
1100
1101 ExName = RVA(BaseAddress, ExNames[mid]);
1102 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1103 return (PVOID)NULL;
1104 }
1105
1106 static PVOID
1107 LdrPEGetExportByOrdinal (
1108 PVOID BaseAddress,
1109 ULONG Ordinal )
1110 {
1111 PIMAGE_EXPORT_DIRECTORY ExportDir;
1112 ULONG ExportDirSize;
1113 PULONG * ExFunctions;
1114 PVOID Function;
1115
1116 ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData (
1117 BaseAddress,
1118 TRUE,
1119 IMAGE_DIRECTORY_ENTRY_EXPORT,
1120 &ExportDirSize);
1121
1122 ExFunctions = (PULONG *)RVA(BaseAddress,
1123 ExportDir->AddressOfFunctions);
1124 DPRINT("LdrPEGetExportByOrdinal(Ordinal %d) = %x\n",
1125 Ordinal,
1126 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base]));
1127
1128 Function = 0 != ExFunctions[Ordinal - ExportDir->Base]
1129 ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1130 : NULL;
1131
1132 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1133 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize))
1134 {
1135 DPRINT("Forward: %s\n", (PCHAR)Function);
1136 Function = LdrPEFixupForward((PCHAR)Function);
1137 }
1138
1139 return Function;
1140 }
1141
1142 static NTSTATUS
1143 LdrPEProcessImportDirectoryEntry(
1144 PVOID DriverBase,
1145 PLDR_DATA_TABLE_ENTRY ImportedModule,
1146 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory )
1147 {
1148 PVOID* ImportAddressList;
1149 PULONG FunctionNameList;
1150 ULONG Ordinal;
1151
1152 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
1153 {
1154 return STATUS_UNSUCCESSFUL;
1155 }
1156
1157 /* Get the import address list. */
1158 ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
1159
1160 /* Get the list of functions to import. */
1161 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1162 {
1163 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
1164 }
1165 else
1166 {
1167 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
1168 }
1169
1170 /* Walk through function list and fixup addresses. */
1171 while (*FunctionNameList != 0L)
1172 {
1173 if ((*FunctionNameList) & 0x80000000)
1174 {
1175 Ordinal = (*FunctionNameList) & 0x7fffffff;
1176 *ImportAddressList = LdrPEGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1177 if ((*ImportAddressList) == NULL)
1178 {
1179 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1180 return STATUS_UNSUCCESSFUL;
1181 }
1182 }
1183 else
1184 {
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)
1189 {
1190 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1191 return STATUS_UNSUCCESSFUL;
1192 }
1193 }
1194 ImportAddressList++;
1195 FunctionNameList++;
1196 }
1197 return STATUS_SUCCESS;
1198 }
1199
1200 static NTSTATUS
1201 LdrPEFixupImports (IN PVOID DllBase,
1202 IN PWCHAR DllName)
1203 {
1204 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1205 PCHAR ImportedName;
1206 PLDR_DATA_TABLE_ENTRY ImportedModule;
1207 NTSTATUS Status;
1208 ULONG Size;
1209
1210 /* Process each import module */
1211 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1212 RtlImageDirectoryEntryToData(DllBase,
1213 TRUE,
1214 IMAGE_DIRECTORY_ENTRY_IMPORT,
1215 &Size);
1216 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1217 while (ImportModuleDirectory->Name)
1218 {
1219 /* Check to make sure that import lib is kernel */
1220 ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
1221
1222 Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
1223 if (!NT_SUCCESS(Status))
1224 {
1225 return Status;
1226 }
1227
1228 Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
1229 if (!NT_SUCCESS(Status))
1230 {
1231 while (TRUE);
1232 return Status;
1233 }
1234
1235 ImportModuleDirectory++;
1236 }
1237 return STATUS_SUCCESS;
1238 }
1239
1240 /* EOF */