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