- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[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.InLoadOrderLinks);
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.InLoadOrderLinks);
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->InLoadOrderLinks);
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 PRTL_PROCESS_MODULES Smi;
394 ANSI_STRING AnsiName;
395 PCHAR p;
396 KIRQL Irql;
397 PUNICODE_STRING UnicodeName;
398 ULONG tmpBufferSize = 0;
399 PWCHAR tmpNameBuffer;
400
401 KeAcquireSpinLock(&ModuleListLock,&Irql);
402
403 /* calculate required size */
404 current_entry = ModuleListHead.Flink;
405 while (current_entry != (&ModuleListHead))
406 {
407 ModuleCount++;
408 current = CONTAINING_RECORD(current_entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
409 tmpBufferSize += current->FullDllName.Length + sizeof(WCHAR) + sizeof(UNICODE_STRING);
410 current_entry = current_entry->Flink;
411 }
412
413 *ReqSize = sizeof(RTL_PROCESS_MODULES)+
414 (ModuleCount - 1) * sizeof(RTL_PROCESS_MODULE_INFORMATION);
415
416 if (Size < *ReqSize)
417 {
418 KeReleaseSpinLock(&ModuleListLock, Irql);
419 return(STATUS_INFO_LENGTH_MISMATCH);
420 }
421
422 /* allocate a temp buffer to store the module names */
423 UnicodeName = ExAllocatePool(NonPagedPool, tmpBufferSize);
424 if (UnicodeName == NULL)
425 {
426 KeReleaseSpinLock(&ModuleListLock, Irql);
427 return STATUS_INSUFFICIENT_RESOURCES;
428 }
429 tmpNameBuffer = (PWCHAR)((ULONG_PTR)UnicodeName + ModuleCount * sizeof(UNICODE_STRING));
430
431 /* fill the buffer */
432 memset(Buffer, '=', Size);
433
434 Smi = (PRTL_PROCESS_MODULES)Buffer;
435 Smi->NumberOfModules = ModuleCount;
436
437 ModuleCount = 0;
438 current_entry = ModuleListHead.Flink;
439 while (current_entry != (&ModuleListHead))
440 {
441 current = CONTAINING_RECORD(current_entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
442
443 Smi->Modules[ModuleCount].Section = 0; /* Always 0 */
444 Smi->Modules[ModuleCount].MappedBase = 0; /* Always 0 */
445 Smi->Modules[ModuleCount].ImageBase = current->DllBase;
446 Smi->Modules[ModuleCount].ImageSize = current->SizeOfImage;
447 Smi->Modules[ModuleCount].Flags = 0; /* Flags ??? (GN) */
448 Smi->Modules[ModuleCount].LoadOrderIndex = (USHORT)ModuleCount;
449 Smi->Modules[ModuleCount].InitOrderIndex = 0;
450 Smi->Modules[ModuleCount].LoadCount = 0; /* FIXME */
451 UnicodeName[ModuleCount].Buffer = tmpNameBuffer;
452 UnicodeName[ModuleCount].MaximumLength = current->FullDllName.Length + sizeof(WCHAR);
453 tmpNameBuffer += UnicodeName[ModuleCount].MaximumLength / sizeof(WCHAR);
454 RtlCopyUnicodeString(&UnicodeName[ModuleCount], &current->FullDllName);
455
456 ModuleCount++;
457 current_entry = current_entry->Flink;
458 }
459
460 KeReleaseSpinLock(&ModuleListLock, Irql);
461
462 for (ModuleCount = 0; ModuleCount < Smi->NumberOfModules; ModuleCount++)
463 {
464 AnsiName.Length = 0;
465 AnsiName.MaximumLength = 255;
466 AnsiName.Buffer = Smi->Modules[ModuleCount].FullPathName;
467 RtlUnicodeStringToAnsiString(&AnsiName, &UnicodeName[ModuleCount], FALSE);
468 AnsiName.Buffer[AnsiName.Length] = 0;
469 Smi->Modules[ModuleCount].InitOrderIndex = AnsiName.Length;
470
471 p = strrchr(AnsiName.Buffer, '\\');
472 if (p == NULL)
473 {
474 Smi->Modules[ModuleCount].OffsetToFileName = 0;
475 }
476 else
477 {
478 p++;
479 Smi->Modules[ModuleCount].OffsetToFileName = p - AnsiName.Buffer;
480 }
481 }
482
483 ExFreePool(UnicodeName);
484
485 return(STATUS_SUCCESS);
486 }
487
488
489 static VOID
490 LdrpBuildModuleBaseName (
491 PUNICODE_STRING BaseName,
492 PUNICODE_STRING FullName )
493 {
494 PWCHAR p;
495
496 DPRINT("LdrpBuildModuleBaseName()\n");
497 DPRINT("FullName %wZ\n", FullName);
498
499 p = wcsrchr(FullName->Buffer, L'\\');
500 if (p == NULL)
501 {
502 p = FullName->Buffer;
503 }
504 else
505 {
506 p++;
507 }
508
509 DPRINT("p %S\n", p);
510
511 RtlInitUnicodeString(BaseName, p);
512 }
513
514
515 static LONG
516 LdrpCompareModuleNames (
517 IN PUNICODE_STRING String1,
518 IN PUNICODE_STRING String2 )
519 {
520 ULONG len1, len2, i;
521 PWCHAR s1, s2, p;
522 WCHAR c1, c2;
523
524 if (String1 && String2)
525 {
526 /* Search String1 for last path component */
527 len1 = String1->Length / sizeof(WCHAR);
528 s1 = String1->Buffer;
529 for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
530 {
531 if (*p == L'\\')
532 {
533 if (i == String1->Length - sizeof(WCHAR))
534 {
535 s1 = NULL;
536 len1 = 0;
537 }
538 else
539 {
540 s1 = p + 1;
541 len1 = (String1->Length - i) / sizeof(WCHAR);
542 }
543 }
544 }
545
546 /* Search String2 for last path component */
547 len2 = String2->Length / sizeof(WCHAR);
548 s2 = String2->Buffer;
549 for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
550 {
551 if (*p == L'\\')
552 {
553 if (i == String2->Length - sizeof(WCHAR))
554 {
555 s2 = NULL;
556 len2 = 0;
557 }
558 else
559 {
560 s2 = p + 1;
561 len2 = (String2->Length - i) / sizeof(WCHAR);
562 }
563 }
564 }
565
566 /* Compare last path components */
567 if (s1 && s2)
568 {
569 while (1)
570 {
571 c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
572 c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
573 if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
574 return(0);
575 if (!c1 || !c2 || c1 != c2)
576 return(c1 - c2);
577 }
578 }
579 }
580
581 return(0);
582 }
583
584 PLDR_DATA_TABLE_ENTRY
585 NTAPI
586 LdrGetModuleObject ( PUNICODE_STRING ModuleName )
587 {
588 PLDR_DATA_TABLE_ENTRY Module;
589 PLIST_ENTRY Entry;
590 KIRQL Irql;
591
592 DPRINT("LdrGetModuleObject(%wZ) called\n", ModuleName);
593
594 KeAcquireSpinLock(&ModuleListLock,&Irql);
595
596 Entry = ModuleListHead.Flink;
597 while (Entry != &ModuleListHead)
598 {
599 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
600
601 DPRINT("Comparing %wZ and %wZ\n",
602 &Module->BaseDllName,
603 ModuleName);
604
605 if (!LdrpCompareModuleNames(&Module->BaseDllName, ModuleName))
606 {
607 DPRINT("Module %wZ\n", &Module->BaseDllName);
608 KeReleaseSpinLock(&ModuleListLock, Irql);
609 return(Module);
610 }
611
612 Entry = Entry->Flink;
613 }
614
615 KeReleaseSpinLock(&ModuleListLock, Irql);
616
617 DPRINT("Could not find module '%wZ'\n", ModuleName);
618
619 return(NULL);
620 }
621
622
623 /* ---------------------------------------------- PE Module support */
624
625 static ULONG
626 LdrLookupPageProtection (
627 PVOID PageStart,
628 PVOID DriverBase,
629 PIMAGE_FILE_HEADER PEFileHeader,
630 PIMAGE_SECTION_HEADER PESectionHeaders )
631 {
632 BOOLEAN Write = FALSE;
633 BOOLEAN Execute = FALSE;
634 ULONG Characteristics;
635 ULONG Idx;
636 ULONG Length;
637 PVOID BaseAddress;
638
639 for (Idx = 0; Idx < PEFileHeader->NumberOfSections && (!Write || !Execute); Idx++)
640 {
641 Characteristics = PESectionHeaders[Idx].Characteristics;
642 if (!(Characteristics & IMAGE_SCN_TYPE_NOLOAD))
643 {
644 Length = max(PESectionHeaders[Idx].Misc.VirtualSize, PESectionHeaders[Idx].SizeOfRawData);
645 BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
646 if (BaseAddress < (PVOID)((ULONG_PTR)PageStart + PAGE_SIZE) &&
647 PageStart < (PVOID)((ULONG_PTR)BaseAddress + Length))
648 {
649 if (Characteristics & IMAGE_SCN_CNT_CODE)
650 {
651 Execute = TRUE;
652 }
653 if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
654 {
655 Write = TRUE;
656 }
657 }
658 }
659 }
660 if (Write && Execute)
661 {
662 return PAGE_EXECUTE_READWRITE;
663 }
664 else if (Execute)
665 {
666 return PAGE_EXECUTE_READ;
667 }
668 else if (Write)
669 {
670 return PAGE_READWRITE;
671 }
672 else
673 {
674 return PAGE_READONLY;
675 }
676 }
677
678 static NTSTATUS
679 LdrPEProcessModule(
680 PVOID ModuleLoadBase,
681 PUNICODE_STRING FileName,
682 PLDR_DATA_TABLE_ENTRY *ModuleObject )
683 {
684 unsigned int DriverSize, Idx;
685 DWORD CurrentSize;
686 PVOID DriverBase;
687 PIMAGE_DOS_HEADER PEDosHeader;
688 PIMAGE_NT_HEADERS PENtHeaders;
689 PIMAGE_SECTION_HEADER PESectionHeaders;
690 PLDR_DATA_TABLE_ENTRY CreatedModuleObject;
691 NTSTATUS Status;
692 KIRQL Irql;
693
694 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
695
696 /* Get header pointers */
697 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
698 PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
699 PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
700 CHECKPOINT;
701
702 /* Check file magic numbers */
703 if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
704 {
705 CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
706 return STATUS_UNSUCCESSFUL;
707 }
708 if (PEDosHeader->e_lfanew == 0)
709 {
710 CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
711 return STATUS_UNSUCCESSFUL;
712 }
713 if (PENtHeaders->Signature != IMAGE_NT_SIGNATURE)
714 {
715 CPRINT("Incorrect PE magic: %08x\n", PENtHeaders->Signature);
716 return STATUS_UNSUCCESSFUL;
717 }
718 if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
719 {
720 CPRINT("Incorrect Architechture: %04x\n", PENtHeaders->FileHeader.Machine);
721 return STATUS_UNSUCCESSFUL;
722 }
723 CHECKPOINT;
724
725 /* FIXME: if image is fixed-address load, then fail */
726
727 /* FIXME: check/verify OS version number */
728
729 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
730 PENtHeaders->OptionalHeader.Magic,
731 PENtHeaders->OptionalHeader.MajorLinkerVersion,
732 PENtHeaders->OptionalHeader.MinorLinkerVersion);
733 DPRINT("Entry Point:%08lx\n", PENtHeaders->OptionalHeader.AddressOfEntryPoint);
734
735 /* Determine the size of the module */
736 DriverSize = 0;
737 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
738 {
739 if (!(PESectionHeaders[Idx].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
740 {
741 CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
742 DriverSize = max(DriverSize, CurrentSize);
743 }
744 }
745 DriverSize = ROUND_UP(DriverSize, PENtHeaders->OptionalHeader.SectionAlignment);
746 DPRINT("DriverSize %x, SizeOfImage %x\n",DriverSize, PENtHeaders->OptionalHeader.SizeOfImage);
747
748 /* Allocate a virtual section for the module */
749 DriverBase = NULL;
750 DriverBase = MmAllocateSection(DriverSize, DriverBase);
751 if (DriverBase == 0)
752 {
753 CPRINT("Failed to allocate a virtual section for driver\n");
754 return STATUS_UNSUCCESSFUL;
755 }
756 DPRINT("DriverBase for %wZ: %x\n", FileName, DriverBase);
757
758 /* Copy headers over */
759 memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
760
761 /* Copy image sections into virtual section */
762 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
763 {
764 CurrentSize = PESectionHeaders[Idx].VirtualAddress + PESectionHeaders[Idx].Misc.VirtualSize;
765 /* Copy current section into current offset of virtual section */
766 if (CurrentSize <= DriverSize &&
767 PESectionHeaders[Idx].SizeOfRawData)
768 {
769 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
770 PESectionHeaders[Idx].VirtualAddress + (ULONG_PTR)DriverBase);
771 memcpy((PVOID)((ULONG_PTR)DriverBase + PESectionHeaders[Idx].VirtualAddress),
772 (PVOID)((ULONG_PTR)ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
773 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
774 ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
775 }
776 }
777
778 /* Perform relocation fixups */
779 Status = LdrPEPerformRelocations(DriverBase, DriverSize);
780 if (!NT_SUCCESS(Status))
781 {
782 // MmFreeSection(DriverBase);
783 return Status;
784 }
785
786 /* Create the module */
787 CreatedModuleObject = ExAllocatePoolWithTag (
788 NonPagedPool, sizeof(LDR_DATA_TABLE_ENTRY), TAG_MODULE_OBJECT );
789 if (CreatedModuleObject == NULL)
790 {
791 // MmFreeSection(DriverBase);
792 return STATUS_INSUFFICIENT_RESOURCES;
793 }
794
795 RtlZeroMemory(CreatedModuleObject, sizeof(LDR_DATA_TABLE_ENTRY));
796
797 /* Initialize ModuleObject data */
798 CreatedModuleObject->DllBase = DriverBase;
799
800 CreatedModuleObject->FullDllName.Length = 0;
801 CreatedModuleObject->FullDllName.MaximumLength = FileName->Length + sizeof(UNICODE_NULL);
802 CreatedModuleObject->FullDllName.Buffer =
803 ExAllocatePoolWithTag(PagedPool, CreatedModuleObject->FullDllName.MaximumLength, TAG_LDR_WSTR);
804 if (CreatedModuleObject->FullDllName.Buffer == NULL)
805 {
806 ExFreePool(CreatedModuleObject);
807 // MmFreeSection(DriverBase);
808 return STATUS_INSUFFICIENT_RESOURCES;
809 }
810
811 RtlCopyUnicodeString(&CreatedModuleObject->FullDllName, FileName);
812 CreatedModuleObject->FullDllName.Buffer[FileName->Length / sizeof(WCHAR)] = 0;
813 LdrpBuildModuleBaseName(&CreatedModuleObject->BaseDllName,
814 &CreatedModuleObject->FullDllName);
815
816 CreatedModuleObject->EntryPoint =
817 (PVOID)((ULONG_PTR)DriverBase +
818 PENtHeaders->OptionalHeader.AddressOfEntryPoint);
819 CreatedModuleObject->SizeOfImage = DriverSize;
820 DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
821
822 /* Perform import fixups */
823 Status = LdrPEFixupImports(CreatedModuleObject);
824 if (!NT_SUCCESS(Status))
825 {
826 // MmFreeSection(DriverBase);
827 ExFreePool(CreatedModuleObject->FullDllName.Buffer);
828 ExFreePool(CreatedModuleObject);
829 return Status;
830 }
831
832 MmSetPageProtect(NULL, DriverBase, PAGE_READONLY);
833 /* Set the protections for the various parts of the driver */
834 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
835 {
836 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
837 ULONG Length;
838 PVOID BaseAddress;
839 PVOID PageAddress;
840 ULONG Protect;
841 Length = PESectionHeaders[Idx].Misc.VirtualSize;
842 BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
843 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
844
845 Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
846 #if 1
847 /*
848 * FIXME:
849 * This driver modifies a string in the first page of the text section while initialising.
850 */
851 if (0 == _wcsicmp(L"fireport.sys", FileName->Buffer))
852 {
853 Protect = PAGE_EXECUTE_READWRITE;
854 }
855 #endif
856 if (PageAddress < RVA(DriverBase, DriverSize))
857 {
858 MmSetPageProtect(NULL, PageAddress, Protect);
859 }
860
861 if (Characteristics & IMAGE_SCN_CNT_CODE)
862 {
863 if (Characteristics & IMAGE_SCN_MEM_WRITE)
864 {
865 Protect = PAGE_EXECUTE_READWRITE;
866 }
867 else
868 {
869 Protect = PAGE_EXECUTE_READ;
870 }
871 }
872 else if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
873 {
874 Protect = PAGE_READWRITE;
875 }
876 else
877 {
878 Protect = PAGE_READONLY;
879 }
880 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
881 while ((ULONG_PTR)PageAddress + PAGE_SIZE < (ULONG_PTR)BaseAddress + Length)
882 {
883 if (PageAddress < RVA(DriverBase, DriverSize))
884 {
885 MmSetPageProtect(NULL, PageAddress, Protect);
886 }
887 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
888 }
889 if (PageAddress < (PVOID)((ULONG_PTR)BaseAddress + Length) &&
890 PageAddress < RVA(DriverBase, DriverSize))
891 {
892 Protect = LdrLookupPageProtection(PageAddress, DriverBase, &PENtHeaders->FileHeader, PESectionHeaders);
893 MmSetPageProtect(NULL, PageAddress, Protect);
894 }
895 }
896
897 /* Insert module */
898 KeAcquireSpinLock(&ModuleListLock, &Irql);
899 InsertTailList(&ModuleListHead,
900 &CreatedModuleObject->InLoadOrderLinks);
901 KeReleaseSpinLock(&ModuleListLock, Irql);
902
903 *ModuleObject = CreatedModuleObject;
904
905 DPRINT("Loading Module %wZ...\n", FileName);
906
907 DPRINT("Module %wZ loaded at 0x%.08x.\n",
908 FileName, CreatedModuleObject->DllBase);
909
910 return STATUS_SUCCESS;
911 }
912
913
914 PVOID
915 INIT_FUNCTION
916 NTAPI
917 LdrSafePEProcessModule (
918 PVOID ModuleLoadBase,
919 PVOID DriverBase,
920 PVOID ImportModuleBase,
921 PULONG DriverSize)
922 {
923 unsigned int Idx;
924 ULONG CurrentSize;
925 PIMAGE_DOS_HEADER PEDosHeader;
926 PIMAGE_NT_HEADERS PENtHeaders;
927 PIMAGE_SECTION_HEADER PESectionHeaders;
928 NTSTATUS Status;
929
930 ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
931
932 /* Get header pointers */
933 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
934 PENtHeaders = RtlImageNtHeader(ModuleLoadBase);
935 PESectionHeaders = IMAGE_FIRST_SECTION(PENtHeaders);
936 CHECKPOINT;
937
938 /* Check file magic numbers */
939 if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
940 {
941 return NULL;
942 }
943 if (PEDosHeader->e_lfanew == 0)
944 {
945 return NULL;
946 }
947 if (PENtHeaders->Signature != IMAGE_NT_SIGNATURE)
948 {
949 return NULL;
950 }
951 if (PENtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
952 {
953 return NULL;
954 }
955
956 ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
957 PENtHeaders->OptionalHeader.Magic,
958 PENtHeaders->OptionalHeader.MajorLinkerVersion,
959 PENtHeaders->OptionalHeader.MinorLinkerVersion);
960 ps("Entry Point:%08lx\n", PENtHeaders->OptionalHeader.AddressOfEntryPoint);
961
962 /* Determine the size of the module */
963 *DriverSize = PENtHeaders->OptionalHeader.SizeOfImage;
964 ps("DriverSize %x\n",*DriverSize);
965
966 /* Copy headers over */
967 if (DriverBase != ModuleLoadBase)
968 {
969 memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders);
970 }
971
972 ps("Hdr: 0x%X\n", PENtHeaders);
973 ps("Hdr->SizeOfHeaders: 0x%X\n", PENtHeaders->OptionalHeader.SizeOfHeaders);
974 ps("FileHdr->NumberOfSections: 0x%X\n", PENtHeaders->FileHeader.NumberOfSections);
975
976 /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
977 address as it is mapped */
978 if (DriverBase != ModuleLoadBase)
979 {
980 CurrentSize = 0;
981
982 /* Copy image sections into virtual section */
983 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
984 {
985 PIMAGE_SECTION_HEADER Section = &PESectionHeaders[Idx];
986 // Copy current section into current offset of virtual section
987 if (Section->SizeOfRawData)
988 {
989 // ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
990 // PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
991 memcpy(Section->VirtualAddress + (char*)DriverBase,
992 Section->PointerToRawData + (char*)ModuleLoadBase,
993 Section->Misc.VirtualSize > Section->SizeOfRawData ? Section->SizeOfRawData : Section->Misc.VirtualSize);
994 }
995 if (Section->SizeOfRawData < Section->Misc.VirtualSize)
996 {
997 memset(Section->VirtualAddress + Section->SizeOfRawData + (char*)DriverBase,
998 0,
999 Section->Misc.VirtualSize - Section->SizeOfRawData);
1000 }
1001 CurrentSize += ROUND_UP(Section->Misc.VirtualSize,
1002 PENtHeaders->OptionalHeader.SectionAlignment);
1003 }
1004
1005 /* Perform relocation fixups */
1006 Status = LdrPEPerformRelocations(DriverBase, *DriverSize);
1007 if (!NT_SUCCESS(Status))
1008 {
1009 return NULL;
1010 }
1011 }
1012
1013 /* Perform import fixups */
1014 Status = LdrPEFixupImports(DriverBase == ModuleLoadBase ? &NtoskrnlModuleObject : &HalModuleObject);
1015 if (!NT_SUCCESS(Status))
1016 {
1017 return NULL;
1018 }
1019
1020 /* Set the page protection for the virtual sections */
1021 MmSetPageProtect(NULL, DriverBase, PAGE_READONLY);
1022 for (Idx = 0; Idx < PENtHeaders->FileHeader.NumberOfSections; Idx++)
1023 {
1024 ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1025 ULONG Length;
1026 PVOID BaseAddress;
1027 PVOID PageAddress;
1028 ULONG Protect;
1029 Length = PESectionHeaders[Idx].Misc.VirtualSize;
1030 BaseAddress = PESectionHeaders[Idx].VirtualAddress + (char*)DriverBase;
1031 PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1032
1033 if (Characteristics & IMAGE_SCN_MEM_EXECUTE)
1034 {
1035 if (Characteristics & IMAGE_SCN_MEM_WRITE)
1036 {
1037 Protect = PAGE_EXECUTE_READWRITE;
1038 }
1039 else
1040 {
1041 Protect = PAGE_EXECUTE_READ;
1042 }
1043 }
1044 else if (Characteristics & IMAGE_SCN_MEM_WRITE)
1045 {
1046 Protect = PAGE_READWRITE;
1047 }
1048 else
1049 {
1050 Protect = PAGE_READONLY;
1051 }
1052 while ((ULONG_PTR)PageAddress < (ULONG_PTR)BaseAddress + Length)
1053 {
1054 MmSetPageProtect(NULL, PageAddress, Protect);
1055 PageAddress = (PVOID)((ULONG_PTR)PageAddress + PAGE_SIZE);
1056 }
1057 if (DriverBase == ModuleLoadBase &&
1058 Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1059 {
1060 /* For ntoskrnl, we must stop after the bss section */
1061 break;
1062 }
1063
1064 }
1065
1066 return DriverBase;
1067 }
1068
1069 static PVOID
1070 LdrPEFixupForward ( PCHAR ForwardName )
1071 {
1072 CHAR NameBuffer[128];
1073 UNICODE_STRING ModuleName;
1074 PCHAR p;
1075 PLDR_DATA_TABLE_ENTRY ModuleObject;
1076
1077 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1078
1079 strcpy(NameBuffer, ForwardName);
1080 p = strchr(NameBuffer, '.');
1081 if (p == NULL)
1082 {
1083 return NULL;
1084 }
1085
1086 *p = 0;
1087
1088 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
1089
1090 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1091 NameBuffer);
1092 ModuleObject = LdrGetModuleObject(&ModuleName);
1093 RtlFreeUnicodeString(&ModuleName);
1094
1095 DPRINT("ModuleObject: %p\n", ModuleObject);
1096
1097 if (ModuleObject == NULL)
1098 {
1099 CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1100 return NULL;
1101 }
1102 return LdrPEGetExportByName(ModuleObject->DllBase, (PUCHAR)(p+1), 0xffff);
1103 }
1104
1105 static NTSTATUS
1106 LdrPEPerformRelocations (
1107 PVOID DriverBase,
1108 ULONG DriverSize)
1109 {
1110 PIMAGE_NT_HEADERS NtHeaders;
1111 PIMAGE_DATA_DIRECTORY RelocationDDir;
1112 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
1113 ULONG Count, i;
1114 PVOID Address, MaxAddress;
1115 PUSHORT TypeOffset;
1116 ULONG_PTR Delta;
1117 SHORT Offset;
1118 USHORT Type;
1119 PUSHORT ShortPtr;
1120 PULONG LongPtr;
1121
1122 NtHeaders = RtlImageNtHeader(DriverBase);
1123
1124 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1125 {
1126 return STATUS_UNSUCCESSFUL;
1127 }
1128
1129 RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1130
1131 if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
1132 {
1133 return STATUS_SUCCESS;
1134 }
1135
1136 Delta = (ULONG_PTR)DriverBase - NtHeaders->OptionalHeader.ImageBase;
1137 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)DriverBase + RelocationDDir->VirtualAddress);
1138 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
1139 MaxAddress = RVA(DriverBase, DriverSize);
1140
1141 while (RelocationDir < RelocationEnd &&
1142 RelocationDir->SizeOfBlock > 0)
1143 {
1144 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
1145 Address = RVA(DriverBase, RelocationDir->VirtualAddress);
1146 TypeOffset = (PUSHORT)(RelocationDir + 1);
1147
1148 for (i = 0; i < Count; i++)
1149 {
1150 Offset = *TypeOffset & 0xFFF;
1151 Type = *TypeOffset >> 12;
1152 ShortPtr = (PUSHORT)(RVA(Address, Offset));
1153
1154 /* Don't relocate after the end of the loaded driver */
1155 if ((PVOID)ShortPtr >= MaxAddress)
1156 {
1157 break;
1158 }
1159
1160 /*
1161 * Don't relocate within the relocation section itself.
1162 * GCC/LD generates sometimes relocation records for the relocation section.
1163 * This is a bug in GCC/LD.
1164 */
1165 if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
1166 (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
1167 {
1168 switch (Type)
1169 {
1170 case IMAGE_REL_BASED_ABSOLUTE:
1171 break;
1172
1173 case IMAGE_REL_BASED_HIGH:
1174 *ShortPtr += HIWORD(Delta);
1175 break;
1176
1177 case IMAGE_REL_BASED_LOW:
1178 *ShortPtr += LOWORD(Delta);
1179 break;
1180
1181 case IMAGE_REL_BASED_HIGHLOW:
1182 LongPtr = (PULONG)ShortPtr;
1183 *LongPtr += Delta;
1184 break;
1185
1186 case IMAGE_REL_BASED_HIGHADJ:
1187 case IMAGE_REL_BASED_MIPS_JMPADDR:
1188 default:
1189 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
1190 DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, *TypeOffset);
1191 return STATUS_UNSUCCESSFUL;
1192 }
1193 }
1194 TypeOffset++;
1195 }
1196 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
1197 }
1198
1199 return STATUS_SUCCESS;
1200 }
1201 #ifndef PATH_MAX
1202 #define PATH_MAX 260
1203 #endif
1204
1205 static NTSTATUS
1206 LdrPEGetOrLoadModule (
1207 PLDR_DATA_TABLE_ENTRY Module,
1208 PCHAR ImportedName,
1209 PLDR_DATA_TABLE_ENTRY* ImportedModule)
1210 {
1211 UNICODE_STRING DriverName;
1212 UNICODE_STRING NameString;
1213 WCHAR NameBuffer[PATH_MAX];
1214 NTSTATUS Status = STATUS_SUCCESS;
1215
1216 if (0 == _stricmp(ImportedName, "ntoskrnl") ||
1217 0 == _stricmp(ImportedName, "ntoskrnl.exe"))
1218 {
1219 *ImportedModule = &NtoskrnlModuleObject;
1220 return STATUS_SUCCESS;
1221 }
1222
1223 if (0 == _stricmp(ImportedName, "hal") ||
1224 0 == _stricmp(ImportedName, "hal.dll"))
1225 {
1226 *ImportedModule = &HalModuleObject;
1227 return STATUS_SUCCESS;
1228 }
1229
1230 RtlCreateUnicodeStringFromAsciiz (&DriverName, ImportedName);
1231 DPRINT("Import module: %wZ\n", &DriverName);
1232
1233 *ImportedModule = LdrGetModuleObject(&DriverName);
1234 if (*ImportedModule == NULL)
1235 {
1236 PWCHAR PathEnd;
1237 ULONG PathLength;
1238
1239 PathEnd = wcsrchr(Module->FullDllName.Buffer, L'\\');
1240 if (NULL != PathEnd)
1241 {
1242 PathLength = (PathEnd - Module->FullDllName.Buffer + 1) * sizeof(WCHAR);
1243 RtlCopyMemory(NameBuffer, Module->FullDllName.Buffer, PathLength);
1244 RtlCopyMemory(NameBuffer + (PathLength / sizeof(WCHAR)), DriverName.Buffer, DriverName.Length);
1245 NameString.Buffer = NameBuffer;
1246 NameString.MaximumLength = NameString.Length = PathLength + DriverName.Length;
1247
1248 /* NULL-terminate */
1249 NameString.MaximumLength++;
1250 NameBuffer[NameString.Length / sizeof(WCHAR)] = 0;
1251
1252 Status = LdrLoadModule(&NameString, ImportedModule);
1253 }
1254 else
1255 {
1256 DPRINT("Module '%wZ' not loaded yet\n", &DriverName);
1257 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\drivers\\");
1258 wcsncat(NameBuffer, DriverName.Buffer, DriverName.Length / sizeof(WCHAR));
1259 RtlInitUnicodeString(&NameString, NameBuffer);
1260 Status = LdrLoadModule(&NameString, ImportedModule);
1261 }
1262 if (!NT_SUCCESS(Status))
1263 {
1264 wcscpy(NameBuffer, L"\\SystemRoot\\system32\\");
1265 wcsncat(NameBuffer, DriverName.Buffer, DriverName.Length / sizeof(WCHAR));
1266 RtlInitUnicodeString(&NameString, NameBuffer);
1267 Status = LdrLoadModule(&NameString, ImportedModule);
1268 if (!NT_SUCCESS(Status))
1269 {
1270 DPRINT1("Unknown import module: %wZ (Status %lx)\n", &DriverName, Status);
1271 }
1272 }
1273 }
1274 RtlFreeUnicodeString(&DriverName);
1275 return Status;
1276 }
1277
1278 static PVOID
1279 LdrPEGetExportByName (
1280 PVOID BaseAddress,
1281 PUCHAR SymbolName,
1282 WORD Hint )
1283 {
1284 PIMAGE_EXPORT_DIRECTORY ExportDir;
1285 PDWORD * ExFunctions;
1286 PDWORD * ExNames;
1287 USHORT * ExOrdinals;
1288 PVOID ExName;
1289 ULONG Ordinal;
1290 PVOID Function;
1291 LONG minn, maxn, mid, res;
1292 ULONG ExportDirSize;
1293
1294 DPRINT("LdrPEGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
1295
1296 ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(BaseAddress,
1297 TRUE,
1298 IMAGE_DIRECTORY_ENTRY_EXPORT,
1299 &ExportDirSize);
1300 if (ExportDir == NULL)
1301 {
1302 DPRINT1("LdrPEGetExportByName(): no export directory!\n");
1303 return NULL;
1304 }
1305
1306
1307 /* The symbol names may be missing entirely */
1308 if (ExportDir->AddressOfNames == 0)
1309 {
1310 DPRINT("LdrPEGetExportByName(): symbol names missing entirely\n");
1311 return NULL;
1312 }
1313
1314 /*
1315 * Get header pointers
1316 */
1317 ExNames = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfNames);
1318 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
1319 ExFunctions = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
1320
1321 /*
1322 * Check the hint first
1323 */
1324 if (Hint < ExportDir->NumberOfNames)
1325 {
1326 ExName = RVA(BaseAddress, ExNames[Hint]);
1327 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
1328 {
1329 Ordinal = ExOrdinals[Hint];
1330 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1331 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
1332 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
1333 {
1334 DPRINT("Forward: %s\n", (PCHAR)Function);
1335 Function = LdrPEFixupForward((PCHAR)Function);
1336 if (Function == NULL)
1337 {
1338 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1339 }
1340 return Function;
1341 }
1342 if (Function != NULL)
1343 {
1344 return Function;
1345 }
1346 }
1347 }
1348
1349 /*
1350 * Binary search
1351 */
1352 minn = 0;
1353 maxn = ExportDir->NumberOfNames - 1;
1354 while (minn <= maxn)
1355 {
1356 mid = (minn + maxn) / 2;
1357
1358 ExName = RVA(BaseAddress, ExNames[mid]);
1359 res = strcmp(ExName, (PCHAR)SymbolName);
1360 if (res == 0)
1361 {
1362 Ordinal = ExOrdinals[mid];
1363 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1364 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
1365 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
1366 {
1367 DPRINT("Forward: %s\n", (PCHAR)Function);
1368 Function = LdrPEFixupForward((PCHAR)Function);
1369 if (Function == NULL)
1370 {
1371 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1372 }
1373 return Function;
1374 }
1375 if (Function != NULL)
1376 {
1377 return Function;
1378 }
1379 }
1380 else if (res > 0)
1381 {
1382 maxn = mid - 1;
1383 }
1384 else
1385 {
1386 minn = mid + 1;
1387 }
1388 }
1389
1390 ExName = RVA(BaseAddress, ExNames[mid]);
1391 DPRINT1("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
1392 return (PVOID)NULL;
1393 }
1394
1395 static PVOID
1396 LdrPEGetExportByOrdinal (
1397 PVOID BaseAddress,
1398 ULONG Ordinal )
1399 {
1400 PIMAGE_EXPORT_DIRECTORY ExportDir;
1401 ULONG ExportDirSize;
1402 PDWORD * ExFunctions;
1403 PVOID Function;
1404
1405 ExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData (
1406 BaseAddress,
1407 TRUE,
1408 IMAGE_DIRECTORY_ENTRY_EXPORT,
1409 &ExportDirSize);
1410
1411 ExFunctions = (PDWORD *)RVA(BaseAddress,
1412 ExportDir->AddressOfFunctions);
1413 DPRINT("LdrPEGetExportByOrdinal(Ordinal %d) = %x\n",
1414 Ordinal,
1415 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base]));
1416
1417 Function = 0 != ExFunctions[Ordinal - ExportDir->Base]
1418 ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1419 : NULL;
1420
1421 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1422 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize))
1423 {
1424 DPRINT("Forward: %s\n", (PCHAR)Function);
1425 Function = LdrPEFixupForward((PCHAR)Function);
1426 }
1427
1428 return Function;
1429 }
1430
1431 static NTSTATUS
1432 LdrPEProcessImportDirectoryEntry(
1433 PVOID DriverBase,
1434 PLDR_DATA_TABLE_ENTRY ImportedModule,
1435 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory )
1436 {
1437 PVOID* ImportAddressList;
1438 PULONG FunctionNameList;
1439 ULONG Ordinal;
1440
1441 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
1442 {
1443 return STATUS_UNSUCCESSFUL;
1444 }
1445
1446 /* Get the import address list. */
1447 ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
1448
1449 /* Get the list of functions to import. */
1450 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1451 {
1452 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
1453 }
1454 else
1455 {
1456 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
1457 }
1458
1459 /* Walk through function list and fixup addresses. */
1460 while (*FunctionNameList != 0L)
1461 {
1462 if ((*FunctionNameList) & 0x80000000)
1463 {
1464 Ordinal = (*FunctionNameList) & 0x7fffffff;
1465 *ImportAddressList = LdrPEGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1466 if ((*ImportAddressList) == NULL)
1467 {
1468 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1469 return STATUS_UNSUCCESSFUL;
1470 }
1471 }
1472 else
1473 {
1474 IMAGE_IMPORT_BY_NAME *pe_name;
1475 pe_name = RVA(DriverBase, *FunctionNameList);
1476 *ImportAddressList = LdrPEGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
1477 if ((*ImportAddressList) == NULL)
1478 {
1479 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1480 return STATUS_UNSUCCESSFUL;
1481 }
1482 }
1483 ImportAddressList++;
1484 FunctionNameList++;
1485 }
1486 return STATUS_SUCCESS;
1487 }
1488
1489 static NTSTATUS
1490 LdrPEFixupImports ( PLDR_DATA_TABLE_ENTRY Module )
1491 {
1492 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1493 PCHAR ImportedName;
1494 PLDR_DATA_TABLE_ENTRY ImportedModule;
1495 NTSTATUS Status;
1496 ULONG Size;
1497
1498 /* Process each import module */
1499 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1500 RtlImageDirectoryEntryToData(Module->DllBase,
1501 TRUE,
1502 IMAGE_DIRECTORY_ENTRY_IMPORT,
1503 &Size);
1504 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1505 while (ImportModuleDirectory->Name)
1506 {
1507 if (Module->SizeOfImage <= ImportModuleDirectory->Name)
1508 {
1509 DPRINT1("Invalid import directory in %wZ\n", &Module->FullDllName);
1510 return STATUS_SECTION_NOT_IMAGE;
1511 }
1512
1513 /* Check to make sure that import lib is kernel */
1514 ImportedName = (PCHAR) Module->DllBase + ImportModuleDirectory->Name;
1515
1516 Status = LdrPEGetOrLoadModule(Module, ImportedName, &ImportedModule);
1517 if (!NT_SUCCESS(Status))
1518 {
1519 return Status;
1520 }
1521
1522 Status = LdrPEProcessImportDirectoryEntry(Module->DllBase, ImportedModule, ImportModuleDirectory);
1523 if (!NT_SUCCESS(Status))
1524 {
1525 return Status;
1526 }
1527
1528 ImportModuleDirectory++;
1529 }
1530 return STATUS_SUCCESS;
1531 }
1532
1533 /* EOF */