4722e5e4cb9d112a6f817debaa588b68d7c21eb0
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /* $Id: loader.c,v 1.135 2003/09/29 20:43:07 navaraf 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 ModuleObject->Base,
543 ModuleObject->Length,
544 TRUE);
545 if (!NT_SUCCESS(Status))
546 {
547 IopFreeDeviceNode(DeviceNode);
548 CPRINT("Driver load failed, status (%x)\n", Status);
549 }
550
551 return(Status);
552 }
553
554
555 NTSTATUS
556 LdrProcessModule(PVOID ModuleLoadBase,
557 PUNICODE_STRING ModuleName,
558 PMODULE_OBJECT *ModuleObject)
559 {
560 PIMAGE_DOS_HEADER PEDosHeader;
561
562 /* If MZ header exists */
563 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
564 if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
565 {
566 return LdrPEProcessModule(ModuleLoadBase,
567 ModuleName,
568 ModuleObject);
569 }
570
571 CPRINT("Module wasn't PE\n");
572 return STATUS_UNSUCCESSFUL;
573 }
574
575
576 PVOID
577 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
578 char *Name,
579 unsigned short Hint)
580 {
581 if (ModuleObject->Flags & MODULE_FLAG_PE)
582 {
583 return LdrPEGetExportAddress(ModuleObject, Name, Hint);
584 }
585 else
586 {
587 return 0;
588 }
589 }
590
591
592 NTSTATUS
593 LdrpQueryModuleInformation(PVOID Buffer,
594 ULONG Size,
595 PULONG ReqSize)
596 {
597 PLIST_ENTRY current_entry;
598 PMODULE_OBJECT current;
599 ULONG ModuleCount = 0;
600 PSYSTEM_MODULE_INFORMATION Smi;
601 ANSI_STRING AnsiName;
602 PCHAR p;
603 KIRQL Irql;
604
605 KeAcquireSpinLock(&ModuleListLock,&Irql);
606
607 /* calculate required size */
608 current_entry = ModuleListHead.Flink;
609 while (current_entry != (&ModuleListHead))
610 {
611 ModuleCount++;
612 current_entry = current_entry->Flink;
613 }
614
615 *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
616 (ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION_ENTRY);
617
618 if (Size < *ReqSize)
619 {
620 KeReleaseSpinLock(&ModuleListLock, Irql);
621 return(STATUS_INFO_LENGTH_MISMATCH);
622 }
623
624 /* fill the buffer */
625 memset(Buffer, '=', Size);
626
627 Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
628 Smi->Count = ModuleCount;
629
630 ModuleCount = 0;
631 current_entry = ModuleListHead.Flink;
632 while (current_entry != (&ModuleListHead))
633 {
634 current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
635
636 Smi->Module[ModuleCount].Unknown1 = 0; /* Always 0 */
637 Smi->Module[ModuleCount].Unknown2 = 0; /* Always 0 */
638 Smi->Module[ModuleCount].Base = current->Base;
639 Smi->Module[ModuleCount].Size = current->Length;
640 Smi->Module[ModuleCount].Flags = 0; /* Flags ??? (GN) */
641 Smi->Module[ModuleCount].Index = ModuleCount;
642 Smi->Module[ModuleCount].NameLength = 0;
643 Smi->Module[ModuleCount].LoadCount = 0; /* FIXME */
644
645 AnsiName.Length = 0;
646 AnsiName.MaximumLength = 256;
647 AnsiName.Buffer = Smi->Module[ModuleCount].ImageName;
648 RtlUnicodeStringToAnsiString(&AnsiName,
649 &current->FullName,
650 FALSE);
651
652 p = strrchr(AnsiName.Buffer, '\\');
653 if (p == NULL)
654 {
655 Smi->Module[ModuleCount].PathLength = 0;
656 }
657 else
658 {
659 p++;
660 Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
661 }
662
663 ModuleCount++;
664 current_entry = current_entry->Flink;
665 }
666
667 KeReleaseSpinLock(&ModuleListLock, Irql);
668
669 return(STATUS_SUCCESS);
670 }
671
672
673 static VOID
674 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
675 PUNICODE_STRING FullName)
676 {
677 UNICODE_STRING Name;
678 PWCHAR p;
679 PWCHAR q;
680
681 DPRINT("LdrpBuildModuleBaseName()\n");
682 DPRINT("FullName %wZ\n", FullName);
683
684 p = wcsrchr(FullName->Buffer, L'\\');
685 if (p == NULL)
686 {
687 p = FullName->Buffer;
688 }
689 else
690 {
691 p++;
692 }
693
694 DPRINT("p %S\n", p);
695
696 RtlCreateUnicodeString(&Name, p);
697
698 q = wcschr(Name.Buffer, L'.');
699 if (q != NULL)
700 {
701 *q = (WCHAR)0;
702 }
703
704 DPRINT("p %S\n", p);
705
706 RtlCreateUnicodeString(BaseName, Name.Buffer);
707 RtlFreeUnicodeString(&Name);
708 }
709
710
711 static LONG
712 LdrpCompareModuleNames(IN PUNICODE_STRING String1,
713 IN PUNICODE_STRING String2)
714 {
715 ULONG len1, len2, i;
716 PWCHAR s1, s2, p;
717 WCHAR c1, c2;
718
719 if (String1 && String2)
720 {
721 /* Search String1 for last path component */
722 len1 = String1->Length / sizeof(WCHAR);
723 s1 = String1->Buffer;
724 for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
725 {
726 if (*p == L'\\')
727 {
728 if (i == String1->Length - sizeof(WCHAR))
729 {
730 s1 = NULL;
731 len1 = 0;
732 }
733 else
734 {
735 s1 = p + 1;
736 len1 = (String1->Length - i) / sizeof(WCHAR);
737 }
738 }
739 }
740
741 /* Search String2 for last path component */
742 len2 = String2->Length / sizeof(WCHAR);
743 s2 = String2->Buffer;
744 for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
745 {
746 if (*p == L'\\')
747 {
748 if (i == String2->Length - sizeof(WCHAR))
749 {
750 s2 = NULL;
751 len2 = 0;
752 }
753 else
754 {
755 s2 = p + 1;
756 len2 = (String2->Length - i) / sizeof(WCHAR);
757 }
758 }
759 }
760
761 /* Compare last path components */
762 if (s1 && s2)
763 {
764 while (1)
765 {
766 c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
767 c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
768 if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
769 return(0);
770 if (!c1 || !c2 || c1 != c2)
771 return(c1 - c2);
772 }
773 }
774 }
775
776 return(0);
777 }
778
779
780 PMODULE_OBJECT
781 LdrGetModuleObject(PUNICODE_STRING ModuleName)
782 {
783 PMODULE_OBJECT Module;
784 PLIST_ENTRY Entry;
785 KIRQL Irql;
786
787 DPRINT("LdrpGetModuleObject(%wZ) called\n", ModuleName);
788
789 KeAcquireSpinLock(&ModuleListLock,&Irql);
790
791 Entry = ModuleListHead.Flink;
792 while (Entry != &ModuleListHead)
793 {
794 Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
795
796 DPRINT("Comparing %wZ and %wZ\n",
797 &Module->BaseName,
798 ModuleName);
799
800 if (!LdrpCompareModuleNames(&Module->BaseName, ModuleName))
801 {
802 DPRINT("Module %wZ\n", &Module->BaseName);
803 KeReleaseSpinLock(&ModuleListLock, Irql);
804 return(Module);
805 }
806
807 Entry = Entry->Flink;
808 }
809
810 KeReleaseSpinLock(&ModuleListLock, Irql);
811
812 DPRINT("Could not find module '%wZ'\n", ModuleName);
813
814 return(NULL);
815 }
816
817
818 /* ---------------------------------------------- PE Module support */
819
820 static BOOL
821 PageNeedsWriteAccess(PVOID PageStart,
822 PVOID DriverBase,
823 PIMAGE_FILE_HEADER PEFileHeader,
824 PIMAGE_SECTION_HEADER PESectionHeaders)
825 {
826 BOOL NeedsWriteAccess;
827 unsigned Idx;
828 ULONG Characteristics;
829 ULONG Length;
830 PVOID BaseAddress;
831
832 NeedsWriteAccess = FALSE;
833 /* Set the protections for the various parts of the driver */
834 for (Idx = 0; Idx < PEFileHeader->NumberOfSections && ! NeedsWriteAccess; Idx++)
835 {
836 Characteristics = PESectionHeaders[Idx].Characteristics;
837 if (!(Characteristics & IMAGE_SECTION_CHAR_CODE) ||
838 (Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
839 Characteristics & IMAGE_SECTION_CHAR_DATA ||
840 Characteristics & IMAGE_SECTION_CHAR_BSS))
841 {
842 Length =
843 max(PESectionHeaders[Idx].Misc.VirtualSize,
844 PESectionHeaders[Idx].SizeOfRawData);
845 BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
846 NeedsWriteAccess = BaseAddress < PageStart + PAGE_SIZE &&
847 PageStart < (PVOID)((PCHAR) BaseAddress + Length);
848 }
849 }
850
851 return(NeedsWriteAccess);
852 }
853
854 static NTSTATUS
855 LdrPEProcessModule(PVOID ModuleLoadBase,
856 PUNICODE_STRING FileName,
857 PMODULE_OBJECT *ModuleObject)
858 {
859 unsigned int DriverSize, Idx;
860 ULONG RelocDelta, NumRelocs;
861 DWORD CurrentSize, TotalRelocs;
862 PVOID DriverBase;
863 PULONG PEMagic;
864 PIMAGE_DOS_HEADER PEDosHeader;
865 PIMAGE_FILE_HEADER PEFileHeader;
866 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
867 PIMAGE_SECTION_HEADER PESectionHeaders;
868 PRELOCATION_DIRECTORY RelocDir;
869 PRELOCATION_ENTRY RelocEntry;
870 PMODULE_OBJECT LibraryModuleObject;
871 PMODULE_OBJECT CreatedModuleObject;
872 PVOID *ImportAddressList;
873 PULONG FunctionNameList;
874 PCHAR pName;
875 WORD Hint;
876 UNICODE_STRING ModuleName;
877 UNICODE_STRING NameString;
878 WCHAR NameBuffer[60];
879 MODULE_TEXT_SECTION* ModuleTextSection;
880 NTSTATUS Status;
881 KIRQL Irql;
882
883 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
884
885 /* Get header pointers */
886 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
887 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
888 PEDosHeader->e_lfanew);
889 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
890 PEDosHeader->e_lfanew + sizeof(ULONG));
891 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
892 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
893 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
894 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
895 sizeof(IMAGE_OPTIONAL_HEADER));
896 CHECKPOINT;
897
898 /* Check file magic numbers */
899 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
900 {
901 CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
902 return STATUS_UNSUCCESSFUL;
903 }
904 if (PEDosHeader->e_lfanew == 0)
905 {
906 CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
907 return STATUS_UNSUCCESSFUL;
908 }
909 if (*PEMagic != IMAGE_PE_MAGIC)
910 {
911 CPRINT("Incorrect PE magic: %08x\n", *PEMagic);
912 return STATUS_UNSUCCESSFUL;
913 }
914 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
915 {
916 CPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
917 return STATUS_UNSUCCESSFUL;
918 }
919 CHECKPOINT;
920
921 /* FIXME: if image is fixed-address load, then fail */
922
923 /* FIXME: check/verify OS version number */
924
925 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
926 PEOptionalHeader->Magic,
927 PEOptionalHeader->MajorLinkerVersion,
928 PEOptionalHeader->MinorLinkerVersion);
929 DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
930 CHECKPOINT;
931
932 /* Determine the size of the module */
933 DriverSize = PEOptionalHeader->SizeOfImage;
934 DPRINT("DriverSize %x\n",DriverSize);
935
936 /* Allocate a virtual section for the module */
937 DriverBase = MmAllocateSection(DriverSize);
938 if (DriverBase == 0)
939 {
940 CPRINT("Failed to allocate a virtual section for driver\n");
941 return STATUS_UNSUCCESSFUL;
942 }
943 DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase);
944 CHECKPOINT;
945 /* Copy headers over */
946 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
947 CurrentSize = 0;
948 /* Copy image sections into virtual section */
949 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
950 {
951 // Copy current section into current offset of virtual section
952 if (PESectionHeaders[Idx].Characteristics &
953 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
954 {
955 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
956 PESectionHeaders[Idx].VirtualAddress + DriverBase);
957 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
958 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
959 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
960 ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
961 }
962 else
963 {
964 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
965 PESectionHeaders[Idx].VirtualAddress + DriverBase);
966 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
967 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
968
969 }
970 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
971 PEOptionalHeader->SectionAlignment);
972
973
974 // CurrentBase = (PVOID)((DWORD)CurrentBase +
975 // ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
976 // PEOptionalHeader->SectionAlignment));
977 }
978
979 /* Perform relocation fixups */
980 RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
981 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
982 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
983 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
984 DriverBase,
985 PEOptionalHeader->ImageBase,
986 RelocDelta);
987 DPRINT("RelocDir %x\n",RelocDir);
988 #if 1
989 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
990 {
991 if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
992 {
993 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
994 PESectionHeaders[Idx].Name,
995 PESectionHeaders[Idx].PointerToRawData);
996 RelocDir = PESectionHeaders[Idx].PointerToRawData +
997 ModuleLoadBase;
998 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
999 break;
1000 }
1001 }
1002 #else
1003 RelocDir = RelocDir + (ULONG)DriverBase;
1004 CurrentSize = PEOptionalHeader->DataDirectory
1005 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1006 #endif
1007 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1008 TotalRelocs = 0;
1009 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1010 {
1011 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
1012 sizeof(WORD);
1013 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
1014 RelocDir,
1015 RelocDir->VirtualAddress,
1016 NumRelocs);*/
1017 RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir +
1018 sizeof(RELOCATION_DIRECTORY));
1019 for (Idx = 0; Idx < NumRelocs; Idx++)
1020 {
1021 ULONG Offset;
1022 ULONG Type;
1023 PDWORD RelocItem;
1024
1025 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1026 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1027 RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress +
1028 Offset);
1029 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
1030 RelocItem,
1031 Type,
1032 Type ? "HIGHLOW" : "ABS",
1033 *RelocItem,
1034 (*RelocItem) + RelocDelta); */
1035 if (Type == 3)
1036 {
1037 (*RelocItem) += RelocDelta;
1038 }
1039 else if (Type != 0)
1040 {
1041 CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1042 return STATUS_UNSUCCESSFUL;
1043 }
1044 }
1045 TotalRelocs += RelocDir->SizeOfBlock;
1046 RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir +
1047 RelocDir->SizeOfBlock);
1048 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
1049 }
1050
1051 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1052 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1053 .VirtualAddress);
1054 /* Perform import fixups */
1055 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1056 {
1057 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1058
1059 /* Process each import module */
1060 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1061 ((DWORD)DriverBase + PEOptionalHeader->
1062 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1063 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1064 while (ImportModuleDirectory->dwRVAModuleName)
1065 {
1066 /* Check to make sure that import lib is kernel */
1067 pName = (PCHAR) DriverBase +
1068 ImportModuleDirectory->dwRVAModuleName;
1069
1070 RtlCreateUnicodeStringFromAsciiz(&ModuleName, pName);
1071 DPRINT("Import module: %wZ\n", &ModuleName);
1072
1073 LibraryModuleObject = LdrGetModuleObject(&ModuleName);
1074 if (LibraryModuleObject == NULL)
1075 {
1076 DPRINT("Module '%wZ' not loaded yet\n", &ModuleName);
1077 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
1078 wcscat(NameBuffer, ModuleName.Buffer);
1079 RtlInitUnicodeString(&NameString, NameBuffer);
1080 Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1081 if (!NT_SUCCESS(Status))
1082 {
1083 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
1084 wcscat(NameBuffer, ModuleName.Buffer);
1085 RtlInitUnicodeString(&NameString, NameBuffer);
1086 Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1087 if (!NT_SUCCESS(Status))
1088 {
1089 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &ModuleName, Status);
1090 return(Status);
1091 }
1092 }
1093 }
1094 /* Get the import address list */
1095 ImportAddressList = (PVOID *) ((DWORD)DriverBase +
1096 ImportModuleDirectory->dwRVAFunctionAddressList);
1097
1098 /* Get the list of functions to import */
1099 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1100 {
1101 FunctionNameList = (PULONG) ((DWORD)DriverBase +
1102 ImportModuleDirectory->dwRVAFunctionNameList);
1103 }
1104 else
1105 {
1106 FunctionNameList = (PULONG) ((DWORD)DriverBase +
1107 ImportModuleDirectory->dwRVAFunctionAddressList);
1108 }
1109 /* Walk through function list and fixup addresses */
1110 while (*FunctionNameList != 0L)
1111 {
1112 if ((*FunctionNameList) & 0x80000000) // hint
1113 {
1114 pName = NULL;
1115
1116
1117 Hint = (*FunctionNameList) & 0xffff;
1118 }
1119 else // hint-name
1120 {
1121 pName = (PCHAR)((DWORD)DriverBase +
1122 *FunctionNameList + 2);
1123 Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
1124 }
1125 DPRINT(" Hint:%04x Name:%s\n", Hint, pName);
1126
1127 /* Fixup the current import symbol */
1128 if (LibraryModuleObject != NULL)
1129 {
1130 *ImportAddressList = LdrGetExportAddress(LibraryModuleObject,
1131 pName,
1132 Hint);
1133 }
1134 else
1135 {
1136 CPRINT("Unresolved kernel symbol: %s\n", pName);
1137 return STATUS_UNSUCCESSFUL;
1138 }
1139 ImportAddressList++;
1140 FunctionNameList++;
1141 }
1142
1143 RtlFreeUnicodeString(&ModuleName);
1144
1145 ImportModuleDirectory++;
1146 }
1147 }
1148
1149 /* Set the protections for the various parts of the driver */
1150 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1151 {
1152 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1153 ULONG Length;
1154 PVOID BaseAddress;
1155 PVOID PageAddress;
1156 if (Characteristics & IMAGE_SECTION_CHAR_CODE &&
1157 !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
1158 Characteristics & IMAGE_SECTION_CHAR_DATA ||
1159 Characteristics & IMAGE_SECTION_CHAR_BSS))
1160 {
1161 Length =
1162 max(PESectionHeaders[Idx].Misc.VirtualSize,
1163 PESectionHeaders[Idx].SizeOfRawData);
1164 BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
1165 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1166 if (! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1167 {
1168 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1169 }
1170 PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1171 while ((PVOID)((PCHAR) PageAddress + PAGE_SIZE) <
1172 (PVOID)((PCHAR) BaseAddress + Length))
1173 {
1174 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1175 PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1176 }
1177 if (PageAddress < (PVOID)((PCHAR) BaseAddress + Length) &&
1178 ! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1179 {
1180 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1181 }
1182 }
1183 }
1184
1185 /* Create the module */
1186 CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
1187 if (CreatedModuleObject == NULL)
1188 {
1189 return(STATUS_INSUFFICIENT_RESOURCES);
1190 }
1191
1192 RtlZeroMemory(CreatedModuleObject, sizeof(MODULE_OBJECT));
1193
1194 /* Initialize ModuleObject data */
1195 CreatedModuleObject->Base = DriverBase;
1196 CreatedModuleObject->Flags = MODULE_FLAG_PE;
1197
1198 RtlCreateUnicodeString(&CreatedModuleObject->FullName,
1199 FileName->Buffer);
1200 LdrpBuildModuleBaseName(&CreatedModuleObject->BaseName,
1201 &CreatedModuleObject->FullName);
1202
1203 CreatedModuleObject->EntryPoint =
1204 (PVOID)((DWORD)DriverBase +
1205 PEOptionalHeader->AddressOfEntryPoint);
1206 CreatedModuleObject->Length = DriverSize;
1207 DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
1208
1209 CreatedModuleObject->Image.PE.FileHeader =
1210 (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
1211
1212 DPRINT("FileHeader at %x\n", CreatedModuleObject->Image.PE.FileHeader);
1213 CreatedModuleObject->Image.PE.OptionalHeader =
1214 (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1215 sizeof(IMAGE_FILE_HEADER));
1216 DPRINT("OptionalHeader at %x\n", CreatedModuleObject->Image.PE.OptionalHeader);
1217 CreatedModuleObject->Image.PE.SectionList =
1218 (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1219 sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
1220 DPRINT("SectionList at %x\n", CreatedModuleObject->Image.PE.SectionList);
1221
1222 /* Insert module */
1223 KeAcquireSpinLock(&ModuleListLock, &Irql);
1224 InsertTailList(&ModuleListHead,
1225 &CreatedModuleObject->ListEntry);
1226 KeReleaseSpinLock(&ModuleListLock, Irql);
1227
1228
1229 ModuleTextSection = ExAllocatePool(NonPagedPool,
1230 sizeof(MODULE_TEXT_SECTION));
1231 assert(ModuleTextSection);
1232 RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
1233 ModuleTextSection->Base = (ULONG)DriverBase;
1234 ModuleTextSection->Length = DriverSize;
1235 ModuleTextSection->Name = ExAllocatePool(NonPagedPool,
1236 (wcslen(CreatedModuleObject->BaseName.Buffer) + 1) * sizeof(WCHAR));
1237 wcscpy(ModuleTextSection->Name, CreatedModuleObject->BaseName.Buffer);
1238 ModuleTextSection->OptionalHeader =
1239 CreatedModuleObject->Image.PE.OptionalHeader;
1240 InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
1241
1242 CreatedModuleObject->TextSection = ModuleTextSection;
1243
1244 *ModuleObject = CreatedModuleObject;
1245
1246 DPRINT("Loading Module %wZ...\n", FileName);
1247
1248 if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
1249 {
1250 DPRINT("Module %wZ loaded at 0x%.08x.\n",
1251 FileName, CreatedModuleObject->Base);
1252 }
1253
1254 return STATUS_SUCCESS;
1255 }
1256
1257
1258 PVOID
1259 LdrSafePEProcessModule(PVOID ModuleLoadBase,
1260 PVOID DriverBase,
1261 PVOID ImportModuleBase,
1262 PULONG DriverSize)
1263 {
1264 unsigned int Idx;
1265 ULONG RelocDelta, NumRelocs;
1266 ULONG CurrentSize, TotalRelocs;
1267 PULONG PEMagic;
1268 PIMAGE_DOS_HEADER PEDosHeader;
1269 PIMAGE_FILE_HEADER PEFileHeader;
1270 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
1271 PIMAGE_SECTION_HEADER PESectionHeaders;
1272 PRELOCATION_DIRECTORY RelocDir;
1273 PRELOCATION_ENTRY RelocEntry;
1274 PVOID *ImportAddressList;
1275 PULONG FunctionNameList;
1276 PCHAR pName;
1277 USHORT Hint;
1278
1279 ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
1280
1281 /* Get header pointers */
1282 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
1283 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
1284 PEDosHeader->e_lfanew);
1285 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
1286 PEDosHeader->e_lfanew + sizeof(ULONG));
1287 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
1288 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
1289 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
1290 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
1291 sizeof(IMAGE_OPTIONAL_HEADER));
1292 CHECKPOINT;
1293
1294 /* Check file magic numbers */
1295 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
1296 {
1297 return 0;
1298 }
1299 if (PEDosHeader->e_lfanew == 0)
1300 {
1301 return 0;
1302 }
1303 if (*PEMagic != IMAGE_PE_MAGIC)
1304 {
1305 return 0;
1306 }
1307 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
1308 {
1309 return 0;
1310 }
1311
1312 ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
1313 PEOptionalHeader->Magic,
1314 PEOptionalHeader->MajorLinkerVersion,
1315 PEOptionalHeader->MinorLinkerVersion);
1316 ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
1317
1318 /* Determine the size of the module */
1319 *DriverSize = PEOptionalHeader->SizeOfImage;
1320 ps("DriverSize %x\n",*DriverSize);
1321
1322 /* Copy headers over */
1323 if (DriverBase != ModuleLoadBase)
1324 {
1325 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
1326 }
1327
1328 ps("Hdr: 0x%X\n", (ULONG)PEOptionalHeader);
1329 ps("Hdr->SizeOfHeaders: 0x%X\n", (ULONG)PEOptionalHeader->SizeOfHeaders);
1330 ps("FileHdr->NumberOfSections: 0x%X\n", (ULONG)PEFileHeader->NumberOfSections);
1331
1332 /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
1333 address as it is mapped */
1334 if (DriverBase != ModuleLoadBase)
1335 {
1336 CurrentSize = 0;
1337
1338 /* Copy image sections into virtual section */
1339 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1340 {
1341 // Copy current section into current offset of virtual section
1342 if (PESectionHeaders[Idx].Characteristics &
1343 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
1344 {
1345 //ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1346 //PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1347 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1348 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
1349 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ?
1350 PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
1351 }
1352 else
1353 {
1354 ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1355 PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1356 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1357 '\0',
1358 PESectionHeaders[Idx].Misc.VirtualSize);
1359 }
1360 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
1361 PEOptionalHeader->SectionAlignment);
1362 }
1363
1364 /* Perform relocation fixups */
1365 RelocDelta = (ULONG) DriverBase - PEOptionalHeader->ImageBase;
1366 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
1367 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
1368 ps("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
1369 DriverBase,
1370 PEOptionalHeader->ImageBase,
1371 RelocDelta);
1372 ps("RelocDir %x\n",RelocDir);
1373
1374 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1375 {
1376 if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
1377 {
1378 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1379 PESectionHeaders[Idx].Name,
1380 PESectionHeaders[Idx].PointerToRawData);
1381 RelocDir = PESectionHeaders[Idx].PointerToRawData + ModuleLoadBase;
1382 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1383 break;
1384 }
1385 }
1386
1387 ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1388
1389 TotalRelocs = 0;
1390 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1391 {
1392 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
1393 sizeof(USHORT);
1394 RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir +
1395 sizeof(RELOCATION_DIRECTORY));
1396 for (Idx = 0; Idx < NumRelocs; Idx++)
1397 {
1398 ULONG Offset;
1399 ULONG Type;
1400 PULONG RelocItem;
1401
1402 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1403 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1404 RelocItem = (PULONG)(DriverBase + RelocDir->VirtualAddress + Offset);
1405 if (Type == 3)
1406 {
1407 (*RelocItem) += RelocDelta;
1408 }
1409 else if (Type != 0)
1410 {
1411 CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1412 return(0);
1413 }
1414 }
1415 TotalRelocs += RelocDir->SizeOfBlock;
1416 RelocDir = (PRELOCATION_DIRECTORY)((ULONG)RelocDir +
1417 RelocDir->SizeOfBlock);
1418 }
1419
1420 ps("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1421 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1422 .VirtualAddress);
1423 }
1424
1425 /* Perform import fixups */
1426 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1427 {
1428 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1429
1430 /* Process each import module */
1431 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1432 ((ULONG)DriverBase + PEOptionalHeader->
1433 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1434
1435 ps("Processeing import directory at %p\n", ImportModuleDirectory);
1436
1437 /* Check to make sure that import lib is kernel */
1438 pName = (PCHAR)DriverBase + ImportModuleDirectory->dwRVAModuleName;
1439
1440 ps("Import module: %s\n", pName);
1441
1442 /* Get the import address list */
1443 ImportAddressList = (PVOID *)((ULONG)DriverBase +
1444 ImportModuleDirectory->dwRVAFunctionAddressList);
1445
1446 ps(" ImportModuleDirectory->dwRVAFunctionAddressList: 0x%X\n",
1447 ImportModuleDirectory->dwRVAFunctionAddressList);
1448 ps(" ImportAddressList: 0x%X\n", ImportAddressList);
1449
1450 /* Get the list of functions to import */
1451 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1452 {
1453 ps("Using function name list.\n");
1454
1455 FunctionNameList = (PULONG)((ULONG)DriverBase +
1456 ImportModuleDirectory->dwRVAFunctionNameList);
1457 }
1458 else
1459 {
1460 ps("Using function address list.\n");
1461
1462 FunctionNameList = (PULONG)((ULONG)DriverBase +
1463 ImportModuleDirectory->dwRVAFunctionAddressList);
1464 }
1465
1466 /* Walk through function list and fixup addresses */
1467 while (*FunctionNameList != 0L)
1468 {
1469 if ((*FunctionNameList) & 0x80000000)
1470 {
1471 /* Hint */
1472 pName = NULL;
1473 Hint = (*FunctionNameList) & 0xffff;
1474 }
1475 else
1476 {
1477 /* Hint name */
1478 pName = (PCHAR)((ULONG)DriverBase + *FunctionNameList + 2);
1479 Hint = *(PWORD)((ULONG)DriverBase + *FunctionNameList);
1480 }
1481 //ps(" Hint:%04x Name:%s(0x%X)(%x)\n", Hint, pName, pName, ImportAddressList);
1482
1483 *ImportAddressList = LdrSafePEGetExportAddress(ImportModuleBase,
1484 pName,
1485 Hint);
1486
1487 ImportAddressList++;
1488 FunctionNameList++;
1489 }
1490 }
1491
1492 ps("Finished importing.\n");
1493
1494 return(0);
1495 }
1496
1497
1498 static PVOID
1499 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
1500 PCHAR Name,
1501 USHORT Hint)
1502 {
1503 PIMAGE_EXPORT_DIRECTORY ExportDir;
1504 ULONG ExportDirSize;
1505 USHORT Idx;
1506 PVOID ExportAddress;
1507 PWORD OrdinalList;
1508 PDWORD FunctionList, NameList;
1509
1510 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1511 RtlImageDirectoryEntryToData(ModuleObject->Base,
1512 TRUE,
1513 IMAGE_DIRECTORY_ENTRY_EXPORT,
1514 &ExportDirSize);
1515 DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
1516 if (ExportDir == NULL)
1517 {
1518 return NULL;
1519 }
1520
1521 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
1522 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
1523 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
1524
1525 ExportAddress = 0;
1526
1527 if (Name != NULL)
1528 {
1529 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1530 {
1531 #if 0
1532 DPRINT(" Name:%s NameList[%d]:%s\n",
1533 Name,
1534 Idx,
1535 (DWORD) ModuleObject->Base + NameList[Idx]);
1536
1537 #endif
1538 if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
1539 {
1540 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1541 FunctionList[OrdinalList[Idx]]);
1542 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
1543 ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
1544 {
1545 DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
1546 ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
1547 DPRINT("ExportAddress: %p\n", ExportAddress);
1548 }
1549
1550 break;
1551 }
1552 }
1553 }
1554 else /* use hint */
1555 {
1556 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1557 FunctionList[Hint - ExportDir->Base]);
1558 }
1559
1560 if (ExportAddress == NULL)
1561 {
1562 DbgPrint("Export not found for %d:%s\n",
1563 Hint,
1564 Name != NULL ? Name : "(Ordinal)");
1565 KEBUGCHECK(0);
1566 }
1567
1568 return(ExportAddress);
1569 }
1570
1571
1572 static PVOID
1573 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
1574 PCHAR Name,
1575 USHORT Hint)
1576 {
1577 USHORT Idx;
1578 PVOID ExportAddress;
1579 PWORD OrdinalList;
1580 PDWORD FunctionList, NameList;
1581 PIMAGE_EXPORT_DIRECTORY ExportDir;
1582 ULONG ExportDirSize;
1583
1584 static BOOLEAN EP = FALSE;
1585
1586 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1587 RtlImageDirectoryEntryToData(ImportModuleBase,
1588 TRUE,
1589 IMAGE_DIRECTORY_ENTRY_EXPORT,
1590 &ExportDirSize);
1591
1592 if (!EP) {
1593 EP = TRUE;
1594 ps("ExportDir %x\n", ExportDir);
1595 }
1596
1597 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ImportModuleBase);
1598 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
1599 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ImportModuleBase);
1600
1601 ExportAddress = 0;
1602
1603 if (Name != NULL)
1604 {
1605 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1606 {
1607 if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
1608 {
1609 ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1610 FunctionList[OrdinalList[Idx]]);
1611 break;
1612 }
1613 }
1614 }
1615 else /* use hint */
1616 {
1617 ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1618
1619 FunctionList[Hint - ExportDir->Base]);
1620 }
1621
1622 if (ExportAddress == 0)
1623 {
1624 ps("Export not found for %d:%s\n",
1625 Hint,
1626 Name != NULL ? Name : "(Ordinal)");
1627 KEBUGCHECK(0);
1628 }
1629 return ExportAddress;
1630 }
1631
1632
1633 static PVOID
1634 LdrPEFixupForward(PCHAR ForwardName)
1635 {
1636 CHAR NameBuffer[128];
1637 UNICODE_STRING ModuleName;
1638 PCHAR p;
1639 PMODULE_OBJECT ModuleObject;
1640
1641 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1642
1643 strcpy(NameBuffer, ForwardName);
1644 p = strchr(NameBuffer, '.');
1645 if (p == NULL)
1646 {
1647 return NULL;
1648 }
1649
1650 *p = 0;
1651
1652 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
1653
1654 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1655 NameBuffer);
1656 ModuleObject = LdrGetModuleObject(&ModuleName);
1657 RtlFreeUnicodeString(&ModuleName);
1658
1659 DPRINT("ModuleObject: %p\n", ModuleObject);
1660
1661 if (ModuleObject == NULL)
1662 {
1663 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1664 return NULL;
1665 }
1666
1667 return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
1668 }
1669
1670 /* EOF */