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