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