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