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