Enable atom functions
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /* $Id: loader.c,v 1.71 2001/03/30 17:26:42 dwelch Exp $
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 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 * Jason Filby (jasonfilby@yahoo.com)
10 * UPDATE HISTORY:
11 * DW 22/05/98 Created
12 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
13 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
14 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
15 * JM 14/12/98 Built initial PE user module loader
16 * RJJ 06/03/99 Moved user PE loader into NTDLL
17 * JF 26/01/2000 Recoded some parts to retrieve export details correctly
18 * DW 27/06/00 Removed redundant header files
19 */
20
21 /* INCLUDES *****************************************************************/
22
23 #include <limits.h>
24 #include <ddk/ntddk.h>
25 #include <internal/module.h>
26 #include <internal/ntoskrnl.h>
27 #include <internal/mm.h>
28 #include <internal/ob.h>
29 #include <internal/ps.h>
30 #include <internal/ldr.h>
31 #include <internal/pool.h>
32
33 #define NDEBUG
34 #include <internal/debug.h>
35
36
37 /* FIXME: this should appear in a kernel header file */
38 NTSTATUS IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry);
39
40 /* MACROS ********************************************************************/
41
42 #define MODULE_ROOT_NAME L"\\Modules\\"
43
44 /* GLOBALS *******************************************************************/
45
46 LIST_ENTRY ModuleListHead;
47 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
48 LIST_ENTRY ModuleTextListHead;
49 STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
50 /* STATIC MODULE_TEXT_SECTION HalTextSection; */
51
52 #define TAG_DRIVER_MEM TAG('D', 'R', 'V', 'M')
53 #define TAG_SYM_BUF TAG('S', 'Y', 'M', 'B')
54
55 /* FORWARD DECLARATIONS ******************************************************/
56
57 PMODULE_OBJECT LdrLoadModule(PUNICODE_STRING Filename);
58 PMODULE_OBJECT LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName);
59 PVOID LdrGetExportAddress(PMODULE_OBJECT ModuleObject, char *Name, unsigned short Hint);
60 static PMODULE_OBJECT LdrOpenModule(PUNICODE_STRING Filename);
61 static NTSTATUS LdrCreateModule(PVOID ObjectBody,
62 PVOID Parent,
63 PWSTR RemainingPath,
64 POBJECT_ATTRIBUTES ObjectAttributes);
65 static VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
66 PUNICODE_STRING FullName);
67
68 /* PE Driver load support */
69 static PMODULE_OBJECT LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName);
70 static PVOID LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
71 char *Name,
72 unsigned short Hint);
73 static PMODULE_OBJECT LdrPEGetModuleObject(PUNICODE_STRING ModuleName);
74 static PVOID LdrPEFixupForward(PCHAR ForwardName);
75
76
77 /* FUNCTIONS *****************************************************************/
78
79 VOID
80 LdrInit1(VOID)
81 {
82 PIMAGE_DOS_HEADER DosHeader;
83 PIMAGE_FILE_HEADER FileHeader;
84 PIMAGE_OPTIONAL_HEADER OptionalHeader;
85 PIMAGE_SECTION_HEADER SectionList;
86
87 InitializeListHead(&ModuleTextListHead);
88
89 DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
90 FileHeader =
91 (PIMAGE_FILE_HEADER) ((DWORD)KERNEL_BASE +
92 DosHeader->e_lfanew + sizeof(ULONG));
93 OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
94 ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
95 SectionList = (PIMAGE_SECTION_HEADER)
96 ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
97 NtoskrnlTextSection.Base = KERNEL_BASE;
98 NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
99 SectionList[0].VirtualAddress;
100 NtoskrnlTextSection.Name = L"ntoskrnl.exe";
101 InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
102 }
103
104 VOID LdrInitModuleManagement(VOID)
105 {
106 HANDLE DirHandle, ModuleHandle;
107 NTSTATUS Status;
108 WCHAR NameBuffer[60];
109 UNICODE_STRING ModuleName;
110 OBJECT_ATTRIBUTES ObjectAttributes;
111 PIMAGE_DOS_HEADER DosHeader;
112 PMODULE_OBJECT ModuleObject;
113
114 /* Register the process object type */
115 IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
116 IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'T');
117 IoDriverObjectType->TotalObjects = 0;
118 IoDriverObjectType->TotalHandles = 0;
119 IoDriverObjectType->MaxObjects = ULONG_MAX;
120 IoDriverObjectType->MaxHandles = ULONG_MAX;
121 IoDriverObjectType->PagedPoolCharge = 0;
122 IoDriverObjectType->NonpagedPoolCharge = sizeof(MODULE);
123 IoDriverObjectType->Dump = NULL;
124 IoDriverObjectType->Open = NULL;
125 IoDriverObjectType->Close = NULL;
126 IoDriverObjectType->Delete = NULL;
127 IoDriverObjectType->Parse = NULL;
128 IoDriverObjectType->Security = NULL;
129 IoDriverObjectType->QueryName = NULL;
130 IoDriverObjectType->OkayToClose = NULL;
131 IoDriverObjectType->Create = LdrCreateModule;
132 RtlInitUnicodeString(&IoDriverObjectType->TypeName, L"Driver");
133
134 /* Create Modules object directory */
135 wcscpy(NameBuffer, MODULE_ROOT_NAME);
136 *(wcsrchr(NameBuffer, L'\\')) = 0;
137 RtlInitUnicodeString (&ModuleName, NameBuffer);
138 InitializeObjectAttributes(&ObjectAttributes,
139 &ModuleName,
140 0,
141 NULL,
142 NULL);
143 DPRINT("Create dir: %wZ\n", &ModuleName);
144 Status = NtCreateDirectoryObject(&DirHandle, 0, &ObjectAttributes);
145 assert(NT_SUCCESS(Status));
146
147 /* Add module entry for NTOSKRNL */
148 wcscpy(NameBuffer, MODULE_ROOT_NAME);
149 wcscat(NameBuffer, L"ntoskrnl.exe");
150 RtlInitUnicodeString (&ModuleName, NameBuffer);
151 DPRINT("Kernel's Module name is: %wZ\n", &ModuleName);
152
153 /* Initialize ObjectAttributes for ModuleObject */
154 InitializeObjectAttributes(&ObjectAttributes,
155 &ModuleName,
156 0,
157 NULL,
158 NULL);
159
160 /* Create module object */
161 ModuleHandle = 0;
162 ModuleObject = ObCreateObject(&ModuleHandle,
163 STANDARD_RIGHTS_REQUIRED,
164 &ObjectAttributes,
165 IoDriverObjectType);
166 assert(ModuleObject != NULL);
167
168 InitializeListHead(&ModuleListHead);
169
170 /* Initialize ModuleObject data */
171 ModuleObject->Base = (PVOID) KERNEL_BASE;
172 ModuleObject->Flags = MODULE_FLAG_PE;
173 InsertTailList(&ModuleListHead,
174 &ModuleObject->ListEntry);
175 RtlCreateUnicodeString(&ModuleObject->FullName,
176 L"ntoskrnl.exe");
177 LdrpBuildModuleBaseName(&ModuleObject->BaseName,
178 &ModuleObject->FullName);
179
180 DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
181 ModuleObject->Image.PE.FileHeader =
182 (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
183 DosHeader->e_lfanew + sizeof(ULONG));
184 ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
185 ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
186 ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
187 ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
188 ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
189 ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
190 DPRINT("ModuleObject:%08x entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
191 ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
192
193 /* FIXME: Add fake module entry for HAL */
194
195 }
196
197 /*
198 * load the auto config drivers.
199 */
200 static VOID LdrLoadAutoConfigDriver (LPWSTR RelativeDriverName)
201 {
202 WCHAR TmpFileName [MAX_PATH];
203 NTSTATUS Status;
204 UNICODE_STRING DriverName;
205
206 DbgPrint("Loading %S\n",RelativeDriverName);
207
208 wcscpy(TmpFileName, L"\\SystemRoot\\system32\\drivers\\");
209 wcscat(TmpFileName, RelativeDriverName);
210 RtlInitUnicodeString (&DriverName, TmpFileName);
211
212 Status = LdrLoadDriver(&DriverName);
213 if (!NT_SUCCESS(Status))
214 {
215 DbgPrint("driver load failed, status (%x)\n", Status);
216 // KeBugCheck(0);
217 }
218 }
219
220
221 VOID LdrLoadAutoConfigDrivers (VOID)
222 {
223 /*
224 * Keyboard driver
225 */
226 LdrLoadAutoConfigDriver( L"keyboard.sys" );
227
228 /*
229 * Raw console driver
230 */
231 LdrLoadAutoConfigDriver( L"blue.sys" );
232
233 /*
234 *
235 */
236 LdrLoadAutoConfigDriver(L"vidport.sys");
237
238 /*
239 *
240 */
241 LdrLoadAutoConfigDriver(L"vgamp.sys");
242
243 /*
244 * Minix filesystem driver
245 */
246 LdrLoadAutoConfigDriver(L"minixfs.sys");
247 }
248
249
250 static NTSTATUS
251 LdrCreateModule(PVOID ObjectBody,
252 PVOID Parent,
253 PWSTR RemainingPath,
254 POBJECT_ATTRIBUTES ObjectAttributes)
255 {
256 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
257 ObjectBody,
258 Parent,
259 RemainingPath);
260 if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
261 {
262 return STATUS_UNSUCCESSFUL;
263 }
264 if (Parent != NULL && RemainingPath != NULL)
265 {
266 ObAddEntryDirectory(Parent, ObjectBody, RemainingPath + 1);
267 }
268
269 return STATUS_SUCCESS;
270 }
271
272 /*
273 * FUNCTION: Loads a kernel driver
274 * ARGUMENTS:
275 * FileName = Driver to load
276 * RETURNS: Status
277 */
278
279 NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename)
280 {
281 PMODULE_OBJECT ModuleObject;
282
283 ModuleObject = LdrLoadModule(Filename);
284 if (ModuleObject == 0)
285 {
286 return STATUS_UNSUCCESSFUL;
287 }
288
289 /* FIXME: should we dereference the ModuleObject here? */
290
291 return IoInitializeDriver(ModuleObject->EntryPoint);
292 }
293
294 NTSTATUS LdrLoadGdiDriver (PUNICODE_STRING DriverName,
295 PVOID *ImageAddress,
296 PVOID *SectionPointer,
297 PVOID *EntryPoint,
298 PVOID *ExportSectionPointer)
299 {
300 PMODULE_OBJECT ModuleObject;
301
302 ModuleObject = LdrLoadModule(DriverName);
303 if (ModuleObject == 0)
304 {
305 return STATUS_UNSUCCESSFUL;
306 }
307
308 if (ImageAddress)
309 *ImageAddress = ModuleObject->Base;
310
311 // if (SectionPointer)
312 // *SectionPointer = ModuleObject->
313
314 if (EntryPoint)
315 *EntryPoint = ModuleObject->EntryPoint;
316
317 // if (ExportSectionPointer)
318 // *ExportSectionPointer = ModuleObject->
319
320 return STATUS_SUCCESS;
321 }
322
323
324 PMODULE_OBJECT
325 LdrLoadModule(PUNICODE_STRING Filename)
326 {
327 PVOID ModuleLoadBase;
328 NTSTATUS Status;
329 HANDLE FileHandle;
330 OBJECT_ATTRIBUTES ObjectAttributes;
331 PMODULE_OBJECT ModuleObject;
332 FILE_STANDARD_INFORMATION FileStdInfo;
333
334 /* Check for module already loaded */
335 if ((ModuleObject = LdrOpenModule(Filename)) != NULL)
336 {
337 return ModuleObject;
338 }
339
340 DPRINT("Loading Module %wZ...\n", Filename);
341
342 /* Open the Module */
343 InitializeObjectAttributes(&ObjectAttributes,
344 Filename,
345 0,
346 NULL,
347 NULL);
348 CHECKPOINT;
349 Status = NtOpenFile(&FileHandle,
350 FILE_ALL_ACCESS,
351 &ObjectAttributes,
352 NULL, 0, 0);
353 CHECKPOINT;
354 if (!NT_SUCCESS(Status))
355 {
356 DbgPrint("Could not open module file: %wZ\n", Filename);
357 return 0;
358 }
359 CHECKPOINT;
360
361 /* Get the size of the file */
362 Status = NtQueryInformationFile(FileHandle,
363 NULL,
364 &FileStdInfo,
365 sizeof(FileStdInfo),
366 FileStandardInformation);
367 if (!NT_SUCCESS(Status))
368 {
369 DbgPrint("Could not get file size\n");
370 return 0;
371 }
372 CHECKPOINT;
373
374 /* Allocate nonpageable memory for driver */
375 ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
376 FileStdInfo.EndOfFile.u.LowPart,
377 TAG_DRIVER_MEM);
378
379 if (ModuleLoadBase == NULL)
380 {
381 DbgPrint("could not allocate memory for module");
382 return 0;
383 }
384 CHECKPOINT;
385
386 /* Load driver into memory chunk */
387 Status = NtReadFile(FileHandle,
388 0, 0, 0, 0,
389 ModuleLoadBase,
390 FileStdInfo.EndOfFile.u.LowPart,
391 0, 0);
392 if (!NT_SUCCESS(Status))
393 {
394 DbgPrint("could not read module file into memory");
395 ExFreePool(ModuleLoadBase);
396
397 return 0;
398 }
399 CHECKPOINT;
400
401 NtClose(FileHandle);
402
403 ModuleObject = LdrProcessModule(ModuleLoadBase, Filename);
404
405 /* Cleanup */
406 ExFreePool(ModuleLoadBase);
407
408 return ModuleObject;
409 }
410
411 NTSTATUS
412 LdrProcessDriver(PVOID ModuleLoadBase, PCHAR FileName)
413 {
414 PMODULE_OBJECT ModuleObject;
415 UNICODE_STRING ModuleName;
416
417 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
418 FileName);
419 ModuleObject = LdrProcessModule(ModuleLoadBase,
420 &ModuleName);
421 RtlFreeUnicodeString(&ModuleName);
422 if (ModuleObject == NULL)
423 {
424 DPRINT1("Driver load was unsuccessful\n");
425 return(STATUS_UNSUCCESSFUL);
426 }
427
428 /* FIXME: should we dereference the ModuleObject here? */
429
430 return(IoInitializeDriver(ModuleObject->EntryPoint));
431 }
432
433 PMODULE_OBJECT
434 LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName)
435 {
436 PIMAGE_DOS_HEADER PEDosHeader;
437
438 /* If MZ header exists */
439 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
440 if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
441 {
442 return LdrPEProcessModule(ModuleLoadBase, ModuleName);
443 }
444
445 DPRINT1("Module wasn't PE\n");
446 return 0;
447 }
448
449 static PMODULE_OBJECT
450 LdrOpenModule(PUNICODE_STRING Filename)
451 {
452 NTSTATUS Status;
453 WCHAR NameBuffer[60];
454 UNICODE_STRING ModuleName;
455 OBJECT_ATTRIBUTES ObjectAttributes;
456 PMODULE_OBJECT ModuleObject;
457 UNICODE_STRING RemainingPath;
458
459 wcscpy(NameBuffer, MODULE_ROOT_NAME);
460 if (wcsrchr(Filename->Buffer, '\\') != 0)
461 {
462 wcscat(NameBuffer, wcsrchr(Filename->Buffer, '\\') + 1);
463 }
464 else
465 {
466 wcscat(NameBuffer, Filename->Buffer);
467 }
468 RtlInitUnicodeString (&ModuleName, NameBuffer);
469 InitializeObjectAttributes(&ObjectAttributes,
470 &ModuleName,
471 0,
472 NULL,
473 NULL);
474
475 Status = ObFindObject(&ObjectAttributes,
476 (PVOID *) &ModuleObject,
477 &RemainingPath,
478 NULL);
479 CHECKPOINT;
480 if (NT_SUCCESS(Status) && (RemainingPath.Buffer == NULL || *(RemainingPath.Buffer) == 0))
481 {
482 DPRINT("Module %wZ at %p\n", Filename, ModuleObject);
483 RtlFreeUnicodeString (&RemainingPath);
484
485 return ModuleObject;
486 }
487
488 RtlFreeUnicodeString (&RemainingPath);
489
490 return NULL;
491 }
492
493 PVOID
494 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
495 char *Name,
496 unsigned short Hint)
497 {
498 if (ModuleObject->Flags & MODULE_FLAG_PE)
499 {
500 return LdrPEGetExportAddress(ModuleObject, Name, Hint);
501 }
502 else
503 {
504 return 0;
505 }
506 }
507
508 NTSTATUS
509 LdrpQueryModuleInformation(PVOID Buffer,
510 ULONG Size,
511 PULONG ReqSize)
512 {
513 PLIST_ENTRY current_entry;
514 PMODULE_OBJECT current;
515 ULONG ModuleCount = 0;
516 PSYSTEM_MODULE_INFORMATION Smi;
517 ANSI_STRING AnsiName;
518 PCHAR p;
519
520 // KeAcquireSpinLock(&ModuleListLock,&oldlvl);
521
522 /* calculate required size */
523 current_entry = ModuleListHead.Flink;
524 while (current_entry != (&ModuleListHead))
525 {
526 ModuleCount++;
527 current_entry = current_entry->Flink;
528 }
529
530 *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
531 (ModuleCount - 1) * sizeof(SYSTEM_MODULE_ENTRY);
532
533 if (Size < *ReqSize)
534 {
535 // KeReleaseSpinLock(&ModuleListLock,oldlvl);
536 return STATUS_INFO_LENGTH_MISMATCH;
537 }
538
539 /* fill the buffer */
540 memset(Buffer, '=', Size);
541
542 Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
543 Smi->Count = ModuleCount;
544
545 ModuleCount = 0;
546 current_entry = ModuleListHead.Flink;
547 while (current_entry != (&ModuleListHead))
548 {
549 current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
550
551 Smi->Module[ModuleCount].Unknown2 = 0; /* Always 0 */
552 Smi->Module[ModuleCount].BaseAddress = current->Base;
553 Smi->Module[ModuleCount].Size = current->Length;
554 Smi->Module[ModuleCount].Unknown3 = 0; /* Flags ??? */
555 Smi->Module[ModuleCount].EntryIndex = ModuleCount;
556
557 AnsiName.Length = 0;
558 AnsiName.MaximumLength = 256;
559 AnsiName.Buffer = Smi->Module[ModuleCount].Name;
560 RtlUnicodeStringToAnsiString(&AnsiName,
561 &current->FullName,
562 FALSE);
563
564 p = strrchr (AnsiName.Buffer, '\\');
565 if (p == NULL)
566 {
567 Smi->Module[ModuleCount].PathLength = 0;
568 Smi->Module[ModuleCount].NameLength = strlen(AnsiName.Buffer);
569 }
570 else
571 {
572 p++;
573 Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
574 Smi->Module[ModuleCount].NameLength = strlen(p);
575 }
576
577 ModuleCount++;
578 current_entry = current_entry->Flink;
579 }
580
581 // KeReleaseSpinLock(&ModuleListLock,oldlvl);
582
583 return STATUS_SUCCESS;
584 }
585
586
587 static VOID
588 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
589 PUNICODE_STRING FullName)
590 {
591 UNICODE_STRING Name;
592 PWCHAR p;
593 PWCHAR q;
594
595 DPRINT("LdrpBuildModuleBaseName()\n");
596 DPRINT("FullName %wZ\n", FullName);
597
598 p = wcsrchr(FullName->Buffer, '\\');
599 if (p == NULL)
600 {
601 p = FullName->Buffer;
602 }
603 else
604 {
605 p++;
606 }
607
608 DPRINT("p %S\n", p);
609
610 RtlCreateUnicodeString(&Name, p);
611
612 q = wcschr(p, '.');
613 if (q != NULL)
614 {
615 *q = (WCHAR)0;
616 }
617
618 DPRINT("p %S\n", p);
619
620 RtlCreateUnicodeString(BaseName, p);
621 RtlFreeUnicodeString(&Name);
622 }
623
624
625 /* ---------------------------------------------- PE Module support */
626
627 PMODULE_OBJECT
628 LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName)
629 {
630 unsigned int DriverSize, Idx, Idx2;
631 ULONG RelocDelta, NumRelocs;
632 DWORD CurrentSize, TotalRelocs;
633 PVOID DriverBase;
634 PULONG PEMagic;
635 PIMAGE_DOS_HEADER PEDosHeader;
636 PIMAGE_FILE_HEADER PEFileHeader;
637 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
638 PIMAGE_SECTION_HEADER PESectionHeaders;
639 PRELOCATION_DIRECTORY RelocDir;
640 PRELOCATION_ENTRY RelocEntry;
641 PMODULE_OBJECT LibraryModuleObject;
642 HANDLE ModuleHandle;
643 PMODULE_OBJECT ModuleObject;
644 PVOID *ImportAddressList;
645 PULONG FunctionNameList;
646 PCHAR pName, SymbolNameBuf;
647 WORD Hint;
648 OBJECT_ATTRIBUTES ObjectAttributes;
649 UNICODE_STRING ModuleName;
650 WCHAR NameBuffer[60];
651 MODULE_TEXT_SECTION* ModuleTextSection;
652
653 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
654
655 /* Get header pointers */
656 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
657 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
658 PEDosHeader->e_lfanew);
659 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
660 PEDosHeader->e_lfanew + sizeof(ULONG));
661 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
662 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
663 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
664 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
665 sizeof(IMAGE_OPTIONAL_HEADER));
666 CHECKPOINT;
667
668 /* Check file magic numbers */
669 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
670 {
671 DbgPrint("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
672 return 0;
673 }
674 if (PEDosHeader->e_lfanew == 0)
675 {
676 DbgPrint("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
677 return 0;
678 }
679 if (*PEMagic != IMAGE_PE_MAGIC)
680 {
681 DbgPrint("Incorrect PE magic: %08x\n", *PEMagic);
682 return 0;
683 }
684 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
685 {
686 DbgPrint("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
687 return 0;
688 }
689 CHECKPOINT;
690
691 /* FIXME: if image is fixed-address load, then fail */
692
693 /* FIXME: check/verify OS version number */
694
695 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
696 PEOptionalHeader->Magic,
697 PEOptionalHeader->MajorLinkerVersion,
698 PEOptionalHeader->MinorLinkerVersion);
699 DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
700 CHECKPOINT;
701
702 /* Determine the size of the module */
703 DriverSize = PEOptionalHeader->SizeOfImage;
704 DPRINT("DriverSize %x\n",DriverSize);
705
706 /* Allocate a virtual section for the module */
707 DriverBase = MmAllocateSection(DriverSize);
708 if (DriverBase == 0)
709 {
710 DbgPrint("Failed to allocate a virtual section for driver\n");
711 return 0;
712 }
713 DbgPrint("DriverBase: %x\n", DriverBase);
714 CHECKPOINT;
715 /* Copy headers over */
716 memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
717 CurrentSize = 0;
718 /* Copy image sections into virtual section */
719 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
720 {
721 // Copy current section into current offset of virtual section
722 if (PESectionHeaders[Idx].Characteristics &
723 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
724 {
725 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
726 PESectionHeaders[Idx].VirtualAddress + DriverBase);
727 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
728 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
729 PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
730 }
731 else
732 {
733 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
734 PESectionHeaders[Idx].VirtualAddress + DriverBase);
735 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
736 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
737
738 }
739 CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
740 PEOptionalHeader->SectionAlignment);
741
742
743 // CurrentBase = (PVOID)((DWORD)CurrentBase +
744 // ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
745 // PEOptionalHeader->SectionAlignment));
746 }
747
748 /* Perform relocation fixups */
749 RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
750 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
751 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
752 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
753 DriverBase,
754 PEOptionalHeader->ImageBase,
755 RelocDelta);
756 DPRINT("RelocDir %x\n",RelocDir);
757 #if 1
758 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
759 {
760 if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
761 {
762 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
763 PESectionHeaders[Idx].Name,
764 PESectionHeaders[Idx].PointerToRawData);
765 RelocDir = PESectionHeaders[Idx].PointerToRawData +
766 ModuleLoadBase;
767 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
768 break;
769 }
770 }
771 #else
772 RelocDir = RelocDir + (ULONG)DriverBase;
773 CurrentSize = PEOptionalHeader->DataDirectory
774 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
775 #endif
776 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
777 TotalRelocs = 0;
778 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
779 {
780 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
781 sizeof(WORD);
782 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
783 RelocDir,
784 RelocDir->VirtualAddress,
785 NumRelocs);*/
786 RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir +
787 sizeof(RELOCATION_DIRECTORY));
788 for (Idx = 0; Idx < NumRelocs; Idx++)
789 {
790 ULONG Offset;
791 ULONG Type;
792 PDWORD RelocItem;
793
794 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
795 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
796 RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress +
797 Offset);
798 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
799 RelocItem,
800 Type,
801 Type ? "HIGHLOW" : "ABS",
802 *RelocItem,
803 (*RelocItem) + RelocDelta); */
804 if (Type == 3)
805 {
806 (*RelocItem) += RelocDelta;
807 }
808 else if (Type != 0)
809 {
810 DbgPrint("Unknown relocation type %x at %x\n",Type, &Type);
811 return 0;
812 }
813 }
814 TotalRelocs += RelocDir->SizeOfBlock;
815 RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir +
816 RelocDir->SizeOfBlock);
817 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
818 }
819
820 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
821 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
822 .VirtualAddress);
823 /* Perform import fixups */
824 if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
825 {
826 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
827
828 SymbolNameBuf = ExAllocatePoolWithTag(NonPagedPool, 512, TAG_SYM_BUF);
829
830 /* Process each import module */
831 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
832 ((DWORD)DriverBase + PEOptionalHeader->
833 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
834 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
835 while (ImportModuleDirectory->dwRVAModuleName)
836 {
837 /* Check to make sure that import lib is kernel */
838 pName = (PCHAR) DriverBase +
839 ImportModuleDirectory->dwRVAModuleName;
840 wcscpy(NameBuffer, MODULE_ROOT_NAME);
841 for (Idx = 0; NameBuffer[Idx] != 0; Idx++)
842 ;
843 for (Idx2 = 0; pName[Idx2] != '\0'; Idx2++)
844 {
845 NameBuffer[Idx + Idx2] = (WCHAR) pName[Idx2];
846 }
847 NameBuffer[Idx + Idx2] = 0;
848 RtlInitUnicodeString (&ModuleName, NameBuffer);
849 DPRINT("Import module: %wZ\n", &ModuleName);
850
851 LibraryModuleObject = LdrLoadModule(&ModuleName);
852 if (LibraryModuleObject == 0)
853 {
854 DbgPrint("Unknown import module: %wZ\n", &ModuleName);
855 }
856 /* Get the import address list */
857 ImportAddressList = (PVOID *) ((DWORD)DriverBase +
858 ImportModuleDirectory->dwRVAFunctionAddressList);
859
860 /* Get the list of functions to import */
861 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
862 {
863 FunctionNameList = (PULONG) ((DWORD)DriverBase +
864 ImportModuleDirectory->dwRVAFunctionNameList);
865 }
866 else
867 {
868 FunctionNameList = (PULONG) ((DWORD)DriverBase +
869 ImportModuleDirectory->dwRVAFunctionAddressList);
870 }
871 /* Walk through function list and fixup addresses */
872 while (*FunctionNameList != 0L)
873 {
874 if ((*FunctionNameList) & 0x80000000) // hint
875 {
876 pName = NULL;
877
878
879 Hint = (*FunctionNameList) & 0xffff;
880 }
881 else // hint-name
882 {
883 pName = (PCHAR)((DWORD)DriverBase +
884 *FunctionNameList + 2);
885 Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
886 }
887 DPRINT(" Hint:%04x Name:%s\n", Hint, pName);
888
889 /* Fixup the current import symbol */
890 if (LibraryModuleObject != NULL)
891 {
892 *ImportAddressList = LdrGetExportAddress(LibraryModuleObject,
893 pName,
894 Hint);
895 }
896 else
897 {
898 DbgPrint("Unresolved kernel symbol: %s\n", pName);
899 return(NULL);
900 }
901 ImportAddressList++;
902 FunctionNameList++;
903 }
904 ImportModuleDirectory++;
905 }
906
907 ExFreePool(SymbolNameBuf);
908 }
909
910 /* Create ModuleName string */
911 wcscpy(NameBuffer, MODULE_ROOT_NAME);
912 if (wcsrchr(FileName->Buffer, '\\') != 0)
913 {
914 wcscat(NameBuffer, wcsrchr(FileName->Buffer, '\\') + 1);
915 }
916 else
917 {
918 wcscat(NameBuffer, FileName->Buffer);
919 }
920 RtlInitUnicodeString (&ModuleName, NameBuffer);
921 DbgPrint("Module name is: %wZ\n", &ModuleName);
922
923 /* Initialize ObjectAttributes for ModuleObject */
924 InitializeObjectAttributes(&ObjectAttributes,
925 &ModuleName,
926 0,
927 NULL,
928 NULL);
929
930 /* Create module object */
931 ModuleHandle = 0;
932 ModuleObject = ObCreateObject(&ModuleHandle,
933 STANDARD_RIGHTS_REQUIRED,
934 &ObjectAttributes,
935 IoDriverObjectType);
936
937 /* Initialize ModuleObject data */
938 ModuleObject->Base = DriverBase;
939 ModuleObject->Flags = MODULE_FLAG_PE;
940 InsertTailList(&ModuleListHead,
941 &ModuleObject->ListEntry);
942 RtlCreateUnicodeString(&ModuleObject->FullName,
943 FileName->Buffer);
944 LdrpBuildModuleBaseName(&ModuleObject->BaseName,
945 &ModuleObject->FullName);
946
947 ModuleObject->EntryPoint = (PVOID) ((DWORD)DriverBase +
948 PEOptionalHeader->AddressOfEntryPoint);
949 ModuleObject->Length = DriverSize;
950 DPRINT("entrypoint at %x\n", ModuleObject->EntryPoint);
951
952 ModuleObject->Image.PE.FileHeader =
953 (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
954
955 DPRINT("FileHeader at %x\n", ModuleObject->Image.PE.FileHeader);
956 ModuleObject->Image.PE.OptionalHeader =
957 (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
958 sizeof(IMAGE_FILE_HEADER));
959 DPRINT("OptionalHeader at %x\n", ModuleObject->Image.PE.OptionalHeader);
960 ModuleObject->Image.PE.SectionList =
961 (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
962 sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
963 DPRINT("SectionList at %x\n", ModuleObject->Image.PE.SectionList);
964
965 ModuleTextSection = ExAllocatePool(NonPagedPool,
966 sizeof(MODULE_TEXT_SECTION));
967 ModuleTextSection->Base = (ULONG)DriverBase;
968 ModuleTextSection->Length = DriverSize;
969 ModuleTextSection->Name =
970 ExAllocatePool(NonPagedPool,
971 (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
972 wcscpy(ModuleTextSection->Name, NameBuffer);
973 InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
974
975 return ModuleObject;
976 }
977
978 static PVOID
979 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
980 char *Name,
981 unsigned short Hint)
982 {
983 WORD Idx;
984 PVOID ExportAddress;
985 PWORD OrdinalList;
986 PDWORD FunctionList, NameList;
987 PIMAGE_EXPORT_DIRECTORY ExportDir;
988 ULONG ExportDirSize;
989
990 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
991 RtlImageDirectoryEntryToData(ModuleObject->Base,
992 TRUE,
993 IMAGE_DIRECTORY_ENTRY_EXPORT,
994 &ExportDirSize);
995 DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
996 if (ExportDir == NULL)
997 {
998 return NULL;
999 }
1000
1001
1002 FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
1003 NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
1004 OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
1005
1006 ExportAddress = 0;
1007
1008 if (Name != NULL)
1009 {
1010 for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1011 {
1012 #if 0
1013 DPRINT(" Name:%s NameList[%d]:%s\n",
1014 Name,
1015 Idx,
1016 (DWORD) ModuleObject->Base + NameList[Idx]);
1017
1018 #endif
1019 if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
1020 {
1021 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1022 FunctionList[OrdinalList[Idx]]);
1023 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
1024 ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
1025 {
1026 DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
1027 ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
1028 DPRINT("ExportAddress: %p\n", ExportAddress);
1029 }
1030
1031 break;
1032 }
1033 }
1034 }
1035 else /* use hint */
1036 {
1037 ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1038 FunctionList[Hint - ExportDir->Base]);
1039 }
1040
1041 if (ExportAddress == 0)
1042 {
1043 DbgPrint("Export not found for %d:%s\n",
1044 Hint,
1045 Name != NULL ? Name : "(Ordinal)");
1046 KeBugCheck(0);
1047 }
1048
1049 return ExportAddress;
1050 }
1051
1052
1053 static PMODULE_OBJECT
1054 LdrPEGetModuleObject(PUNICODE_STRING ModuleName)
1055 {
1056 PLIST_ENTRY Entry;
1057 PMODULE_OBJECT Module;
1058
1059 DPRINT("LdrPEGetModuleObject (ModuleName %wZ)\n",
1060 ModuleName);
1061
1062 Entry = ModuleListHead.Flink;
1063
1064 while (Entry != &ModuleListHead)
1065 {
1066 Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
1067
1068 DPRINT("Comparing %wZ and %wZ\n",
1069 &Module->BaseName,
1070 ModuleName);
1071
1072 if (!RtlCompareUnicodeString(&Module->BaseName, ModuleName, TRUE))
1073 {
1074 DPRINT("Module %x\n", Module);
1075 return Module;
1076 }
1077
1078 Entry = Entry->Flink;
1079 }
1080
1081 DbgPrint("LdrPEGetModuleObject: Failed to find dll %wZ\n", ModuleName);
1082
1083 return NULL;
1084 }
1085
1086
1087 static PVOID
1088 LdrPEFixupForward(PCHAR ForwardName)
1089 {
1090 CHAR NameBuffer[128];
1091 UNICODE_STRING ModuleName;
1092 PCHAR p;
1093 PMODULE_OBJECT ModuleObject;
1094
1095 DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1096
1097 strcpy(NameBuffer, ForwardName);
1098 p = strchr(NameBuffer, '.');
1099 if (p == NULL)
1100 {
1101 return NULL;
1102 }
1103
1104 *p = 0;
1105
1106 DPRINT("Driver: %s Function: %s\n", NameBuffer, p+1);
1107
1108 RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1109 NameBuffer);
1110 ModuleObject = LdrPEGetModuleObject(&ModuleName);
1111 RtlFreeUnicodeString(&ModuleName);
1112
1113 DPRINT("ModuleObject: %p\n", ModuleObject);
1114
1115 if (ModuleObject == NULL)
1116 {
1117 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1118 return NULL;
1119 }
1120
1121 return LdrPEGetExportAddress(ModuleObject, p+1, 0);
1122 }
1123
1124
1125 /* EOF */