Pass requested base address to MmAllocateSection()
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /* $Id: loader.c,v 1.148 2004/10/09 12:17:53 gvg Exp $
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 STATIC MODULE_OBJECT NtoskrnlModuleObject;
47 STATIC 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 = NtOpenFile(&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 = NtQueryInformationFile(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 = NtReadFile(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 NtClose(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_MAGIC && 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_SECTION_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_SECTION_CHAR_CODE)
680 {
681 Execute = TRUE;
682 }
683 if (Characteristics & (IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_BSS))
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_MAGIC)
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_PE_MAGIC)
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_SECTION_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) + sizeof(IMAGE_OPTIONAL_HEADER));
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 /* Set the protections for the various parts of the driver */
874 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
875 {
876 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
877 ULONG Length;
878 PVOID BaseAddress;
879 PVOID PageAddress;
880 ULONG Protect;
881 Length = PESectionHeaders[Idx].Misc.VirtualSize;
882 BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
883 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
884
885 Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
886 #if 1
887 /*
888 * FIXME:
889 * This driver modifies a string in the first page of the text section while initialising.
890 */
891 if (0 == _wcsicmp(L"fireport.sys", FileName->Buffer))
892 {
893 Protect = PAGE_EXECUTE_READWRITE;
894 }
895 #endif
896 if (PageAddress < DriverBase + DriverSize)
897 {
898 MmSetPageProtect(NULL, PageAddress, Protect);
899 }
900
901 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
902 {
903 if (Characteristics & IMAGE_SECTION_CHAR_WRITABLE)
904 {
905 Protect = PAGE_EXECUTE_READWRITE;
906 }
907 else
908 {
909 Protect = PAGE_EXECUTE_READ;
910 }
911 }
912 else if (Characteristics & (IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_BSS))
913 {
914 Protect = PAGE_READWRITE;
915 }
916 else
917 {
918 Protect = PAGE_READONLY;
919 }
920 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
921 while ((ULONG_PTR)PageAddress + PAGE_SIZE < (ULONG_PTR)BaseAddress + Length)
922 {
923 if (PageAddress < DriverBase + DriverSize)
924 {
925 MmSetPageProtect(NULL, PageAddress, Protect);
926 }
927 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
928 }
929 if (PageAddress < (PVOID)((ULONG_PTR)BaseAddress + Length) &&
930 PageAddress < DriverBase + DriverSize)
931 {
932 Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
933 MmSetPageProtect(NULL, PageAddress, Protect);
934 }
935 }
936
937 /* Insert module */
938 KeAcquireSpinLock(&ModuleListLock, &Irql);
939 InsertTailList(&ModuleListHead,
940 &CreatedModuleObject->ListEntry);
941 KeReleaseSpinLock(&ModuleListLock, Irql);
942
943
944 ModuleTextSection = ExAllocatePool(NonPagedPool,
945 sizeof(MODULE_TEXT_SECTION));
946 assert(ModuleTextSection);
947 RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
948 ModuleTextSection->Base = (ULONG)DriverBase;
949 ModuleTextSection->Length = DriverSize;
950 ModuleTextSection->Name = ExAllocatePool(NonPagedPool,
951 (CreatedModuleObject->BaseName.Length + 1) * sizeof(WCHAR));
952 RtlCopyMemory(ModuleTextSection->Name,
953 CreatedModuleObject->BaseName.Buffer,
954 CreatedModuleObject->BaseName.Length);
955 ModuleTextSection->Name[CreatedModuleObject->BaseName.Length / sizeof(WCHAR)] = 0;
956 ModuleTextSection->OptionalHeader =
957 CreatedModuleObject->Image.PE.OptionalHeader;
958 InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
959
960 CreatedModuleObject->TextSection = ModuleTextSection;
961
962 *ModuleObject = CreatedModuleObject;
963
964 DPRINT("Loading Module %wZ...\n", FileName);
965
966 if (KdDebuggerEnabled && (KdDebugState & KD_DEBUG_GDB))
967 {
968 DPRINT("Module %wZ loaded at 0x%.08x.\n",
969 FileName, CreatedModuleObject->Base);
970 }
971
972 return STATUS_SUCCESS;
973 }
974
975
976 PVOID INIT_FUNCTION
977 LdrSafePEProcessModule(PVOID ModuleLoadBase,
978 PVOID DriverBase,
979 PVOID ImportModuleBase,
980 PULONG DriverSize)
981 {
982 unsigned int Idx;
983 ULONG CurrentSize;
984 PIMAGE_DOS_HEADER PEDosHeader;
985 PIMAGE_NT_HEADERS PENtHeaders;
986 PIMAGE_SECTION_HEADER PESectionHeaders;
987 NTSTATUS Status;
988
989 ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
990
991 /* Get header pointers */
992 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
993 PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
994 PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
995 CHECKPOINT;
996
997 /* Check file magic numbers */
998 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
999 {
1000 return NULL;
1001 }
1002 if (PEDosHeader->e_lfanew == 0)
1003 {
1004 return NULL;
1005 }
1006 if (PENtHeaders->Signature != IMAGE_PE_MAGIC)
1007 {
1008 return NULL;
1009 }
1010 if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
1011 {
1012 return NULL;
1013 }
1014
1015 ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
1016 PENtHeaders->OptionalHeader.Magic,
1017 PENtHeaders->OptionalHeader.MajorLinkerVersion,
1018 PENtHeaders->OptionalHeader.MinorLinkerVersion);
1019 ps("Entry Point:%08lx\n", PENtHeaders->OptionalHeader.AddressOfEntryPoint);
1020
1021 /* Determine the size of the module */
1022 *DriverSize = PENtHeaders->OptionalHeader.SizeOfImage;
1023 ps("DriverSize %x\n",*DriverSize);
1024
1025 /* Copy headers over */
1026 if (DriverBase != ModuleLoadBase)
1027 {
1028 memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
1029 }
1030
1031 ps("Hdr: 0x%X\n", PENtHeaders);
1032 ps("Hdr->SizeOfHeaders: 0x%X\n", PENtHeaders->OptionalHeader.SizeOfHeaders);
1033 ps("FileHdr->NumberOfSections: 0x%X\n", PENtHeaders->FileHeader.NumberOfSections);
1034
1035 /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
1036 address as it is mapped */
1037 if (DriverBase != ModuleLoadBase)
1038 {
1039 CurrentSize = 0;
1040
1041 /* Copy image sections into virtual section */
1042 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
1043 {
1044 PIMAGE_SECTION_HEADER Section = &PESectionHeaders[Idx];
1045 // Copy current section into current offset of virtual section
1046 if (Section->SizeOfRawData)
1047 {
1048 // ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1049 // PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1050 memcpy(Section->VirtualAddress + (char*)DriverBase,
1051 Section->PointerToRawData + (char*)ModuleLoadBase,
1052 Section->Misc.VirtualSize > Section->SizeOfRawData ? Section->SizeOfRawData : Section->Misc.VirtualSize);
1053 }
1054 if (Section->SizeOfRawData < Section->Misc.VirtualSize)
1055 {
1056 memset(Section->VirtualAddress + Section->SizeOfRawData + (char*)DriverBase,
1057 0,
1058 Section->Misc.VirtualSize - Section->SizeOfRawData);
1059 }
1060 CurrentSize += ROUND_UP(Section->Misc.VirtualSize,
1061 PENtHeaders->OptionalHeader.SectionAlignment);
1062 }
1063
1064 /* Perform relocation fixups */
1065 Status = LdrPEPerformRelocations(DriverBase, *DriverSize);
1066 if (!NT_SUCCESS(Status))
1067 {
1068 return NULL;
1069 }
1070 }
1071
1072 /* Perform import fixups */
1073 Status = LdrPEFixupImports(DriverBase == ModuleLoadBase ? &NtoskrnlModuleObject : &HalModuleObject);
1074 if (!NT_SUCCESS(Status))
1075 {
1076 return NULL;
1077 }
1078
1079 /* Set the page protection for the virtual sections */
1080 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
1081 {
1082 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1083 ULONG Length;
1084 PVOID BaseAddress;
1085 PVOID PageAddress;
1086 ULONG Protect;
1087 Length = PESectionHeaders[Idx].Misc.VirtualSize;
1088 BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
1089 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1090
1091 if (Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE)
1092 {
1093 if (Characteristics & IMAGE_SECTION_CHAR_WRITABLE)
1094 {
1095 Protect = PAGE_EXECUTE_READWRITE;
1096 }
1097 else
1098 {
1099 Protect = PAGE_EXECUTE_READ;
1100 }
1101 }
1102 else if (Characteristics & IMAGE_SECTION_CHAR_WRITABLE)
1103 {
1104 Protect = PAGE_READWRITE;
1105 }
1106 else
1107 {
1108 Protect = PAGE_READONLY;
1109 }
1110 while ((ULONG_PTR)PageAddress < (ULONG_PTR)BaseAddress + Length)
1111 {
1112 MmSetPageProtect(NULL, PageAddress, Protect);
1113 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
1114 }
1115 if (DriverBase == ModuleLoadBase &&
1116 Characteristics & IMAGE_SECTION_CHAR_BSS)
1117 {
1118 /* For ntoskrnl, we must stop after the bss section */
1119 break;
1120 }
1121
1122 }
1123
1124 return DriverBase;
1125 }
1126
1127 static PVOID
1128 LdrPEFixupForward(PCHAR ForwardName)
1129 {
1130 CHAR NameBuffer[128];
1131 UNICODE_STRING ModuleName;
1132 PCHAR p;
1133 PMODULE_OBJECT ModuleObject;
1134
1135 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1136
1137 strcpy(NameBuffer, ForwardName);
1138 p = strchr(NameBuffer, '.');
1139 if (p == NULL)
1140 {
1141 return NULL;
1142 }
1143
1144 *p = 0;
1145
1146 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
1147
1148 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1149 NameBuffer);
1150 ModuleObject = LdrGetModuleObject(&ModuleName);
1151 RtlFreeUnicodeString(&ModuleName);
1152
1153 DPRINT("ModuleObject: %p\n", ModuleObject);
1154
1155 if (ModuleObject == NULL)
1156 {
1157 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1158 return NULL;
1159 }
1160 return LdrPEGetExportByName(ModuleObject->Base, p+1, 0xffff);
1161 }
1162
1163 static NTSTATUS
1164 LdrPEPerformRelocations(PVOID DriverBase,
1165 ULONG DriverSize)
1166 {
1167 PIMAGE_NT_HEADERS NtHeaders;
1168 PIMAGE_DATA_DIRECTORY RelocationDDir;
1169 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
1170 ULONG Count, i;
1171 PVOID Address, MaxAddress;
1172 PUSHORT TypeOffset;
1173 ULONG_PTR Delta;
1174 SHORT Offset;
1175 USHORT Type;
1176 PUSHORT ShortPtr;
1177 PULONG LongPtr;
1178
1179 NtHeaders = RtlImageNtHeader(DriverBase);
1180
1181 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1182 {
1183 return STATUS_UNSUCCESSFUL;
1184 }
1185
1186 RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1187
1188 if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
1189 {
1190 return STATUS_SUCCESS;
1191 }
1192
1193 Delta = (ULONG_PTR)DriverBase - NtHeaders->OptionalHeader.ImageBase;
1194 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)DriverBase + RelocationDDir->VirtualAddress);
1195 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
1196 MaxAddress = DriverBase + DriverSize;
1197
1198 while (RelocationDir < RelocationEnd &&
1199 RelocationDir->SizeOfBlock > 0)
1200 {
1201 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
1202 Address = DriverBase + RelocationDir->VirtualAddress;
1203 TypeOffset = (PUSHORT)(RelocationDir + 1);
1204
1205 for (i = 0; i < Count; i++)
1206 {
1207 Offset = *TypeOffset & 0xFFF;
1208 Type = *TypeOffset >> 12;
1209 ShortPtr = (PUSHORT)(Address + Offset);
1210
1211 /* Don't relocate after the end of the loaded driver */
1212 if ((PVOID)ShortPtr >= MaxAddress)
1213 {
1214 break;
1215 }
1216
1217 /*
1218 * Don't relocate within the relocation section itself.
1219 * GCC/LD generates sometimes relocation records for the relecotion section.
1220 * This is a bug in GCC/LD.
1221 */
1222 if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
1223 (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
1224 {
1225 switch (Type)
1226 {
1227 case IMAGE_REL_BASED_ABSOLUTE:
1228 break;
1229
1230 case IMAGE_REL_BASED_HIGH:
1231 *ShortPtr += HIWORD(Delta);
1232 break;
1233
1234 case IMAGE_REL_BASED_LOW:
1235 *ShortPtr += LOWORD(Delta);
1236 break;
1237
1238 case IMAGE_REL_BASED_HIGHLOW:
1239 LongPtr = (PULONG)ShortPtr;
1240 *LongPtr += Delta;
1241 break;
1242
1243 case IMAGE_REL_BASED_HIGHADJ:
1244 case IMAGE_REL_BASED_MIPS_JMPADDR:
1245 default:
1246 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
1247 DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, *TypeOffset);
1248 return STATUS_UNSUCCESSFUL;
1249 }
1250 }
1251 TypeOffset++;
1252 }
1253 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
1254 }
1255
1256 return STATUS_SUCCESS;
1257 }
1258
1259 static NTSTATUS
1260 LdrPEGetOrLoadModule(PMODULE_OBJECT Module,
1261 PCHAR ImportedName,
1262 PMODULE_OBJECT* ImportedModule)
1263 {
1264 UNICODE_STRING DriverName;
1265 UNICODE_STRING NameString;
1266 WCHAR NameBuffer[PATH_MAX];
1267 NTSTATUS Status = STATUS_SUCCESS;
1268
1269 if (0 == _stricmp(ImportedName, "ntoskrnl") ||
1270 0 == _stricmp(ImportedName, "ntoskrnl.exe"))
1271 {
1272 *ImportedModule = &NtoskrnlModuleObject;
1273 return STATUS_SUCCESS;
1274 }
1275
1276 if (0 == _stricmp(ImportedName, "hal") ||
1277 0 == _stricmp(ImportedName, "hal.dll"))
1278 {
1279 *ImportedModule = &HalModuleObject;
1280 return STATUS_SUCCESS;
1281 }
1282
1283 RtlCreateUnicodeStringFromAsciiz (&DriverName, ImportedName);
1284 DPRINT("Import module: %wZ\n", &DriverName);
1285
1286 *ImportedModule = LdrGetModuleObject(&DriverName);
1287 if (*ImportedModule == NULL)
1288 {
1289 PWCHAR PathEnd;
1290 ULONG PathLength;
1291
1292 PathEnd = wcsrchr(Module->FullName.Buffer, L'\\');
1293 if (NULL != PathEnd)
1294 {
1295 PathLength = (PathEnd - Module->FullName.Buffer + 1) * sizeof(WCHAR);
1296 RtlCopyMemory(NameBuffer, Module->FullName.Buffer, PathLength);
1297 RtlCopyMemory(NameBuffer + (PathLength / sizeof(WCHAR)), DriverName.Buffer, DriverName.Length);
1298 NameString.Buffer = NameBuffer;
1299 NameString.MaximumLength = NameString.Length = PathLength + DriverName.Length;
1300
1301 /* NULL-terminate */
1302 NameString.MaximumLength++;
1303 NameBuffer[NameString.Length / sizeof(WCHAR)] = 0;
1304
1305 Status = LdrLoadModule(&NameString, ImportedModule);
1306 }
1307 else
1308 {
1309 DPRINT("Module '%wZ' not loaded yet\n", &DriverName);
1310 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
1311 wcsncat(NameBuffer, DriverName.Buffer, DriverName.Length / sizeof(WCHAR));
1312 RtlInitUnicodeString(&NameString, NameBuffer);
1313 Status = LdrLoadModule(&NameString, ImportedModule);
1314 }
1315 if (!NT_SUCCESS(Status))
1316 {
1317 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
1318 wcsncat(NameBuffer, DriverName.Buffer, DriverName.Length / sizeof(WCHAR));
1319 RtlInitUnicodeString(&NameString, NameBuffer);
1320 Status = LdrLoadModule(&NameString, ImportedModule);
1321 if (!NT_SUCCESS(Status))
1322 {
1323 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &DriverName, Status);
1324 }
1325 }
1326 }
1327 RtlFreeUnicodeString(&DriverName);
1328 return Status;
1329 }
1330
1331 static PVOID
1332 LdrPEGetExportByName(PVOID BaseAddress,
1333 PUCHAR SymbolName,
1334 WORD Hint)
1335 {
1336 PIMAGE_EXPORT_DIRECTORY ExportDir;
1337 PDWORD * ExFunctions;
1338 PDWORD * ExNames;
1339 USHORT * ExOrdinals;
1340 ULONG i;
1341 PVOID ExName;
1342 ULONG Ordinal;
1343 PVOID Function;
1344 LONG minn, maxn;
1345 ULONG ExportDirSize;
1346
1347 DPRINT("LdrPEGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
1348
1349 ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(BaseAddress,
1350 TRUE,
1351 IMAGE_DIRECTORY_ENTRY_EXPORT,
1352 &ExportDirSize);
1353 if (ExportDir == NULL)
1354 {
1355 DPRINT1("LdrPEGetExportByName(): no export directory!\n");
1356 return NULL;
1357 }
1358
1359
1360 /* The symbol names may be missing entirely */
1361 if (ExportDir->AddressOfNames == 0)
1362 {
1363 DPRINT("LdrPEGetExportByName(): symbol names missing entirely\n");
1364 return NULL;
1365 }
1366
1367 /*
1368 * Get header pointers
1369 */
1370 ExNames = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfNames);
1371 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
1372 ExFunctions = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
1373
1374 /*
1375 * Check the hint first
1376 */
1377 if (Hint < ExportDir->NumberOfNames)
1378 {
1379 ExName = RVA(BaseAddress, ExNames[Hint]);
1380 if (strcmp(ExName, SymbolName) == 0)
1381 {
1382 Ordinal = ExOrdinals[Hint];
1383 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1384 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
1385 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
1386 {
1387 DPRINT("Forward: %s\n", (PCHAR)Function);
1388 Function = LdrPEFixupForward((PCHAR)Function);
1389 if (Function == NULL)
1390 {
1391 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1392 }
1393 return Function;
1394 }
1395 if (Function != NULL)
1396 {
1397 return Function;
1398 }
1399 }
1400 }
1401
1402 /*
1403 * Try a binary search first
1404 */
1405 minn = 0;
1406 maxn = ExportDir->NumberOfNames - 1;
1407 while (minn <= maxn)
1408 {
1409 LONG mid;
1410 LONG res;
1411
1412 mid = (minn + maxn) / 2;
1413
1414 ExName = RVA(BaseAddress, ExNames[mid]);
1415 res = strcmp(ExName, SymbolName);
1416 if (res == 0)
1417 {
1418 Ordinal = ExOrdinals[mid];
1419 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1420 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
1421 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
1422 {
1423 DPRINT("Forward: %s\n", (PCHAR)Function);
1424 Function = LdrPEFixupForward((PCHAR)Function);
1425 if (Function == NULL)
1426 {
1427 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1428 }
1429 return Function;
1430 }
1431 if (Function != NULL)
1432 {
1433 return Function;
1434 }
1435 }
1436 else if (minn == maxn)
1437 {
1438 DPRINT("LdrPEGetExportByName(): binary search failed\n");
1439 break;
1440 }
1441 else if (res > 0)
1442 {
1443 maxn = mid - 1;
1444 }
1445 else
1446 {
1447 minn = mid + 1;
1448 }
1449 }
1450
1451 /*
1452 * Fall back on a linear search
1453 */
1454 DPRINT("LdrPEGetExportByName(): Falling back on a linear search of export table\n");
1455 for (i = 0; i < ExportDir->NumberOfNames; i++)
1456 {
1457 ExName = RVA(BaseAddress, ExNames[i]);
1458 if (strcmp(ExName,SymbolName) == 0)
1459 {
1460 Ordinal = ExOrdinals[i];
1461 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1462 DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
1463 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
1464 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
1465 {
1466 DPRINT("Forward: %s\n", (PCHAR)Function);
1467 Function = LdrPEFixupForward((PCHAR)Function);
1468 }
1469 if (Function == NULL)
1470 {
1471 break;
1472 }
1473 return Function;
1474 }
1475 }
1476 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1477 return (PVOID)NULL;
1478 }
1479
1480 static PVOID
1481 LdrPEGetExportByOrdinal (PVOID BaseAddress,
1482 ULONG Ordinal)
1483 {
1484 PIMAGE_EXPORT_DIRECTORY ExportDir;
1485 ULONG ExportDirSize;
1486 PDWORD * ExFunctions;
1487 PVOID Function;
1488
1489 ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData (BaseAddress,
1490 TRUE,
1491 IMAGE_DIRECTORY_ENTRY_EXPORT,
1492 &ExportDirSize);
1493
1494 ExFunctions = (PDWORD *)RVA(BaseAddress,
1495 ExportDir->AddressOfFunctions);
1496 DPRINT("LdrPEGetExportByOrdinal(Ordinal %d) = %x\n",
1497 Ordinal,
1498 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base]));
1499
1500 Function = 0 != ExFunctions[Ordinal - ExportDir->Base]
1501 ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1502 : NULL;
1503
1504 if (((ULONG)Function >= (ULONG)ExportDir) &&
1505 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
1506 {
1507 DPRINT("Forward: %s\n", (PCHAR)Function);
1508 Function = LdrPEFixupForward((PCHAR)Function);
1509 }
1510
1511 return Function;
1512 }
1513
1514 static NTSTATUS
1515 LdrPEProcessImportDirectoryEntry(PVOID DriverBase,
1516 PMODULE_OBJECT ImportedModule,
1517 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory)
1518 {
1519 PVOID* ImportAddressList;
1520 PULONG FunctionNameList;
1521 ULONG Ordinal;
1522
1523 if (ImportModuleDirectory == NULL || ImportModuleDirectory->dwRVAModuleName == 0)
1524 {
1525 return STATUS_UNSUCCESSFUL;
1526 }
1527
1528 /* Get the import address list. */
1529 ImportAddressList = (PVOID*)(DriverBase + ImportModuleDirectory->dwRVAFunctionAddressList);
1530
1531 /* Get the list of functions to import. */
1532 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1533 {
1534 FunctionNameList = (PULONG) (DriverBase + ImportModuleDirectory->dwRVAFunctionNameList);
1535 }
1536 else
1537 {
1538 FunctionNameList = (PULONG)(DriverBase + ImportModuleDirectory->dwRVAFunctionAddressList);
1539 }
1540
1541 /* Walk through function list and fixup addresses. */
1542 while (*FunctionNameList != 0L)
1543 {
1544 if ((*FunctionNameList) & 0x80000000)
1545 {
1546 Ordinal = (*FunctionNameList) & 0x7fffffff;
1547 *ImportAddressList = LdrPEGetExportByOrdinal(ImportedModule->Base, Ordinal);
1548 if ((*ImportAddressList) == NULL)
1549 {
1550 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullName);
1551 return STATUS_UNSUCCESSFUL;
1552 }
1553 }
1554 else
1555 {
1556 IMAGE_IMPORT_BY_NAME *pe_name;
1557 pe_name = RVA(DriverBase, *FunctionNameList);
1558 *ImportAddressList = LdrPEGetExportByName(ImportedModule->Base, pe_name->Name, pe_name->Hint);
1559 if ((*ImportAddressList) == NULL)
1560 {
1561 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullName);
1562 return STATUS_UNSUCCESSFUL;
1563 }
1564 }
1565 ImportAddressList++;
1566 FunctionNameList++;
1567 }
1568 return STATUS_SUCCESS;
1569 }
1570
1571 static NTSTATUS
1572 LdrPEFixupImports(PMODULE_OBJECT Module)
1573 {
1574 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1575 PCHAR ImportedName;
1576 PMODULE_OBJECT ImportedModule;
1577 NTSTATUS Status;
1578
1579 /* Process each import module */
1580 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1581 RtlImageDirectoryEntryToData(Module->Base,
1582 TRUE,
1583 IMAGE_DIRECTORY_ENTRY_IMPORT,
1584 NULL);
1585 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1586 while (ImportModuleDirectory->dwRVAModuleName)
1587 {
1588 /* Check to make sure that import lib is kernel */
1589 ImportedName = (PCHAR) Module->Base + ImportModuleDirectory->dwRVAModuleName;
1590
1591 Status = LdrPEGetOrLoadModule(Module, ImportedName, &ImportedModule);
1592 if (!NT_SUCCESS(Status))
1593 {
1594 return Status;
1595 }
1596
1597 Status = LdrPEProcessImportDirectoryEntry(Module->Base, ImportedModule, ImportModuleDirectory);
1598 if (!NT_SUCCESS(Status))
1599 {
1600 return Status;
1601 }
1602
1603 ImportModuleDirectory++;
1604 }
1605 return STATUS_SUCCESS;
1606 }
1607
1608 /* EOF */