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