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