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