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