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