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