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