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