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