2003-06-01 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /* $Id: loader.c,v 1.131 2003/06/01 14:59:02 chorns Exp $
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 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 * Jason Filby (jasonfilby@yahoo.com)
10 * Casper S. Hornstrup (chorns@users.sourceforge.net)
11 * UPDATE HISTORY:
12 * DW 22/05/98 Created
13 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
14 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
15 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
16 * JM 14/12/98 Built initial PE user module loader
17 * RJJ 06/03/99 Moved user PE loader into NTDLL
18 * JF 26/01/2000 Recoded some parts to retrieve export details correctly
19 * DW 27/06/2000 Removed redundant header files
20 * CSH 11/04/2001 Added automatic loading of module symbols if they exist
21 * KJK 02/04/2003 Nebbet-ized a couple of type names
22 */
23
24
25 /* INCLUDES *****************************************************************/
26
27 #include <limits.h>
28 #include <ddk/ntddk.h>
29 #include <roscfg.h>
30 #include <internal/module.h>
31 #include <internal/ntoskrnl.h>
32 #include <internal/kd.h>
33 #include <internal/io.h>
34 #include <internal/mm.h>
35 #include <internal/ps.h>
36 #include <internal/ldr.h>
37 #include <internal/pool.h>
38 #include <internal/kd.h>
39 #include <ntos/minmax.h>
40
41 #ifdef HALDBG
42 #include <internal/ntosdbg.h>
43 #else
44 #define ps(args...)
45 #endif
46
47 #define NDEBUG
48 #include <internal/debug.h>
49
50 /* GLOBALS *******************************************************************/
51
52 LIST_ENTRY ModuleListHead;
53 KSPIN_LOCK ModuleListLock;
54
55 LIST_ENTRY ModuleTextListHead;
56 STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
57 STATIC MODULE_TEXT_SECTION LdrHalTextSection;
58 ULONG_PTR LdrHalBase;
59
60 #define TAG_DRIVER_MEM TAG('D', 'R', 'V', 'M')
61
62 /* FORWARD DECLARATIONS ******************************************************/
63
64 NTSTATUS
65 LdrProcessModule(PVOID ModuleLoadBase,
66 PUNICODE_STRING ModuleName,
67 PMODULE_OBJECT *ModuleObject);
68
69 PVOID
70 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
71 char *Name,
72 unsigned short Hint);
73
74 static VOID
75 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
76 PUNICODE_STRING FullName);
77
78 static LONG
79 LdrpCompareModuleNames(IN PUNICODE_STRING String1,
80 IN PUNICODE_STRING String2);
81
82
83 /* PE Driver load support */
84 static NTSTATUS LdrPEProcessModule(PVOID ModuleLoadBase,
85 PUNICODE_STRING FileName,
86 PMODULE_OBJECT *ModuleObject);
87 static PVOID
88 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
89 PCHAR Name,
90 USHORT Hint);
91
92 static PVOID
93 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
94 PCHAR Name,
95 USHORT Hint);
96
97 static PVOID
98 LdrPEFixupForward(PCHAR ForwardName);
99
100
101 /* FUNCTIONS *****************************************************************/
102
103 VOID
104 LdrInitDebug(PLOADER_MODULE Module, PWCH Name)
105 {
106 PLIST_ENTRY current_entry;
107 MODULE_TEXT_SECTION* current;
108
109 current_entry = ModuleTextListHead.Flink;
110 while (current_entry != &ModuleTextListHead)
111 {
112 current =
113 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
114 if (wcscmp(current->Name, Name) == 0)
115 {
116 break;
117 }
118 current_entry = current_entry->Flink;
119 }
120
121 if (current_entry == &ModuleTextListHead)
122 {
123 return;
124 }
125 }
126
127 VOID
128 LdrInit1(VOID)
129 {
130 PIMAGE_DOS_HEADER DosHeader;
131 PIMAGE_FILE_HEADER FileHeader;
132 PIMAGE_OPTIONAL_HEADER OptionalHeader;
133 PIMAGE_SECTION_HEADER SectionList;
134
135 InitializeListHead(&ModuleTextListHead);
136
137 /* Setup ntoskrnl.exe text section */
138 DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
139 FileHeader =
140 (PIMAGE_FILE_HEADER) ((DWORD)KERNEL_BASE +
141 DosHeader->e_lfanew + sizeof(ULONG));
142 OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
143 ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
144 SectionList = (PIMAGE_SECTION_HEADER)
145 ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
146 NtoskrnlTextSection.Base = KERNEL_BASE;
147 NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
148 SectionList[0].VirtualAddress;
149 NtoskrnlTextSection.Name = KERNEL_MODULE_NAME;
150 NtoskrnlTextSection.OptionalHeader = OptionalHeader;
151 InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
152
153 /* Setup hal.dll text section */
154 DosHeader = (PIMAGE_DOS_HEADER)LdrHalBase;
155 FileHeader =
156 (PIMAGE_FILE_HEADER) ((DWORD)LdrHalBase +
157 DosHeader->e_lfanew + sizeof(ULONG));
158 OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
159 ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
160 SectionList = (PIMAGE_SECTION_HEADER)
161 ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
162 LdrHalTextSection.Base = LdrHalBase;
163 LdrHalTextSection.Length = SectionList[0].Misc.VirtualSize +
164 SectionList[0].VirtualAddress;
165 LdrHalTextSection.Name = HAL_MODULE_NAME;
166 LdrHalTextSection.OptionalHeader = OptionalHeader;
167 InsertTailList(&ModuleTextListHead, &LdrHalTextSection.ListEntry);
168
169 /* Hook for KDB on initialization of the loader. */
170 KDB_LOADERINIT_HOOK(&NtoskrnlTextSection, &LdrHalTextSection);
171 }
172
173
174 VOID
175 LdrInitModuleManagement(VOID)
176 {
177 PIMAGE_DOS_HEADER DosHeader;
178 PMODULE_OBJECT ModuleObject;
179
180 /* Initialize the module list and spinlock */
181 InitializeListHead(&ModuleListHead);
182 KeInitializeSpinLock(&ModuleListLock);
183
184 /* Create module object for NTOSKRNL */
185 ModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
186 assert(ModuleObject != NULL);
187 RtlZeroMemory(ModuleObject, sizeof(MODULE_OBJECT));
188
189 /* Initialize ModuleObject data */
190 ModuleObject->Base = (PVOID) KERNEL_BASE;
191 ModuleObject->Flags = MODULE_FLAG_PE;
192 RtlCreateUnicodeString(&ModuleObject->FullName,
193 KERNEL_MODULE_NAME);
194 LdrpBuildModuleBaseName(&ModuleObject->BaseName,
195 &ModuleObject->FullName);
196
197 DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
198 ModuleObject->Image.PE.FileHeader =
199 (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
200 DosHeader->e_lfanew + sizeof(ULONG));
201 ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
202 ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
203 ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
204 ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
205 ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
206 ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
207 DPRINT("ModuleObject:%08x entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
208 ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
209 ModuleObject->TextSection = &NtoskrnlTextSection;
210
211 InsertTailList(&ModuleListHead,
212 &ModuleObject->ListEntry);
213
214 /* Create module object for HAL */
215 ModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
216 assert(ModuleObject != NULL);
217 RtlZeroMemory(ModuleObject, sizeof(MODULE_OBJECT));
218
219 /* Initialize ModuleObject data */
220 ModuleObject->Base = (PVOID) LdrHalBase;
221 ModuleObject->Flags = MODULE_FLAG_PE;
222
223 RtlCreateUnicodeString(&ModuleObject->FullName,
224 HAL_MODULE_NAME);
225 LdrpBuildModuleBaseName(&ModuleObject->BaseName,
226 &ModuleObject->FullName);
227
228 DosHeader = (PIMAGE_DOS_HEADER) LdrHalBase;
229 ModuleObject->Image.PE.FileHeader =
230 (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
231 DosHeader->e_lfanew + sizeof(ULONG));
232 ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
233 ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
234 ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
235 ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
236 ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
237 ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
238 DPRINT("ModuleObject:%08x entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
239 ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
240 ModuleObject->TextSection = &LdrHalTextSection;
241
242 InsertTailList(&ModuleListHead,
243 &ModuleObject->ListEntry);
244 }
245
246 NTSTATUS
247 LdrpLoadImage(PUNICODE_STRING DriverName,
248 PVOID *ModuleBase,
249 PVOID *SectionPointer,
250 PVOID *EntryPoint,
251 PVOID *ExportSectionPointer)
252 {
253 PMODULE_OBJECT ModuleObject;
254 NTSTATUS Status;
255
256 ModuleObject = LdrGetModuleObject(DriverName);
257 if (ModuleObject == NULL)
258 {
259 Status = LdrLoadModule(DriverName, &ModuleObject);
260 if (!NT_SUCCESS(Status))
261 {
262 return(Status);
263 }
264 }
265
266 if (ModuleBase)
267 *ModuleBase = ModuleObject->Base;
268
269 // if (SectionPointer)
270 // *SectionPointer = ModuleObject->
271
272 if (EntryPoint)
273 *EntryPoint = ModuleObject->EntryPoint;
274
275 // if (ExportSectionPointer)
276 // *ExportSectionPointer = ModuleObject->
277
278 return(STATUS_SUCCESS);
279 }
280
281
282 NTSTATUS
283 LdrpUnloadImage(PVOID ModuleBase)
284 {
285 return(STATUS_NOT_IMPLEMENTED);
286 }
287
288
289 NTSTATUS
290 LdrpLoadAndCallImage(PUNICODE_STRING ModuleName)
291 {
292 PDRIVER_INITIALIZE DriverEntry;
293 PMODULE_OBJECT ModuleObject;
294 NTSTATUS Status;
295
296 ModuleObject = LdrGetModuleObject(ModuleName);
297 if (ModuleObject != NULL)
298 {
299 return(STATUS_IMAGE_ALREADY_LOADED);
300 }
301
302 Status = LdrLoadModule(ModuleName, &ModuleObject);
303 if (!NT_SUCCESS(Status))
304 {
305 return(Status);
306 }
307
308 DriverEntry = (PDRIVER_INITIALIZE)ModuleObject->EntryPoint;
309
310 Status = DriverEntry(NULL, NULL);
311 if (!NT_SUCCESS(Status))
312 {
313 LdrUnloadModule(ModuleObject);
314 }
315
316 return(Status);
317 }
318
319
320 NTSTATUS
321 LdrLoadModule(PUNICODE_STRING Filename,
322 PMODULE_OBJECT *ModuleObject)
323 {
324 PVOID ModuleLoadBase;
325 NTSTATUS Status;
326 HANDLE FileHandle;
327 OBJECT_ATTRIBUTES ObjectAttributes;
328 PMODULE_OBJECT Module;
329 FILE_STANDARD_INFORMATION FileStdInfo;
330 IO_STATUS_BLOCK IoStatusBlock;
331
332 *ModuleObject = NULL;
333
334 DPRINT("Loading Module %wZ...\n", Filename);
335
336 /* Open the Module */
337 InitializeObjectAttributes(&ObjectAttributes,
338 Filename,
339 0,
340 NULL,
341 NULL);
342 CHECKPOINT;
343 Status = NtOpenFile(&FileHandle,
344 FILE_ALL_ACCESS,
345 &ObjectAttributes,
346 &IoStatusBlock,
347 0,
348 FILE_SYNCHRONOUS_IO_NONALERT);
349 CHECKPOINT;
350 if (!NT_SUCCESS(Status))
351 {
352 CPRINT("Could not open module file: %wZ\n", Filename);
353 return(Status);
354 }
355 CHECKPOINT;
356
357 /* Get the size of the file */
358 Status = NtQueryInformationFile(FileHandle,
359 &IoStatusBlock,
360 &FileStdInfo,
361 sizeof(FileStdInfo),
362 FileStandardInformation);
363 if (!NT_SUCCESS(Status))
364 {
365 CPRINT("Could not get file size\n");
366 NtClose(FileHandle);
367 return(Status);
368 }
369 CHECKPOINT;
370
371 /* Allocate nonpageable memory for driver */
372 ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
373 FileStdInfo.EndOfFile.u.LowPart,
374 TAG_DRIVER_MEM);
375 if (ModuleLoadBase == NULL)
376 {
377 CPRINT("Could not allocate memory for module");
378 NtClose(FileHandle);
379 return(STATUS_INSUFFICIENT_RESOURCES);
380 }
381 CHECKPOINT;
382
383 /* Load driver into memory chunk */
384 Status = NtReadFile(FileHandle,
385 0, 0, 0,
386 &IoStatusBlock,
387 ModuleLoadBase,
388 FileStdInfo.EndOfFile.u.LowPart,
389 0, 0);
390 if (!NT_SUCCESS(Status))
391 {
392 CPRINT("Could not read module file into memory");
393 ExFreePool(ModuleLoadBase);
394 NtClose(FileHandle);
395 return(Status);
396 }
397 CHECKPOINT;
398
399 NtClose(FileHandle);
400
401 Status = LdrProcessModule(ModuleLoadBase,
402 Filename,
403 &Module);
404 if (!NT_SUCCESS(Status))
405 {
406 CPRINT("Could not process module");
407 ExFreePool(ModuleLoadBase);
408 return(Status);
409 }
410
411 /* Cleanup */
412 ExFreePool(ModuleLoadBase);
413
414 *ModuleObject = Module;
415
416 /* Hook for KDB on loading a driver. */
417 KDB_LOADDRIVER_HOOK(Filename, Module);
418
419 return(STATUS_SUCCESS);
420 }
421
422
423 NTSTATUS
424 LdrUnloadModule(PMODULE_OBJECT ModuleObject)
425 {
426 KIRQL Irql;
427
428 /* Remove the module from the module list */
429 KeAcquireSpinLock(&ModuleListLock,&Irql);
430 RemoveEntryList(&ModuleObject->ListEntry);
431 KeReleaseSpinLock(&ModuleListLock, Irql);
432
433 /* Hook for KDB on unloading a driver. */
434 KDB_UNLOADDRIVER_HOOK(ModuleObject);
435
436 /* Free text section */
437 if (ModuleObject->TextSection != NULL)
438 {
439 ExFreePool(ModuleObject->TextSection->Name);
440 RemoveEntryList(&ModuleObject->TextSection->ListEntry);
441 ExFreePool(ModuleObject->TextSection);
442 ModuleObject->TextSection = NULL;
443 }
444
445 /* Free module section */
446 // MmFreeSection(ModuleObject->Base);
447
448 ExFreePool(ModuleObject);
449
450 return(STATUS_SUCCESS);
451 }
452
453
454 NTSTATUS
455 LdrInitializeBootStartDriver(PVOID ModuleLoadBase,
456 PCHAR FileName,
457 ULONG ModuleLength)
458 {
459 PMODULE_OBJECT ModuleObject;
460 UNICODE_STRING ModuleName;
461 PDEVICE_NODE DeviceNode;
462 NTSTATUS Status;
463
464 WCHAR Buffer[MAX_PATH];
465 ULONG Length;
466 LPWSTR Start;
467 LPWSTR Ext;
468 PCHAR FileExt;
469 CHAR TextBuffer [256];
470 ULONG x, y, cx, cy;
471
472 HalQueryDisplayParameters(&x, &y, &cx, &cy);
473 RtlFillMemory(TextBuffer, x, ' ');
474 TextBuffer[x] = '\0';
475 HalSetDisplayParameters(0, y-1);
476 HalDisplayString(TextBuffer);
477
478 sprintf(TextBuffer, "Initializing %s...\n", FileName);
479 HalSetDisplayParameters(0, y-1);
480 HalDisplayString(TextBuffer);
481 HalSetDisplayParameters(cx, cy);
482
483 /* Split the filename into base name and extension */
484 FileExt = strrchr(FileName, '.');
485 if (FileExt != NULL)
486 Length = FileExt - FileName;
487 else
488 Length = strlen(FileName);
489
490 if ((FileExt != NULL) && (strcmp(FileExt, ".sym") == 0))
491 {
492 KDB_SYMBOLFILE_HOOK(ModuleLoadBase, FileName, Length);
493 return(STATUS_SUCCESS);
494 }
495 else if ((FileExt != NULL) && !(strcmp(FileExt, ".sys") == 0))
496 {
497 CPRINT("Ignoring non-driver file %s\n", FileName);
498 return STATUS_SUCCESS;
499 }
500
501 /* Use IopRootDeviceNode for now */
502 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
503 if (!NT_SUCCESS(Status))
504 {
505 CPRINT("Driver load failed, status (%x)\n", Status);
506 return(Status);
507 }
508
509 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
510 FileName);
511 Status = LdrProcessModule(ModuleLoadBase,
512 &ModuleName,
513 &ModuleObject);
514 RtlFreeUnicodeString(&ModuleName);
515 if (ModuleObject == NULL)
516 {
517 IopFreeDeviceNode(DeviceNode);
518 CPRINT("Driver load failed, status (%x)\n", Status);
519 return(STATUS_UNSUCCESSFUL);
520 }
521
522
523 /* Get the service name from the module name */
524 Start = wcsrchr(ModuleObject->BaseName.Buffer, L'\\');
525 if (Start == NULL)
526 Start = ModuleObject->BaseName.Buffer;
527 else
528 Start++;
529
530 Ext = wcsrchr(ModuleObject->BaseName.Buffer, L'.');
531 if (Ext != NULL)
532 Length = Ext - Start;
533 else
534 Length = wcslen(Start);
535
536 wcsncpy(Buffer, Start, Length);
537 Buffer[Length] = 0;
538 RtlCreateUnicodeString(&DeviceNode->ServiceName, Buffer);
539
540 Status = IopInitializeDriver(ModuleObject->EntryPoint,
541 DeviceNode, FALSE);
542 if (!NT_SUCCESS(Status))
543 {
544 IopFreeDeviceNode(DeviceNode);
545 CPRINT("Driver load failed, status (%x)\n", Status);
546 }
547
548 return(Status);
549 }
550
551
552 NTSTATUS
553 LdrProcessModule(PVOID ModuleLoadBase,
554 PUNICODE_STRING ModuleName,
555 PMODULE_OBJECT *ModuleObject)
556 {
557 PIMAGE_DOS_HEADER PEDosHeader;
558
559 /* If MZ header exists */
560 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
561 if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
562 {
563 return LdrPEProcessModule(ModuleLoadBase,
564 ModuleName,
565 ModuleObject);
566 }
567
568 CPRINT("Module wasn't PE\n");
569 return STATUS_UNSUCCESSFUL;
570 }
571
572
573 PVOID
574 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
575 char *Name,
576 unsigned short Hint)
577 {
578 if (ModuleObject->Flags & MODULE_FLAG_PE)
579 {
580 return LdrPEGetExportAddress(ModuleObject, Name, Hint);
581 }
582 else
583 {
584 return 0;
585 }
586 }
587
588
589 NTSTATUS
590 LdrpQueryModuleInformation(PVOID Buffer,
591 ULONG Size,
592 PULONG ReqSize)
593 {
594 PLIST_ENTRY current_entry;
595 PMODULE_OBJECT current;
596 ULONG ModuleCount = 0;
597 PSYSTEM_MODULE_INFORMATION Smi;
598 ANSI_STRING AnsiName;
599 PCHAR p;
600 KIRQL Irql;
601
602 KeAcquireSpinLock(&ModuleListLock,&Irql);
603
604 /* calculate required size */
605 current_entry = ModuleListHead.Flink;
606 while (current_entry != (&ModuleListHead))
607 {
608 ModuleCount++;
609 current_entry = current_entry->Flink;
610 }
611
612 *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
613 (ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION_ENTRY);
614
615 if (Size < *ReqSize)
616 {
617 KeReleaseSpinLock(&ModuleListLock, Irql);
618 return(STATUS_INFO_LENGTH_MISMATCH);
619 }
620
621 /* fill the buffer */
622 memset(Buffer, '=', Size);
623
624 Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
625 Smi->Count = ModuleCount;
626
627 ModuleCount = 0;
628 current_entry = ModuleListHead.Flink;
629 while (current_entry != (&ModuleListHead))
630 {
631 current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
632
633 Smi->Module[ModuleCount].Unknown1 = 0; /* Always 0 */
634 Smi->Module[ModuleCount].Unknown2 = 0; /* Always 0 */
635 Smi->Module[ModuleCount].Base = current->Base;
636 Smi->Module[ModuleCount].Size = current->Length;
637 Smi->Module[ModuleCount].Flags = 0; /* Flags ??? (GN) */
638 Smi->Module[ModuleCount].Index = ModuleCount;
639 Smi->Module[ModuleCount].NameLength = 0;
640 Smi->Module[ModuleCount].LoadCount = 0; /* FIXME */
641
642 AnsiName.Length = 0;
643 AnsiName.MaximumLength = 256;
644 AnsiName.Buffer = Smi->Module[ModuleCount].ImageName;
645 RtlUnicodeStringToAnsiString(&AnsiName,
646 &current->FullName,
647 FALSE);
648
649 p = strrchr(AnsiName.Buffer, '\\');
650 if (p == NULL)
651 {
652 Smi->Module[ModuleCount].PathLength = 0;
653 }
654 else
655 {
656 p++;
657 Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
658 }
659
660 ModuleCount++;
661 current_entry = current_entry->Flink;
662 }
663
664 KeReleaseSpinLock(&ModuleListLock, Irql);
665
666 return(STATUS_SUCCESS);
667 }
668
669
670 static VOID
671 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
672 PUNICODE_STRING FullName)
673 {
674 UNICODE_STRING Name;
675 PWCHAR p;
676 PWCHAR q;
677
678 DPRINT("LdrpBuildModuleBaseName()\n");
679 DPRINT("FullName %wZ\n", FullName);
680
681 p = wcsrchr(FullName->Buffer, L'\\');
682 if (p == NULL)
683 {
684 p = FullName->Buffer;
685 }
686 else
687 {
688 p++;
689 }
690
691 DPRINT("p %S\n", p);
692
693 RtlCreateUnicodeString(&Name, p);
694
695 q = wcschr(Name.Buffer, L'.');
696 if (q != NULL)
697 {
698 *q = (WCHAR)0;
699 }
700
701 DPRINT("p %S\n", p);
702
703 RtlCreateUnicodeString(BaseName, Name.Buffer);
704 RtlFreeUnicodeString(&Name);
705 }
706
707
708 static LONG
709 LdrpCompareModuleNames(IN PUNICODE_STRING String1,
710 IN PUNICODE_STRING String2)
711 {
712 ULONG len1, len2, i;
713 PWCHAR s1, s2, p;
714 WCHAR c1, c2;
715
716 if (String1 && String2)
717 {
718 /* Search String1 for last path component */
719 len1 = String1->Length / sizeof(WCHAR);
720 s1 = String1->Buffer;
721 for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
722 {
723 if (*p == L'\\')
724 {
725 if (i == String1->Length - sizeof(WCHAR))
726 {
727 s1 = NULL;
728 len1 = 0;
729 }
730 else
731 {
732 s1 = p + 1;
733 len1 = (String1->Length - i) / sizeof(WCHAR);
734 }
735 }
736 }
737
738 /* Search String2 for last path component */
739 len2 = String2->Length / sizeof(WCHAR);
740 s2 = String2->Buffer;
741 for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
742 {
743 if (*p == L'\\')
744 {
745 if (i == String2->Length - sizeof(WCHAR))
746 {
747 s2 = NULL;
748 len2 = 0;
749 }
750 else
751 {
752 s2 = p + 1;
753 len2 = (String2->Length - i) / sizeof(WCHAR);
754 }
755 }
756 }
757
758 /* Compare last path components */
759 if (s1 && s2)
760 {
761 while (1)
762 {
763 c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
764 c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
765 if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
766 return(0);
767 if (!c1 || !c2 || c1 != c2)
768 return(c1 - c2);
769 }
770 }
771 }
772
773 return(0);
774 }
775
776
777 PMODULE_OBJECT
778 LdrGetModuleObject(PUNICODE_STRING ModuleName)
779 {
780 PMODULE_OBJECT Module;
781 PLIST_ENTRY Entry;
782 KIRQL Irql;
783
784 DPRINT("LdrpGetModuleObject(%wZ) called\n", ModuleName);
785
786 KeAcquireSpinLock(&ModuleListLock,&Irql);
787
788 Entry = ModuleListHead.Flink;
789 while (Entry != &ModuleListHead)
790 {
791 Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
792
793 DPRINT("Comparing %wZ and %wZ\n",
794 &Module->BaseName,
795 ModuleName);
796
797 if (!LdrpCompareModuleNames(&Module->BaseName, ModuleName))
798 {
799 DPRINT("Module %wZ\n", &Module->BaseName);
800 KeReleaseSpinLock(&ModuleListLock, Irql);
801 return(Module);
802 }
803
804 Entry = Entry->Flink;
805 }
806
807 KeReleaseSpinLock(&ModuleListLock, Irql);
808
809 DPRINT("Could not find module '%wZ'\n", ModuleName);
810
811 return(NULL);
812 }
813
814
815 /* ---------------------------------------------- PE Module support */
816
817 static BOOL
818 PageNeedsWriteAccess(PVOID PageStart,
819 PVOID DriverBase,
820 PIMAGE_FILE_HEADER PEFileHeader,
821 PIMAGE_SECTION_HEADER PESectionHeaders)
822 {
823 BOOL NeedsWriteAccess;
824 unsigned Idx;
825 ULONG Characteristics;
826 ULONG Length;
827 PVOID BaseAddress;
828
829 NeedsWriteAccess = FALSE;
830 /* Set the protections for the various parts of the driver */
831 for (Idx = 0; Idx < PEFileHeader->NumberOfSections && ! NeedsWriteAccess; Idx++)
832 {
833 Characteristics = PESectionHeaders[Idx].Characteristics;
834 if (!(Characteristics & IMAGE_SECTION_CHAR_CODE) ||
835 (Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
836 Characteristics & IMAGE_SECTION_CHAR_DATA ||
837 Characteristics & IMAGE_SECTION_CHAR_BSS))
838 {
839 Length =
840 max(PESectionHeaders[Idx].Misc.VirtualSize,
841 PESectionHeaders[Idx].SizeOfRawData);
842 BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
843 NeedsWriteAccess = BaseAddress < PageStart + PAGE_SIZE &&
844 PageStart < (PVOID)((PCHAR) BaseAddress + Length);
845 }
846 }
847
848 return(NeedsWriteAccess);
849 }
850
851 static NTSTATUS
852 LdrPEProcessModule(PVOID ModuleLoadBase,
853 PUNICODE_STRING FileName,
854 PMODULE_OBJECT *ModuleObject)
855 {
856 unsigned int DriverSize, Idx;
857 ULONG RelocDelta, NumRelocs;
858 DWORD CurrentSize, TotalRelocs;
859 PVOID DriverBase;
860 PULONG PEMagic;
861 PIMAGE_DOS_HEADER PEDosHeader;
862 PIMAGE_FILE_HEADER PEFileHeader;
863 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
864 PIMAGE_SECTION_HEADER PESectionHeaders;
865 PRELOCATION_DIRECTORY RelocDir;
866 PRELOCATION_ENTRY RelocEntry;
867 PMODULE_OBJECT LibraryModuleObject;
868 PMODULE_OBJECT CreatedModuleObject;
869 PVOID *ImportAddressList;
870 PULONG FunctionNameList;
871 PCHAR pName;
872 WORD Hint;
873 UNICODE_STRING ModuleName;
874 UNICODE_STRING NameString;
875 WCHAR NameBuffer[60];
876 MODULE_TEXT_SECTION* ModuleTextSection;
877 NTSTATUS Status;
878 KIRQL Irql;
879
880 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
881
882 /* Get header pointers */
883 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
884 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
885 PEDosHeader->e_lfanew);
886 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
887 PEDosHeader->e_lfanew + sizeof(ULONG));
888 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
889 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
890 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
891 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
892 sizeof(IMAGE_OPTIONAL_HEADER));
893 CHECKPOINT;
894
895 /* Check file magic numbers */
896 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
897 {
898 CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
899 return STATUS_UNSUCCESSFUL;
900 }
901 if (PEDosHeader->e_lfanew == 0)
902 {
903 CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
904 return STATUS_UNSUCCESSFUL;
905 }
906 if (*PEMagic != IMAGE_PE_MAGIC)
907 {
908 CPRINT("Incorrect PE magic: %08x\n", *PEMagic);
909 return STATUS_UNSUCCESSFUL;
910 }
911 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
912 {
913 CPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
914 return STATUS_UNSUCCESSFUL;
915 }
916 CHECKPOINT;
917
918 /* FIXME: if image is fixed-address load, then fail */
919
920 /* FIXME: check/verify OS version number */
921
922 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
923 PEOptionalHeader->Magic,
924 PEOptionalHeader->MajorLinkerVersion,
925 PEOptionalHeader->MinorLinkerVersion);
926 DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
927 CHECKPOINT;
928
929 /* Determine the size of the module */
930 DriverSize = PEOptionalHeader->SizeOfImage;
931 DPRINT("DriverSize %x\n",DriverSize);
932
933 /* Allocate a virtual section for the module */
934 DriverBase = MmAllocateSection(DriverSize);
935 if (DriverBase == 0)
936 {
937 CPRINT("Failed to allocate a virtual section for driver\n");
938 return STATUS_UNSUCCESSFUL;
939 }
940 DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase);
941 CHECKPOINT;
942 /* Copy headers over */
943 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
944 CurrentSize = 0;
945 /* Copy image sections into virtual section */
946 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
947 {
948 // Copy current section into current offset of virtual section
949 if (PESectionHeaders[Idx].Characteristics &
950 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
951 {
952 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
953 PESectionHeaders[Idx].VirtualAddress + DriverBase);
954 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
955 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
956 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
957 ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
958 }
959 else
960 {
961 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
962 PESectionHeaders[Idx].VirtualAddress + DriverBase);
963 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
964 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
965
966 }
967 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
968 PEOptionalHeader->SectionAlignment);
969
970
971 // CurrentBase = (PVOID)((DWORD)CurrentBase +
972 // ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
973 // PEOptionalHeader->SectionAlignment));
974 }
975
976 /* Perform relocation fixups */
977 RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
978 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
979 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
980 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
981 DriverBase,
982 PEOptionalHeader->ImageBase,
983 RelocDelta);
984 DPRINT("RelocDir %x\n",RelocDir);
985 #if 1
986 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
987 {
988 if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
989 {
990 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
991 PESectionHeaders[Idx].Name,
992 PESectionHeaders[Idx].PointerToRawData);
993 RelocDir = PESectionHeaders[Idx].PointerToRawData +
994 ModuleLoadBase;
995 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
996 break;
997 }
998 }
999 #else
1000 RelocDir = RelocDir + (ULONG)DriverBase;
1001 CurrentSize = PEOptionalHeader->DataDirectory
1002 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1003 #endif
1004 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1005 TotalRelocs = 0;
1006 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1007 {
1008 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
1009 sizeof(WORD);
1010 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
1011 RelocDir,
1012 RelocDir->VirtualAddress,
1013 NumRelocs);*/
1014 RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir +
1015 sizeof(RELOCATION_DIRECTORY));
1016 for (Idx = 0; Idx < NumRelocs; Idx++)
1017 {
1018 ULONG Offset;
1019 ULONG Type;
1020 PDWORD RelocItem;
1021
1022 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1023 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1024 RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress +
1025 Offset);
1026 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
1027 RelocItem,
1028 Type,
1029 Type ? "HIGHLOW" : "ABS",
1030 *RelocItem,
1031 (*RelocItem) + RelocDelta); */
1032 if (Type == 3)
1033 {
1034 (*RelocItem) += RelocDelta;
1035 }
1036 else if (Type != 0)
1037 {
1038 CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1039 return STATUS_UNSUCCESSFUL;
1040 }
1041 }
1042 TotalRelocs += RelocDir->SizeOfBlock;
1043 RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir +
1044 RelocDir->SizeOfBlock);
1045 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
1046 }
1047
1048 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1049 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1050 .VirtualAddress);
1051 /* Perform import fixups */
1052 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1053 {
1054 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1055
1056 /* Process each import module */
1057 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1058 ((DWORD)DriverBase + PEOptionalHeader->
1059 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1060 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1061 while (ImportModuleDirectory->dwRVAModuleName)
1062 {
1063 /* Check to make sure that import lib is kernel */
1064 pName = (PCHAR) DriverBase +
1065 ImportModuleDirectory->dwRVAModuleName;
1066
1067 RtlCreateUnicodeStringFromAsciiz(&ModuleName, pName);
1068 DPRINT("Import module: %wZ\n", &ModuleName);
1069
1070 LibraryModuleObject = LdrGetModuleObject(&ModuleName);
1071 if (LibraryModuleObject == NULL)
1072 {
1073 DPRINT("Module '%wZ' not loaded yet\n", &ModuleName);
1074 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
1075 wcscat(NameBuffer, ModuleName.Buffer);
1076 RtlInitUnicodeString(&NameString, NameBuffer);
1077 Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1078 if (!NT_SUCCESS(Status))
1079 {
1080 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
1081 wcscat(NameBuffer, ModuleName.Buffer);
1082 RtlInitUnicodeString(&NameString, NameBuffer);
1083 Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1084 if (!NT_SUCCESS(Status))
1085 {
1086 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &ModuleName, Status);
1087 return(Status);
1088 }
1089 }
1090 }
1091 /* Get the import address list */
1092 ImportAddressList = (PVOID *) ((DWORD)DriverBase +
1093 ImportModuleDirectory->dwRVAFunctionAddressList);
1094
1095 /* Get the list of functions to import */
1096 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1097 {
1098 FunctionNameList = (PULONG) ((DWORD)DriverBase +
1099 ImportModuleDirectory->dwRVAFunctionNameList);
1100 }
1101 else
1102 {
1103 FunctionNameList = (PULONG) ((DWORD)DriverBase +
1104 ImportModuleDirectory->dwRVAFunctionAddressList);
1105 }
1106 /* Walk through function list and fixup addresses */
1107 while (*FunctionNameList != 0L)
1108 {
1109 if ((*FunctionNameList) & 0x80000000) // hint
1110 {
1111 pName = NULL;
1112
1113
1114 Hint = (*FunctionNameList) & 0xffff;
1115 }
1116 else // hint-name
1117 {
1118 pName = (PCHAR)((DWORD)DriverBase +
1119 *FunctionNameList + 2);
1120 Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
1121 }
1122 DPRINT(" Hint:%04x Name:%s\n", Hint, pName);
1123
1124 /* Fixup the current import symbol */
1125 if (LibraryModuleObject != NULL)
1126 {
1127 *ImportAddressList = LdrGetExportAddress(LibraryModuleObject,
1128 pName,
1129 Hint);
1130 }
1131 else
1132 {
1133 CPRINT("Unresolved kernel symbol: %s\n", pName);
1134 return STATUS_UNSUCCESSFUL;
1135 }
1136 ImportAddressList++;
1137 FunctionNameList++;
1138 }
1139
1140 RtlFreeUnicodeString(&ModuleName);
1141
1142 ImportModuleDirectory++;
1143 }
1144 }
1145
1146 /* Set the protections for the various parts of the driver */
1147 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1148 {
1149 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1150 ULONG Length;
1151 PVOID BaseAddress;
1152 PVOID PageAddress;
1153 if (Characteristics & IMAGE_SECTION_CHAR_CODE &&
1154 !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
1155 Characteristics & IMAGE_SECTION_CHAR_DATA ||
1156 Characteristics & IMAGE_SECTION_CHAR_BSS))
1157 {
1158 Length =
1159 max(PESectionHeaders[Idx].Misc.VirtualSize,
1160 PESectionHeaders[Idx].SizeOfRawData);
1161 BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
1162 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1163 if (! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1164 {
1165 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1166 }
1167 PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1168 while ((PVOID)((PCHAR) PageAddress + PAGE_SIZE) <
1169 (PVOID)((PCHAR) BaseAddress + Length))
1170 {
1171 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1172 PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1173 }
1174 if (PageAddress < (PVOID)((PCHAR) BaseAddress + Length) &&
1175 ! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1176 {
1177 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1178 }
1179 }
1180 }
1181
1182 /* Create the module */
1183 CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
1184 if (CreatedModuleObject == NULL)
1185 {
1186 return(STATUS_INSUFFICIENT_RESOURCES);
1187 }
1188
1189 RtlZeroMemory(CreatedModuleObject, sizeof(MODULE_OBJECT));
1190
1191 /* Initialize ModuleObject data */
1192 CreatedModuleObject->Base = DriverBase;
1193 CreatedModuleObject->Flags = MODULE_FLAG_PE;
1194
1195 RtlCreateUnicodeString(&CreatedModuleObject->FullName,
1196 FileName->Buffer);
1197 LdrpBuildModuleBaseName(&CreatedModuleObject->BaseName,
1198 &CreatedModuleObject->FullName);
1199
1200 CreatedModuleObject->EntryPoint =
1201 (PVOID)((DWORD)DriverBase +
1202 PEOptionalHeader->AddressOfEntryPoint);
1203 CreatedModuleObject->Length = DriverSize;
1204 DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
1205
1206 CreatedModuleObject->Image.PE.FileHeader =
1207 (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
1208
1209 DPRINT("FileHeader at %x\n", CreatedModuleObject->Image.PE.FileHeader);
1210 CreatedModuleObject->Image.PE.OptionalHeader =
1211 (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1212 sizeof(IMAGE_FILE_HEADER));
1213 DPRINT("OptionalHeader at %x\n", CreatedModuleObject->Image.PE.OptionalHeader);
1214 CreatedModuleObject->Image.PE.SectionList =
1215 (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1216 sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
1217 DPRINT("SectionList at %x\n", CreatedModuleObject->Image.PE.SectionList);
1218
1219 /* Insert module */
1220 KeAcquireSpinLock(&ModuleListLock, &Irql);
1221 InsertTailList(&ModuleListHead,
1222 &CreatedModuleObject->ListEntry);
1223 KeReleaseSpinLock(&ModuleListLock, Irql);
1224
1225
1226 ModuleTextSection = ExAllocatePool(NonPagedPool,
1227 sizeof(MODULE_TEXT_SECTION));
1228 assert(ModuleTextSection);
1229 RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
1230 ModuleTextSection->Base = (ULONG)DriverBase;
1231 ModuleTextSection->Length = DriverSize;
1232 ModuleTextSection->Name = ExAllocatePool(NonPagedPool,
1233 (wcslen(CreatedModuleObject->BaseName.Buffer) + 1) * sizeof(WCHAR));
1234 wcscpy(ModuleTextSection->Name, CreatedModuleObject->BaseName.Buffer);
1235 ModuleTextSection->OptionalHeader =
1236 CreatedModuleObject->Image.PE.OptionalHeader;
1237 InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
1238
1239 CreatedModuleObject->TextSection = ModuleTextSection;
1240
1241 *ModuleObject = CreatedModuleObject;
1242
1243 DPRINT("Loading Module %wZ...\n", FileName);
1244
1245 if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
1246 {
1247 DPRINT("Module %wZ loaded at 0x%.08x.\n",
1248 FileName, CreatedModuleObject->Base);
1249 }
1250
1251 return STATUS_SUCCESS;
1252 }
1253
1254
1255 PVOID
1256 LdrSafePEProcessModule(PVOID ModuleLoadBase,
1257 PVOID DriverBase,
1258 PVOID ImportModuleBase,
1259 PULONG DriverSize)
1260 {
1261 unsigned int Idx;
1262 ULONG RelocDelta, NumRelocs;
1263 ULONG CurrentSize, TotalRelocs;
1264 PULONG PEMagic;
1265 PIMAGE_DOS_HEADER PEDosHeader;
1266 PIMAGE_FILE_HEADER PEFileHeader;
1267 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
1268 PIMAGE_SECTION_HEADER PESectionHeaders;
1269 PRELOCATION_DIRECTORY RelocDir;
1270 PRELOCATION_ENTRY RelocEntry;
1271 PVOID *ImportAddressList;
1272 PULONG FunctionNameList;
1273 PCHAR pName;
1274 USHORT Hint;
1275
1276 ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
1277
1278 /* Get header pointers */
1279 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
1280 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
1281 PEDosHeader->e_lfanew);
1282 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
1283 PEDosHeader->e_lfanew + sizeof(ULONG));
1284 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
1285 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
1286 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
1287 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
1288 sizeof(IMAGE_OPTIONAL_HEADER));
1289 CHECKPOINT;
1290
1291 /* Check file magic numbers */
1292 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
1293 {
1294 return 0;
1295 }
1296 if (PEDosHeader->e_lfanew == 0)
1297 {
1298 return 0;
1299 }
1300 if (*PEMagic != IMAGE_PE_MAGIC)
1301 {
1302 return 0;
1303 }
1304 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
1305 {
1306 return 0;
1307 }
1308
1309 ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
1310 PEOptionalHeader->Magic,
1311 PEOptionalHeader->MajorLinkerVersion,
1312 PEOptionalHeader->MinorLinkerVersion);
1313 ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
1314
1315 /* Determine the size of the module */
1316 *DriverSize = PEOptionalHeader->SizeOfImage;
1317 ps("DriverSize %x\n",*DriverSize);
1318
1319 /* Copy headers over */
1320 if (DriverBase != ModuleLoadBase)
1321 {
1322 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
1323 }
1324
1325 ps("Hdr: 0x%X\n", (ULONG)PEOptionalHeader);
1326 ps("Hdr->SizeOfHeaders: 0x%X\n", (ULONG)PEOptionalHeader->SizeOfHeaders);
1327 ps("FileHdr->NumberOfSections: 0x%X\n", (ULONG)PEFileHeader->NumberOfSections);
1328
1329 /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
1330 address as it is mapped */
1331 if (DriverBase != ModuleLoadBase)
1332 {
1333 CurrentSize = 0;
1334
1335 /* Copy image sections into virtual section */
1336 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1337 {
1338 // Copy current section into current offset of virtual section
1339 if (PESectionHeaders[Idx].Characteristics &
1340 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
1341 {
1342 //ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1343 //PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1344 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1345 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
1346 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ?
1347 PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
1348 }
1349 else
1350 {
1351 ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1352 PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1353 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1354 '\0',
1355 PESectionHeaders[Idx].Misc.VirtualSize);
1356 }
1357 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
1358 PEOptionalHeader->SectionAlignment);
1359 }
1360
1361 /* Perform relocation fixups */
1362 RelocDelta = (ULONG) DriverBase - PEOptionalHeader->ImageBase;
1363 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
1364 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
1365 ps("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
1366 DriverBase,
1367 PEOptionalHeader->ImageBase,
1368 RelocDelta);
1369 ps("RelocDir %x\n",RelocDir);
1370
1371 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1372 {
1373 if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
1374 {
1375 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1376 PESectionHeaders[Idx].Name,
1377 PESectionHeaders[Idx].PointerToRawData);
1378 RelocDir = PESectionHeaders[Idx].PointerToRawData + ModuleLoadBase;
1379 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1380 break;
1381 }
1382 }
1383
1384 ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1385
1386 TotalRelocs = 0;
1387 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1388 {
1389 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
1390 sizeof(USHORT);
1391 RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir +
1392 sizeof(RELOCATION_DIRECTORY));
1393 for (Idx = 0; Idx < NumRelocs; Idx++)
1394 {
1395 ULONG Offset;
1396 ULONG Type;
1397 PULONG RelocItem;
1398
1399 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1400 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1401 RelocItem = (PULONG)(DriverBase + RelocDir->VirtualAddress + Offset);
1402 if (Type == 3)
1403 {
1404 (*RelocItem) += RelocDelta;
1405 }
1406 else if (Type != 0)
1407 {
1408 CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1409 return(0);
1410 }
1411 }
1412 TotalRelocs += RelocDir->SizeOfBlock;
1413 RelocDir = (PRELOCATION_DIRECTORY)((ULONG)RelocDir +
1414 RelocDir->SizeOfBlock);
1415 }
1416
1417 ps("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1418 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1419 .VirtualAddress);
1420 }
1421
1422 /* Perform import fixups */
1423 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1424 {
1425 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1426
1427 /* Process each import module */
1428 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1429 ((ULONG)DriverBase + PEOptionalHeader->
1430 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1431
1432 ps("Processeing import directory at %p\n", ImportModuleDirectory);
1433
1434 /* Check to make sure that import lib is kernel */
1435 pName = (PCHAR)DriverBase + ImportModuleDirectory->dwRVAModuleName;
1436
1437 ps("Import module: %s\n", pName);
1438
1439 /* Get the import address list */
1440 ImportAddressList = (PVOID *)((ULONG)DriverBase +
1441 ImportModuleDirectory->dwRVAFunctionAddressList);
1442
1443 ps(" ImportModuleDirectory->dwRVAFunctionAddressList: 0x%X\n",
1444 ImportModuleDirectory->dwRVAFunctionAddressList);
1445 ps(" ImportAddressList: 0x%X\n", ImportAddressList);
1446
1447 /* Get the list of functions to import */
1448 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1449 {
1450 ps("Using function name list.\n");
1451
1452 FunctionNameList = (PULONG)((ULONG)DriverBase +
1453 ImportModuleDirectory->dwRVAFunctionNameList);
1454 }
1455 else
1456 {
1457 ps("Using function address list.\n");
1458
1459 FunctionNameList = (PULONG)((ULONG)DriverBase +
1460 ImportModuleDirectory->dwRVAFunctionAddressList);
1461 }
1462
1463 /* Walk through function list and fixup addresses */
1464 while (*FunctionNameList != 0L)
1465 {
1466 if ((*FunctionNameList) & 0x80000000)
1467 {
1468 /* Hint */
1469 pName = NULL;
1470 Hint = (*FunctionNameList) & 0xffff;
1471 }
1472 else
1473 {
1474 /* Hint name */
1475 pName = (PCHAR)((ULONG)DriverBase + *FunctionNameList + 2);
1476 Hint = *(PWORD)((ULONG)DriverBase + *FunctionNameList);
1477 }
1478 //ps(" Hint:%04x Name:%s(0x%X)(%x)\n", Hint, pName, pName, ImportAddressList);
1479
1480 *ImportAddressList = LdrSafePEGetExportAddress(ImportModuleBase,
1481 pName,
1482 Hint);
1483
1484 ImportAddressList++;
1485 FunctionNameList++;
1486 }
1487 }
1488
1489 ps("Finished importing.\n");
1490
1491 return(0);
1492 }
1493
1494
1495 static PVOID
1496 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
1497 PCHAR Name,
1498 USHORT Hint)
1499 {
1500 PIMAGE_EXPORT_DIRECTORY ExportDir;
1501 ULONG ExportDirSize;
1502 USHORT Idx;
1503 PVOID ExportAddress;
1504 PWORD OrdinalList;
1505 PDWORD FunctionList, NameList;
1506
1507 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1508 RtlImageDirectoryEntryToData(ModuleObject->Base,
1509 TRUE,
1510 IMAGE_DIRECTORY_ENTRY_EXPORT,
1511 &ExportDirSize);
1512 DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
1513 if (ExportDir == NULL)
1514 {
1515 return NULL;
1516 }
1517
1518 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
1519 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
1520 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
1521
1522 ExportAddress = 0;
1523
1524 if (Name != NULL)
1525 {
1526 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1527 {
1528 #if 0
1529 DPRINT(" Name:%s NameList[%d]:%s\n",
1530 Name,
1531 Idx,
1532 (DWORD) ModuleObject->Base + NameList[Idx]);
1533
1534 #endif
1535 if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
1536 {
1537 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1538 FunctionList[OrdinalList[Idx]]);
1539 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
1540 ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
1541 {
1542 DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
1543 ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
1544 DPRINT("ExportAddress: %p\n", ExportAddress);
1545 }
1546
1547 break;
1548 }
1549 }
1550 }
1551 else /* use hint */
1552 {
1553 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1554 FunctionList[Hint - ExportDir->Base]);
1555 }
1556
1557 if (ExportAddress == NULL)
1558 {
1559 CPRINT("Export not found for %d:%s\n",
1560 Hint,
1561 Name != NULL ? Name : "(Ordinal)");
1562 KeBugCheck(0);
1563 }
1564
1565 return(ExportAddress);
1566 }
1567
1568
1569 static PVOID
1570 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
1571 PCHAR Name,
1572 USHORT Hint)
1573 {
1574 USHORT Idx;
1575 PVOID ExportAddress;
1576 PWORD OrdinalList;
1577 PDWORD FunctionList, NameList;
1578 PIMAGE_EXPORT_DIRECTORY ExportDir;
1579 ULONG ExportDirSize;
1580
1581 static BOOLEAN EP = FALSE;
1582
1583 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1584 RtlImageDirectoryEntryToData(ImportModuleBase,
1585 TRUE,
1586 IMAGE_DIRECTORY_ENTRY_EXPORT,
1587 &ExportDirSize);
1588
1589 if (!EP) {
1590 EP = TRUE;
1591 ps("ExportDir %x\n", ExportDir);
1592 }
1593
1594 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ImportModuleBase);
1595 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
1596 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ImportModuleBase);
1597
1598 ExportAddress = 0;
1599
1600 if (Name != NULL)
1601 {
1602 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1603 {
1604 if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
1605 {
1606 ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1607 FunctionList[OrdinalList[Idx]]);
1608 break;
1609 }
1610 }
1611 }
1612 else /* use hint */
1613 {
1614 ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1615
1616 FunctionList[Hint - ExportDir->Base]);
1617 }
1618
1619 if (ExportAddress == 0)
1620 {
1621 ps("Export not found for %d:%s\n",
1622 Hint,
1623 Name != NULL ? Name : "(Ordinal)");
1624 KeBugCheck(0);
1625 }
1626 return ExportAddress;
1627 }
1628
1629
1630 static PVOID
1631 LdrPEFixupForward(PCHAR ForwardName)
1632 {
1633 CHAR NameBuffer[128];
1634 UNICODE_STRING ModuleName;
1635 PCHAR p;
1636 PMODULE_OBJECT ModuleObject;
1637
1638 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1639
1640 strcpy(NameBuffer, ForwardName);
1641 p = strchr(NameBuffer, '.');
1642 if (p == NULL)
1643 {
1644 return NULL;
1645 }
1646
1647 *p = 0;
1648
1649 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
1650
1651 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1652 NameBuffer);
1653 ModuleObject = LdrGetModuleObject(&ModuleName);
1654 RtlFreeUnicodeString(&ModuleName);
1655
1656 DPRINT("ModuleObject: %p\n", ModuleObject);
1657
1658 if (ModuleObject == NULL)
1659 {
1660 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1661 return NULL;
1662 }
1663
1664 return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
1665 }
1666
1667 /* EOF */