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