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