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