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