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