1 /* $Id: utils.c,v 1.30 2000/08/27 22:36:45 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
11 /* INCLUDES *****************************************************************/
13 #include <reactos/config.h>
14 #include <ddk/ntddk.h>
18 #include <ntdll/ldr.h>
19 #include <ntos/minmax.h>
21 #ifdef DBG_NTDLL_LDR_UTILS
24 #include <ntdll/ntdll.h>
26 /* FUNCTIONS *****************************************************************/
29 /* Type for a DLL's entry point */
35 ULONG ul_reason_for_call
,
41 LdrFindDll (PDLL
* Dll
,PUNICODE_STRING Name
);
42 //LdrFindDll (PDLL* Dll,PCHAR Name);
44 /**********************************************************************
63 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
65 IN PUNICODE_STRING Name
,
66 OUT PVOID
*BaseAddress OPTIONAL
)
68 WCHAR fqname
[255] = L
"\\SystemRoot\\system32\\";
69 // ANSI_STRING AnsiString;
70 UNICODE_STRING UnicodeString
;
71 OBJECT_ATTRIBUTES FileObjectAttributes
;
72 char BlockBuffer
[1024];
73 PIMAGE_DOS_HEADER DosHeader
;
75 PIMAGE_NT_HEADERS NTHeaders
;
77 ULONG InitialViewSize
;
81 PDLLMAIN_FUNC Entrypoint
= NULL
;
86 *BaseAddress
= LdrDllListHead
.BaseAddress
;
87 return STATUS_SUCCESS
;
92 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
96 * Build the DLL's absolute name
99 if (wcsncmp(Name
->Buffer
, L
"\\??\\", 3) != 0)
101 wcscat(fqname
, Name
->Buffer
);
104 wcsncpy(fqname
, Name
->Buffer
, 256);
106 DPRINT("fqname \"%S\"\n", fqname
);
109 * Open the DLL's image file.
111 if (LdrFindDll(&Dll
, Name
) == STATUS_SUCCESS
)
113 DPRINT ("DLL %wZ already loaded.\n", Name
);
114 *BaseAddress
= Dll
->BaseAddress
;
115 return STATUS_SUCCESS
;
122 RtlAnsiStringToUnicodeString(
128 RtlInitUnicodeString(&UnicodeString
,
131 InitializeObjectAttributes(
132 & FileObjectAttributes
,
139 DPRINT("Opening dll \"%wZ\"\n", &UnicodeString
);
144 & FileObjectAttributes
,
149 if (!NT_SUCCESS(Status
))
151 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
152 &UnicodeString
, Status
);
166 if (!NT_SUCCESS(Status
))
168 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
173 * Overlay DOS and NT headers structures to the
174 * buffer with DLL's header raw data.
176 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
177 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
179 * Check it is a PE image file.
181 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
182 || (DosHeader
->e_lfanew
== 0L)
183 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
185 DPRINT("NTDLL format invalid\n");
188 return STATUS_UNSUCCESSFUL
;
191 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
192 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
194 DPRINT("ImageBase 0x%08x\n", ImageBase
);
197 * Create a section for dll.
199 Status
= ZwCreateSection(
208 if (!NT_SUCCESS(Status
))
210 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
215 * Map the dll into the process.
219 + sizeof (IMAGE_NT_HEADERS
)
220 + sizeof (IMAGE_SECTION_HEADER
) * NTHeaders
->FileHeader
.NumberOfSections
;
221 Status
= ZwMapViewOfSection(
233 if (!NT_SUCCESS(Status
))
235 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
242 Dll
= RtlAllocateHeap(
247 Dll
->Headers
= NTHeaders
;
248 Dll
->BaseAddress
= (PVOID
)ImageBase
;
249 Dll
->Next
= LdrDllListHead
.Next
;
250 Dll
->Prev
= & LdrDllListHead
;
251 Dll
->ReferenceCount
= 1;
252 LdrDllListHead
.Next
->Prev
= Dll
;
253 LdrDllListHead
.Next
= Dll
;
256 if ((Dll
->Headers
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
261 (PDLLMAIN_FUNC
) LdrPEStartup(
265 if (Entrypoint
!= NULL
)
267 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
268 if (FALSE
== Entrypoint(
274 DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname
);
275 /* FIXME: should clean up and fail */
279 DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname
);
284 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname
);
288 *BaseAddress
= Dll
->BaseAddress
;
289 return STATUS_SUCCESS
;
293 /**********************************************************************
308 //static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
309 static NTSTATUS
LdrFindDll(PDLL
* Dll
, PUNICODE_STRING Name
)
311 PIMAGE_EXPORT_DIRECTORY ExportDir
;
312 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
314 UNICODE_STRING DllName
;
316 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name
);
318 current
= & LdrDllListHead
;
320 // NULL is the current process
325 return STATUS_SUCCESS
;
330 OptionalHeader
= & current
->Headers
->OptionalHeader
;
331 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
332 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
334 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
335 ((ULONG
)ExportDir
+ (ULONG
)current
->BaseAddress
);
337 DPRINT("Scanning %x %x %x\n",ExportDir
->Name
,
338 current
->BaseAddress
,
339 (ExportDir
->Name
+ current
->BaseAddress
));
341 RtlCreateUnicodeStringFromAsciiz (&DllName
,
342 ExportDir
->Name
+ current
->BaseAddress
);
344 DPRINT("Scanning %wZ %wZ\n", &DllName
, Name
);
346 if (RtlCompareUnicodeString(&DllName
, Name
, TRUE
) == 0)
349 current
->ReferenceCount
++;
350 RtlFreeUnicodeString (&DllName
);
351 return STATUS_SUCCESS
;
354 current
= current
->Next
;
356 } while (current
!= & LdrDllListHead
);
358 RtlFreeUnicodeString (&DllName
);
360 DPRINT("Failed to find dll %wZ\n", Name
);
362 return STATUS_UNSUCCESSFUL
;
366 /**********************************************************************
381 NTSTATUS
LdrMapSections(HANDLE ProcessHandle
,
383 HANDLE SectionHandle
,
384 PIMAGE_NT_HEADERS NTHeaders
)
389 for (i
= 0; (i
< NTHeaders
->FileHeader
.NumberOfSections
); i
++)
391 PIMAGE_SECTION_HEADER Sections
;
392 LARGE_INTEGER Offset
;
396 Sections
= (PIMAGE_SECTION_HEADER
) SECHDROFFSET(ImageBase
);
397 Base
= (ULONG
) (Sections
[i
].VirtualAddress
+ ImageBase
);
398 Offset
.u
.LowPart
= Sections
[i
].PointerToRawData
;
399 Offset
.u
.HighPart
= 0;
401 Size
= max(Sections
[i
].Misc
.VirtualSize
, Sections
[i
].SizeOfRawData
);
403 DPRINT("Mapping section %d offset %x base %x size %x\n",
404 i
, Offset
.u
.LowPart
, Base
, Sections
[i
].Misc
.VirtualSize
);
405 DPRINT("Size %x\n", Sections
[i
].SizeOfRawData
);
407 Status
= ZwMapViewOfSection(SectionHandle
,
417 if (!NT_SUCCESS(Status
))
419 DPRINT("Failed to map section");
423 return STATUS_SUCCESS
;
427 /**********************************************************************
429 * LdrGetExportByOrdinal
443 LdrGetExportByOrdinal (
448 PIMAGE_EXPORT_DIRECTORY ExportDir
;
449 PDWORD
* ExFunctions
;
452 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
453 RtlImageDirectoryEntryToData (BaseAddress
,
455 IMAGE_DIRECTORY_ENTRY_EXPORT
,
459 ExOrdinals
= (USHORT
*)
462 ExportDir
->AddressOfNameOrdinals
464 ExFunctions
= (PDWORD
*)
467 ExportDir
->AddressOfFunctions
470 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
472 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
474 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
478 /**********************************************************************
499 PIMAGE_EXPORT_DIRECTORY ExportDir
;
500 PDWORD
* ExFunctions
;
508 // "LdrFindExport(Module %x, SymbolName %s)\n",
513 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
514 RtlImageDirectoryEntryToData (BaseAddress
,
516 IMAGE_DIRECTORY_ENTRY_EXPORT
,
520 * Get header pointers
525 ExportDir
->AddressOfNames
527 ExOrdinals
= (USHORT
*)
530 ExportDir
->AddressOfNameOrdinals
532 ExFunctions
= (PDWORD
*)
535 ExportDir
->AddressOfFunctions
538 ( i
< ExportDir
->NumberOfFunctions
);
547 // "Comparing '%s' '%s'\n",
551 if (strcmp(ExName
,SymbolName
) == 0)
553 Ordinal
= ExOrdinals
[i
];
554 return(RVA(BaseAddress
, ExFunctions
[Ordinal
]));
558 DbgPrint("LdrGetExportByName() = failed to find %s\n",SymbolName
);
564 /**********************************************************************
566 * LdrPerformRelocations
569 * Relocate a DLL's memory image.
580 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
583 USHORT NumberOfEntries
;
589 PRELOCATION_DIRECTORY RelocationDir
;
590 PRELOCATION_ENTRY RelocationBlock
;
594 RelocationRVA
= NTHeaders
->OptionalHeader
595 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
600 RelocationDir
= (PRELOCATION_DIRECTORY
)
601 ((PCHAR
)ImageBase
+ RelocationRVA
);
603 while (RelocationDir
->SizeOfBlock
)
605 Delta32
= (ULONG
)(ImageBase
-
606 NTHeaders
->OptionalHeader
.ImageBase
);
607 RelocationBlock
= (PRELOCATION_ENTRY
) (
610 + sizeof (RELOCATION_DIRECTORY
)
613 RelocationDir
->SizeOfBlock
614 - sizeof (RELOCATION_DIRECTORY
)
616 / sizeof (RELOCATION_ENTRY
);
619 (i
< NumberOfEntries
);
624 RelocationBlock
[i
].TypeOffset
627 + RelocationDir
->VirtualAddress
;
629 * What kind of relocations should we perform
630 * for the current entry?
632 switch (RelocationBlock
[i
].TypeOffset
>> 12)
634 case TYPE_RELOC_ABSOLUTE
:
637 case TYPE_RELOC_HIGH
:
638 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
639 *pValue16
+= Delta32
>> 16;
643 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
644 *pValue16
+= Delta32
& 0xffff;
647 case TYPE_RELOC_HIGHLOW
:
648 pValue32
= (PULONG
) (ImageBase
+ Offset
);
649 *pValue32
+= Delta32
;
652 case TYPE_RELOC_HIGHADJ
:
653 /* FIXME: do the highadjust fixup */
655 "TYPE_RELOC_HIGHADJ fixup not implemented"
658 return(STATUS_UNSUCCESSFUL
);
661 DPRINT("unexpected fixup type\n");
662 return STATUS_UNSUCCESSFUL
;
665 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
666 RelocationDir
= (PRELOCATION_DIRECTORY
) (
672 return STATUS_SUCCESS
;
676 /**********************************************************************
681 * Compute the entry point for every symbol the DLL imports
682 * from other modules.
693 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
696 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
701 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
705 * Process each import module.
707 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
708 ImageBase
+ NTHeaders
->OptionalHeader
709 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
711 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
713 while (ImportModuleDirectory
->dwRVAModuleName
)
715 PVOID
* ImportAddressList
;
716 PULONG FunctionNameList
;
717 UNICODE_STRING DllName
;
721 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
722 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
724 RtlCreateUnicodeStringFromAsciiz (&DllName
,
725 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
727 Status
= LdrLoadDll(NULL
,
731 // +ImportModuleDirectory->dwRVAModuleName),
733 RtlFreeUnicodeString (&DllName
);
734 if (!NT_SUCCESS(Status
))
740 * Get the import address list.
742 ImportAddressList
= (PVOID
*)(NTHeaders
->OptionalHeader
.ImageBase
743 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
746 * Get the list of functions to import.
748 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
750 FunctionNameList
= (PULONG
) (
752 + ImportModuleDirectory
->dwRVAFunctionNameList
757 FunctionNameList
= (PULONG
) (
759 + ImportModuleDirectory
->dwRVAFunctionAddressList
763 * Walk through function list and fixup addresses.
765 while (*FunctionNameList
!= 0L)
767 if ((*FunctionNameList
) & 0x80000000)
769 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
771 LdrGetExportByOrdinal(BaseAddress
,
782 + *FunctionNameList
);
785 LdrGetExportByName(BaseAddress
,
787 if ((*ImportAddressList
) == NULL
)
789 DbgPrint("Failed to import %s\n", pName
);
790 return STATUS_UNSUCCESSFUL
;
796 ImportModuleDirectory
++;
798 return STATUS_SUCCESS
;
802 /**********************************************************************
807 * 1. Map the DLL's sections into memory.
808 * 2. Relocate, if needed the DLL.
809 * 3. Fixup any imported symbol.
810 * 4. Compute the DLL's entry point.
814 * Address at which the DLL's image
818 * Handle of the section that contains
822 * NULL on error; otherwise the entry point
823 * to call for initializing the DLL.
830 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
831 HANDLE SectionHandle
)
834 PEPFUNC EntryPoint
= NULL
;
835 PIMAGE_DOS_HEADER DosHeader
;
836 PIMAGE_NT_HEADERS NTHeaders
;
840 * Overlay DOS and WNT headers structures
841 * to the DLL's image.
843 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
844 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
847 * Initialize image sections.
849 if (SectionHandle
!= NULL
)
851 LdrMapSections(NtCurrentProcess(),
858 * If the base address is different from the
859 * one the DLL is actually loaded, perform any
862 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
864 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
865 if (!NT_SUCCESS(Status
))
867 DbgPrint("LdrPerformRelocations() failed\n");
873 * If the DLL's imports symbols from other
874 * modules, fixup the imported calls entry points.
876 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
877 .VirtualAddress
!= 0)
879 DPRINT("About to fixup imports\n");
880 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
881 if (!NT_SUCCESS(Status
))
883 DbgPrint("LdrFixupImports() failed\n");
889 * Compute the DLL's entry point's address.
891 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
893 EntryPoint
= (PEPFUNC
) (ImageBase
894 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
896 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
902 LdrUnloadDll (IN PVOID BaseAddress
)
904 PDLLMAIN_FUNC Entrypoint
;
908 if (BaseAddress
== NULL
)
909 return STATUS_SUCCESS
;
911 Dll
= &LdrDllListHead
;
915 if (Dll
->BaseAddress
== BaseAddress
)
918 if ( Dll
->ReferenceCount
> 1 )
920 Dll
->ReferenceCount
--;
921 return STATUS_SUCCESS
;
925 if ((Dll
->Headers
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
927 Entrypoint
= (PDLLMAIN_FUNC
) LdrPEStartup(Dll
->BaseAddress
,
929 if (Entrypoint
!= NULL
)
931 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
932 Entrypoint(Dll
->BaseAddress
,
938 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
941 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
944 ZwClose (Dll
->SectionHandle
);
949 } while (Dll
!= & LdrDllListHead
);
951 DPRINT("NTDLL.LDR: Dll not found\n")
953 return STATUS_UNSUCCESSFUL
;
957 static PIMAGE_RESOURCE_DIRECTORY_ENTRY
958 LdrGetNextEntry(IMAGE_RESOURCE_DIRECTORY
*ResourceDir
, LPCWSTR ResourceName
, ULONG Offset
)
960 WORD NumberOfNamedEntries
;
961 WORD NumberOfIdEntries
;
965 if ( (((ULONG
)ResourceDir
) & 0xF0000000) != 0 ) {
966 return (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)NULL
;
969 NumberOfIdEntries
= ResourceDir
->NumberOfIdEntries
;
970 NumberOfNamedEntries
= ResourceDir
->NumberOfNamedEntries
;
971 if ( ( NumberOfIdEntries
+ NumberOfNamedEntries
) == 0) {
972 return &ResourceDir
->DirectoryEntries
[0];
975 if ( HIWORD(ResourceName
) != 0 ) {
976 Length
= wcslen(ResourceName
);
977 Entries
= ResourceDir
->NumberOfNamedEntries
;
979 IMAGE_RESOURCE_DIR_STRING_U
*DirString
;
982 DirString
= (IMAGE_RESOURCE_DIR_STRING_U
*)(((ULONG
)ResourceDir
->DirectoryEntries
[Entries
].Name
& (~0xF0000000)) + Offset
);
984 if ( DirString
->Length
== Length
&& wcscmp(DirString
->NameString
, ResourceName
) == 0 ) {
985 return &ResourceDir
->DirectoryEntries
[Entries
];
987 } while (Entries
> 0);
990 Entries
= ResourceDir
->NumberOfIdEntries
+ ResourceDir
->NumberOfNamedEntries
;
994 if ( (LPWSTR
)ResourceDir
->DirectoryEntries
[Entries
].Name
== ResourceName
) {
995 return &ResourceDir
->DirectoryEntries
[Entries
];
997 } while (Entries
> ResourceDir
->NumberOfNamedEntries
);
1006 NTSTATUS
LdrFindResource_U(DLL
*Dll
, IMAGE_RESOURCE_DATA_ENTRY
**ResourceDataEntry
,LPCWSTR ResourceName
, ULONG ResourceType
,ULONG Language
)
1008 IMAGE_RESOURCE_DIRECTORY
*ResourceTypeDir
;
1009 IMAGE_RESOURCE_DIRECTORY
*ResourceNameDir
;
1010 IMAGE_RESOURCE_DIRECTORY
*ResourceLangDir
;
1012 IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceTypeDirEntry
;
1013 IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceNameDirEntry
;
1014 IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceLangDirEntry
;
1016 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
1022 OptionalHeader
= & Dll
->Headers
->OptionalHeader
;
1023 ResourceTypeDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1024 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1025 ResourceTypeDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1026 ((ULONG
)ResourceTypeDir
+ (ULONG
)Dll
->BaseAddress
);
1029 Offset
= (ULONG
)ResourceTypeDir
;
1031 ResourceTypeDirEntry
= LdrGetNextEntry(ResourceTypeDir
, (LPWSTR
)ResourceType
, Offset
);
1033 if ( ResourceTypeDirEntry
!= NULL
) {
1034 ResourceNameDir
= (IMAGE_RESOURCE_DIRECTORY
*)((ResourceTypeDirEntry
->OffsetToData
& (~0xF0000000)) + Offset
);
1036 ResourceNameDirEntry
= LdrGetNextEntry(ResourceNameDir
, ResourceName
, Offset
);
1038 if ( ResourceNameDirEntry
!= NULL
) {
1040 ResourceLangDir
= (IMAGE_RESOURCE_DIRECTORY
*)((ResourceNameDirEntry
->OffsetToData
& (~0xF0000000)) + Offset
);
1042 ResourceLangDirEntry
= LdrGetNextEntry(ResourceLangDir
, (LPWSTR
)Language
, Offset
);
1043 if ( ResourceLangDirEntry
!= NULL
) {
1045 *ResourceDataEntry
= (IMAGE_RESOURCE_DATA_ENTRY
*)(ResourceLangDirEntry
->OffsetToData
+
1046 (ULONG
)ResourceTypeDir
);
1047 return STATUS_SUCCESS
;
1065 LdrAccessResource(IN PVOID BaseAddress
,
1066 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
1067 OUT PVOID
*Resource OPTIONAL
,
1068 OUT PULONG Size OPTIONAL
)
1070 PIMAGE_SECTION_HEADER Section
;
1071 PIMAGE_NT_HEADERS NtHeader
;
1078 Data
= (ULONG
)RtlImageDirectoryEntryToData (BaseAddress
,
1080 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1083 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1085 if ((ULONG
)BaseAddress
& 1)
1087 /* loaded as ordinary file */
1088 NtHeader
= RtlImageNtHeader((PVOID
)((ULONG
)BaseAddress
& ~1UL));
1089 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1090 Section
= RtlImageRvaToSection (NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
1091 if (Section
== NULL
)
1093 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1096 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
)
1098 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
1099 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
1100 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
1106 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
1111 *Size
= ResourceDataEntry
->Size
;
1114 return STATUS_SUCCESS
;
1120 LdrDisableThreadCalloutsForDll (
1121 IN PVOID BaseAddress
,
1125 /* FIXME: implement it! */
1127 return STATUS_SUCCESS
;
1132 LdrFindResourceDirectory_U (IN PVOID BaseAddress
,
1137 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1138 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1141 NTSTATUS Status
= STATUS_SUCCESS
;
1144 /* Get the pointer to the resource directory */
1145 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1146 RtlImageDirectoryEntryToData (BaseAddress
,
1148 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1152 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1155 /* Let's go into resource tree */
1156 for (i
= 0; i
< level
; i
++, name
++)
1158 EntryCount
= ResDir
->NumberOfNamedEntries
;
1159 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1160 if ((ULONG
)(*name
) & 0xFFFF0000)
1162 /* Resource name is a unicode string */
1163 for (; EntryCount
--; ResEntry
++)
1165 /* Scan entries for equal name */
1166 if (ResEntry
->Name
& 0x80000000)
1168 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1169 if (!wcsncmp( *name
, ws
+ 1, *ws
) && wcslen( *name
) == (int)*ws
)
1178 /* We use ID number instead of string */
1179 ResEntry
+= EntryCount
;
1180 EntryCount
= ResDir
->NumberOfIdEntries
;
1181 for (; EntryCount
--; ResEntry
++)
1183 /* Scan entries for equal name */
1184 if (ResEntry
->Name
== (ULONG
)(*name
))
1192 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1195 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1198 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
1199 /* Just use first language entry */
1200 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1202 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1208 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1211 return STATUS_INVALID_PARAMETER
;
1214 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
1219 *addr
= (PVOID
)ResDir
;
1227 LdrGetDllHandle (IN ULONG Unknown1
,
1229 IN PUNICODE_STRING DllName
,
1230 OUT PVOID
*BaseAddress
)
1232 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1233 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
1234 ANSI_STRING AnsiName
;
1237 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1238 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1240 current
= &LdrDllListHead
;
1242 // NULL is the current process
1243 if ( DllName
== NULL
)
1245 *BaseAddress
= current
->BaseAddress
;
1246 DPRINT1("BaseAddress %x\n", *BaseAddress
);
1247 return STATUS_SUCCESS
;
1250 RtlUnicodeStringToAnsiString (&AnsiName
, DllName
, TRUE
);
1254 OptionalHeader
= & current
->Headers
->OptionalHeader
;
1255 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1256 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
1258 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1259 ((ULONG
)ExportDir
+ (ULONG
)current
->BaseAddress
);
1261 DPRINT("Scanning %x %x %x\n",ExportDir
->Name
,
1262 current
->BaseAddress
,
1263 (ExportDir
->Name
+ current
->BaseAddress
));
1264 DPRINT("Scanning %s %s\n",
1265 ExportDir
->Name
+ current
->BaseAddress
, AnsiName
.Buffer
);
1267 if (!_stricmp(ExportDir
->Name
+ current
->BaseAddress
, AnsiName
.Buffer
))
1269 RtlFreeAnsiString (&AnsiName
);
1270 *BaseAddress
= current
->BaseAddress
;
1271 DPRINT1("BaseAddress %x\n", *BaseAddress
);
1272 return STATUS_SUCCESS
;
1275 current
= current
->Next
;
1277 } while (current
!= & LdrDllListHead
);
1279 DbgPrint("Failed to find dll %s\n", AnsiName
.Buffer
);
1280 RtlFreeAnsiString (&AnsiName
);
1281 *BaseAddress
= NULL
;
1283 return STATUS_UNSUCCESSFUL
;
1288 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1289 IN PANSI_STRING Name
,
1291 OUT PVOID
*ProcedureAddress
)
1293 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1299 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1300 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1302 /* Get the pointer to the export directory */
1303 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1304 RtlImageDirectoryEntryToData (BaseAddress
,
1306 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1309 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1311 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1313 return STATUS_INVALID_PARAMETER
;
1316 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1317 if (Name
&& Name
->Length
)
1320 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1321 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1322 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1324 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1326 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1327 return STATUS_SUCCESS
;
1330 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1335 Ordinal
&= 0x0000FFFF;
1336 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1338 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1339 return STATUS_SUCCESS
;
1341 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1344 return STATUS_PROCEDURE_NOT_FOUND
;