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