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