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