d3331d311734f06abc3cfd0d4f2534f919a995df
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /* $Id: loader.c,v 1.137 2003/10/15 17:04:39 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 INIT_FUNCTION
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 INIT_FUNCTION
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 INIT_FUNCTION
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 #if 0
944 DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase);
945 #else
946 DbgPrint("DriverBase for %wZ", FileName);
947 DbgPrint(": %x\n", DriverBase);
948 #endif
949 CHECKPOINT;
950 /* Copy headers over */
951 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
952 CurrentSize = 0;
953 /* Copy image sections into virtual section */
954 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
955 {
956 // Copy current section into current offset of virtual section
957 if (PESectionHeaders[Idx].Characteristics &
958 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
959 {
960 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
961 PESectionHeaders[Idx].VirtualAddress + DriverBase);
962 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
963 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
964 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
965 ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
966 }
967 else
968 {
969 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
970 PESectionHeaders[Idx].VirtualAddress + DriverBase);
971 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
972 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
973
974 }
975 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
976 PEOptionalHeader->SectionAlignment);
977
978
979 // CurrentBase = (PVOID)((DWORD)CurrentBase +
980 // ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
981 // PEOptionalHeader->SectionAlignment));
982 }
983
984 /* Perform relocation fixups */
985 RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
986 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
987 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
988 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
989 DriverBase,
990 PEOptionalHeader->ImageBase,
991 RelocDelta);
992 DPRINT("RelocDir %x\n",RelocDir);
993 #if 1
994 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
995 {
996 if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
997 {
998 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
999 PESectionHeaders[Idx].Name,
1000 PESectionHeaders[Idx].PointerToRawData);
1001 RelocDir = PESectionHeaders[Idx].PointerToRawData +
1002 ModuleLoadBase;
1003 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1004 break;
1005 }
1006 }
1007 #else
1008 RelocDir = RelocDir + (ULONG)DriverBase;
1009 CurrentSize = PEOptionalHeader->DataDirectory
1010 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1011 #endif
1012 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1013 TotalRelocs = 0;
1014 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1015 {
1016 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
1017 sizeof(WORD);
1018 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
1019 RelocDir,
1020 RelocDir->VirtualAddress,
1021 NumRelocs);*/
1022 RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir +
1023 sizeof(RELOCATION_DIRECTORY));
1024 for (Idx = 0; Idx < NumRelocs; Idx++)
1025 {
1026 ULONG Offset;
1027 ULONG Type;
1028 PDWORD RelocItem;
1029
1030 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1031 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1032 RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress +
1033 Offset);
1034 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
1035 RelocItem,
1036 Type,
1037 Type ? "HIGHLOW" : "ABS",
1038 *RelocItem,
1039 (*RelocItem) + RelocDelta); */
1040 if (Type == 3)
1041 {
1042 (*RelocItem) += RelocDelta;
1043 }
1044 else if (Type != 0)
1045 {
1046 CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1047 return STATUS_UNSUCCESSFUL;
1048 }
1049 }
1050 TotalRelocs += RelocDir->SizeOfBlock;
1051 RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir +
1052 RelocDir->SizeOfBlock);
1053 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
1054 }
1055
1056 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1057 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1058 .VirtualAddress);
1059 /* Perform import fixups */
1060 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1061 {
1062 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1063
1064 /* Process each import module */
1065 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1066 ((DWORD)DriverBase + PEOptionalHeader->
1067 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1068 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1069 while (ImportModuleDirectory->dwRVAModuleName)
1070 {
1071 /* Check to make sure that import lib is kernel */
1072 pName = (PCHAR) DriverBase +
1073 ImportModuleDirectory->dwRVAModuleName;
1074
1075 RtlCreateUnicodeStringFromAsciiz(&ModuleName, pName);
1076 DPRINT("Import module: %wZ\n", &ModuleName);
1077
1078 LibraryModuleObject = LdrGetModuleObject(&ModuleName);
1079 if (LibraryModuleObject == NULL)
1080 {
1081 DPRINT("Module '%wZ' not loaded yet\n", &ModuleName);
1082 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
1083 wcscat(NameBuffer, ModuleName.Buffer);
1084 RtlInitUnicodeString(&NameString, NameBuffer);
1085 Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1086 if (!NT_SUCCESS(Status))
1087 {
1088 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
1089 wcscat(NameBuffer, ModuleName.Buffer);
1090 RtlInitUnicodeString(&NameString, NameBuffer);
1091 Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1092 if (!NT_SUCCESS(Status))
1093 {
1094 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &ModuleName, Status);
1095 return(Status);
1096 }
1097 }
1098 }
1099 /* Get the import address list */
1100 ImportAddressList = (PVOID *) ((DWORD)DriverBase +
1101 ImportModuleDirectory->dwRVAFunctionAddressList);
1102
1103 /* Get the list of functions to import */
1104 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1105 {
1106 FunctionNameList = (PULONG) ((DWORD)DriverBase +
1107 ImportModuleDirectory->dwRVAFunctionNameList);
1108 }
1109 else
1110 {
1111 FunctionNameList = (PULONG) ((DWORD)DriverBase +
1112 ImportModuleDirectory->dwRVAFunctionAddressList);
1113 }
1114 /* Walk through function list and fixup addresses */
1115 while (*FunctionNameList != 0L)
1116 {
1117 if ((*FunctionNameList) & 0x80000000) // hint
1118 {
1119 pName = NULL;
1120
1121
1122 Hint = (*FunctionNameList) & 0xffff;
1123 }
1124 else // hint-name
1125 {
1126 pName = (PCHAR)((DWORD)DriverBase +
1127 *FunctionNameList + 2);
1128 Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
1129 }
1130 DPRINT(" Hint:%04x Name:%s\n", Hint, pName);
1131
1132 /* Fixup the current import symbol */
1133 if (LibraryModuleObject != NULL)
1134 {
1135 *ImportAddressList = LdrGetExportAddress(LibraryModuleObject,
1136 pName,
1137 Hint);
1138 }
1139 else
1140 {
1141 CPRINT("Unresolved kernel symbol: %s\n", pName);
1142 return STATUS_UNSUCCESSFUL;
1143 }
1144 ImportAddressList++;
1145 FunctionNameList++;
1146 }
1147
1148 RtlFreeUnicodeString(&ModuleName);
1149
1150 ImportModuleDirectory++;
1151 }
1152 }
1153
1154 /* Set the protections for the various parts of the driver */
1155 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1156 {
1157 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1158 ULONG Length;
1159 PVOID BaseAddress;
1160 PVOID PageAddress;
1161 if (Characteristics & IMAGE_SECTION_CHAR_CODE &&
1162 !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
1163 Characteristics & IMAGE_SECTION_CHAR_DATA ||
1164 Characteristics & IMAGE_SECTION_CHAR_BSS))
1165 {
1166 Length =
1167 max(PESectionHeaders[Idx].Misc.VirtualSize,
1168 PESectionHeaders[Idx].SizeOfRawData);
1169 BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
1170 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1171 if (! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1172 {
1173 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1174 }
1175 PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1176 while ((PVOID)((PCHAR) PageAddress + PAGE_SIZE) <
1177 (PVOID)((PCHAR) BaseAddress + Length))
1178 {
1179 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1180 PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1181 }
1182 if (PageAddress < (PVOID)((PCHAR) BaseAddress + Length) &&
1183 ! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1184 {
1185 MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1186 }
1187 }
1188 }
1189
1190 /* Create the module */
1191 CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
1192 if (CreatedModuleObject == NULL)
1193 {
1194 return(STATUS_INSUFFICIENT_RESOURCES);
1195 }
1196
1197 RtlZeroMemory(CreatedModuleObject, sizeof(MODULE_OBJECT));
1198
1199 /* Initialize ModuleObject data */
1200 CreatedModuleObject->Base = DriverBase;
1201 CreatedModuleObject->Flags = MODULE_FLAG_PE;
1202
1203 RtlCreateUnicodeString(&CreatedModuleObject->FullName,
1204 FileName->Buffer);
1205 LdrpBuildModuleBaseName(&CreatedModuleObject->BaseName,
1206 &CreatedModuleObject->FullName);
1207
1208 CreatedModuleObject->EntryPoint =
1209 (PVOID)((DWORD)DriverBase +
1210 PEOptionalHeader->AddressOfEntryPoint);
1211 CreatedModuleObject->Length = DriverSize;
1212 DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
1213
1214 CreatedModuleObject->Image.PE.FileHeader =
1215 (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
1216
1217 DPRINT("FileHeader at %x\n", CreatedModuleObject->Image.PE.FileHeader);
1218 CreatedModuleObject->Image.PE.OptionalHeader =
1219 (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1220 sizeof(IMAGE_FILE_HEADER));
1221 DPRINT("OptionalHeader at %x\n", CreatedModuleObject->Image.PE.OptionalHeader);
1222 CreatedModuleObject->Image.PE.SectionList =
1223 (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1224 sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
1225 DPRINT("SectionList at %x\n", CreatedModuleObject->Image.PE.SectionList);
1226
1227 /* Insert module */
1228 KeAcquireSpinLock(&ModuleListLock, &Irql);
1229 InsertTailList(&ModuleListHead,
1230 &CreatedModuleObject->ListEntry);
1231 KeReleaseSpinLock(&ModuleListLock, Irql);
1232
1233
1234 ModuleTextSection = ExAllocatePool(NonPagedPool,
1235 sizeof(MODULE_TEXT_SECTION));
1236 assert(ModuleTextSection);
1237 RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
1238 ModuleTextSection->Base = (ULONG)DriverBase;
1239 ModuleTextSection->Length = DriverSize;
1240 ModuleTextSection->Name = ExAllocatePool(NonPagedPool,
1241 (wcslen(CreatedModuleObject->BaseName.Buffer) + 1) * sizeof(WCHAR));
1242 wcscpy(ModuleTextSection->Name, CreatedModuleObject->BaseName.Buffer);
1243 ModuleTextSection->OptionalHeader =
1244 CreatedModuleObject->Image.PE.OptionalHeader;
1245 InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
1246
1247 CreatedModuleObject->TextSection = ModuleTextSection;
1248
1249 *ModuleObject = CreatedModuleObject;
1250
1251 DPRINT("Loading Module %wZ...\n", FileName);
1252
1253 if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
1254 {
1255 DPRINT("Module %wZ loaded at 0x%.08x.\n",
1256 FileName, CreatedModuleObject->Base);
1257 }
1258
1259 return STATUS_SUCCESS;
1260 }
1261
1262
1263 PVOID
1264 LdrSafePEProcessModule(PVOID ModuleLoadBase,
1265 PVOID DriverBase,
1266 PVOID ImportModuleBase,
1267 PULONG DriverSize)
1268 {
1269 unsigned int Idx;
1270 ULONG RelocDelta, NumRelocs;
1271 ULONG CurrentSize, TotalRelocs;
1272 PULONG PEMagic;
1273 PIMAGE_DOS_HEADER PEDosHeader;
1274 PIMAGE_FILE_HEADER PEFileHeader;
1275 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
1276 PIMAGE_SECTION_HEADER PESectionHeaders;
1277 PRELOCATION_DIRECTORY RelocDir;
1278 PRELOCATION_ENTRY RelocEntry;
1279 PVOID *ImportAddressList;
1280 PULONG FunctionNameList;
1281 PCHAR pName;
1282 USHORT Hint;
1283
1284 ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
1285
1286 /* Get header pointers */
1287 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
1288 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
1289 PEDosHeader->e_lfanew);
1290 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
1291 PEDosHeader->e_lfanew + sizeof(ULONG));
1292 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
1293 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
1294 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
1295 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
1296 sizeof(IMAGE_OPTIONAL_HEADER));
1297 CHECKPOINT;
1298
1299 /* Check file magic numbers */
1300 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
1301 {
1302 return 0;
1303 }
1304 if (PEDosHeader->e_lfanew == 0)
1305 {
1306 return 0;
1307 }
1308 if (*PEMagic != IMAGE_PE_MAGIC)
1309 {
1310 return 0;
1311 }
1312 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
1313 {
1314 return 0;
1315 }
1316
1317 ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
1318 PEOptionalHeader->Magic,
1319 PEOptionalHeader->MajorLinkerVersion,
1320 PEOptionalHeader->MinorLinkerVersion);
1321 ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
1322
1323 /* Determine the size of the module */
1324 *DriverSize = PEOptionalHeader->SizeOfImage;
1325 ps("DriverSize %x\n",*DriverSize);
1326
1327 /* Copy headers over */
1328 if (DriverBase != ModuleLoadBase)
1329 {
1330 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
1331 }
1332
1333 ps("Hdr: 0x%X\n", (ULONG)PEOptionalHeader);
1334 ps("Hdr->SizeOfHeaders: 0x%X\n", (ULONG)PEOptionalHeader->SizeOfHeaders);
1335 ps("FileHdr->NumberOfSections: 0x%X\n", (ULONG)PEFileHeader->NumberOfSections);
1336
1337 /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
1338 address as it is mapped */
1339 if (DriverBase != ModuleLoadBase)
1340 {
1341 CurrentSize = 0;
1342
1343 /* Copy image sections into virtual section */
1344 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1345 {
1346 // Copy current section into current offset of virtual section
1347 if (PESectionHeaders[Idx].Characteristics &
1348 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
1349 {
1350 //ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1351 //PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1352 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1353 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
1354 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ?
1355 PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
1356 }
1357 else
1358 {
1359 ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1360 PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1361 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1362 '\0',
1363 PESectionHeaders[Idx].Misc.VirtualSize);
1364 }
1365 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
1366 PEOptionalHeader->SectionAlignment);
1367 }
1368
1369 /* Perform relocation fixups */
1370 RelocDelta = (ULONG) DriverBase - PEOptionalHeader->ImageBase;
1371 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
1372 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
1373 ps("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
1374 DriverBase,
1375 PEOptionalHeader->ImageBase,
1376 RelocDelta);
1377 ps("RelocDir %x\n",RelocDir);
1378
1379 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1380 {
1381 if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
1382 {
1383 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1384 PESectionHeaders[Idx].Name,
1385 PESectionHeaders[Idx].PointerToRawData);
1386 RelocDir = PESectionHeaders[Idx].PointerToRawData + ModuleLoadBase;
1387 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1388 break;
1389 }
1390 }
1391
1392 ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1393
1394 TotalRelocs = 0;
1395 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1396 {
1397 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
1398 sizeof(USHORT);
1399 RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir +
1400 sizeof(RELOCATION_DIRECTORY));
1401 for (Idx = 0; Idx < NumRelocs; Idx++)
1402 {
1403 ULONG Offset;
1404 ULONG Type;
1405 PULONG RelocItem;
1406
1407 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1408 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1409 RelocItem = (PULONG)(DriverBase + RelocDir->VirtualAddress + Offset);
1410 if (Type == 3)
1411 {
1412 (*RelocItem) += RelocDelta;
1413 }
1414 else if (Type != 0)
1415 {
1416 CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1417 return(0);
1418 }
1419 }
1420 TotalRelocs += RelocDir->SizeOfBlock;
1421 RelocDir = (PRELOCATION_DIRECTORY)((ULONG)RelocDir +
1422 RelocDir->SizeOfBlock);
1423 }
1424
1425 ps("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1426 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1427 .VirtualAddress);
1428 }
1429
1430 /* Perform import fixups */
1431 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1432 {
1433 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1434
1435 /* Process each import module */
1436 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1437 ((ULONG)DriverBase + PEOptionalHeader->
1438 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1439
1440 ps("Processeing import directory at %p\n", ImportModuleDirectory);
1441
1442 /* Check to make sure that import lib is kernel */
1443 pName = (PCHAR)DriverBase + ImportModuleDirectory->dwRVAModuleName;
1444
1445 ps("Import module: %s\n", pName);
1446
1447 /* Get the import address list */
1448 ImportAddressList = (PVOID *)((ULONG)DriverBase +
1449 ImportModuleDirectory->dwRVAFunctionAddressList);
1450
1451 ps(" ImportModuleDirectory->dwRVAFunctionAddressList: 0x%X\n",
1452 ImportModuleDirectory->dwRVAFunctionAddressList);
1453 ps(" ImportAddressList: 0x%X\n", ImportAddressList);
1454
1455 /* Get the list of functions to import */
1456 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1457 {
1458 ps("Using function name list.\n");
1459
1460 FunctionNameList = (PULONG)((ULONG)DriverBase +
1461 ImportModuleDirectory->dwRVAFunctionNameList);
1462 }
1463 else
1464 {
1465 ps("Using function address list.\n");
1466
1467 FunctionNameList = (PULONG)((ULONG)DriverBase +
1468 ImportModuleDirectory->dwRVAFunctionAddressList);
1469 }
1470
1471 /* Walk through function list and fixup addresses */
1472 while (*FunctionNameList != 0L)
1473 {
1474 if ((*FunctionNameList) & 0x80000000)
1475 {
1476 /* Hint */
1477 pName = NULL;
1478 Hint = (*FunctionNameList) & 0xffff;
1479 }
1480 else
1481 {
1482 /* Hint name */
1483 pName = (PCHAR)((ULONG)DriverBase + *FunctionNameList + 2);
1484 Hint = *(PWORD)((ULONG)DriverBase + *FunctionNameList);
1485 }
1486 //ps(" Hint:%04x Name:%s(0x%X)(%x)\n", Hint, pName, pName, ImportAddressList);
1487
1488 *ImportAddressList = LdrSafePEGetExportAddress(ImportModuleBase,
1489 pName,
1490 Hint);
1491
1492 ImportAddressList++;
1493 FunctionNameList++;
1494 }
1495 }
1496
1497 ps("Finished importing.\n");
1498
1499 return(0);
1500 }
1501
1502
1503 static PVOID
1504 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
1505 PCHAR Name,
1506 USHORT Hint)
1507 {
1508 PIMAGE_EXPORT_DIRECTORY ExportDir;
1509 ULONG ExportDirSize;
1510 USHORT Idx;
1511 PVOID ExportAddress;
1512 PWORD OrdinalList;
1513 PDWORD FunctionList, NameList;
1514
1515 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1516 RtlImageDirectoryEntryToData(ModuleObject->Base,
1517 TRUE,
1518 IMAGE_DIRECTORY_ENTRY_EXPORT,
1519 &ExportDirSize);
1520 DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
1521 if (ExportDir == NULL)
1522 {
1523 return NULL;
1524 }
1525
1526 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
1527 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
1528 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
1529
1530 ExportAddress = 0;
1531
1532 if (Name != NULL)
1533 {
1534 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1535 {
1536 #if 0
1537 DPRINT(" Name:%s NameList[%d]:%s\n",
1538 Name,
1539 Idx,
1540 (DWORD) ModuleObject->Base + NameList[Idx]);
1541
1542 #endif
1543 if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
1544 {
1545 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1546 FunctionList[OrdinalList[Idx]]);
1547 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
1548 ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
1549 {
1550 DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
1551 ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
1552 DPRINT("ExportAddress: %p\n", ExportAddress);
1553 }
1554
1555 break;
1556 }
1557 }
1558 }
1559 else /* use hint */
1560 {
1561 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1562 FunctionList[Hint - ExportDir->Base]);
1563 }
1564
1565 if (ExportAddress == NULL)
1566 {
1567 DbgPrint("Export not found for %d:%s\n",
1568 Hint,
1569 Name != NULL ? Name : "(Ordinal)");
1570 KEBUGCHECK(0);
1571 }
1572
1573 return(ExportAddress);
1574 }
1575
1576
1577 static PVOID
1578 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
1579 PCHAR Name,
1580 USHORT Hint)
1581 {
1582 USHORT Idx;
1583 PVOID ExportAddress;
1584 PWORD OrdinalList;
1585 PDWORD FunctionList, NameList;
1586 PIMAGE_EXPORT_DIRECTORY ExportDir;
1587 ULONG ExportDirSize;
1588
1589 static BOOLEAN EP = FALSE;
1590
1591 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1592 RtlImageDirectoryEntryToData(ImportModuleBase,
1593 TRUE,
1594 IMAGE_DIRECTORY_ENTRY_EXPORT,
1595 &ExportDirSize);
1596
1597 if (!EP) {
1598 EP = TRUE;
1599 ps("ExportDir %x\n", ExportDir);
1600 }
1601
1602 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ImportModuleBase);
1603 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
1604 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ImportModuleBase);
1605
1606 ExportAddress = 0;
1607
1608 if (Name != NULL)
1609 {
1610 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1611 {
1612 if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
1613 {
1614 ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1615 FunctionList[OrdinalList[Idx]]);
1616 break;
1617 }
1618 }
1619 }
1620 else /* use hint */
1621 {
1622 ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1623
1624 FunctionList[Hint - ExportDir->Base]);
1625 }
1626
1627 if (ExportAddress == 0)
1628 {
1629 ps("Export not found for %d:%s\n",
1630 Hint,
1631 Name != NULL ? Name : "(Ordinal)");
1632 KEBUGCHECK(0);
1633 }
1634 return ExportAddress;
1635 }
1636
1637
1638 static PVOID
1639 LdrPEFixupForward(PCHAR ForwardName)
1640 {
1641 CHAR NameBuffer[128];
1642 UNICODE_STRING ModuleName;
1643 PCHAR p;
1644 PMODULE_OBJECT ModuleObject;
1645
1646 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1647
1648 strcpy(NameBuffer, ForwardName);
1649 p = strchr(NameBuffer, '.');
1650 if (p == NULL)
1651 {
1652 return NULL;
1653 }
1654
1655 *p = 0;
1656
1657 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
1658
1659 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1660 NameBuffer);
1661 ModuleObject = LdrGetModuleObject(&ModuleName);
1662 RtlFreeUnicodeString(&ModuleName);
1663
1664 DPRINT("ModuleObject: %p\n", ModuleObject);
1665
1666 if (ModuleObject == NULL)
1667 {
1668 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1669 return NULL;
1670 }
1671
1672 return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
1673 }
1674
1675 /* EOF */