1 /* $Id: utils.c,v 1.32 2000/09/01 17:05:09 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)
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
18 /* INCLUDES *****************************************************************/
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27 #include <napi/shared_data.h>
30 #ifdef DBG_NTDLL_LDR_UTILS
33 #include <ntdll/ntdll.h>
35 /* PROTOTYPES ****************************************************************/
38 /* Type for a DLL's entry point */
44 ULONG ul_reason_for_call
,
50 LdrFindDll (PLDR_MODULE
*Dll
,PUNICODE_STRING Name
);
53 /* FUNCTIONS *****************************************************************/
55 /***************************************************************************
60 * Adjusts the name of a dll to a fully qualified name.
63 * FullDllName: Pointer to caller supplied storage for the fully
65 * DllName: Pointer to the dll name.
66 * BaseName: TRUE: Only the file name is passed to FullDllName
67 * FALSE: The full path is preserved in FullDllName
75 * A given path is not affected by the adjustment, but the file
79 * ntdll.xyz --> ntdll.xyz
83 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
84 PUNICODE_STRING DllName
,
87 WCHAR Buffer
[MAX_PATH
];
92 Length
= DllName
->Length
/ sizeof(WCHAR
);
96 /* get the base dll name */
97 Pointer
= DllName
->Buffer
+ Length
;
104 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
107 Length
= Extension
- Pointer
;
108 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
112 /* get the full dll name */
113 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
116 /* Build the DLL's absolute name */
117 Extension
= wcsrchr (Buffer
, L
'.');
118 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
120 /* with extension - remove dot if it's the last character */
121 if (Buffer
[Length
- 1] == L
'.')
127 /* name without extension - assume that it is .dll */
128 memmove (Buffer
+ Length
, L
".dll", 10);
131 RtlCreateUnicodeString (FullDllName
,
136 /***************************************************************************
153 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
155 IN PUNICODE_STRING Name
,
156 OUT PVOID
*BaseAddress OPTIONAL
)
158 WCHAR SearchPathBuffer
[MAX_PATH
];
159 WCHAR FullDosName
[MAX_PATH
];
160 UNICODE_STRING AdjustedName
;
161 UNICODE_STRING FullNtFileName
;
162 OBJECT_ATTRIBUTES FileObjectAttributes
;
163 char BlockBuffer
[1024];
164 PIMAGE_DOS_HEADER DosHeader
;
166 PIMAGE_NT_HEADERS NTHeaders
;
168 ULONG InitialViewSize
;
171 HANDLE SectionHandle
;
172 PDLLMAIN_FUNC Entrypoint
= NULL
;
177 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
178 return STATUS_SUCCESS
;
183 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
186 /* adjust the full dll name */
187 LdrAdjustDllName (&AdjustedName
,
190 DPRINT("AdjustedName: %wZ\n", &AdjustedName
);
193 * Test if dll is already loaded.
195 if (LdrFindDll(&Module
, &AdjustedName
) == STATUS_SUCCESS
)
197 DPRINT("DLL %wZ already loaded.\n", &AdjustedName
);
198 if (Module
->LoadCount
!= -1)
200 *BaseAddress
= Module
->BaseAddress
;
201 return STATUS_SUCCESS
;
204 if (SearchPath
== NULL
)
206 PKUSER_SHARED_DATA SharedUserData
=
207 (PKUSER_SHARED_DATA
)USER_SHARED_DATA_BASE
;
209 SearchPath
= SearchPathBuffer
;
210 wcscpy (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
211 wcscat (SearchPathBuffer
, L
"\\system32;");
212 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
215 DPRINT("SearchPath %S\n", SearchPath
);
217 if (RtlDosSearchPath_U (SearchPath
,
223 return STATUS_DLL_NOT_FOUND
;
225 DPRINT("FullDosName %S\n", FullDosName
);
227 RtlFreeUnicodeString (&AdjustedName
);
229 if (!RtlDosPathNameToNtPathName_U (FullDosName
,
233 return STATUS_DLL_NOT_FOUND
;
235 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
237 InitializeObjectAttributes(
238 & FileObjectAttributes
,
245 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
250 & FileObjectAttributes
,
255 if (!NT_SUCCESS(Status
))
257 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
258 &FullNtFileName
, Status
);
259 RtlFreeUnicodeString (&FullNtFileName
);
262 RtlFreeUnicodeString (&FullNtFileName
);
275 if (!NT_SUCCESS(Status
))
277 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
282 * Overlay DOS and NT headers structures to the
283 * buffer with DLL's header raw data.
285 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
286 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
288 * Check it is a PE image file.
290 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
291 || (DosHeader
->e_lfanew
== 0L)
292 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
294 DPRINT("NTDLL format invalid\n");
297 return STATUS_UNSUCCESSFUL
;
300 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
301 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
303 DPRINT("ImageBase 0x%08x\n", ImageBase
);
306 * Create a section for dll.
308 Status
= ZwCreateSection(
317 if (!NT_SUCCESS(Status
))
319 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
325 * Map the dll into the process.
329 + sizeof (IMAGE_NT_HEADERS
)
330 + sizeof (IMAGE_SECTION_HEADER
) * NTHeaders
->FileHeader
.NumberOfSections
;
331 Status
= ZwMapViewOfSection(
343 if (!NT_SUCCESS(Status
))
345 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
352 Module
= RtlAllocateHeap(
357 Module
->BaseAddress
= (PVOID
)ImageBase
;
358 Module
->SizeOfImage
= ImageSize
;
359 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
361 /* loading while app is running */
362 Module
->LoadCount
= 1;
367 * loading while app is initializing
368 * dll must not be unloaded
370 Module
->LoadCount
= -1;
373 Module
->TlsIndex
= 0; // ???
374 Module
->CheckSum
= 0; // ???
375 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
377 RtlCreateUnicodeString (&Module
->FullDllName
,
379 RtlCreateUnicodeString (&Module
->BaseDllName
,
380 wcsrchr(FullDosName
, L
'\\') + 1);
382 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
383 &Module
->InLoadOrderModuleList
);
385 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
387 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
391 (PDLLMAIN_FUNC
) LdrPEStartup(
396 if (Entrypoint
!= NULL
)
398 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
399 if (FALSE
== Entrypoint(
405 DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname
);
406 /* FIXME: should clean up and fail */
410 DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname
);
415 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname
);
419 Module
->EntryPoint
= (ULONG
)Entrypoint
;
421 *BaseAddress
= Module
->BaseAddress
;
422 return STATUS_SUCCESS
;
426 /***************************************************************************
441 static NTSTATUS
LdrFindDll(PLDR_MODULE
*Dll
, PUNICODE_STRING Name
)
443 PLIST_ENTRY ModuleListHead
;
447 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name
);
449 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
450 Entry
= ModuleListHead
->Flink
;
452 // NULL is the current process
455 *Dll
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
456 return STATUS_SUCCESS
;
459 while (Entry
!= ModuleListHead
)
461 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
463 DPRINT("Scanning %wZ %wZ\n", &Module
->BaseDllName
, Name
);
465 if (RtlCompareUnicodeString(&Module
->BaseDllName
, Name
, TRUE
) == 0)
468 return STATUS_SUCCESS
;
471 Entry
= Entry
->Flink
;
474 DPRINT("Failed to find dll %wZ\n", Name
);
476 return STATUS_UNSUCCESSFUL
;
480 /**********************************************************************
495 NTSTATUS
LdrMapSections(HANDLE ProcessHandle
,
497 HANDLE SectionHandle
,
498 PIMAGE_NT_HEADERS NTHeaders
)
503 for (i
= 0; (i
< NTHeaders
->FileHeader
.NumberOfSections
); i
++)
505 PIMAGE_SECTION_HEADER Sections
;
506 LARGE_INTEGER Offset
;
510 Sections
= (PIMAGE_SECTION_HEADER
) SECHDROFFSET(ImageBase
);
511 Base
= (ULONG
) (Sections
[i
].VirtualAddress
+ ImageBase
);
512 Offset
.u
.LowPart
= Sections
[i
].PointerToRawData
;
513 Offset
.u
.HighPart
= 0;
515 Size
= max(Sections
[i
].Misc
.VirtualSize
, Sections
[i
].SizeOfRawData
);
517 DPRINT("Mapping section %d offset %x base %x size %x\n",
518 i
, Offset
.u
.LowPart
, Base
, Sections
[i
].Misc
.VirtualSize
);
519 DPRINT("Size %x\n", Sections
[i
].SizeOfRawData
);
521 Status
= ZwMapViewOfSection(SectionHandle
,
531 if (!NT_SUCCESS(Status
))
533 DPRINT("Failed to map section");
537 return STATUS_SUCCESS
;
541 /**********************************************************************
543 * LdrGetExportByOrdinal
557 LdrGetExportByOrdinal (
562 PIMAGE_EXPORT_DIRECTORY ExportDir
;
563 PDWORD
* ExFunctions
;
566 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
567 RtlImageDirectoryEntryToData (BaseAddress
,
569 IMAGE_DIRECTORY_ENTRY_EXPORT
,
573 ExOrdinals
= (USHORT
*)
576 ExportDir
->AddressOfNameOrdinals
578 ExFunctions
= (PDWORD
*)
581 ExportDir
->AddressOfFunctions
584 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
586 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
588 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
592 /**********************************************************************
613 PIMAGE_EXPORT_DIRECTORY ExportDir
;
614 PDWORD
* ExFunctions
;
622 // "LdrFindExport(Module %x, SymbolName %s)\n",
627 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
628 RtlImageDirectoryEntryToData (BaseAddress
,
630 IMAGE_DIRECTORY_ENTRY_EXPORT
,
634 * Get header pointers
639 ExportDir
->AddressOfNames
641 ExOrdinals
= (USHORT
*)
644 ExportDir
->AddressOfNameOrdinals
646 ExFunctions
= (PDWORD
*)
649 ExportDir
->AddressOfFunctions
652 ( i
< ExportDir
->NumberOfFunctions
);
661 // "Comparing '%s' '%s'\n",
665 if (strcmp(ExName
,SymbolName
) == 0)
667 Ordinal
= ExOrdinals
[i
];
668 return(RVA(BaseAddress
, ExFunctions
[Ordinal
]));
672 DbgPrint("LdrGetExportByName() = failed to find %s\n",SymbolName
);
678 /**********************************************************************
680 * LdrPerformRelocations
683 * Relocate a DLL's memory image.
694 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
697 USHORT NumberOfEntries
;
703 PRELOCATION_DIRECTORY RelocationDir
;
704 PRELOCATION_ENTRY RelocationBlock
;
708 RelocationRVA
= NTHeaders
->OptionalHeader
709 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
714 RelocationDir
= (PRELOCATION_DIRECTORY
)
715 ((PCHAR
)ImageBase
+ RelocationRVA
);
717 while (RelocationDir
->SizeOfBlock
)
719 Delta32
= (ULONG
)(ImageBase
-
720 NTHeaders
->OptionalHeader
.ImageBase
);
721 RelocationBlock
= (PRELOCATION_ENTRY
) (
724 + sizeof (RELOCATION_DIRECTORY
)
727 RelocationDir
->SizeOfBlock
728 - sizeof (RELOCATION_DIRECTORY
)
730 / sizeof (RELOCATION_ENTRY
);
733 (i
< NumberOfEntries
);
738 RelocationBlock
[i
].TypeOffset
741 + RelocationDir
->VirtualAddress
;
743 * What kind of relocations should we perform
744 * for the current entry?
746 switch (RelocationBlock
[i
].TypeOffset
>> 12)
748 case TYPE_RELOC_ABSOLUTE
:
751 case TYPE_RELOC_HIGH
:
752 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
753 *pValue16
+= Delta32
>> 16;
757 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
758 *pValue16
+= Delta32
& 0xffff;
761 case TYPE_RELOC_HIGHLOW
:
762 pValue32
= (PULONG
) (ImageBase
+ Offset
);
763 *pValue32
+= Delta32
;
766 case TYPE_RELOC_HIGHADJ
:
767 /* FIXME: do the highadjust fixup */
769 "TYPE_RELOC_HIGHADJ fixup not implemented"
772 return(STATUS_UNSUCCESSFUL
);
775 DPRINT("unexpected fixup type\n");
776 return STATUS_UNSUCCESSFUL
;
779 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
780 RelocationDir
= (PRELOCATION_DIRECTORY
) (
786 return STATUS_SUCCESS
;
790 /**********************************************************************
795 * Compute the entry point for every symbol the DLL imports
796 * from other modules.
807 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
810 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
815 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
819 * Process each import module.
821 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
822 ImageBase
+ NTHeaders
->OptionalHeader
823 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
825 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
827 while (ImportModuleDirectory
->dwRVAModuleName
)
829 PVOID
* ImportAddressList
;
830 PULONG FunctionNameList
;
831 UNICODE_STRING DllName
;
835 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
836 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
838 RtlCreateUnicodeStringFromAsciiz (&DllName
,
839 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
841 Status
= LdrLoadDll(NULL
,
845 RtlFreeUnicodeString (&DllName
);
846 if (!NT_SUCCESS(Status
))
852 * Get the import address list.
854 ImportAddressList
= (PVOID
*)(NTHeaders
->OptionalHeader
.ImageBase
855 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
858 * Get the list of functions to import.
860 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
862 FunctionNameList
= (PULONG
) (
864 + ImportModuleDirectory
->dwRVAFunctionNameList
869 FunctionNameList
= (PULONG
) (
871 + ImportModuleDirectory
->dwRVAFunctionAddressList
875 * Walk through function list and fixup addresses.
877 while (*FunctionNameList
!= 0L)
879 if ((*FunctionNameList
) & 0x80000000)
881 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
883 LdrGetExportByOrdinal(BaseAddress
,
894 + *FunctionNameList
);
897 LdrGetExportByName(BaseAddress
,
899 if ((*ImportAddressList
) == NULL
)
901 DbgPrint("Failed to import %s\n", pName
);
902 return STATUS_UNSUCCESSFUL
;
908 ImportModuleDirectory
++;
910 return STATUS_SUCCESS
;
914 /**********************************************************************
919 * 1. Map the DLL's sections into memory.
920 * 2. Relocate, if needed the DLL.
921 * 3. Fixup any imported symbol.
922 * 4. Compute the DLL's entry point.
926 * Address at which the DLL's image
930 * Handle of the section that contains
934 * NULL on error; otherwise the entry point
935 * to call for initializing the DLL.
942 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
943 HANDLE SectionHandle
)
946 PEPFUNC EntryPoint
= NULL
;
947 PIMAGE_DOS_HEADER DosHeader
;
948 PIMAGE_NT_HEADERS NTHeaders
;
951 * Overlay DOS and WNT headers structures
952 * to the DLL's image.
954 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
955 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
958 * Initialize image sections.
960 if (SectionHandle
!= NULL
)
962 LdrMapSections(NtCurrentProcess(),
969 * If the base address is different from the
970 * one the DLL is actually loaded, perform any
973 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
975 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
976 if (!NT_SUCCESS(Status
))
978 DbgPrint("LdrPerformRelocations() failed\n");
984 * If the DLL's imports symbols from other
985 * modules, fixup the imported calls entry points.
987 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
988 .VirtualAddress
!= 0)
990 DPRINT("About to fixup imports\n");
991 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
992 if (!NT_SUCCESS(Status
))
994 DbgPrint("LdrFixupImports() failed\n");
1000 * Compute the DLL's entry point's address.
1002 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1004 EntryPoint
= (PEPFUNC
) (ImageBase
1005 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1007 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1013 LdrUnloadDll (IN PVOID BaseAddress
)
1015 PIMAGE_NT_HEADERS NtHeaders
;
1016 PDLLMAIN_FUNC Entrypoint
;
1017 PLIST_ENTRY ModuleListHead
;
1022 if (BaseAddress
== NULL
)
1023 return STATUS_SUCCESS
;
1025 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1026 Entry
= ModuleListHead
->Flink
;
1028 while (Entry
!= ModuleListHead
);
1030 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1031 if (Module
->BaseAddress
== BaseAddress
)
1033 if (Module
->LoadCount
== -1)
1035 /* never unload this dll */
1036 return STATUS_SUCCESS
;
1038 else if (Module
->LoadCount
> 1)
1040 Module
->LoadCount
--;
1041 return STATUS_SUCCESS
;
1044 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1045 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1047 Entrypoint
= (PDLLMAIN_FUNC
) LdrPEStartup(Module
->BaseAddress
,
1048 Module
->SectionHandle
);
1049 if (Entrypoint
!= NULL
)
1051 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1052 Entrypoint(Module
->BaseAddress
,
1058 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1061 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1062 Module
->BaseAddress
);
1063 ZwClose (Module
->SectionHandle
);
1065 /* remove the module entry from the list */
1066 RtlFreeUnicodeString (&Module
->FullDllName
);
1067 RtlFreeUnicodeString (&Module
->BaseDllName
);
1068 RemoveEntryList (Entry
);
1069 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1074 Entry
= Entry
->Flink
;
1077 DPRINT("NTDLL.LDR: Dll not found\n")
1079 return STATUS_UNSUCCESSFUL
;
1084 LdrFindResource_U(PVOID BaseAddress
,
1085 PLDR_RESOURCE_INFO ResourceInfo
,
1087 PIMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
)
1089 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1090 PIMAGE_RESOURCE_DIRECTORY ResBase
;
1091 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1092 NTSTATUS Status
= STATUS_SUCCESS
;
1098 DPRINT ("LdrFindResource_U()\n");
1100 /* Get the pointer to the resource directory */
1101 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1102 RtlImageDirectoryEntryToData (BaseAddress
,
1104 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1108 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1111 DPRINT("ResourceDirectory: %x\n", (ULONG
)ResDir
);
1115 /* Let's go into resource tree */
1116 for (i
= 0; i
< Level
; i
++)
1118 DPRINT("ResDir: %x\n", (ULONG
)ResDir
);
1119 Id
= ((PULONG
)ResourceInfo
)[i
];
1120 EntryCount
= ResDir
->NumberOfNamedEntries
;
1121 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1122 DPRINT("ResEntry %x\n", (ULONG
)ResEntry
);
1123 if (Id
& 0xFFFF0000)
1125 /* Resource name is a unicode string */
1126 for (; EntryCount
--; ResEntry
++)
1128 /* Scan entries for equal name */
1129 if (ResEntry
->Name
& 0x80000000)
1131 ws
= (PWCHAR
)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1132 if (!wcsncmp((PWCHAR
)Id
, ws
+ 1, *ws
) &&
1133 wcslen((PWCHAR
)Id
) == (int)*ws
)
1142 /* We use ID number instead of string */
1143 ResEntry
+= EntryCount
;
1144 EntryCount
= ResDir
->NumberOfIdEntries
;
1145 for (; EntryCount
--; ResEntry
++)
1147 /* Scan entries for equal name */
1148 if (ResEntry
->Name
== Id
)
1150 DPRINT("ID entry found %x\n", Id
);
1155 DPRINT("Error %lu\n", i
);
1160 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1163 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1166 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1168 /* Use the first available language */
1169 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1172 return STATUS_RESOURCE_LANG_NOT_FOUND
;
1175 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1178 return STATUS_INVALID_PARAMETER
;
1181 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
1182 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
1184 DPRINT("ResourceDataEntry: %x\n", (ULONG
)ResDir
);
1186 if (ResourceDataEntry
)
1188 *ResourceDataEntry
= (PVOID
)ResDir
;
1196 LdrAccessResource(IN PVOID BaseAddress
,
1197 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
1198 OUT PVOID
*Resource OPTIONAL
,
1199 OUT PULONG Size OPTIONAL
)
1201 PIMAGE_SECTION_HEADER Section
;
1202 PIMAGE_NT_HEADERS NtHeader
;
1209 Data
= (ULONG
)RtlImageDirectoryEntryToData (BaseAddress
,
1211 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1214 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1216 if ((ULONG
)BaseAddress
& 1)
1218 /* loaded as ordinary file */
1219 NtHeader
= RtlImageNtHeader((PVOID
)((ULONG
)BaseAddress
& ~1UL));
1220 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1221 Section
= RtlImageRvaToSection (NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
1222 if (Section
== NULL
)
1224 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1227 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
)
1229 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
1230 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
1231 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
1237 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
1242 *Size
= ResourceDataEntry
->Size
;
1245 return STATUS_SUCCESS
;
1250 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress
)
1252 PLIST_ENTRY ModuleListHead
;
1257 Status
= STATUS_DLL_NOT_FOUND
;
1259 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1260 Entry
= ModuleListHead
->Flink
;
1262 while (Entry
!= ModuleListHead
);
1264 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1265 if (Module
->BaseAddress
== BaseAddress
)
1267 if (Module
->TlsIndex
== 0)
1269 Module
->Flags
|= 0x00040000;
1270 Status
= STATUS_SUCCESS
;
1275 Entry
= Entry
->Flink
;
1283 LdrFindResourceDirectory_U (IN PVOID BaseAddress
,
1288 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1289 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1292 NTSTATUS Status
= STATUS_SUCCESS
;
1295 /* Get the pointer to the resource directory */
1296 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1297 RtlImageDirectoryEntryToData (BaseAddress
,
1299 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1303 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1306 /* Let's go into resource tree */
1307 for (i
= 0; i
< level
; i
++, name
++)
1309 EntryCount
= ResDir
->NumberOfNamedEntries
;
1310 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1311 if ((ULONG
)(*name
) & 0xFFFF0000)
1313 /* Resource name is a unicode string */
1314 for (; EntryCount
--; ResEntry
++)
1316 /* Scan entries for equal name */
1317 if (ResEntry
->Name
& 0x80000000)
1319 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1320 if (!wcsncmp( *name
, ws
+ 1, *ws
) && wcslen( *name
) == (int)*ws
)
1329 /* We use ID number instead of string */
1330 ResEntry
+= EntryCount
;
1331 EntryCount
= ResDir
->NumberOfIdEntries
;
1332 for (; EntryCount
--; ResEntry
++)
1334 /* Scan entries for equal name */
1335 if (ResEntry
->Name
== (ULONG
)(*name
))
1343 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1346 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1349 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
1350 /* Just use first language entry */
1351 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1353 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1359 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1362 return STATUS_INVALID_PARAMETER
;
1365 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
1370 *addr
= (PVOID
)ResDir
;
1378 LdrGetDllHandle (IN ULONG Unknown1
,
1380 IN PUNICODE_STRING DllName
,
1381 OUT PVOID
*BaseAddress
)
1383 UNICODE_STRING FullDllName
;
1384 PLIST_ENTRY ModuleListHead
;
1388 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1389 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1391 /* NULL is the current executable */
1392 if ( DllName
== NULL
)
1394 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1395 DPRINT1("BaseAddress %x\n", *BaseAddress
);
1396 return STATUS_SUCCESS
;
1399 LdrAdjustDllName (&FullDllName
,
1403 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1404 Entry
= ModuleListHead
->Flink
;
1406 while (Entry
!= ModuleListHead
)
1408 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1410 DPRINT("Scanning %wZ %wZ\n",
1411 &Module
->BaseDllName
,
1414 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
))
1416 RtlFreeUnicodeString (&FullDllName
);
1417 *BaseAddress
= Module
->BaseAddress
;
1418 DPRINT("BaseAddress %x\n", *BaseAddress
);
1419 return STATUS_SUCCESS
;
1422 Entry
= Entry
->Flink
;
1425 DbgPrint("Failed to find dll %wZ\n", &FullDllName
);
1426 RtlFreeUnicodeString (&FullDllName
);
1427 *BaseAddress
= NULL
;
1428 return STATUS_DLL_NOT_FOUND
;
1433 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1434 IN PANSI_STRING Name
,
1436 OUT PVOID
*ProcedureAddress
)
1438 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1444 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1445 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1447 /* Get the pointer to the export directory */
1448 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1449 RtlImageDirectoryEntryToData (BaseAddress
,
1451 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1454 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1456 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1458 return STATUS_INVALID_PARAMETER
;
1461 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1462 if (Name
&& Name
->Length
)
1465 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1466 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1467 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1469 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1471 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1472 return STATUS_SUCCESS
;
1475 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1480 Ordinal
&= 0x0000FFFF;
1481 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1483 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1484 return STATUS_SUCCESS
;
1486 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1489 return STATUS_PROCEDURE_NOT_FOUND
;
1494 LdrShutdownProcess (VOID
)
1497 return STATUS_SUCCESS
;
1502 LdrShutdownThread (VOID
)
1505 return STATUS_SUCCESS
;