1 /* $Id: loader.c,v 1.73 2001/04/16 02:02:05 dwelch Exp $
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 * Casper S. Hornstrup (chorns@users.sourceforge.net)
13 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
14 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
15 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
16 * JM 14/12/98 Built initial PE user module loader
17 * RJJ 06/03/99 Moved user PE loader into NTDLL
18 * JF 26/01/2000 Recoded some parts to retrieve export details correctly
19 * DW 27/06/2000 Removed redundant header files
20 * CSH 11/04/2001 Added automatic loading of module symbols if they exist
24 /* INCLUDES *****************************************************************/
27 #include <ddk/ntddk.h>
28 #include <internal/config.h>
29 #include <internal/module.h>
30 #include <internal/ntoskrnl.h>
31 #include <internal/mm.h>
32 #include <internal/ob.h>
33 #include <internal/ps.h>
34 #include <internal/ldr.h>
35 #include <internal/pool.h>
38 #include <internal/debug.h>
41 /* FIXME: this should appear in a kernel header file */
42 NTSTATUS
IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry
);
44 /* MACROS ********************************************************************/
46 #define MODULE_ROOT_NAME L"\\Modules\\"
48 /* GLOBALS *******************************************************************/
50 LIST_ENTRY ModuleListHead
;
51 POBJECT_TYPE EXPORTED IoDriverObjectType
= NULL
;
52 LIST_ENTRY ModuleTextListHead
;
53 STATIC MODULE_TEXT_SECTION NtoskrnlTextSection
;
54 /* STATIC MODULE_TEXT_SECTION HalTextSection; */
56 #define TAG_DRIVER_MEM TAG('D', 'R', 'V', 'M')
57 #define TAG_SYM_BUF TAG('S', 'Y', 'M', 'B')
59 /* FORWARD DECLARATIONS ******************************************************/
61 PMODULE_OBJECT
LdrLoadModule(PUNICODE_STRING Filename
);
62 PMODULE_OBJECT
LdrProcessModule(PVOID ModuleLoadBase
, PUNICODE_STRING ModuleName
);
63 PVOID
LdrGetExportAddress(PMODULE_OBJECT ModuleObject
, char *Name
, unsigned short Hint
);
64 static PMODULE_OBJECT
LdrOpenModule(PUNICODE_STRING Filename
);
65 static NTSTATUS
LdrCreateModule(PVOID ObjectBody
,
68 POBJECT_ATTRIBUTES ObjectAttributes
);
69 static VOID
LdrpBuildModuleBaseName(PUNICODE_STRING BaseName
,
70 PUNICODE_STRING FullName
);
72 /* PE Driver load support */
73 static PMODULE_OBJECT
LdrPEProcessModule(PVOID ModuleLoadBase
, PUNICODE_STRING FileName
);
74 static PVOID
LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject
,
77 static PMODULE_OBJECT
LdrPEGetModuleObject(PUNICODE_STRING ModuleName
);
78 static PVOID
LdrPEFixupForward(PCHAR ForwardName
);
81 /* FUNCTIONS *****************************************************************/
84 LdrInitDebug(PLOADER_MODULE Module
, PWCH Name
)
86 PLIST_ENTRY current_entry
;
87 MODULE_TEXT_SECTION
* current
;
89 current_entry
= ModuleTextListHead
.Flink
;
90 while (current_entry
!= &ModuleTextListHead
)
93 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
94 if (wcscmp(current
->Name
, Name
) == 0)
98 current_entry
= current_entry
->Flink
;
101 if (current_entry
== &ModuleTextListHead
)
106 current
->SymbolsBase
= (PVOID
)Module
->ModStart
;
107 current
->SymbolsLength
= Module
->ModEnd
- Module
->ModStart
;
113 PIMAGE_DOS_HEADER DosHeader
;
114 PIMAGE_FILE_HEADER FileHeader
;
115 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
116 PIMAGE_SECTION_HEADER SectionList
;
118 InitializeListHead(&ModuleTextListHead
);
120 DosHeader
= (PIMAGE_DOS_HEADER
) KERNEL_BASE
;
122 (PIMAGE_FILE_HEADER
) ((DWORD
)KERNEL_BASE
+
123 DosHeader
->e_lfanew
+ sizeof(ULONG
));
124 OptionalHeader
= (PIMAGE_OPTIONAL_HEADER
)
125 ((DWORD
)FileHeader
+ sizeof(IMAGE_FILE_HEADER
));
126 SectionList
= (PIMAGE_SECTION_HEADER
)
127 ((DWORD
)OptionalHeader
+ sizeof(IMAGE_OPTIONAL_HEADER
));
128 NtoskrnlTextSection
.Base
= KERNEL_BASE
;
129 NtoskrnlTextSection
.Length
= SectionList
[0].Misc
.VirtualSize
+
130 SectionList
[0].VirtualAddress
;
131 NtoskrnlTextSection
.Name
= L
"ntoskrnl.exe";
132 NtoskrnlTextSection
.SymbolsBase
= NULL
;
133 NtoskrnlTextSection
.SymbolsLength
= 0;
134 InsertTailList(&ModuleTextListHead
, &NtoskrnlTextSection
.ListEntry
);
137 VOID
LdrInitModuleManagement(VOID
)
139 HANDLE DirHandle
, ModuleHandle
;
141 WCHAR NameBuffer
[60];
142 UNICODE_STRING ModuleName
;
143 OBJECT_ATTRIBUTES ObjectAttributes
;
144 PIMAGE_DOS_HEADER DosHeader
;
145 PMODULE_OBJECT ModuleObject
;
147 /* Register the process object type */
148 IoDriverObjectType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
149 IoDriverObjectType
->Tag
= TAG('D', 'R', 'V', 'T');
150 IoDriverObjectType
->TotalObjects
= 0;
151 IoDriverObjectType
->TotalHandles
= 0;
152 IoDriverObjectType
->MaxObjects
= ULONG_MAX
;
153 IoDriverObjectType
->MaxHandles
= ULONG_MAX
;
154 IoDriverObjectType
->PagedPoolCharge
= 0;
155 IoDriverObjectType
->NonpagedPoolCharge
= sizeof(MODULE
);
156 IoDriverObjectType
->Dump
= NULL
;
157 IoDriverObjectType
->Open
= NULL
;
158 IoDriverObjectType
->Close
= NULL
;
159 IoDriverObjectType
->Delete
= NULL
;
160 IoDriverObjectType
->Parse
= NULL
;
161 IoDriverObjectType
->Security
= NULL
;
162 IoDriverObjectType
->QueryName
= NULL
;
163 IoDriverObjectType
->OkayToClose
= NULL
;
164 IoDriverObjectType
->Create
= LdrCreateModule
;
165 RtlInitUnicodeString(&IoDriverObjectType
->TypeName
, L
"Driver");
167 /* Create Modules object directory */
168 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
169 *(wcsrchr(NameBuffer
, L
'\\')) = 0;
170 RtlInitUnicodeString (&ModuleName
, NameBuffer
);
171 InitializeObjectAttributes(&ObjectAttributes
,
176 DPRINT("Create dir: %wZ\n", &ModuleName
);
177 Status
= NtCreateDirectoryObject(&DirHandle
, 0, &ObjectAttributes
);
178 assert(NT_SUCCESS(Status
));
180 /* Add module entry for NTOSKRNL */
181 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
182 wcscat(NameBuffer
, L
"ntoskrnl.exe");
183 RtlInitUnicodeString (&ModuleName
, NameBuffer
);
184 DPRINT("Kernel's Module name is: %wZ\n", &ModuleName
);
186 /* Initialize ObjectAttributes for ModuleObject */
187 InitializeObjectAttributes(&ObjectAttributes
,
193 /* Create module object */
195 ModuleObject
= ObCreateObject(&ModuleHandle
,
196 STANDARD_RIGHTS_REQUIRED
,
199 assert(ModuleObject
!= NULL
);
201 InitializeListHead(&ModuleListHead
);
203 /* Initialize ModuleObject data */
204 ModuleObject
->Base
= (PVOID
) KERNEL_BASE
;
205 ModuleObject
->Flags
= MODULE_FLAG_PE
;
206 InsertTailList(&ModuleListHead
,
207 &ModuleObject
->ListEntry
);
208 RtlCreateUnicodeString(&ModuleObject
->FullName
,
210 LdrpBuildModuleBaseName(&ModuleObject
->BaseName
,
211 &ModuleObject
->FullName
);
213 DosHeader
= (PIMAGE_DOS_HEADER
) KERNEL_BASE
;
214 ModuleObject
->Image
.PE
.FileHeader
=
215 (PIMAGE_FILE_HEADER
) ((DWORD
) ModuleObject
->Base
+
216 DosHeader
->e_lfanew
+ sizeof(ULONG
));
217 ModuleObject
->Image
.PE
.OptionalHeader
= (PIMAGE_OPTIONAL_HEADER
)
218 ((DWORD
)ModuleObject
->Image
.PE
.FileHeader
+ sizeof(IMAGE_FILE_HEADER
));
219 ModuleObject
->Image
.PE
.SectionList
= (PIMAGE_SECTION_HEADER
)
220 ((DWORD
)ModuleObject
->Image
.PE
.OptionalHeader
+ sizeof(IMAGE_OPTIONAL_HEADER
));
221 ModuleObject
->EntryPoint
= (PVOID
) ((DWORD
) ModuleObject
->Base
+
222 ModuleObject
->Image
.PE
.OptionalHeader
->AddressOfEntryPoint
);
223 DPRINT("ModuleObject:%08x entrypoint at %x\n", ModuleObject
, ModuleObject
->EntryPoint
);
224 ModuleObject
->Length
= ModuleObject
->Image
.PE
.OptionalHeader
->SizeOfImage
;
226 /* FIXME: Add fake module entry for HAL */
231 * load the auto config drivers.
233 static VOID
LdrLoadAutoConfigDriver (LPWSTR RelativeDriverName
)
235 WCHAR TmpFileName
[MAX_PATH
];
237 UNICODE_STRING DriverName
;
239 DbgPrint("Loading %S\n",RelativeDriverName
);
241 wcscpy(TmpFileName
, L
"\\SystemRoot\\system32\\drivers\\");
242 wcscat(TmpFileName
, RelativeDriverName
);
243 RtlInitUnicodeString (&DriverName
, TmpFileName
);
245 Status
= LdrLoadDriver(&DriverName
);
246 if (!NT_SUCCESS(Status
))
248 DbgPrint("driver load failed, status (%x)\n", Status
);
255 BOOLEAN
LdrReadLine(PCHAR Line
,
266 while ((*Size
> 0) && ((ch
= *Block
) != (CHAR
)13))
278 if ((*Size
> 0) && (*Block
== (CHAR
)10))
289 ULONG
HexL(PCHAR Buffer
)
298 while ((j
> 0) && ((ch
= Buffer
[i
]) != ' '))
301 if ((ch
>= '0') && (ch
<= '9'))
302 Value
|= ((ch
- '0') << j
);
303 if ((ch
>= 'A') && (ch
<= 'F'))
304 Value
|= ((10 + (ch
- 'A')) << j
);
306 if ((ch
>= 'a') && (ch
<= 'f'))
307 Value
|= ((10 + (ch
- 'a')) << j
);
313 PSYMBOL
LdrParseLine(PCHAR Line
,
315 PBOOLEAN ImageBaseValid
)
317 Line format: [ADDRESS] <TYPE> <NAME>
320 A = Image information
321 t = Symbol in text segment
322 T = Symbol in text segment
323 d = Symbol in data segment
324 D = Symbol in data segment
325 b = Symbol in BSS segment
326 B = Symbol in BSS segment
327 ? = Unknown segment or symbol in unknown segment
330 ANSI_STRING AnsiString
;
337 *ImageBaseValid
= FALSE
;
339 if ((Line
[0] == (CHAR
)0) || (Line
[0] == ' '))
342 Address
= HexL(Line
);
344 Line
= strchr(Line
, ' ');
351 Line
= strchr(Line
, ' ');
356 Str
= strchr(Line
, ' ');
358 strcpy((char*)&Buffer
, Line
);
360 strncpy((char*)&Buffer
, Line
, Str
- Line
);
362 if ((Type
== 'A') && (strcmp((char*)&Buffer
, "__image_base__")) == 0)
364 *ImageBase
= Address
;
365 *ImageBaseValid
= TRUE
;
369 /* We only want symbols in the .text segment */
370 if ((Type
!= 't') && (Type
!= 'T'))
373 /* Discard other symbols we can't use */
374 if ((Buffer
[0] != '_') || ((Buffer
[0] == '_') && (Buffer
[1] == '_')))
377 Symbol
= ExAllocatePool(NonPagedPool
, sizeof(SYMBOL
));
383 Symbol
->RelativeAddress
= Address
;
385 RtlInitAnsiString(&AnsiString
, (PCSZ
)&Buffer
);
386 RtlAnsiStringToUnicodeString(&Symbol
->Name
, &AnsiString
, TRUE
);
391 VOID
LdrLoadModuleSymbols(PMODULE_OBJECT ModuleObject
,
392 MODULE_TEXT_SECTION
* ModuleTextSection
)
394 Symbols must be sorted by address, e.g.
395 "nm --numeric-sort module.sys > module.sym"
398 WCHAR TmpFileName
[MAX_PATH
];
401 UNICODE_STRING Filename
;
402 OBJECT_ATTRIBUTES ObjectAttributes
;
405 PVOID FileBuffer
, FilePtr
;
407 FILE_STANDARD_INFORMATION FileStdInfo
;
408 BOOLEAN ImageBaseValid
;
410 PSYMBOL Symbol
, CurrentSymbol
= NULL
;
412 /* Get the path to the symbol store */
413 wcscpy(TmpFileName
, L
"\\SystemRoot\\symbols\\");
415 /* Get the symbol filename from the module name */
416 Start
= wcsrchr(ModuleObject
->BaseName
.Buffer
, L
'\\');
418 Start
= ModuleObject
->BaseName
.Buffer
;
422 Ext
= wcsrchr(ModuleObject
->BaseName
.Buffer
, L
'.');
424 Length
= Ext
- Start
;
426 Length
= wcslen(Start
);
428 wcsncat(TmpFileName
, Start
, Length
);
429 wcscat(TmpFileName
, L
".sym");
430 RtlInitUnicodeString(&Filename
, TmpFileName
);
433 InitializeObjectAttributes(&ObjectAttributes
,
439 Status
= ZwOpenFile(&FileHandle
,
443 if (!NT_SUCCESS(Status
))
445 DPRINT("Could not open symbol file: %wZ\n", &Filename
);
449 DbgPrint("Loading symbols from %wZ...\n", &Filename
);
451 /* Get the size of the file */
452 Status
= ZwQueryInformationFile(FileHandle
,
456 FileStandardInformation
);
457 if (!NT_SUCCESS(Status
))
459 DPRINT("Could not get file size\n");
463 /* Allocate nonpageable memory for symbol file */
464 FileBuffer
= ExAllocatePool(NonPagedPool
,
465 FileStdInfo
.EndOfFile
.u
.LowPart
);
467 if (FileBuffer
== NULL
)
469 DPRINT("Could not allocate memory for symbol file\n");
473 /* Load file into memory chunk */
474 Status
= ZwReadFile(FileHandle
,
477 FileStdInfo
.EndOfFile
.u
.LowPart
,
479 if (!NT_SUCCESS(Status
))
481 DPRINT("Could not read symbol file into memory\n");
482 ExFreePool(FileBuffer
);
488 ModuleTextSection
->Symbols
.SymbolCount
= 0;
489 ModuleTextSection
->Symbols
.Symbols
= NULL
;
491 FilePtr
= FileBuffer
;
492 Length
= FileStdInfo
.EndOfFile
.u
.LowPart
;
494 while (LdrReadLine((PCHAR
)&Line
, &FilePtr
, &Length
))
496 Symbol
= LdrParseLine((PCHAR
)&Line
, &Tmp
, &ImageBaseValid
);
503 Symbol
->RelativeAddress
-= ImageBase
;
505 if (ModuleTextSection
->Symbols
.Symbols
== NULL
)
506 ModuleTextSection
->Symbols
.Symbols
= Symbol
;
508 CurrentSymbol
->Next
= Symbol
;
510 CurrentSymbol
= Symbol
;
512 ModuleTextSection
->Symbols
.SymbolCount
++;
516 ExFreePool(FileBuffer
);
521 VOID
LdrLoadAutoConfigDrivers (VOID
)
527 WCHAR NameBuffer
[60];
528 UNICODE_STRING ModuleName
;
529 PMODULE_OBJECT ModuleObject
;
530 OBJECT_ATTRIBUTES ObjectAttributes
;
531 UNICODE_STRING RemainingPath
;
533 /* Load symbols for ntoskrnl.exe and hal.dll because \SystemRoot
534 is created after their module entries */
536 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
537 wcscat(NameBuffer
, L
"ntoskrnl.exe");
538 RtlInitUnicodeString(&ModuleName
, NameBuffer
);
540 InitializeObjectAttributes(&ObjectAttributes
,
546 Status
= ObFindObject(&ObjectAttributes
,
547 (PVOID
*)&ModuleObject
,
550 if (NT_SUCCESS(Status
)) {
551 RtlFreeUnicodeString(&RemainingPath
);
553 LdrLoadModuleSymbols(ModuleObject
, &NtoskrnlTextSection
);
556 /* FIXME: Load symbols for hal.dll */
563 LdrLoadAutoConfigDriver( L
"keyboard.sys" );
568 LdrLoadAutoConfigDriver( L
"blue.sys" );
573 LdrLoadAutoConfigDriver(L
"vidport.sys");
578 LdrLoadAutoConfigDriver(L
"vgamp.sys");
581 * Minix filesystem driver
583 LdrLoadAutoConfigDriver(L
"minixfs.sys");
592 LdrLoadAutoConfigDriver(L
"ndis.sys");
595 * Novell Eagle 2000 driver
597 LdrLoadAutoConfigDriver(L
"ne2000.sys");
600 * TCP/IP protocol driver
602 LdrLoadAutoConfigDriver(L
"tcpip.sys");
607 LdrLoadAutoConfigDriver(L
"tditest.sys");
610 * Ancillary Function Driver
612 LdrLoadAutoConfigDriver(L
"afd.sys");
618 LdrCreateModule(PVOID ObjectBody
,
621 POBJECT_ATTRIBUTES ObjectAttributes
)
623 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
627 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+ 1, '\\') != NULL
)
629 return STATUS_UNSUCCESSFUL
;
631 if (Parent
!= NULL
&& RemainingPath
!= NULL
)
633 ObAddEntryDirectory(Parent
, ObjectBody
, RemainingPath
+ 1);
636 return STATUS_SUCCESS
;
640 * FUNCTION: Loads a kernel driver
642 * FileName = Driver to load
646 NTSTATUS
LdrLoadDriver(PUNICODE_STRING Filename
)
648 PMODULE_OBJECT ModuleObject
;
650 ModuleObject
= LdrLoadModule(Filename
);
651 if (ModuleObject
== 0)
653 return STATUS_UNSUCCESSFUL
;
656 /* FIXME: should we dereference the ModuleObject here? */
658 return IoInitializeDriver(ModuleObject
->EntryPoint
);
661 NTSTATUS
LdrLoadGdiDriver (PUNICODE_STRING DriverName
,
663 PVOID
*SectionPointer
,
665 PVOID
*ExportSectionPointer
)
667 PMODULE_OBJECT ModuleObject
;
669 ModuleObject
= LdrLoadModule(DriverName
);
670 if (ModuleObject
== 0)
672 return STATUS_UNSUCCESSFUL
;
676 *ImageAddress
= ModuleObject
->Base
;
678 // if (SectionPointer)
679 // *SectionPointer = ModuleObject->
682 *EntryPoint
= ModuleObject
->EntryPoint
;
684 // if (ExportSectionPointer)
685 // *ExportSectionPointer = ModuleObject->
687 return STATUS_SUCCESS
;
692 LdrLoadModule(PUNICODE_STRING Filename
)
694 PVOID ModuleLoadBase
;
697 OBJECT_ATTRIBUTES ObjectAttributes
;
698 PMODULE_OBJECT ModuleObject
;
699 FILE_STANDARD_INFORMATION FileStdInfo
;
701 /* Check for module already loaded */
702 if ((ModuleObject
= LdrOpenModule(Filename
)) != NULL
)
707 DPRINT("Loading Module %wZ...\n", Filename
);
709 /* Open the Module */
710 InitializeObjectAttributes(&ObjectAttributes
,
716 Status
= NtOpenFile(&FileHandle
,
721 if (!NT_SUCCESS(Status
))
723 DbgPrint("Could not open module file: %wZ\n", Filename
);
728 /* Get the size of the file */
729 Status
= NtQueryInformationFile(FileHandle
,
733 FileStandardInformation
);
734 if (!NT_SUCCESS(Status
))
736 DbgPrint("Could not get file size\n");
741 /* Allocate nonpageable memory for driver */
742 ModuleLoadBase
= ExAllocatePoolWithTag(NonPagedPool
,
743 FileStdInfo
.EndOfFile
.u
.LowPart
,
746 if (ModuleLoadBase
== NULL
)
748 DbgPrint("could not allocate memory for module");
753 /* Load driver into memory chunk */
754 Status
= NtReadFile(FileHandle
,
757 FileStdInfo
.EndOfFile
.u
.LowPart
,
759 if (!NT_SUCCESS(Status
))
761 DbgPrint("could not read module file into memory");
762 ExFreePool(ModuleLoadBase
);
770 ModuleObject
= LdrProcessModule(ModuleLoadBase
, Filename
);
773 ExFreePool(ModuleLoadBase
);
779 LdrProcessDriver(PVOID ModuleLoadBase
, PCHAR FileName
)
781 PMODULE_OBJECT ModuleObject
;
782 UNICODE_STRING ModuleName
;
784 RtlCreateUnicodeStringFromAsciiz(&ModuleName
,
786 ModuleObject
= LdrProcessModule(ModuleLoadBase
,
788 RtlFreeUnicodeString(&ModuleName
);
789 if (ModuleObject
== NULL
)
791 DPRINT1("Driver load was unsuccessful\n");
792 return(STATUS_UNSUCCESSFUL
);
795 /* FIXME: should we dereference the ModuleObject here? */
797 return(IoInitializeDriver(ModuleObject
->EntryPoint
));
801 LdrProcessModule(PVOID ModuleLoadBase
, PUNICODE_STRING ModuleName
)
803 PIMAGE_DOS_HEADER PEDosHeader
;
805 /* If MZ header exists */
806 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
807 if (PEDosHeader
->e_magic
== IMAGE_DOS_MAGIC
&& PEDosHeader
->e_lfanew
!= 0L)
809 return LdrPEProcessModule(ModuleLoadBase
, ModuleName
);
812 DPRINT1("Module wasn't PE\n");
816 static PMODULE_OBJECT
817 LdrOpenModule(PUNICODE_STRING Filename
)
820 WCHAR NameBuffer
[60];
821 UNICODE_STRING ModuleName
;
822 OBJECT_ATTRIBUTES ObjectAttributes
;
823 PMODULE_OBJECT ModuleObject
;
824 UNICODE_STRING RemainingPath
;
826 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
827 if (wcsrchr(Filename
->Buffer
, '\\') != 0)
829 wcscat(NameBuffer
, wcsrchr(Filename
->Buffer
, '\\') + 1);
833 wcscat(NameBuffer
, Filename
->Buffer
);
835 RtlInitUnicodeString (&ModuleName
, NameBuffer
);
836 InitializeObjectAttributes(&ObjectAttributes
,
842 Status
= ObFindObject(&ObjectAttributes
,
843 (PVOID
*) &ModuleObject
,
847 if (NT_SUCCESS(Status
) && (RemainingPath
.Buffer
== NULL
|| *(RemainingPath
.Buffer
) == 0))
849 DPRINT("Module %wZ at %p\n", Filename
, ModuleObject
);
850 RtlFreeUnicodeString (&RemainingPath
);
855 RtlFreeUnicodeString (&RemainingPath
);
861 LdrGetExportAddress(PMODULE_OBJECT ModuleObject
,
865 if (ModuleObject
->Flags
& MODULE_FLAG_PE
)
867 return LdrPEGetExportAddress(ModuleObject
, Name
, Hint
);
876 LdrpQueryModuleInformation(PVOID Buffer
,
880 PLIST_ENTRY current_entry
;
881 PMODULE_OBJECT current
;
882 ULONG ModuleCount
= 0;
883 PSYSTEM_MODULE_INFORMATION Smi
;
884 ANSI_STRING AnsiName
;
887 // KeAcquireSpinLock(&ModuleListLock,&oldlvl);
889 /* calculate required size */
890 current_entry
= ModuleListHead
.Flink
;
891 while (current_entry
!= (&ModuleListHead
))
894 current_entry
= current_entry
->Flink
;
897 *ReqSize
= sizeof(SYSTEM_MODULE_INFORMATION
)+
898 (ModuleCount
- 1) * sizeof(SYSTEM_MODULE_ENTRY
);
902 // KeReleaseSpinLock(&ModuleListLock,oldlvl);
903 return STATUS_INFO_LENGTH_MISMATCH
;
906 /* fill the buffer */
907 memset(Buffer
, '=', Size
);
909 Smi
= (PSYSTEM_MODULE_INFORMATION
)Buffer
;
910 Smi
->Count
= ModuleCount
;
913 current_entry
= ModuleListHead
.Flink
;
914 while (current_entry
!= (&ModuleListHead
))
916 current
= CONTAINING_RECORD(current_entry
,MODULE_OBJECT
,ListEntry
);
918 Smi
->Module
[ModuleCount
].Unknown2
= 0; /* Always 0 */
919 Smi
->Module
[ModuleCount
].BaseAddress
= current
->Base
;
920 Smi
->Module
[ModuleCount
].Size
= current
->Length
;
921 Smi
->Module
[ModuleCount
].Unknown3
= 0; /* Flags ??? */
922 Smi
->Module
[ModuleCount
].EntryIndex
= ModuleCount
;
925 AnsiName
.MaximumLength
= 256;
926 AnsiName
.Buffer
= Smi
->Module
[ModuleCount
].Name
;
927 RtlUnicodeStringToAnsiString(&AnsiName
,
931 p
= strrchr (AnsiName
.Buffer
, '\\');
934 Smi
->Module
[ModuleCount
].PathLength
= 0;
935 Smi
->Module
[ModuleCount
].NameLength
= strlen(AnsiName
.Buffer
);
940 Smi
->Module
[ModuleCount
].PathLength
= p
- AnsiName
.Buffer
;
941 Smi
->Module
[ModuleCount
].NameLength
= strlen(p
);
945 current_entry
= current_entry
->Flink
;
948 // KeReleaseSpinLock(&ModuleListLock,oldlvl);
950 return STATUS_SUCCESS
;
955 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName
,
956 PUNICODE_STRING FullName
)
962 DPRINT("LdrpBuildModuleBaseName()\n");
963 DPRINT("FullName %wZ\n", FullName
);
965 p
= wcsrchr(FullName
->Buffer
, '\\');
968 p
= FullName
->Buffer
;
977 RtlCreateUnicodeString(&Name
, p
);
987 RtlCreateUnicodeString(BaseName
, p
);
988 RtlFreeUnicodeString(&Name
);
992 /* ---------------------------------------------- PE Module support */
995 LdrPEProcessModule(PVOID ModuleLoadBase
, PUNICODE_STRING FileName
)
997 unsigned int DriverSize
, Idx
, Idx2
;
998 ULONG RelocDelta
, NumRelocs
;
999 DWORD CurrentSize
, TotalRelocs
;
1002 PIMAGE_DOS_HEADER PEDosHeader
;
1003 PIMAGE_FILE_HEADER PEFileHeader
;
1004 PIMAGE_OPTIONAL_HEADER PEOptionalHeader
;
1005 PIMAGE_SECTION_HEADER PESectionHeaders
;
1006 PRELOCATION_DIRECTORY RelocDir
;
1007 PRELOCATION_ENTRY RelocEntry
;
1008 PMODULE_OBJECT LibraryModuleObject
;
1009 HANDLE ModuleHandle
;
1010 PMODULE_OBJECT ModuleObject
;
1011 PVOID
*ImportAddressList
;
1012 PULONG FunctionNameList
;
1013 PCHAR pName
, SymbolNameBuf
;
1015 OBJECT_ATTRIBUTES ObjectAttributes
;
1016 UNICODE_STRING ModuleName
;
1017 WCHAR NameBuffer
[60];
1018 MODULE_TEXT_SECTION
* ModuleTextSection
;
1020 DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase
);
1022 /* Get header pointers */
1023 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
1024 PEMagic
= (PULONG
) ((unsigned int) ModuleLoadBase
+
1025 PEDosHeader
->e_lfanew
);
1026 PEFileHeader
= (PIMAGE_FILE_HEADER
) ((unsigned int) ModuleLoadBase
+
1027 PEDosHeader
->e_lfanew
+ sizeof(ULONG
));
1028 PEOptionalHeader
= (PIMAGE_OPTIONAL_HEADER
) ((unsigned int) ModuleLoadBase
+
1029 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
));
1030 PESectionHeaders
= (PIMAGE_SECTION_HEADER
) ((unsigned int) ModuleLoadBase
+
1031 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
) +
1032 sizeof(IMAGE_OPTIONAL_HEADER
));
1035 /* Check file magic numbers */
1036 if (PEDosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
1038 DbgPrint("Incorrect MZ magic: %04x\n", PEDosHeader
->e_magic
);
1041 if (PEDosHeader
->e_lfanew
== 0)
1043 DbgPrint("Invalid lfanew offset: %08x\n", PEDosHeader
->e_lfanew
);
1046 if (*PEMagic
!= IMAGE_PE_MAGIC
)
1048 DbgPrint("Incorrect PE magic: %08x\n", *PEMagic
);
1051 if (PEFileHeader
->Machine
!= IMAGE_FILE_MACHINE_I386
)
1053 DbgPrint("Incorrect Architechture: %04x\n", PEFileHeader
->Machine
);
1058 /* FIXME: if image is fixed-address load, then fail */
1060 /* FIXME: check/verify OS version number */
1062 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
1063 PEOptionalHeader
->Magic
,
1064 PEOptionalHeader
->MajorLinkerVersion
,
1065 PEOptionalHeader
->MinorLinkerVersion
);
1066 DPRINT("Entry Point:%08lx\n", PEOptionalHeader
->AddressOfEntryPoint
);
1069 /* Determine the size of the module */
1070 DriverSize
= PEOptionalHeader
->SizeOfImage
;
1071 DPRINT("DriverSize %x\n",DriverSize
);
1073 /* Allocate a virtual section for the module */
1074 DriverBase
= MmAllocateSection(DriverSize
);
1075 if (DriverBase
== 0)
1077 DbgPrint("Failed to allocate a virtual section for driver\n");
1080 DbgPrint("DriverBase: %x\n", DriverBase
);
1082 /* Copy headers over */
1083 memcpy(DriverBase
, ModuleLoadBase
, PEOptionalHeader
->SizeOfHeaders
);
1085 /* Copy image sections into virtual section */
1086 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
1088 // Copy current section into current offset of virtual section
1089 if (PESectionHeaders
[Idx
].Characteristics
&
1090 (IMAGE_SECTION_CHAR_CODE
| IMAGE_SECTION_CHAR_DATA
))
1092 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
1093 PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
);
1094 memcpy(PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
,
1095 (PVOID
)(ModuleLoadBase
+ PESectionHeaders
[Idx
].PointerToRawData
),
1096 PESectionHeaders
[Idx
].Misc
.VirtualSize
> PESectionHeaders
[Idx
].SizeOfRawData
? PESectionHeaders
[Idx
].SizeOfRawData
: PESectionHeaders
[Idx
].Misc
.VirtualSize
);
1100 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
1101 PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
);
1102 memset(PESectionHeaders
[Idx
].VirtualAddress
+ DriverBase
,
1103 '\0', PESectionHeaders
[Idx
].Misc
.VirtualSize
);
1106 CurrentSize
+= ROUND_UP(PESectionHeaders
[Idx
].Misc
.VirtualSize
,
1107 PEOptionalHeader
->SectionAlignment
);
1110 // CurrentBase = (PVOID)((DWORD)CurrentBase +
1111 // ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
1112 // PEOptionalHeader->SectionAlignment));
1115 /* Perform relocation fixups */
1116 RelocDelta
= (DWORD
) DriverBase
- PEOptionalHeader
->ImageBase
;
1117 RelocDir
= (PRELOCATION_DIRECTORY
)(PEOptionalHeader
->DataDirectory
[
1118 IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
);
1119 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
1121 PEOptionalHeader
->ImageBase
,
1123 DPRINT("RelocDir %x\n",RelocDir
);
1125 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
1127 if (PESectionHeaders
[Idx
].VirtualAddress
== (DWORD
)RelocDir
)
1129 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1130 PESectionHeaders
[Idx
].Name
,
1131 PESectionHeaders
[Idx
].PointerToRawData
);
1132 RelocDir
= PESectionHeaders
[Idx
].PointerToRawData
+
1134 CurrentSize
= PESectionHeaders
[Idx
].Misc
.VirtualSize
;
1139 RelocDir
= RelocDir
+ (ULONG
)DriverBase
;
1140 CurrentSize
= PEOptionalHeader
->DataDirectory
1141 [IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
1143 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir
, CurrentSize
);
1145 while (TotalRelocs
< CurrentSize
&& RelocDir
->SizeOfBlock
!= 0)
1147 NumRelocs
= (RelocDir
->SizeOfBlock
- sizeof(RELOCATION_DIRECTORY
)) /
1149 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
1151 RelocDir->VirtualAddress,
1153 RelocEntry
= (PRELOCATION_ENTRY
) ((DWORD
)RelocDir
+
1154 sizeof(RELOCATION_DIRECTORY
));
1155 for (Idx
= 0; Idx
< NumRelocs
; Idx
++)
1161 Offset
= RelocEntry
[Idx
].TypeOffset
& 0xfff;
1162 Type
= (RelocEntry
[Idx
].TypeOffset
>> 12) & 0xf;
1163 RelocItem
= (PDWORD
)(DriverBase
+ RelocDir
->VirtualAddress
+
1165 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
1168 Type ? "HIGHLOW" : "ABS",
1170 (*RelocItem) + RelocDelta); */
1173 (*RelocItem
) += RelocDelta
;
1177 DbgPrint("Unknown relocation type %x at %x\n",Type
, &Type
);
1181 TotalRelocs
+= RelocDir
->SizeOfBlock
;
1182 RelocDir
= (PRELOCATION_DIRECTORY
)((DWORD
)RelocDir
+
1183 RelocDir
->SizeOfBlock
);
1184 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
1187 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1188 PEOptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1190 /* Perform import fixups */
1191 if (PEOptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
)
1193 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1195 SymbolNameBuf
= ExAllocatePoolWithTag(NonPagedPool
, 512, TAG_SYM_BUF
);
1197 /* Process each import module */
1198 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1199 ((DWORD
)DriverBase
+ PEOptionalHeader
->
1200 DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
);
1201 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
1202 while (ImportModuleDirectory
->dwRVAModuleName
)
1204 /* Check to make sure that import lib is kernel */
1205 pName
= (PCHAR
) DriverBase
+
1206 ImportModuleDirectory
->dwRVAModuleName
;
1207 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
1208 for (Idx
= 0; NameBuffer
[Idx
] != 0; Idx
++)
1210 for (Idx2
= 0; pName
[Idx2
] != '\0'; Idx2
++)
1212 NameBuffer
[Idx
+ Idx2
] = (WCHAR
) pName
[Idx2
];
1214 NameBuffer
[Idx
+ Idx2
] = 0;
1215 RtlInitUnicodeString (&ModuleName
, NameBuffer
);
1216 DPRINT("Import module: %wZ\n", &ModuleName
);
1218 LibraryModuleObject
= LdrLoadModule(&ModuleName
);
1219 if (LibraryModuleObject
== 0)
1221 DbgPrint("Unknown import module: %wZ\n", &ModuleName
);
1223 /* Get the import address list */
1224 ImportAddressList
= (PVOID
*) ((DWORD
)DriverBase
+
1225 ImportModuleDirectory
->dwRVAFunctionAddressList
);
1227 /* Get the list of functions to import */
1228 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1230 FunctionNameList
= (PULONG
) ((DWORD
)DriverBase
+
1231 ImportModuleDirectory
->dwRVAFunctionNameList
);
1235 FunctionNameList
= (PULONG
) ((DWORD
)DriverBase
+
1236 ImportModuleDirectory
->dwRVAFunctionAddressList
);
1238 /* Walk through function list and fixup addresses */
1239 while (*FunctionNameList
!= 0L)
1241 if ((*FunctionNameList
) & 0x80000000) // hint
1246 Hint
= (*FunctionNameList
) & 0xffff;
1250 pName
= (PCHAR
)((DWORD
)DriverBase
+
1251 *FunctionNameList
+ 2);
1252 Hint
= *(PWORD
)((DWORD
)DriverBase
+ *FunctionNameList
);
1254 DPRINT(" Hint:%04x Name:%s\n", Hint
, pName
);
1256 /* Fixup the current import symbol */
1257 if (LibraryModuleObject
!= NULL
)
1259 *ImportAddressList
= LdrGetExportAddress(LibraryModuleObject
,
1265 DbgPrint("Unresolved kernel symbol: %s\n", pName
);
1268 ImportAddressList
++;
1271 ImportModuleDirectory
++;
1274 ExFreePool(SymbolNameBuf
);
1277 /* Create ModuleName string */
1278 wcscpy(NameBuffer
, MODULE_ROOT_NAME
);
1279 if (wcsrchr(FileName
->Buffer
, '\\') != 0)
1281 wcscat(NameBuffer
, wcsrchr(FileName
->Buffer
, '\\') + 1);
1285 wcscat(NameBuffer
, FileName
->Buffer
);
1287 RtlInitUnicodeString (&ModuleName
, NameBuffer
);
1288 DbgPrint("Module name is: %wZ\n", &ModuleName
);
1290 /* Initialize ObjectAttributes for ModuleObject */
1291 InitializeObjectAttributes(&ObjectAttributes
,
1297 /* Create module object */
1299 ModuleObject
= ObCreateObject(&ModuleHandle
,
1300 STANDARD_RIGHTS_REQUIRED
,
1302 IoDriverObjectType
);
1304 /* Initialize ModuleObject data */
1305 ModuleObject
->Base
= DriverBase
;
1306 ModuleObject
->Flags
= MODULE_FLAG_PE
;
1307 InsertTailList(&ModuleListHead
,
1308 &ModuleObject
->ListEntry
);
1309 RtlCreateUnicodeString(&ModuleObject
->FullName
,
1311 LdrpBuildModuleBaseName(&ModuleObject
->BaseName
,
1312 &ModuleObject
->FullName
);
1314 ModuleObject
->EntryPoint
= (PVOID
) ((DWORD
)DriverBase
+
1315 PEOptionalHeader
->AddressOfEntryPoint
);
1316 ModuleObject
->Length
= DriverSize
;
1317 DPRINT("entrypoint at %x\n", ModuleObject
->EntryPoint
);
1319 ModuleObject
->Image
.PE
.FileHeader
=
1320 (PIMAGE_FILE_HEADER
) ((unsigned int) DriverBase
+ PEDosHeader
->e_lfanew
+ sizeof(ULONG
));
1322 DPRINT("FileHeader at %x\n", ModuleObject
->Image
.PE
.FileHeader
);
1323 ModuleObject
->Image
.PE
.OptionalHeader
=
1324 (PIMAGE_OPTIONAL_HEADER
) ((unsigned int) DriverBase
+ PEDosHeader
->e_lfanew
+ sizeof(ULONG
) +
1325 sizeof(IMAGE_FILE_HEADER
));
1326 DPRINT("OptionalHeader at %x\n", ModuleObject
->Image
.PE
.OptionalHeader
);
1327 ModuleObject
->Image
.PE
.SectionList
=
1328 (PIMAGE_SECTION_HEADER
) ((unsigned int) DriverBase
+ PEDosHeader
->e_lfanew
+ sizeof(ULONG
) +
1329 sizeof(IMAGE_FILE_HEADER
) + sizeof(IMAGE_OPTIONAL_HEADER
));
1330 DPRINT("SectionList at %x\n", ModuleObject
->Image
.PE
.SectionList
);
1332 ModuleTextSection
= ExAllocatePool(NonPagedPool
,
1333 sizeof(MODULE_TEXT_SECTION
));
1334 ModuleTextSection
->Base
= (ULONG
)DriverBase
;
1335 ModuleTextSection
->Length
= DriverSize
;
1336 ModuleTextSection
->SymbolsBase
= NULL
;
1337 ModuleTextSection
->SymbolsLength
= 0;
1338 ModuleTextSection
->Name
=
1339 ExAllocatePool(NonPagedPool
,
1340 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
1341 wcscpy(ModuleTextSection
->Name
, NameBuffer
);
1342 InsertTailList(&ModuleTextListHead
, &ModuleTextSection
->ListEntry
);
1346 /* Load symbols for module if available */
1347 LdrLoadModuleSymbols(ModuleObject
, ModuleTextSection
);
1351 return ModuleObject
;
1355 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject
,
1357 unsigned short Hint
)
1360 PVOID ExportAddress
;
1362 PDWORD FunctionList
, NameList
;
1363 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1364 ULONG ExportDirSize
;
1366 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1367 RtlImageDirectoryEntryToData(ModuleObject
->Base
,
1369 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1371 DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir
, ExportDirSize
);
1372 if (ExportDir
== NULL
)
1378 FunctionList
= (PDWORD
)((DWORD
)ExportDir
->AddressOfFunctions
+ ModuleObject
->Base
);
1379 NameList
= (PDWORD
)((DWORD
)ExportDir
->AddressOfNames
+ ModuleObject
->Base
);
1380 OrdinalList
= (PWORD
)((DWORD
)ExportDir
->AddressOfNameOrdinals
+ ModuleObject
->Base
);
1386 for (Idx
= 0; Idx
< ExportDir
->NumberOfNames
; Idx
++)
1389 DPRINT(" Name:%s NameList[%d]:%s\n",
1392 (DWORD
) ModuleObject
->Base
+ NameList
[Idx
]);
1395 if (!strcmp(Name
, (PCHAR
) ((DWORD
)ModuleObject
->Base
+ NameList
[Idx
])))
1397 ExportAddress
= (PVOID
) ((DWORD
)ModuleObject
->Base
+
1398 FunctionList
[OrdinalList
[Idx
]]);
1399 if (((ULONG
)ExportAddress
>= (ULONG
)ExportDir
) &&
1400 ((ULONG
)ExportAddress
< (ULONG
)ExportDir
+ ExportDirSize
))
1402 DPRINT("Forward: %s\n", (PCHAR
)ExportAddress
);
1403 ExportAddress
= LdrPEFixupForward((PCHAR
)ExportAddress
);
1404 DPRINT("ExportAddress: %p\n", ExportAddress
);
1413 ExportAddress
= (PVOID
) ((DWORD
)ModuleObject
->Base
+
1414 FunctionList
[Hint
- ExportDir
->Base
]);
1417 if (ExportAddress
== 0)
1419 DbgPrint("Export not found for %d:%s\n",
1421 Name
!= NULL
? Name
: "(Ordinal)");
1425 return ExportAddress
;
1429 static PMODULE_OBJECT
1430 LdrPEGetModuleObject(PUNICODE_STRING ModuleName
)
1433 PMODULE_OBJECT Module
;
1435 DPRINT("LdrPEGetModuleObject (ModuleName %wZ)\n",
1438 Entry
= ModuleListHead
.Flink
;
1440 while (Entry
!= &ModuleListHead
)
1442 Module
= CONTAINING_RECORD(Entry
, MODULE_OBJECT
, ListEntry
);
1444 DPRINT("Comparing %wZ and %wZ\n",
1448 if (!RtlCompareUnicodeString(&Module
->BaseName
, ModuleName
, TRUE
))
1450 DPRINT("Module %x\n", Module
);
1454 Entry
= Entry
->Flink
;
1457 DbgPrint("LdrPEGetModuleObject: Failed to find dll %wZ\n", ModuleName
);
1464 LdrPEFixupForward(PCHAR ForwardName
)
1466 CHAR NameBuffer
[128];
1467 UNICODE_STRING ModuleName
;
1469 PMODULE_OBJECT ModuleObject
;
1471 DPRINT("LdrPEFixupForward (%s)\n", ForwardName
);
1473 strcpy(NameBuffer
, ForwardName
);
1474 p
= strchr(NameBuffer
, '.');
1482 DPRINT("Driver: %s Function: %s\n", NameBuffer
, p
+1);
1484 RtlCreateUnicodeStringFromAsciiz(&ModuleName
,
1486 ModuleObject
= LdrPEGetModuleObject(&ModuleName
);
1487 RtlFreeUnicodeString(&ModuleName
);
1489 DPRINT("ModuleObject: %p\n", ModuleObject
);
1491 if (ModuleObject
== NULL
)
1493 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer
);
1497 return LdrPEGetExportAddress(ModuleObject
, p
+1, 0);