2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ldr/loader.c
5 * PURPOSE: Loaders for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
10 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
11 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
12 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
13 * JM 14/12/98 Built initial PE user module loader
14 * RJJ 06/03/99 Moved user PE loader into NTDLL
17 /* INCLUDES *****************************************************************/
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>
29 #include <internal/string.h>
30 #include <internal/symbol.h>
32 #include <ddk/ntddk.h>
35 #include <internal/debug.h>
37 /* FIXME: this should appear in a kernel header file */
38 NTSTATUS
IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry
);
40 /* MACROS ********************************************************************/
42 #define MODULE_ROOT_NAME L"\\Modules\\"
44 /* GLOBALS *******************************************************************/
46 POBJECT_TYPE ObModuleType
= NULL
;
48 /* FORWARD DECLARATIONS ******************************************************/
50 NTSTATUS
LdrLoadDriver(PUNICODE_STRING Filename
);
51 NTSTATUS
LdrProcessDriver(PVOID ModuleLoadBase
);
53 PMODULE_OBJECT
LdrLoadModule(PUNICODE_STRING Filename
);
54 PMODULE_OBJECT
LdrProcessModule(PVOID ModuleLoadBase
);
55 PVOID
LdrGetExportAddress(PMODULE_OBJECT ModuleObject
, char *Name
, unsigned short Hint
);
56 static PIMAGE_SECTION_HEADER
LdrPEGetEnclosingSectionHeader(DWORD RVA
,
57 PMODULE_OBJECT ModuleObject
);
58 static NTSTATUS
LdrCreateModule(PVOID ObjectBody
,
61 POBJECT_ATTRIBUTES ObjectAttributes
);
63 /* PE Driver load support */
64 static PMODULE_OBJECT
LdrPEProcessModule(PVOID ModuleLoadBase
);
65 static PVOID
LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject
,
68 static unsigned int LdrGetKernelSymbolAddr(char *Name
);
70 /* COFF Driver load support */
71 static PMODULE_OBJECT
LdrCOFFProcessModule(PVOID ModuleLoadBase
);
72 static BOOLEAN
LdrCOFFDoRelocations(module
*Module
, unsigned int SectionIndex
);
73 static BOOLEAN
LdrCOFFDoAddr32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
);
74 static BOOLEAN
LdrCOFFDoReloc32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
);
75 static void LdrCOFFGetSymbolName(module
*Module
, unsigned int Idx
, char *Name
);
76 static unsigned int LdrCOFFGetSymbolValue(module
*Module
, unsigned int Idx
);
77 static unsigned int LdrCOFFGetSymbolValueByName(module
*Module
, char *SymbolName
, unsigned int Idx
);
79 /* FUNCTIONS *****************************************************************/
81 VOID
LdrInitModuleManagement(VOID
)
83 HANDLE DirHandle
, ModuleHandle
;
86 ANSI_STRING AnsiString
;
87 UNICODE_STRING ModuleName
;
88 OBJECT_ATTRIBUTES ObjectAttributes
;
89 PIMAGE_DOS_HEADER DosHeader
;
90 PMODULE_OBJECT ModuleObject
;
92 /* Register the process object type */
93 ObModuleType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
94 ObModuleType
->TotalObjects
= 0;
95 ObModuleType
->TotalHandles
= 0;
96 ObModuleType
->MaxObjects
= ULONG_MAX
;
97 ObModuleType
->MaxHandles
= ULONG_MAX
;
98 ObModuleType
->PagedPoolCharge
= 0;
99 ObModuleType
->NonpagedPoolCharge
= sizeof(MODULE
);
100 ObModuleType
->Dump
= NULL
;
101 ObModuleType
->Open
= NULL
;
102 ObModuleType
->Close
= NULL
;
103 ObModuleType
->Delete
= NULL
;
104 ObModuleType
->Parse
= NULL
;
105 ObModuleType
->Security
= NULL
;
106 ObModuleType
->QueryName
= NULL
;
107 ObModuleType
->OkayToClose
= NULL
;
108 ObModuleType
->Create
= LdrCreateModule
;
109 RtlInitAnsiString(&AnsiString
, "Module");
110 RtlAnsiStringToUnicodeString(&ObModuleType
->TypeName
, &AnsiString
, TRUE
);
112 /* Create Modules object directory */
113 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
114 *(wcsrchr(NameBuffer
, L
'\\')) = 0;
115 ModuleName
.Length
= ModuleName
.MaximumLength
= wcslen(NameBuffer
);
116 ModuleName
.Buffer
= NameBuffer
;
117 InitializeObjectAttributes(&ObjectAttributes
,
122 DPRINT("Create dir: %W\n", &ModuleName
);
123 Status
= ZwCreateDirectoryObject(&DirHandle
, 0, &ObjectAttributes
);
124 assert(NT_SUCCESS(Status
));
126 /* Add module entry for NTOSKRNL */
127 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
128 wcscat(NameBuffer
, L
"ntoskrnl.exe");
129 ModuleName
.Length
= ModuleName
.MaximumLength
= wcslen(NameBuffer
);
130 ModuleName
.Buffer
= NameBuffer
;
131 DPRINT("Kernel's Module name is: %W\n", &ModuleName
);
133 /* Initialize ObjectAttributes for ModuleObject */
134 InitializeObjectAttributes(&ObjectAttributes
,
140 /* Create module object */
142 ModuleObject
= ObCreateObject(&ModuleHandle
,
143 STANDARD_RIGHTS_REQUIRED
,
146 assert(ModuleObject
!= NULL
);
148 /* Initialize ModuleObject data */
149 ModuleObject
->Base
= (PVOID
) KERNEL_BASE
;
150 ModuleObject
->Flags
= MODULE_FLAG_PE
;
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
);
163 /* FIXME: Add fake module entry for HAL */
168 LdrCreateModule(PVOID ObjectBody
,
171 POBJECT_ATTRIBUTES ObjectAttributes
)
173 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %w)\n",
177 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+ 1, '\\') != NULL
)
179 return STATUS_UNSUCCESSFUL
;
181 if (Parent
!= NULL
&& RemainingPath
!= NULL
)
183 ObAddEntryDirectory(Parent
, ObjectBody
, RemainingPath
+ 1);
186 return STATUS_SUCCESS
;
190 * load the auto config drivers.
192 VOID
LdrLoadAutoConfigDrivers(VOID
)
195 ANSI_STRING AnsiDriverName
;
196 UNICODE_STRING DriverName
;
198 RtlInitAnsiString(&AnsiDriverName
,"\\??\\C:\\reactos\\system\\drivers\\keyboard.sys");
199 RtlAnsiStringToUnicodeString(&DriverName
, &AnsiDriverName
, TRUE
);
200 Status
= LdrLoadDriver(&DriverName
);
201 RtlFreeUnicodeString(&DriverName
);
202 if (!NT_SUCCESS(Status
))
204 DbgPrint("driver load failed, status;%d(%x)\n", Status
, Status
);
205 DbgPrintErrorMessage(Status
);
207 RtlInitAnsiString(&AnsiDriverName
,"\\??\\C:\\reactos\\system\\drivers\\blue.sys");
208 RtlAnsiStringToUnicodeString(&DriverName
, &AnsiDriverName
, TRUE
);
209 Status
= LdrLoadDriver(&DriverName
);
210 RtlFreeUnicodeString(&DriverName
);
211 if (!NT_SUCCESS(Status
))
213 DbgPrint("driver load failed, status;%d(%x)\n", Status
, Status
);
214 DbgPrintErrorMessage(Status
);
220 * FUNCTION: Loads a kernel driver
222 * FileName = Driver to load
227 LdrLoadDriver(PUNICODE_STRING Filename
)
229 PMODULE_OBJECT ModuleObject
;
231 ModuleObject
= LdrLoadModule(Filename
);
232 if (ModuleObject
== 0)
234 return STATUS_UNSUCCESSFUL
;
237 /* FIXME: should we dereference the ModuleObject here? */
239 return IoInitializeDriver(ModuleObject
->EntryPoint
);
243 LdrLoadModule(PUNICODE_STRING Filename
)
245 PVOID ModuleLoadBase
;
248 OBJECT_ATTRIBUTES ObjectAttributes
;
249 PMODULE_OBJECT ModuleObject
;
250 FILE_STANDARD_INFORMATION FileStdInfo
;
251 WCHAR NameBuffer
[60];
253 UNICODE_STRING ModuleName
;
255 DPRINT("Loading Module %W...\n", Filename
);
257 /* Check for module already loaded */
258 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
259 if (wcsrchr(Filename
->Buffer
, '\\') != 0)
261 wcscat(NameBuffer
, wcsrchr(Filename
->Buffer
, '\\') + 1);
265 wcscat(NameBuffer
, Filename
->Buffer
);
267 ModuleName
.Length
= ModuleName
.MaximumLength
= wcslen(NameBuffer
);
268 ModuleName
.Buffer
= NameBuffer
;
269 InitializeObjectAttributes(&ObjectAttributes
,
274 Status
= ObFindObject(&ObjectAttributes
,
275 (PVOID
*) &ModuleObject
,
278 if (NT_SUCCESS(Status
) && *RemainingPath
== 0)
283 if (!wcsncmp(Filename
->Buffer
, MODULE_ROOT_NAME
, wcslen(MODULE_ROOT_NAME
)))
288 /* Open the Module */
289 InitializeObjectAttributes(&ObjectAttributes
,
295 Status
= ZwOpenFile(&FileHandle
,
300 if (!NT_SUCCESS(Status
))
302 DbgPrint("Could not open module file: %W\n", Filename
);
307 /* Get the size of the file */
308 Status
= ZwQueryInformationFile(FileHandle
,
312 FileStandardInformation
);
313 if (!NT_SUCCESS(Status
))
315 DbgPrint("Could not get file size\n");
320 /* Allocate nonpageable memory for driver */
321 ModuleLoadBase
= ExAllocatePool(NonPagedPool
,
322 FileStdInfo
.EndOfFile
.u
.LowPart
);
323 if (ModuleLoadBase
== NULL
)
325 DbgPrint("could not allocate memory for module");
330 /* Load driver into memory chunk */
331 Status
= ZwReadFile(FileHandle
,
334 FileStdInfo
.EndOfFile
.u
.LowPart
,
336 if (!NT_SUCCESS(Status
))
338 DbgPrint("could not read module file into memory");
339 ExFreePool(ModuleLoadBase
);
347 ModuleObject
= LdrProcessModule(ModuleLoadBase
);
350 ExFreePool(ModuleLoadBase
);
356 LdrProcessDriver(PVOID ModuleLoadBase
)
358 PMODULE_OBJECT ModuleObject
;
360 ModuleObject
= LdrProcessModule(ModuleLoadBase
);
361 if (ModuleObject
== 0)
363 return STATUS_UNSUCCESSFUL
;
366 /* FIXME: should we dereference the ModuleObject here? */
368 return IoInitializeDriver(ModuleObject
->EntryPoint
);
372 LdrProcessModule(PVOID ModuleLoadBase
)
374 PIMAGE_DOS_HEADER PEDosHeader
;
376 /* If MZ header exists */
377 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
378 if (PEDosHeader
->e_magic
== IMAGE_DOS_MAGIC
&& PEDosHeader
->e_lfanew
!= 0L)
380 return LdrPEProcessModule(ModuleLoadBase
);
383 if (PEDosHeader
->e_magic
== IMAGE_DOS_MAGIC
)
387 else /* Assume COFF format and load */
389 return LdrCOFFProcessModule(ModuleLoadBase
);
397 LdrGetExportAddress(PMODULE_OBJECT ModuleObject
,
401 if (ModuleObject
->Flags
& MODULE_FLAG_PE
)
403 return LdrPEGetExportAddress(ModuleObject
, Name
, Hint
);
411 /* ---------------------------------------------- PE Module support */
414 LdrPEProcessModule(PVOID ModuleLoadBase
)
416 unsigned int DriverSize
, Idx
, Idx2
;
417 ULONG RelocDelta
, NumRelocs
;
418 DWORD CurrentSize
, TotalRelocs
;
419 PVOID DriverBase
, CurrentBase
;
421 PIMAGE_DOS_HEADER PEDosHeader
;
422 PIMAGE_FILE_HEADER PEFileHeader
;
423 PIMAGE_OPTIONAL_HEADER PEOptionalHeader
;
424 PIMAGE_SECTION_HEADER PESectionHeaders
;
425 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
426 PRELOCATION_DIRECTORY RelocDir
;
427 PRELOCATION_ENTRY RelocEntry
;
428 PMODULE_OBJECT LibraryModuleObject
;
430 PMODULE_OBJECT ModuleObject
;
431 PVOID
*ImportAddressList
;
432 PULONG FunctionNameList
;
433 PCHAR pName
, SymbolNameBuf
;
435 OBJECT_ATTRIBUTES ObjectAttributes
;
436 UNICODE_STRING ModuleName
;
437 WCHAR NameBuffer
[60];
439 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase
);
441 /* Get header pointers */
442 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
443 PEMagic
= (PULONG
) ((unsigned int) ModuleLoadBase
+
444 PEDosHeader
->e_lfanew
);
445 PEFileHeader
= (PIMAGE_FILE_HEADER
) ((unsigned int) ModuleLoadBase
+
446 PEDosHeader
->e_lfanew
+ sizeof(ULONG
));
447 PEOptionalHeader
= (PIMAGE_OPTIONAL_HEADER
) ((unsigned int) ModuleLoadBase
+
448 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
));
449 PESectionHeaders
= (PIMAGE_SECTION_HEADER
) ((unsigned int) ModuleLoadBase
+
450 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
) +
451 sizeof(IMAGE_OPTIONAL_HEADER
));
454 /* Check file magic numbers */
455 if (PEDosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
457 DbgPrint("Incorrect MZ magic: %04x\n", PEDosHeader
->e_magic
);
460 if (PEDosHeader
->e_lfanew
== 0)
462 DbgPrint("Invalid lfanew offset: %08x\n", PEDosHeader
->e_lfanew
);
465 if (*PEMagic
!= IMAGE_PE_MAGIC
)
467 DbgPrint("Incorrect PE magic: %08x\n", *PEMagic
);
470 if (PEFileHeader
->Machine
!= IMAGE_FILE_MACHINE_I386
)
472 DbgPrint("Incorrect Architechture: %04x\n", PEFileHeader
->Machine
);
477 /* FIXME: if image is fixed-address load, then fail */
479 /* FIXME: check/verify OS version number */
481 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
482 PEOptionalHeader
->Magic
,
483 PEOptionalHeader
->MajorLinkerVersion
,
484 PEOptionalHeader
->MinorLinkerVersion
);
485 DPRINT("Entry Point:%08lx\n", PEOptionalHeader
->AddressOfEntryPoint
);
488 /* Determine the size of the module */
490 DriverSize
= PEOptionalHeader
->SizeOfImage
;
491 DPRINT("DriverSize %x\n",DriverSize
);
493 /* Allocate a virtual section for the module */
494 DriverBase
= MmAllocateSection(DriverSize
);
497 DbgPrint("Failed to allocate a virtual section for driver\n");
501 DPRINT("Module is at base %x\n",DriverBase
);
503 /* Copy image sections into virtual section */
504 memcpy(DriverBase
, ModuleLoadBase
, PESectionHeaders
[0].PointerToRawData
);
505 CurrentBase
= (PVOID
) ((DWORD
)DriverBase
+ PESectionHeaders
[0].PointerToRawData
);
507 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
509 /* Copy current section into current offset of virtual section */
510 if (PESectionHeaders
[Idx
].Characteristics
&
511 (IMAGE_SECTION_CHAR_CODE
| IMAGE_SECTION_CHAR_DATA
))
513 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
514 PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
);
515 memcpy(PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
,
516 (PVOID
)(ModuleLoadBase
+ PESectionHeaders
[Idx
].PointerToRawData
),
517 PESectionHeaders
[Idx
].SizeOfRawData
);
521 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
522 PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
);
523 memset(PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
,
524 '\0', PESectionHeaders
[Idx
].SizeOfRawData
);
526 CurrentSize
+= ROUND_UP(PESectionHeaders
[Idx
].SizeOfRawData
,
527 PEOptionalHeader
->SectionAlignment
);
528 CurrentBase
= (PVOID
)((DWORD
)CurrentBase
+
529 ROUND_UP(PESectionHeaders
[Idx
].SizeOfRawData
,
530 PEOptionalHeader
->SectionAlignment
));
533 /* Perform relocation fixups */
534 RelocDelta
= (DWORD
) DriverBase
- PEOptionalHeader
->ImageBase
;
535 RelocDir
= (PRELOCATION_DIRECTORY
)(PEOptionalHeader
->DataDirectory
[
536 IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
);
537 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
539 PEOptionalHeader
->ImageBase
,
541 DPRINT("RelocDir %x\n",RelocDir
);
542 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
544 if (PESectionHeaders
[Idx
].VirtualAddress
== (DWORD
)RelocDir
)
546 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
547 PESectionHeaders
[Idx
].Name
,
548 PESectionHeaders
[Idx
].PointerToRawData
);
549 RelocDir
= PESectionHeaders
[Idx
].PointerToRawData
+
551 CurrentSize
= PESectionHeaders
[Idx
].Misc
.VirtualSize
;
555 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir
, CurrentSize
);
557 while (TotalRelocs
< CurrentSize
&& RelocDir
->SizeOfBlock
!= 0)
559 NumRelocs
= (RelocDir
->SizeOfBlock
- sizeof(RELOCATION_DIRECTORY
)) /
561 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
563 RelocDir->VirtualAddress,
565 RelocEntry
= (PRELOCATION_ENTRY
) ((DWORD
)RelocDir
+
566 sizeof(RELOCATION_DIRECTORY
));
567 for (Idx
= 0; Idx
< NumRelocs
; Idx
++)
573 Offset
= RelocEntry
[Idx
].TypeOffset
& 0xfff;
574 Type
= (RelocEntry
[Idx
].TypeOffset
>> 12) & 0xf;
575 RelocItem
= (PDWORD
)(DriverBase
+ RelocDir
->VirtualAddress
+
577 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
580 Type ? "HIGHLOW" : "ABS",
582 (*RelocItem) + RelocDelta); */
585 (*RelocItem
) += RelocDelta
;
589 DbgPrint("Unknown relocation type %x\n",Type
);
593 TotalRelocs
+= RelocDir
->SizeOfBlock
;
594 RelocDir
= (PRELOCATION_DIRECTORY
)((DWORD
)RelocDir
+
595 RelocDir
->SizeOfBlock
);
596 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
599 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
600 PEOptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
602 /* Perform import fixups */
603 if (PEOptionalHeader
->DataDirectory
[
604 IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
)
606 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
608 SymbolNameBuf
= ExAllocatePool(NonPagedPool
, 512);
610 /* Process each import module */
611 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
612 ((DWORD
)DriverBase
+ PEOptionalHeader
->
613 DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
);
614 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
615 while (ImportModuleDirectory
->dwRVAModuleName
)
617 /* Check to make sure that import lib is kernel */
618 pName
= (PCHAR
) DriverBase
+
619 ImportModuleDirectory
->dwRVAModuleName
;
620 if (!strcmp(pName
, "ntoskrnl.exe") || !strcmp(pName
, "HAL.dll"))
622 LibraryModuleObject
= NULL
;
623 DPRINT("Kernel imports\n");
627 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
628 for (Idx
= 0; NameBuffer
[Idx
] != 0; Idx
++)
630 for (Idx2
= 0; pName
[Idx2
] != '\0'; Idx2
++)
632 NameBuffer
[Idx
+ Idx2
] = (WCHAR
) pName
[Idx2
];
634 NameBuffer
[Idx
+ Idx2
] = 0;
635 ModuleName
.Length
= ModuleName
.MaximumLength
= wcslen(NameBuffer
);
636 ModuleName
.Buffer
= NameBuffer
;
637 DPRINT("Import module: %W\n", &ModuleName
);
638 LibraryModuleObject
= LdrLoadModule(&ModuleName
);
639 if (LibraryModuleObject
== 0)
641 DbgPrint("Unknown import module: %W\n", &ModuleName
);
644 /* Get the import address list */
645 ImportAddressList
= (PVOID
*) ((DWORD
)DriverBase
+
646 ImportModuleDirectory
->dwRVAFunctionAddressList
);
648 /* Get the list of functions to import */
649 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
651 FunctionNameList
= (PULONG
) ((DWORD
)DriverBase
+
652 ImportModuleDirectory
->dwRVAFunctionNameList
);
656 FunctionNameList
= (PULONG
) ((DWORD
)DriverBase
+
657 ImportModuleDirectory
->dwRVAFunctionAddressList
);
659 /* Walk through function list and fixup addresses */
660 while (*FunctionNameList
!= 0L)
662 if ((*FunctionNameList
) & 0x80000000) // hint
665 Hint
= (*FunctionNameList
) & 0xffff;
669 pName
= (PCHAR
)((DWORD
)DriverBase
+
670 *FunctionNameList
+ 2);
671 Hint
= *(PWORD
)((DWORD
)DriverBase
+ *FunctionNameList
);
673 DPRINT(" Hint:%04x Name:%s\n", Hint
, pName
);
675 /* Fixup the current import symbol */
676 if (LibraryModuleObject
!= NULL
)
678 *ImportAddressList
= LdrGetExportAddress(LibraryModuleObject
,
684 /* Get address for symbol */
685 *SymbolNameBuf
= '_';
686 strcpy(SymbolNameBuf
+ 1, pName
);
687 *ImportAddressList
= (PVOID
) LdrGetKernelSymbolAddr(SymbolNameBuf
);
688 if (*ImportAddressList
== 0L)
690 DbgPrint("Unresolved kernel symbol: %s\n", pName
);
696 ImportModuleDirectory
++;
699 ExFreePool(SymbolNameBuf
);
702 /* Create ModuleName string */
703 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
704 if (PEOptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
705 .VirtualAddress
!= 0)
707 ExportDirectory
= (PIMAGE_EXPORT_DIRECTORY
) (DriverBase
+
708 PEOptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
710 wcscat(NameBuffer
, DriverBase
+ ExportDirectory
->Name
);
716 sprintf(buf
, "%08X", (DWORD
) DriverBase
);
717 for (Idx
= 0; NameBuffer
[Idx
] != 0; Idx
++)
720 while ((NameBuffer
[Idx
+ Idx2
] = (WCHAR
) buf
[Idx2
]) != 0)
723 ModuleName
.Length
= ModuleName
.MaximumLength
= wcslen(NameBuffer
);
724 ModuleName
.Buffer
= NameBuffer
;
725 DPRINT("Module name is: %W\n", &ModuleName
);
727 /* Initialize ObjectAttributes for ModuleObject */
728 InitializeObjectAttributes(&ObjectAttributes
,
734 /* Create module object */
736 ModuleObject
= ObCreateObject(&ModuleHandle
,
737 STANDARD_RIGHTS_REQUIRED
,
741 /* Initialize ModuleObject data */
742 ModuleObject
->Base
= DriverBase
;
743 ModuleObject
->Flags
= MODULE_FLAG_PE
;
744 ModuleObject
->EntryPoint
= (PVOID
) ((DWORD
)DriverBase
+
745 PEOptionalHeader
->AddressOfEntryPoint
);
746 DPRINT("entrypoint at %x\n", ModuleObject
->EntryPoint
);
747 ModuleObject
->Image
.PE
.FileHeader
=
748 (PIMAGE_FILE_HEADER
) ((unsigned int) DriverBase
+
749 PEDosHeader
->e_lfanew
+ sizeof(ULONG
));
750 DPRINT("FileHeader at %x\n", ModuleObject
->Image
.PE
.FileHeader
);
751 ModuleObject
->Image
.PE
.OptionalHeader
=
752 (PIMAGE_OPTIONAL_HEADER
) ((unsigned int) DriverBase
+
753 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
));
754 DPRINT("OptionalHeader at %x\n", ModuleObject
->Image
.PE
.OptionalHeader
);
755 ModuleObject
->Image
.PE
.SectionList
=
756 (PIMAGE_SECTION_HEADER
) ((unsigned int) DriverBase
+
757 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
) +
758 sizeof(IMAGE_OPTIONAL_HEADER
));
759 DPRINT("SectionList at %x\n", ModuleObject
->Image
.PE
.SectionList
);
765 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject
,
770 DWORD ExportsStartRVA
, ExportsEndRVA
, Delta
;
773 PDWORD FunctionList
, NameList
;
774 PIMAGE_SECTION_HEADER SectionHeader
;
775 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
777 ExportsStartRVA
= ModuleObject
->Image
.PE
.OptionalHeader
->DataDirectory
778 [IMAGE_DIRECTORY_ENTRY_EXPORT
].VirtualAddress
;
779 ExportsEndRVA
= ExportsStartRVA
+
780 ModuleObject
->Image
.PE
.OptionalHeader
->DataDirectory
781 [IMAGE_DIRECTORY_ENTRY_EXPORT
].Size
;
782 /* Get the IMAGE_SECTION_HEADER that contains the exports. This is
783 usually the .edata section, but doesn't have to be. */
784 SectionHeader
= LdrPEGetEnclosingSectionHeader(ExportsStartRVA
, ModuleObject
);
789 Delta
= (DWORD
)(SectionHeader
->VirtualAddress
-
790 SectionHeader
->PointerToRawData
);
791 ExportDirectory
= MakePtr(PIMAGE_EXPORT_DIRECTORY
,
793 ExportsStartRVA
- Delta
);
795 FunctionList
= (PDWORD
)((DWORD
)ExportDirectory
->AddressOfFunctions
-
796 Delta
+ ModuleObject
->Base
);
797 NameList
= (PDWORD
)((DWORD
)ExportDirectory
->AddressOfNames
-
798 Delta
+ ModuleObject
->Base
);
799 OrdinalList
= (PWORD
)((DWORD
)ExportDirectory
->AddressOfNameOrdinals
-
800 Delta
+ ModuleObject
->Base
);
801 DPRINT("Delta:%08x\n", Delta
);
802 DPRINT("Func:%08x RVA:%08x Name:%08x RVA:%08x Ord:%08x RVA:%08x\n", FunctionList
,
803 ExportDirectory
->AddressOfFunctions
, NameList
,
804 ExportDirectory
->AddressOfNames
, OrdinalList
,
805 ExportDirectory
->AddressOfNameOrdinals
);
806 DPRINT("NumNames:%d NumFuncs:%d\n", ExportDirectory
->NumberOfNames
,
807 ExportDirectory
->NumberOfFunctions
);
812 for (Idx
= 0; Idx
< ExportDirectory
->NumberOfNames
; Idx
++)
814 DPRINT(" Name:%s NameList[%d]:%s\n", Name
, Idx
, NameList
[Idx
]);
815 if (!strcmp(Name
, (PCHAR
) ((DWORD
)ModuleObject
->Base
+ NameList
[Idx
])))
817 ExportAddress
= (PVOID
) ((DWORD
)ModuleObject
->Base
+
818 FunctionList
[OrdinalList
[Idx
]]);
825 ExportAddress
= (PVOID
) ((DWORD
)ModuleObject
->Base
+
826 FunctionList
[Hint
- ExportDirectory
->Base
]);
828 if (ExportAddress
== 0)
830 DbgPrint("Export not found for %d:%s\n", Hint
, Name
!= NULL
? Name
: "(Ordinal)");
833 return ExportAddress
;
836 static PIMAGE_SECTION_HEADER
837 LdrPEGetEnclosingSectionHeader(DWORD RVA
,
838 PMODULE_OBJECT ModuleObject
)
840 PIMAGE_SECTION_HEADER SectionHeader
= SECHDROFFSET(ModuleObject
->Base
);
843 for (i
= 0; i
< ModuleObject
->Image
.PE
.FileHeader
->NumberOfSections
;
844 i
++, SectionHeader
++)
846 /* Is the RVA within this section? */
847 if ((RVA
>= SectionHeader
->VirtualAddress
) &&
848 (RVA
< (SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
)))
850 return SectionHeader
;
857 /* ------------------------------------------- COFF Module support */
860 LdrCOFFProcessModule(PVOID ModuleLoadBase
)
863 char SymbolName
[255];
871 PMODULE_OBJECT ModuleObject
;
872 OBJECT_ATTRIBUTES ObjectAttributes
;
873 UNICODE_STRING ModuleName
;
874 WCHAR NameBuffer
[60];
876 /* Get header pointers */
877 FileHeader
= ModuleLoadBase
;
878 AOUTHeader
= ModuleLoadBase
+ FILHSZ
;
881 /* Check COFF magic value */
882 if (I386BADMAG(*FileHeader
))
884 DbgPrint("Module has bad magic value (%x)\n",
885 FileHeader
->f_magic
);
890 /* Allocate and initialize a module definition structure */
891 Module
= (module
*) ExAllocatePool(NonPagedPool
, sizeof(module
));
896 Module
->sym_list
= (SYMENT
*)(ModuleLoadBase
+ FileHeader
->f_symptr
);
897 Module
->str_tab
= (char *)(ModuleLoadBase
+ FileHeader
->f_symptr
+
898 FileHeader
->f_nsyms
* SYMESZ
);
899 Module
->scn_list
= (SCNHDR
*)(ModuleLoadBase
+ FILHSZ
+
900 FileHeader
->f_opthdr
);
902 Module
->raw_data_off
= (ULONG
) ModuleLoadBase
;
903 Module
->nsyms
= FileHeader
->f_nsyms
;
906 /* Determine the length of the module */
907 for (i
= 0; i
< FileHeader
->f_nscns
; i
++)
909 DPRINT("Section name: %.8s\n", Module
->scn_list
[i
].s_name
);
910 DPRINT("size %x vaddr %x size %x\n",
912 Module
->scn_list
[i
].s_vaddr
,
913 Module
->scn_list
[i
].s_size
);
914 if (Module
->scn_list
[i
].s_flags
& STYP_TEXT
)
916 Module
->text_base
= Module
->scn_list
[i
].s_vaddr
;
918 if (Module
->scn_list
[i
].s_flags
& STYP_DATA
)
920 Module
->data_base
= Module
->scn_list
[i
].s_vaddr
;
922 if (Module
->scn_list
[i
].s_flags
& STYP_BSS
)
924 Module
->bss_base
= Module
->scn_list
[i
].s_vaddr
;
927 (Module
->scn_list
[i
].s_vaddr
+ Module
->scn_list
[i
].s_size
))
929 Module
->size
= Module
->size
+ Module
->scn_list
[i
].s_vaddr
+
930 Module
->scn_list
[i
].s_size
;
935 /* Allocate a section for the module */
936 Module
->base
= (unsigned int) MmAllocateSection(Module
->size
);
937 if (Module
->base
== 0)
939 DbgPrint("Failed to alloc section for module\n");
945 /* Adjust section vaddrs for allocated area */
946 Module
->data_base
= Module
->data_base
+ Module
->base
;
947 Module
->text_base
= Module
->text_base
+ Module
->base
;
948 Module
->bss_base
= Module
->bss_base
+ Module
->base
;
950 /* Relocate module and fixup imports */
951 for (i
= 0; i
< FileHeader
->f_nscns
; i
++)
953 if (Module
->scn_list
[i
].s_flags
& STYP_TEXT
||
954 Module
->scn_list
[i
].s_flags
& STYP_DATA
)
956 memcpy((PVOID
)(Module
->base
+ Module
->scn_list
[i
].s_vaddr
),
957 (PVOID
)(ModuleLoadBase
+ Module
->scn_list
[i
].s_scnptr
),
958 Module
->scn_list
[i
].s_size
);
959 if (!LdrCOFFDoRelocations(Module
, i
))
961 DbgPrint("Relocation failed for section %s\n",
962 Module
->scn_list
[i
].s_name
);
964 /* FIXME: unallocate all sections here */
971 if (Module
->scn_list
[i
].s_flags
& STYP_BSS
)
973 memset((PVOID
)(Module
->base
+ Module
->scn_list
[i
].s_vaddr
),
975 Module
->scn_list
[i
].s_size
);
979 DPRINT("Module base: %x\n", Module
->base
);
981 /* Find the entry point */
984 for (i
= 0; i
< FileHeader
->f_nsyms
; i
++)
986 LdrCOFFGetSymbolName(Module
, i
, SymbolName
);
987 if (!strcmp(SymbolName
, "_DriverEntry"))
989 EntryOffset
= Module
->sym_list
[i
].e_value
;
991 DPRINT("Found entry at %x\n", EntryOffset
);
996 DbgPrint("No module entry point defined\n");
999 /* FIXME: unallocate all sections here */
1004 /* Get the address of the module initalization routine */
1005 EntryRoutine
= (PVOID
)(Module
->base
+ EntryOffset
);
1007 /* Create ModuleName string */
1008 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
1009 /* FIXME: someone who is interested needs to fix this. */
1010 wcscat(NameBuffer
, L
"BOGUS.o");
1011 ModuleName
.Length
= ModuleName
.MaximumLength
= wcslen(NameBuffer
);
1012 ModuleName
.Buffer
= NameBuffer
;
1013 DPRINT("Module name is: %w", NameBuffer
);
1015 /* Initialize ObjectAttributes for ModuleObject */
1016 InitializeObjectAttributes(&ObjectAttributes
,
1022 /* Create module object */
1024 ModuleObject
= ObCreateObject(&ModuleHandle
,
1025 OBJECT_TYPE_ALL_ACCESS
,
1029 /* Initialize ModuleObject data */
1030 ModuleObject
->Base
= (PVOID
) Module
->base
;
1031 ModuleObject
->Flags
= MODULE_FLAG_COFF
;
1032 ModuleObject
->EntryPoint
= (PVOID
) (Module
->base
+ EntryOffset
);
1033 DPRINT("entrypoint at %x\n", ModuleObject
->EntryPoint
);
1034 /* FIXME: the COFF headers need to be copied into the module
1035 space, and the ModuleObject needs to be set to point to them */
1040 return ModuleObject
;
1043 /* LdrCOFFDoRelocations
1044 * FUNCTION: Do the relocations for a module section
1046 * Module = Pointer to the module
1047 * SectionIndex = Index of the section to be relocated
1048 * RETURNS: Success or failure
1052 LdrCOFFDoRelocations(module
*Module
, unsigned int SectionIndex
)
1054 SCNHDR
*Section
= &Module
->scn_list
[SectionIndex
];
1055 RELOC
*Relocation
= (RELOC
*)(Module
->raw_data_off
+ Section
->s_relptr
);
1058 DPRINT("SectionIndex %d Name %.8s Relocs %d\n",
1060 Module
->scn_list
[SectionIndex
].s_name
,
1063 for (j
= 0; j
< Section
->s_nreloc
; j
++)
1065 DPRINT("vaddr %x symndex %x",
1066 Relocation
->r_vaddr
,
1067 Relocation
->r_symndx
);
1069 switch (Relocation
->r_type
)
1072 if (!LdrCOFFDoAddr32Reloc(Module
, Section
, Relocation
))
1079 if (!LdrCOFFDoReloc32Reloc(Module
, Section
, Relocation
))
1086 DbgPrint("%.8s: Unknown relocation type %x at %d in module\n",
1087 Module
->scn_list
[SectionIndex
].s_name
,
1094 DPRINT("%.8s: relocations done\n", Module
->scn_list
[SectionIndex
].s_name
);
1100 * FUNCTION: Performs a addr32 relocation on a loaded module
1102 * mod = module to perform the relocation on
1103 * scn = Section to perform the relocation in
1104 * reloc = Pointer to a data structure describing the relocation
1105 * RETURNS: Success or failure
1106 * NOTE: This fixes up a relocation needed when changing the base address of a
1111 LdrCOFFDoAddr32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
)
1114 unsigned int *Location
;
1116 Value
= LdrCOFFGetSymbolValue(Module
, Relocation
->r_symndx
);
1117 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
1118 DPRINT("ADDR32 loc %x value %x *loc %x\n", Location
, Value
, *Location
);
1119 *Location
= (*Location
) + Module
->base
;
1125 * FUNCTION: Performs a reloc32 relocation on a loaded module
1127 * mod = module to perform the relocation on
1128 * scn = Section to perform the relocation in
1129 * reloc = Pointer to a data structure describing the relocation
1130 * RETURNS: Success or failure
1131 * NOTE: This fixes up an undefined reference to a kernel function in a module
1135 LdrCOFFDoReloc32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
)
1139 unsigned int *Location
;
1141 memset(Name
, 0, 255);
1142 LdrCOFFGetSymbolName(Module
, Relocation
->r_symndx
, Name
);
1143 Value
= (unsigned int) LdrGetKernelSymbolAddr(Name
);
1146 Value
= LdrCOFFGetSymbolValueByName(Module
, Name
, Relocation
->r_symndx
);
1149 DbgPrint("Undefined symbol %s in module\n", Name
);
1152 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
1153 // (*Location) = (*Location) + Value + Module->base - Section->s_vaddr;
1154 (*Location
) = (*Location
);
1155 DPRINT("Module->base %x Section->s_vaddr %x\n",
1161 DPRINT("REL32 value %x name %s\n", Value
, Name
);
1162 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
1163 DPRINT("old %x ", *Location
);
1164 DPRINT("Module->base %x Section->s_vaddr %x\n",
1167 (*Location
) = (*Location
) + Value
- Module
->base
+ Section
->s_vaddr
;
1168 DPRINT("new %x\n", *Location
);
1175 * FUNCTION: Get the name of a symbol from a loaded module by ordinal
1178 * i = index of symbol
1179 * name (OUT) = pointer to a string where the symbol name will be
1184 LdrCOFFGetSymbolName(module
*Module
, unsigned int Idx
, char *Name
)
1186 if (Module
->sym_list
[Idx
].e
.e_name
[0] != 0)
1188 strncpy(Name
, Module
->sym_list
[Idx
].e
.e_name
, 8);
1193 strcpy(Name
, &Module
->str_tab
[Module
->sym_list
[Idx
].e
.e
.e_offset
]);
1198 * FUNCTION: Get the value of a module defined symbol
1201 * i = index of symbol
1202 * RETURNS: The value of the symbol
1203 * NOTE: This fixes up references to known sections
1207 LdrCOFFGetSymbolValue(module
*Module
, unsigned int Idx
)
1211 LdrCOFFGetSymbolName(Module
, Idx
, Name
);
1212 DPRINT("name %s ", Name
);
1214 /* Check if the symbol is a section we have relocated */
1215 if (strcmp(Name
, ".text") == 0)
1217 return Module
->text_base
;
1219 if (strcmp(Name
, ".data") == 0)
1221 return Module
->data_base
;
1223 if (strcmp(Name
, ".bss") == 0)
1225 return Module
->bss_base
;
1228 return Module
->sym_list
[Idx
].e_value
;
1232 * FUNCTION: Get the address of a kernel symbol
1234 * name = symbol name
1235 * RETURNS: The address of the symbol on success
1240 LdrGetKernelSymbolAddr(char *Name
)
1245 if ((s
=strchr(Name
,'@'))!=NULL
)
1248 DPRINT("Name %s ",Name
);
1250 while (symbol_table
[i
].name
!= NULL
)
1252 if (strcmp(symbol_table
[i
].name
, Name
) == 0)
1257 DPRINT("Matched with %s\n",symbol_table
[i
].name
);
1259 return symbol_table
[i
].value
;
1271 LdrCOFFGetSymbolValueByName(module
*Module
,
1278 DPRINT("LdrCOFFGetSymbolValueByName(sname %s, idx %x)\n", SymbolName
, Idx
);
1280 for (i
= 0; i
< Module
->nsyms
; i
++)
1282 LdrCOFFGetSymbolName(Module
, i
, Name
);
1283 DPRINT("Scanning %s Value %x\n", Name
, Module
->sym_list
[i
].e_value
);
1284 if (strcmp(Name
, SymbolName
) == 0)
1286 DPRINT("Returning %x\n", Module
->sym_list
[i
].e_value
);
1287 return Module
->sym_list
[i
].e_value
;