3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/utils.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
14 * - Handle loading flags correctly
15 * - Handle errors correctly (unload dll's)
16 * - Implement a faster way to find modules (hash table)
20 /* INCLUDES *****************************************************************/
22 #include <reactos/config.h>
23 #include <ddk/ntddk.h>
27 #include <ntdll/ldr.h>
28 #include <ntos/minmax.h>
30 #define LDRP_PROCESS_CREATION_TIME 0x8000000
32 #ifdef DBG_NTDLL_LDR_UTILS
35 #include <ntdll/ntdll.h>
37 /* GLOBALS *******************************************************************/
39 typedef struct _TLS_DATA
41 PVOID StartAddressOfRawData
;
44 PIMAGE_TLS_CALLBACK TlsAddressOfCallBacks
;
46 } TLS_DATA
, *PTLS_DATA
;
48 static PTLS_DATA LdrpTlsArray
= NULL
;
49 static ULONG LdrpTlsCount
= 0;
50 static ULONG LdrpTlsSize
= 0;
51 static HANDLE LdrpKnownDllsDirHandle
= NULL
;
52 static UNICODE_STRING LdrpKnownDllPath
= {0, 0, NULL
};
53 static PLDR_MODULE LdrpLastModule
= NULL
;
54 extern PLDR_MODULE ExeModule
;
56 /* PROTOTYPES ****************************************************************/
58 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_MODULE
*Module
, BOOLEAN Ref
);
59 static PVOID
LdrFixupForward(PCHAR ForwardName
);
60 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
61 static NTSTATUS
LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
63 IN PUNICODE_STRING Name
,
64 OUT PLDR_MODULE
*Module
,
65 OUT PVOID
*BaseAddress OPTIONAL
);
66 static NTSTATUS
LdrpAttachProcess(VOID
);
67 static VOID
LdrpDetachProcess(BOOLEAN UnloadAll
);
69 /* FUNCTIONS *****************************************************************/
71 #if defined(DBG) || defined(KDBG)
74 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
85 #endif /* DBG || KDBG */
88 LdrMappedAsDataFile(PVOID
*BaseAddress
)
90 if (0 != ((DWORD_PTR
) *BaseAddress
& (PAGE_SIZE
- 1)))
92 *BaseAddress
= (PVOID
) ((DWORD_PTR
) *BaseAddress
& ~ ((DWORD_PTR
) PAGE_SIZE
- 1));
99 static inline LONG
LdrpDecrementLoadCount(PLDR_MODULE Module
, BOOLEAN Locked
)
104 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
106 LoadCount
= Module
->LoadCount
;
107 if (Module
->LoadCount
> 0)
113 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
118 static inline LONG
LdrpIncrementLoadCount(PLDR_MODULE Module
, BOOLEAN Locked
)
123 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
125 LoadCount
= Module
->LoadCount
;
126 if (Module
->LoadCount
>= 0)
132 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
137 static inline VOID
LdrpAcquireTlsSlot(PLDR_MODULE Module
, ULONG Size
, BOOLEAN Locked
)
141 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
143 Module
->TlsIndex
= (SHORT
)LdrpTlsCount
;
148 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
152 static inline VOID
LdrpTlsCallback(PLDR_MODULE Module
, ULONG dwReason
)
154 PIMAGE_TLS_CALLBACK TlsCallback
;
155 if (Module
->TlsIndex
>= 0 && Module
->LoadCount
== -1)
157 TlsCallback
= LdrpTlsArray
[Module
->TlsIndex
].TlsAddressOfCallBacks
;
162 TRACE_LDR("%wZ - Calling tls callback at %x\n",
163 &Module
->BaseDllName
, TlsCallback
);
164 TlsCallback(Module
->BaseAddress
, dwReason
, NULL
);
171 static BOOLEAN
LdrpCallDllEntry(PLDR_MODULE Module
, DWORD dwReason
, PVOID lpReserved
)
173 if (!(Module
->Flags
& IMAGE_DLL
) ||
174 Module
->EntryPoint
== 0)
178 LdrpTlsCallback(Module
, dwReason
);
179 return ((PDLLMAIN_FUNC
)Module
->EntryPoint
)(Module
->BaseAddress
, dwReason
, lpReserved
);
183 LdrpInitializeTlsForThread(VOID
)
189 PTEB Teb
= NtCurrentTeb();
191 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule
->BaseDllName
);
193 Teb
->StaticUnicodeString
.Length
= 0;
194 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
195 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
197 if (LdrpTlsCount
> 0)
199 TlsPointers
= RtlAllocateHeap(RtlGetProcessHeap(),
201 LdrpTlsCount
* sizeof(PVOID
) + LdrpTlsSize
);
202 if (TlsPointers
== NULL
)
204 DPRINT1("failed to allocate thread tls data\n");
205 return STATUS_NO_MEMORY
;
208 TlsData
= (PVOID
)TlsPointers
+ LdrpTlsCount
* sizeof(PVOID
);
209 Teb
->ThreadLocalStoragePointer
= TlsPointers
;
211 TlsInfo
= LdrpTlsArray
;
212 for (i
= 0; i
< LdrpTlsCount
; i
++, TlsInfo
++)
214 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo
->Module
->BaseDllName
);
215 TlsPointers
[i
] = TlsData
;
216 if (TlsInfo
->TlsDataSize
)
218 memcpy(TlsData
, TlsInfo
->StartAddressOfRawData
, TlsInfo
->TlsDataSize
);
219 TlsData
+= TlsInfo
->TlsDataSize
;
221 if (TlsInfo
->TlsZeroSize
)
223 memset(TlsData
, 0, TlsInfo
->TlsZeroSize
);
224 TlsData
+= TlsInfo
->TlsZeroSize
;
228 DPRINT("LdrpInitializeTlsForThread() done\n");
229 return STATUS_SUCCESS
;
233 LdrpInitializeTlsForProccess(VOID
)
235 PLIST_ENTRY ModuleListHead
;
238 PIMAGE_TLS_DIRECTORY TlsDirectory
;
241 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule
->BaseDllName
);
243 if (LdrpTlsCount
> 0)
245 LdrpTlsArray
= RtlAllocateHeap(RtlGetProcessHeap(),
247 LdrpTlsCount
* sizeof(TLS_DATA
));
248 if (LdrpTlsArray
== NULL
)
250 DPRINT1("Failed to allocate global tls data\n");
251 return STATUS_NO_MEMORY
;
254 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
255 Entry
= ModuleListHead
->Flink
;
256 while (Entry
!= ModuleListHead
)
258 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
259 if (Module
->LoadCount
== -1 &&
260 Module
->TlsIndex
>= 0)
262 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
263 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
265 IMAGE_DIRECTORY_ENTRY_TLS
,
267 assert(Module
->TlsIndex
< LdrpTlsCount
);
268 TlsData
= &LdrpTlsArray
[Module
->TlsIndex
];
269 TlsData
->StartAddressOfRawData
= (PVOID
)TlsDirectory
->StartAddressOfRawData
;
270 TlsData
->TlsDataSize
= TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
;
271 TlsData
->TlsZeroSize
= TlsDirectory
->SizeOfZeroFill
;
272 if (TlsDirectory
->AddressOfCallBacks
)
273 TlsData
->TlsAddressOfCallBacks
= *TlsDirectory
->AddressOfCallBacks
;
275 TlsData
->TlsAddressOfCallBacks
= NULL
;
276 TlsData
->Module
= Module
;
278 DbgPrint("TLS directory for %wZ\n", &Module
->BaseDllName
);
279 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory
->StartAddressOfRawData
);
280 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory
->EndAddressOfRawData
);
281 DbgPrint("SizeOfRawData: %d\n", TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
);
282 DbgPrint("AddressOfIndex: %x\n", TlsDirectory
->AddressOfIndex
);
283 DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory
->AddressOfCallBacks
, *TlsDirectory
->AddressOfCallBacks
);
284 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory
->SizeOfZeroFill
);
285 DbgPrint("Characteristics: %x\n", TlsDirectory
->Characteristics
);
289 * Is this region allways writable ?
291 *(PULONG
)TlsDirectory
->AddressOfIndex
= Module
->TlsIndex
;
294 Entry
= Entry
->Flink
;
297 DPRINT("LdrpInitializeTlsForProccess() done\n");
298 return STATUS_SUCCESS
;
304 OBJECT_ATTRIBUTES ObjectAttributes
;
305 UNICODE_STRING LinkTarget
;
311 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule
->BaseDllName
);
313 /* Get handle to the 'KnownDlls' directory */
314 RtlInitUnicodeString(&Name
,
316 InitializeObjectAttributes(&ObjectAttributes
,
318 OBJ_CASE_INSENSITIVE
,
321 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
322 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
324 if (!NT_SUCCESS(Status
))
326 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
327 LdrpKnownDllsDirHandle
= NULL
;
331 /* Allocate target name string */
332 LinkTarget
.Length
= 0;
333 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
334 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
336 MAX_PATH
* sizeof(WCHAR
));
337 if (LinkTarget
.Buffer
== NULL
)
339 NtClose(LdrpKnownDllsDirHandle
);
340 LdrpKnownDllsDirHandle
= NULL
;
344 RtlInitUnicodeString(&Name
,
346 InitializeObjectAttributes(&ObjectAttributes
,
348 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
349 LdrpKnownDllsDirHandle
,
351 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
352 SYMBOLIC_LINK_ALL_ACCESS
,
354 if (!NT_SUCCESS(Status
))
356 RtlFreeUnicodeString(&LinkTarget
);
357 NtClose(LdrpKnownDllsDirHandle
);
358 LdrpKnownDllsDirHandle
= NULL
;
362 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
366 if (!NT_SUCCESS(Status
))
368 RtlFreeUnicodeString(&LinkTarget
);
369 NtClose(LdrpKnownDllsDirHandle
);
370 LdrpKnownDllsDirHandle
= NULL
;
373 RtlCreateUnicodeString(&LdrpKnownDllPath
,
376 RtlFreeUnicodeString(&LinkTarget
);
378 DPRINT("LdrpInitLoader() done\n");
382 /***************************************************************************
387 * Adjusts the name of a dll to a fully qualified name.
390 * FullDllName: Pointer to caller supplied storage for the fully
391 * qualified dll name.
392 * DllName: Pointer to the dll name.
393 * BaseName: TRUE: Only the file name is passed to FullDllName
394 * FALSE: The full path is preserved in FullDllName
402 * A given path is not affected by the adjustment, but the file
404 * ntdll --> ntdll.dll
406 * ntdll.xyz --> ntdll.xyz
409 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
410 PUNICODE_STRING DllName
,
413 WCHAR Buffer
[MAX_PATH
];
418 Length
= DllName
->Length
/ sizeof(WCHAR
);
422 /* get the base dll name */
423 Pointer
= DllName
->Buffer
+ Length
;
430 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
433 Length
= Extension
- Pointer
;
434 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
435 Buffer
[Length
] = L
'\0';
439 /* get the full dll name */
440 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
441 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
444 /* Build the DLL's absolute name */
445 Extension
= wcsrchr (Buffer
, L
'.');
446 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
448 /* with extension - remove dot if it's the last character */
449 if (Buffer
[Length
- 1] == L
'.')
455 /* name without extension - assume that it is .dll */
456 memmove (Buffer
+ Length
, L
".dll", 10);
459 RtlCreateUnicodeString(FullDllName
, Buffer
);
463 LdrAddModuleEntry(PVOID ImageBase
,
464 PIMAGE_NT_HEADERS NTHeaders
,
469 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
471 memset(Module
, 0, sizeof(LDR_MODULE
));
472 Module
->BaseAddress
= (PVOID
)ImageBase
;
473 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
474 if (Module
->EntryPoint
!= 0)
475 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
476 Module
->ResidentSize
= LdrpGetResidentSize(NTHeaders
);
477 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
479 /* loading while app is running */
480 Module
->LoadCount
= 1;
483 * loading while app is initializing
484 * dll must not be unloaded
486 Module
->LoadCount
= -1;
490 Module
->TlsIndex
= -1;
491 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
492 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
494 RtlCreateUnicodeString (&Module
->FullDllName
,
496 RtlCreateUnicodeString (&Module
->BaseDllName
,
497 wcsrchr(FullDosName
, L
'\\') + 1);
498 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
500 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
501 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
502 &Module
->InLoadOrderModuleList
);
503 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
510 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
511 OUT PUNICODE_STRING FullDosName
,
512 OUT PHANDLE SectionHandle
)
514 OBJECT_ATTRIBUTES ObjectAttributes
;
517 DPRINT("LdrpMapKnownDll() called\n");
519 if (LdrpKnownDllsDirHandle
== NULL
)
521 DPRINT("Invalid 'KnownDlls' directory\n");
522 return STATUS_UNSUCCESSFUL
;
525 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
527 InitializeObjectAttributes(&ObjectAttributes
,
529 OBJ_CASE_INSENSITIVE
,
530 LdrpKnownDllsDirHandle
,
532 Status
= NtOpenSection(SectionHandle
,
533 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
535 if (!NT_SUCCESS(Status
))
537 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
541 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
542 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
543 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
545 FullDosName
->MaximumLength
);
546 if (FullDosName
->Buffer
== NULL
)
548 FullDosName
->Length
= 0;
549 FullDosName
->MaximumLength
= 0;
550 return STATUS_SUCCESS
;
553 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
554 wcscat(FullDosName
->Buffer
, L
"\\");
555 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
557 DPRINT("FullDosName '%wZ'\n", FullDosName
);
559 DPRINT("LdrpMapKnownDll() done\n");
561 return STATUS_SUCCESS
;
566 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
567 IN PUNICODE_STRING DllName
,
568 OUT PUNICODE_STRING FullDosName
,
569 IN BOOLEAN MapAsDataFile
,
570 OUT PHANDLE SectionHandle
)
572 WCHAR SearchPathBuffer
[MAX_PATH
];
573 WCHAR DosName
[MAX_PATH
];
574 UNICODE_STRING FullNtFileName
;
575 OBJECT_ATTRIBUTES FileObjectAttributes
;
577 char BlockBuffer
[1024];
578 PIMAGE_DOS_HEADER DosHeader
;
579 PIMAGE_NT_HEADERS NTHeaders
;
580 IO_STATUS_BLOCK IoStatusBlock
;
584 DPRINT("LdrpMapDllImageFile() called\n");
586 if (SearchPath
== NULL
)
588 /* get application running path */
590 wcscpy (SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
592 len
= wcslen (SearchPathBuffer
);
594 while (len
&& SearchPathBuffer
[len
- 1] != L
'\\')
597 if (len
) SearchPathBuffer
[len
-1] = L
'\0';
599 wcscat (SearchPathBuffer
, L
";");
601 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
602 wcscat (SearchPathBuffer
, L
"\\system32;");
603 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
604 wcscat (SearchPathBuffer
, L
";.");
606 SearchPath
= SearchPathBuffer
;
609 if (RtlDosSearchPath_U (SearchPath
,
615 return STATUS_DLL_NOT_FOUND
;
618 if (!RtlDosPathNameToNtPathName_U (DosName
,
622 return STATUS_DLL_NOT_FOUND
;
624 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
626 InitializeObjectAttributes(&FileObjectAttributes
,
632 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
634 Status
= NtOpenFile(&FileHandle
,
635 GENERIC_READ
|SYNCHRONIZE
,
636 &FileObjectAttributes
,
639 FILE_SYNCHRONOUS_IO_NONALERT
);
640 if (!NT_SUCCESS(Status
))
642 DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
643 &FullNtFileName
, Status
);
644 RtlFreeUnicodeString (&FullNtFileName
);
647 RtlFreeUnicodeString (&FullNtFileName
);
649 Status
= NtReadFile(FileHandle
,
658 if (!NT_SUCCESS(Status
))
660 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
665 * Overlay DOS and NT headers structures to the
666 * buffer with DLL's header raw data.
668 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
669 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
671 * Check it is a PE image file.
673 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
674 || (DosHeader
->e_lfanew
== 0L)
675 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
677 DPRINT("NTDLL format invalid\n");
680 return STATUS_UNSUCCESSFUL
;
684 * Create a section for dll.
686 Status
= NtCreateSection(SectionHandle
,
691 SEC_COMMIT
| (MapAsDataFile
? 0 : SEC_IMAGE
),
695 if (!NT_SUCCESS(Status
))
697 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
701 RtlCreateUnicodeString(FullDosName
,
709 /***************************************************************************
726 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
728 IN PUNICODE_STRING Name
,
729 OUT PVOID
*BaseAddress OPTIONAL
)
734 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
736 SearchPath
? " from " : "",
737 SearchPath
? SearchPath
: L
"");
741 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
742 return STATUS_SUCCESS
;
747 Status
= LdrpLoadModule(SearchPath
, LoadFlags
, Name
, &Module
, BaseAddress
);
748 if (NT_SUCCESS(Status
) && 0 == (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
))
750 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
751 Status
= LdrpAttachProcess();
752 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
753 if (NT_SUCCESS(Status
))
755 *BaseAddress
= Module
->BaseAddress
;
762 /***************************************************************************
764 * LdrFindEntryForAddress
779 LdrFindEntryForAddress(PVOID Address
,
782 PLIST_ENTRY ModuleListHead
;
784 PLDR_MODULE ModulePtr
;
786 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
788 if (NtCurrentPeb()->Ldr
== NULL
)
789 return(STATUS_NO_MORE_ENTRIES
);
791 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
792 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
793 Entry
= ModuleListHead
->Flink
;
794 if (Entry
== ModuleListHead
)
796 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
797 return(STATUS_NO_MORE_ENTRIES
);
800 while (Entry
!= ModuleListHead
)
802 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
804 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
806 if ((Address
>= ModulePtr
->BaseAddress
) &&
807 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->ResidentSize
)))
810 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
811 return(STATUS_SUCCESS
);
814 Entry
= Entry
->Flink
;
817 DPRINT("Failed to find module entry.\n");
819 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
820 return(STATUS_NO_MORE_ENTRIES
);
824 /***************************************************************************
826 * LdrFindEntryForName
840 LdrFindEntryForName(PUNICODE_STRING Name
,
844 PLIST_ENTRY ModuleListHead
;
846 PLDR_MODULE ModulePtr
;
847 BOOLEAN ContainsPath
;
848 UNICODE_STRING AdjustedName
;
851 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name
);
853 if (NtCurrentPeb()->Ldr
== NULL
)
854 return(STATUS_NO_MORE_ENTRIES
);
856 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
857 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
858 Entry
= ModuleListHead
->Flink
;
859 if (Entry
== ModuleListHead
)
861 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
862 return(STATUS_NO_MORE_ENTRIES
);
865 // NULL is the current process
869 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
870 return(STATUS_SUCCESS
);
873 LdrAdjustDllName (&AdjustedName
, Name
, FALSE
);
875 ContainsPath
= (AdjustedName
.Length
>= 2 * sizeof(WCHAR
) && L
':' == AdjustedName
.Buffer
[1]);
876 for (i
= 0; ! ContainsPath
&& i
< AdjustedName
.Length
/ sizeof(WCHAR
); i
++)
878 ContainsPath
= L
'\\' == AdjustedName
.Buffer
[i
] ||
879 L
'/' == AdjustedName
.Buffer
[i
];
884 if ((! ContainsPath
&&
885 0 == RtlCompareUnicodeString(&LdrpLastModule
->BaseDllName
, &AdjustedName
, TRUE
)) ||
887 0 == RtlCompareUnicodeString(&LdrpLastModule
->FullDllName
, &AdjustedName
, TRUE
)))
889 *Module
= LdrpLastModule
;
890 if (Ref
&& (*Module
)->LoadCount
!= -1)
892 (*Module
)->LoadCount
++;
894 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
895 RtlFreeUnicodeString(&AdjustedName
);
896 return(STATUS_SUCCESS
);
899 while (Entry
!= ModuleListHead
)
901 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
903 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, &AdjustedName
);
905 if ((! ContainsPath
&&
906 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, &AdjustedName
, TRUE
)) ||
908 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, &AdjustedName
, TRUE
)))
910 *Module
= LdrpLastModule
= ModulePtr
;
911 if (Ref
&& ModulePtr
->LoadCount
!= -1)
913 ModulePtr
->LoadCount
++;
915 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
916 RtlFreeUnicodeString(&AdjustedName
);
917 return(STATUS_SUCCESS
);
920 Entry
= Entry
->Flink
;
923 DPRINT("Failed to find dll %wZ\n", Name
);
924 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
925 RtlFreeUnicodeString(&AdjustedName
);
926 return(STATUS_NO_MORE_ENTRIES
);
929 /**********************************************************************
945 LdrFixupForward(PCHAR ForwardName
)
947 CHAR NameBuffer
[128];
948 UNICODE_STRING DllName
;
954 strcpy(NameBuffer
, ForwardName
);
955 p
= strchr(NameBuffer
, '.');
960 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
961 RtlCreateUnicodeStringFromAsciiz (&DllName
,
964 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
966 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
968 if (!NT_SUCCESS(Status
))
970 Status
= LdrLoadDll(NULL
,
971 LDRP_PROCESS_CREATION_TIME
,
974 if (NT_SUCCESS(Status
))
976 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
979 RtlFreeUnicodeString (&DllName
);
980 if (!NT_SUCCESS(Status
))
982 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer
);
986 DPRINT("BaseAddress: %p\n", Module
->BaseAddress
);
988 return LdrGetExportByName(Module
->BaseAddress
, (PUCHAR
)(p
+1), -1);
995 /**********************************************************************
997 * LdrGetExportByOrdinal
1011 LdrGetExportByOrdinal (
1016 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1017 ULONG ExportDirSize
;
1018 PDWORD
* ExFunctions
;
1021 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1022 RtlImageDirectoryEntryToData (BaseAddress
,
1024 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1028 ExFunctions
= (PDWORD
*)
1031 ExportDir
->AddressOfFunctions
1034 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
1036 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1039 Function
= (0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1040 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1043 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1044 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1046 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1047 Function
= LdrFixupForward((PCHAR
)Function
);
1054 /**********************************************************************
1056 * LdrGetExportByName
1067 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1068 * both with NumberOfNames entries.
1072 LdrGetExportByName(PVOID BaseAddress
,
1076 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1077 PDWORD
* ExFunctions
;
1079 USHORT
* ExOrdinals
;
1085 ULONG ExportDirSize
;
1087 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1089 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1090 RtlImageDirectoryEntryToData(BaseAddress
,
1092 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1094 if (ExportDir
== NULL
)
1096 DPRINT1("LdrGetExportByName(): no export directory!\n");
1101 //The symbol names may be missing entirely
1102 if (ExportDir
->AddressOfNames
== 0)
1104 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1109 * Get header pointers
1111 ExNames
= (PDWORD
*)RVA(BaseAddress
,
1112 ExportDir
->AddressOfNames
);
1113 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
1114 ExportDir
->AddressOfNameOrdinals
);
1115 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
1116 ExportDir
->AddressOfFunctions
);
1119 * Check the hint first
1121 if (Hint
< ExportDir
->NumberOfNames
)
1123 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1124 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1126 Ordinal
= ExOrdinals
[Hint
];
1127 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1128 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1129 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1131 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1132 Function
= LdrFixupForward((PCHAR
)Function
);
1133 if (Function
== NULL
)
1135 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1139 if (Function
!= NULL
)
1145 * Try a binary search first
1148 maxn
= ExportDir
->NumberOfNames
- 1;
1149 while (minn
<= maxn
)
1154 mid
= (minn
+ maxn
) / 2;
1156 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1157 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
1160 Ordinal
= ExOrdinals
[mid
];
1161 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1162 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1163 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1165 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1166 Function
= LdrFixupForward((PCHAR
)Function
);
1167 if (Function
== NULL
)
1169 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1173 if (Function
!= NULL
)
1176 else if (minn
== maxn
)
1178 DPRINT("LdrGetExportByName(): binary search failed\n");
1192 * Fall back on a linear search
1194 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1195 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1197 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1198 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1200 Ordinal
= ExOrdinals
[i
];
1201 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1202 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1203 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1204 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1206 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1207 Function
= LdrFixupForward((PCHAR
)Function
);
1209 if (Function
== NULL
)
1216 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1221 /**********************************************************************
1223 * LdrPerformRelocations
1226 * Relocate a DLL's memory image.
1238 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
,
1241 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1242 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
1243 ULONG Count
, ProtectSize
, OldProtect
, OldProtect2
;
1244 PVOID Page
, ProtectPage
, ProtectPage2
;
1249 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1251 return STATUS_UNSUCCESSFUL
;
1255 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1257 if (RelocationDDir
->VirtualAddress
== 0 || RelocationDDir
->Size
== 0)
1259 return STATUS_SUCCESS
;
1262 ProtectSize
= PAGE_SIZE
;
1263 Delta
= (ULONG_PTR
)ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
;
1264 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1265 RelocationDDir
->VirtualAddress
);
1266 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1267 RelocationDDir
->VirtualAddress
+ RelocationDDir
->Size
);
1269 while (RelocationDir
< RelocationEnd
&&
1270 RelocationDir
->SizeOfBlock
> 0)
1272 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) /
1274 Page
= ImageBase
+ RelocationDir
->VirtualAddress
;
1275 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
1277 /* Unprotect the page(s) we're about to relocate. */
1279 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1284 if (!NT_SUCCESS(Status
))
1286 DPRINT1("Failed to unprotect relocation target.\n");
1290 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
<
1291 NTHeaders
->OptionalHeader
.SizeOfImage
)
1293 ProtectPage2
= ProtectPage
+ PAGE_SIZE
;
1294 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1299 if (!NT_SUCCESS(Status
))
1301 DPRINT1("Failed to unprotect relocation target (2).\n");
1302 NtProtectVirtualMemory(NtCurrentProcess(),
1312 ProtectPage2
= NULL
;
1315 RelocationDir
= LdrProcessRelocationBlock(Page
,
1319 if (RelocationDir
== NULL
)
1320 return STATUS_UNSUCCESSFUL
;
1322 /* Restore old page protection. */
1323 NtProtectVirtualMemory(NtCurrentProcess(),
1329 if (ProtectPage2
!= NULL
)
1331 NtProtectVirtualMemory(NtCurrentProcess(),
1339 return STATUS_SUCCESS
;
1343 LdrpGetOrLoadModule(PWCHAR SerachPath
,
1345 PLDR_MODULE
* Module
,
1348 UNICODE_STRING DllName
;
1351 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name
);
1353 RtlCreateUnicodeStringFromAsciiz (&DllName
, Name
);
1355 Status
= LdrFindEntryForName (&DllName
, Module
, Load
);
1356 if (Load
&& !NT_SUCCESS(Status
))
1358 Status
= LdrpLoadModule(SerachPath
,
1359 NtCurrentPeb()->Ldr
->Initialized
? 0 : LDRP_PROCESS_CREATION_TIME
,
1363 if (NT_SUCCESS(Status
))
1365 Status
= LdrFindEntryForName (&DllName
, Module
, FALSE
);
1367 if (!NT_SUCCESS(Status
))
1369 DPRINT1("failed to load %wZ\n", &DllName
);
1372 RtlFreeUnicodeString (&DllName
);
1377 LdrpProcessImportDirectoryEntry(PLDR_MODULE Module
,
1378 PLDR_MODULE ImportedModule
,
1379 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
)
1382 PVOID
* ImportAddressList
;
1383 PULONG FunctionNameList
;
1389 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->dwRVAModuleName
== 0)
1391 return STATUS_UNSUCCESSFUL
;
1394 /* Get the import address list. */
1395 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1397 /* Get the list of functions to import. */
1398 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1400 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1404 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1407 /* Get the size of IAT. */
1409 while (FunctionNameList
[IATSize
] != 0L)
1414 /* Unprotect the region we are about to write into. */
1415 IATBase
= (PVOID
)ImportAddressList
;
1416 IATSize
*= sizeof(PVOID
*);
1417 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1422 if (!NT_SUCCESS(Status
))
1424 DPRINT1("Failed to unprotect IAT.\n");
1428 /* Walk through function list and fixup addresses. */
1429 while (*FunctionNameList
!= 0L)
1431 if ((*FunctionNameList
) & 0x80000000)
1433 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1434 *ImportAddressList
= LdrGetExportByOrdinal(ImportedModule
->BaseAddress
, Ordinal
);
1435 if ((*ImportAddressList
) == NULL
)
1437 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1438 return STATUS_UNSUCCESSFUL
;
1443 IMAGE_IMPORT_BY_NAME
*pe_name
;
1444 pe_name
= RVA(Module
->BaseAddress
, *FunctionNameList
);
1445 *ImportAddressList
= LdrGetExportByName(ImportedModule
->BaseAddress
, pe_name
->Name
, pe_name
->Hint
);
1446 if ((*ImportAddressList
) == NULL
)
1448 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1449 return STATUS_UNSUCCESSFUL
;
1452 ImportAddressList
++;
1456 /* Protect the region we are about to write into. */
1457 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1462 if (!NT_SUCCESS(Status
))
1464 DPRINT1("Failed to protect IAT.\n");
1468 return STATUS_SUCCESS
;
1472 LdrpProcessImportDirectory(
1474 PLDR_MODULE ImportedModule
,
1478 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1481 DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
1482 Module
, &Module
->BaseDllName
, ImportedName
);
1485 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1486 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1488 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1490 if (ImportModuleDirectory
== NULL
)
1492 return STATUS_UNSUCCESSFUL
;
1495 while (ImportModuleDirectory
->dwRVAModuleName
)
1497 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1498 if (0 == _stricmp(Name
, ImportedName
))
1500 Status
= LdrpProcessImportDirectoryEntry(Module
,
1502 ImportModuleDirectory
);
1503 if (!NT_SUCCESS(Status
))
1508 ImportModuleDirectory
++;
1512 return STATUS_SUCCESS
;
1517 LdrpAdjustImportDirectory(PLDR_MODULE Module
,
1518 PLDR_MODULE ImportedModule
,
1521 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1523 PVOID
* ImportAddressList
;
1526 PULONG FunctionNameList
;
1531 PIMAGE_NT_HEADERS NTHeaders
;
1534 DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
1535 Module
, &Module
->BaseDllName
, ImportedModule
, &ImportedModule
->BaseDllName
, ImportedName
);
1537 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1538 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1540 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1542 if (ImportModuleDirectory
== NULL
)
1544 return STATUS_UNSUCCESSFUL
;
1547 while (ImportModuleDirectory
->dwRVAModuleName
)
1549 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1550 if (0 == _stricmp(Name
, (PCHAR
)ImportedName
))
1553 /* Get the import address list. */
1554 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1556 /* Get the list of functions to import. */
1557 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1559 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1563 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1566 /* Get the size of IAT. */
1568 while (FunctionNameList
[IATSize
] != 0L)
1573 /* Unprotect the region we are about to write into. */
1574 IATBase
= (PVOID
)ImportAddressList
;
1575 IATSize
*= sizeof(PVOID
*);
1576 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1581 if (!NT_SUCCESS(Status
))
1583 DPRINT1("Failed to unprotect IAT.\n");
1587 NTHeaders
= RtlImageNtHeader (ImportedModule
->BaseAddress
);
1588 Start
= (PVOID
)NTHeaders
->OptionalHeader
.ImageBase
;
1589 End
= Start
+ ImportedModule
->ResidentSize
;
1590 Offset
= ImportedModule
->BaseAddress
- Start
;
1592 /* Walk through function list and fixup addresses. */
1593 while (*FunctionNameList
!= 0L)
1595 if (*ImportAddressList
>= Start
&& *ImportAddressList
< End
)
1597 (*ImportAddressList
) += Offset
;
1599 ImportAddressList
++;
1603 /* Protect the region we are about to write into. */
1604 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1609 if (!NT_SUCCESS(Status
))
1611 DPRINT1("Failed to protect IAT.\n");
1615 ImportModuleDirectory
++;
1617 return STATUS_SUCCESS
;
1621 /**********************************************************************
1626 * Compute the entry point for every symbol the DLL imports
1627 * from other modules.
1639 LdrFixupImports(IN PWSTR SearchPath OPTIONAL
,
1640 IN PLDR_MODULE Module
)
1642 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1643 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectoryCurrent
;
1644 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
1645 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
1646 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1649 PLDR_MODULE ImportedModule
;
1652 DPRINT("LdrFixupImports(SearchPath %x, Module %x)\n", SearchPath
, Module
);
1654 /* Check for tls data */
1655 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
1656 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1658 IMAGE_DIRECTORY_ENTRY_TLS
,
1662 TlsSize
= TlsDirectory
->EndAddressOfRawData
1663 - TlsDirectory
->StartAddressOfRawData
1664 + TlsDirectory
->SizeOfZeroFill
;
1666 NtCurrentPeb()->Ldr
->Initialized
)
1668 TRACE_LDR("Trying to load dynamicly %wZ which contains a tls directory\n",
1669 &Module
->BaseDllName
);
1670 return STATUS_UNSUCCESSFUL
;
1674 * Process each import module.
1676 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1677 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1679 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1682 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
1683 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1685 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
1688 if (BoundImportDescriptor
!= NULL
&& ImportModuleDirectory
== NULL
)
1690 DPRINT1("%wZ has only a bound import directory\n", &Module
->BaseDllName
);
1691 return STATUS_UNSUCCESSFUL
;
1693 if (BoundImportDescriptor
)
1695 DPRINT("BoundImportDescriptor %x\n", BoundImportDescriptor
);
1697 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
1698 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
1700 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
1701 TRACE_LDR("%wZ bound to %s\n", &Module
->BaseDllName
, ImportedName
);
1702 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1703 if (!NT_SUCCESS(Status
))
1705 DPRINT1("failed to load %s\n", ImportedName
);
1708 if (Module
== ImportedModule
)
1710 LdrpDecrementLoadCount(Module
, FALSE
);
1712 if (ImportedModule
->TimeDateStamp
!= BoundImportDescriptorCurrent
->TimeDateStamp
)
1714 TRACE_LDR("%wZ has stale binding to %wZ\n",
1715 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1716 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1717 if (!NT_SUCCESS(Status
))
1719 DPRINT1("failed to import %s\n", ImportedName
);
1725 BOOLEAN WrongForwarder
;
1726 WrongForwarder
= FALSE
;
1727 if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1729 TRACE_LDR("%wZ has stale binding to %s\n",
1730 &Module
->BaseDllName
, ImportedName
);
1734 TRACE_LDR("%wZ has correct binding to %wZ\n",
1735 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1737 if (BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
)
1739 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef
;
1741 PLDR_MODULE ForwarderModule
;
1742 PCHAR ForwarderName
;
1744 BoundForwarderRef
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundImportDescriptorCurrent
+ 1);
1745 for (i
= 0; i
< BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
; i
++, BoundForwarderRef
++)
1747 ForwarderName
= (PCHAR
)BoundImportDescriptor
+ BoundForwarderRef
->OffsetModuleName
;
1748 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1749 &Module
->BaseDllName
, ForwarderName
, ImportedName
);
1750 Status
= LdrpGetOrLoadModule(SearchPath
, ForwarderName
, &ForwarderModule
, TRUE
);
1751 if (!NT_SUCCESS(Status
))
1753 DPRINT1("failed to load %s\n", ForwarderName
);
1756 if (Module
== ImportedModule
)
1758 LdrpDecrementLoadCount(Module
, FALSE
);
1760 if (ForwarderModule
->TimeDateStamp
!= BoundForwarderRef
->TimeDateStamp
||
1761 ForwarderModule
->Flags
& IMAGE_NOT_AT_BASE
)
1763 TRACE_LDR("%wZ has stale binding to %s\n",
1764 &Module
->BaseDllName
, ForwarderName
);
1765 WrongForwarder
= TRUE
;
1769 TRACE_LDR("%wZ has correct binding to %s\n",
1770 &Module
->BaseDllName
, ForwarderName
);
1774 if (WrongForwarder
||
1775 ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1777 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1778 if (!NT_SUCCESS(Status
))
1780 DPRINT1("failed to import %s\n", ImportedName
);
1784 else if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1786 TRACE_LDR("Adjust imports for %s from %wZ\n",
1787 ImportedName
, &Module
->BaseDllName
);
1788 Status
= LdrpAdjustImportDirectory(Module
, ImportedModule
, ImportedName
);
1789 if (!NT_SUCCESS(Status
))
1791 DPRINT1("failed to adjust import entries for %s\n", ImportedName
);
1795 else if (WrongForwarder
)
1799 * Update only forwarders
1801 TRACE_LDR("Stale BIND %s from %wZ\n",
1802 ImportedName
, &Module
->BaseDllName
);
1803 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1804 if (!NT_SUCCESS(Status
))
1806 DPRINT1("faild to import %s\n", ImportedName
);
1815 BoundImportDescriptorCurrent
+= BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
+ 1;
1818 else if (ImportModuleDirectory
)
1820 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1822 ImportModuleDirectoryCurrent
= ImportModuleDirectory
;
1823 while (ImportModuleDirectoryCurrent
->dwRVAModuleName
)
1825 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectoryCurrent
->dwRVAModuleName
;
1826 TRACE_LDR("%wZ imports functions from %s\n", &Module
->BaseDllName
, ImportedName
);
1828 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1829 if (!NT_SUCCESS(Status
))
1831 DPRINT1("failed to load %s\n", ImportedName
);
1834 if (Module
== ImportedModule
)
1836 LdrpDecrementLoadCount(Module
, FALSE
);
1839 TRACE_LDR("Initializing imports for %wZ from %s\n",
1840 &Module
->BaseDllName
, ImportedName
);
1841 Status
= LdrpProcessImportDirectoryEntry(Module
, ImportedModule
, ImportModuleDirectoryCurrent
);
1842 if (!NT_SUCCESS(Status
))
1844 DPRINT1("failed to import %s\n", ImportedName
);
1847 ImportModuleDirectoryCurrent
++;
1851 if (TlsDirectory
&& TlsSize
> 0)
1853 LdrpAcquireTlsSlot(Module
, TlsSize
, FALSE
);
1856 return STATUS_SUCCESS
;
1860 /**********************************************************************
1865 * 1. Relocate, if needed the EXE.
1866 * 2. Fixup any imported symbol.
1867 * 3. Compute the EXE's entry point.
1871 * Address at which the EXE's image
1875 * Handle of the section that contains
1879 * NULL on error; otherwise the entry point
1880 * to call for initializing the DLL.
1885 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
1886 * Currently the function is only used for the exe.
1888 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1889 HANDLE SectionHandle
,
1890 PLDR_MODULE
* Module
,
1894 PEPFUNC EntryPoint
= NULL
;
1895 PIMAGE_DOS_HEADER DosHeader
;
1896 PIMAGE_NT_HEADERS NTHeaders
;
1897 PLDR_MODULE tmpModule
;
1899 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1900 ImageBase
, (ULONG
)SectionHandle
);
1903 * Overlay DOS and WNT headers structures
1904 * to the DLL's image.
1906 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1907 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1910 * If the base address is different from the
1911 * one the DLL is actually loaded, perform any
1914 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1916 DPRINT("LDR: Performing relocations\n");
1917 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1918 if (!NT_SUCCESS(Status
))
1920 DPRINT1("LdrPerformRelocations() failed\n");
1927 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1928 (*Module
)->SectionHandle
= SectionHandle
;
1932 Module
= &tmpModule
;
1933 Status
= LdrFindEntryForAddress(ImageBase
, Module
);
1934 if (!NT_SUCCESS(Status
))
1940 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1942 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
1946 * If the DLL's imports symbols from other
1947 * modules, fixup the imported calls entry points.
1949 DPRINT("About to fixup imports\n");
1950 Status
= LdrFixupImports(NULL
, *Module
);
1951 if (!NT_SUCCESS(Status
))
1953 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module
)->BaseDllName
);
1956 DPRINT("Fixup done\n");
1957 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
1958 Status
= LdrpInitializeTlsForProccess();
1959 if (NT_SUCCESS(Status
))
1961 Status
= LdrpAttachProcess();
1963 if (NT_SUCCESS(Status
))
1965 LdrpTlsCallback(*Module
, DLL_PROCESS_ATTACH
);
1969 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1970 if (!NT_SUCCESS(Status
))
1977 * Compute the DLL's entry point's address.
1979 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1980 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1981 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1983 EntryPoint
= (PEPFUNC
) (ImageBase
1984 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1986 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1991 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
1993 IN PUNICODE_STRING Name
,
1994 PLDR_MODULE
*Module
,
1995 PVOID
*BaseAddress OPTIONAL
)
1997 UNICODE_STRING AdjustedName
;
1998 UNICODE_STRING FullDosName
;
2000 PLDR_MODULE tmpModule
;
2001 HANDLE SectionHandle
;
2004 PIMAGE_NT_HEADERS NtHeaders
;
2005 BOOLEAN MappedAsDataFile
;
2009 Module
= &tmpModule
;
2011 /* adjust the full dll name */
2012 LdrAdjustDllName(&AdjustedName
, Name
, FALSE
);
2014 DPRINT("%wZ\n", &AdjustedName
);
2016 MappedAsDataFile
= FALSE
;
2017 /* Test if dll is already loaded */
2018 Status
= LdrFindEntryForName(&AdjustedName
, Module
, TRUE
);
2019 if (NT_SUCCESS(Status
))
2021 RtlFreeUnicodeString(&AdjustedName
);
2022 if (NULL
!= BaseAddress
)
2024 *BaseAddress
= (*Module
)->BaseAddress
;
2029 /* Open or create dll image section */
2030 Status
= LdrpMapKnownDll(&AdjustedName
, &FullDosName
, &SectionHandle
);
2031 if (!NT_SUCCESS(Status
))
2033 MappedAsDataFile
= (0 != (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
));
2034 Status
= LdrpMapDllImageFile(SearchPath
, &AdjustedName
, &FullDosName
,
2035 MappedAsDataFile
, &SectionHandle
);
2037 if (!NT_SUCCESS(Status
))
2039 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName
, Status
);
2040 RtlFreeUnicodeString(&AdjustedName
);
2043 RtlFreeUnicodeString(&AdjustedName
);
2044 /* Map the dll into the process */
2047 Status
= NtMapViewOfSection(SectionHandle
,
2057 if (!NT_SUCCESS(Status
))
2059 DPRINT1("map view of section failed (Status %x)\n", Status
);
2060 RtlFreeUnicodeString(&FullDosName
);
2061 NtClose(SectionHandle
);
2064 if (NULL
!= BaseAddress
)
2066 *BaseAddress
= ImageBase
;
2068 /* Get and check the NT headers */
2069 NtHeaders
= RtlImageNtHeader(ImageBase
);
2070 if (NtHeaders
== NULL
)
2072 DPRINT1("RtlImageNtHeaders() failed\n");
2073 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2074 NtClose (SectionHandle
);
2075 RtlFreeUnicodeString(&FullDosName
);
2076 return STATUS_UNSUCCESSFUL
;
2078 DPRINT("Mapped %wZ at %x\n", &FullDosName
, ImageBase
);
2079 if (MappedAsDataFile
)
2081 assert(NULL
!= BaseAddress
);
2082 if (NULL
!= BaseAddress
)
2084 *BaseAddress
= (PVOID
) ((char *) *BaseAddress
+ 1);
2087 RtlFreeUnicodeString(&FullDosName
);
2088 NtClose(SectionHandle
);
2089 return STATUS_SUCCESS
;
2091 /* If the base address is different from the
2092 * one the DLL is actually loaded, perform any
2094 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2096 DPRINT1("Relocating (%x -> %x) %wZ\n",
2097 NtHeaders
->OptionalHeader
.ImageBase
, ImageBase
, &FullDosName
);
2098 Status
= LdrPerformRelocations(NtHeaders
, ImageBase
);
2099 if (!NT_SUCCESS(Status
))
2101 DPRINT1("LdrPerformRelocations() failed\n");
2102 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2103 NtClose (SectionHandle
);
2104 RtlFreeUnicodeString(&FullDosName
);
2105 return STATUS_UNSUCCESSFUL
;
2108 *Module
= LdrAddModuleEntry(ImageBase
, NtHeaders
, FullDosName
.Buffer
);
2109 (*Module
)->SectionHandle
= SectionHandle
;
2110 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2112 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
2114 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
2116 (*Module
)->Flags
|= IMAGE_DLL
;
2118 /* fixup the imported calls entry points */
2119 Status
= LdrFixupImports(SearchPath
, *Module
);
2120 if (!NT_SUCCESS(Status
))
2122 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module
)->BaseDllName
, Status
);
2125 #if defined(DBG) || defined(KDBG)
2126 LdrpLoadUserModuleSymbols(*Module
);
2127 #endif /* DBG || KDBG */
2128 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2129 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
2130 &(*Module
)->InInitializationOrderModuleList
);
2131 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2133 return STATUS_SUCCESS
;
2137 LdrpUnloadModule(PLDR_MODULE Module
,
2140 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
2141 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
2142 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
2144 PLDR_MODULE ImportedModule
;
2151 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2154 LoadCount
= LdrpDecrementLoadCount(Module
, Unload
);
2156 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module
->BaseDllName
, LoadCount
);
2160 /* ?????????????????? */
2163 else if (LoadCount
== 1)
2165 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
2166 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2168 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
2170 if (BoundImportDescriptor
)
2172 /* dereferencing all imported modules, use the bound import descriptor */
2173 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
2174 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
2176 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
2177 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2178 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2179 if (!NT_SUCCESS(Status
))
2181 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2185 if (Module
!= ImportedModule
)
2187 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2188 if (!NT_SUCCESS(Status
))
2190 DPRINT1("unable to unload %s\n", ImportedName
);
2194 BoundImportDescriptorCurrent
++;
2199 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
2200 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2202 IMAGE_DIRECTORY_ENTRY_IMPORT
,
2204 if (ImportModuleDirectory
)
2206 /* dereferencing all imported modules, use the import descriptor */
2207 while (ImportModuleDirectory
->dwRVAModuleName
)
2209 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
2210 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2211 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2212 if (!NT_SUCCESS(Status
))
2214 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2218 if (Module
!= ImportedModule
)
2220 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2221 if (!NT_SUCCESS(Status
))
2223 DPRINT1("unable to unload %s\n", ImportedName
);
2227 ImportModuleDirectory
++;
2235 LdrpDetachProcess(FALSE
);
2236 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2238 return STATUS_SUCCESS
;
2246 LdrUnloadDll (IN PVOID BaseAddress
)
2251 if (BaseAddress
== NULL
)
2252 return STATUS_SUCCESS
;
2254 if (LdrMappedAsDataFile(&BaseAddress
))
2256 Status
= NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
2260 Status
= LdrFindEntryForAddress(BaseAddress
, &Module
);
2261 if (NT_SUCCESS(Status
))
2263 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module
->BaseDllName
);
2264 Status
= LdrpUnloadModule(Module
, TRUE
);
2275 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
2277 PLIST_ENTRY ModuleListHead
;
2282 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
2284 Status
= STATUS_DLL_NOT_FOUND
;
2285 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2286 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2287 Entry
= ModuleListHead
->Flink
;
2288 while (Entry
!= ModuleListHead
)
2290 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2292 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
2294 if (Module
->BaseAddress
== BaseAddress
)
2296 if (Module
->TlsIndex
== -1)
2298 Module
->Flags
|= DONT_CALL_FOR_THREAD
;
2299 Status
= STATUS_SUCCESS
;
2303 Entry
= Entry
->Flink
;
2305 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2313 LdrGetDllHandle(IN PWCHAR Path OPTIONAL
,
2315 IN PUNICODE_STRING DllName
,
2316 OUT PVOID
* BaseAddress
)
2321 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName
, Path
? Path
: L
"");
2323 /* NULL is the current executable */
2324 if (DllName
== NULL
)
2326 *BaseAddress
= ExeModule
->BaseAddress
;
2327 DPRINT("BaseAddress %x\n", *BaseAddress
);
2328 return STATUS_SUCCESS
;
2331 Status
= LdrFindEntryForName(DllName
, &Module
, FALSE
);
2332 if (NT_SUCCESS(Status
))
2334 *BaseAddress
= Module
->BaseAddress
;
2335 return STATUS_SUCCESS
;
2338 DPRINT("Failed to find dll %wZ\n", DllName
);
2339 *BaseAddress
= NULL
;
2340 return STATUS_DLL_NOT_FOUND
;
2348 LdrGetProcedureAddress (IN PVOID BaseAddress
,
2349 IN PANSI_STRING Name
,
2351 OUT PVOID
*ProcedureAddress
)
2353 if (Name
&& Name
->Length
)
2355 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name
);
2359 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal
);
2362 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
2363 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
2365 if (Name
&& Name
->Length
)
2368 *ProcedureAddress
= LdrGetExportByName(BaseAddress
, (PUCHAR
)Name
->Buffer
, 0xffff);
2369 if (*ProcedureAddress
!= NULL
)
2371 return STATUS_SUCCESS
;
2373 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
2378 Ordinal
&= 0x0000FFFF;
2379 *ProcedureAddress
= LdrGetExportByOrdinal(BaseAddress
, (WORD
)Ordinal
);
2380 if (*ProcedureAddress
)
2382 return STATUS_SUCCESS
;
2384 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
2386 return STATUS_PROCEDURE_NOT_FOUND
;
2389 /**********************************************************************
2394 * Unload dll's which are no longer referenced from others dll's
2405 * The loader lock must be held on enty.
2408 LdrpDetachProcess(BOOLEAN UnloadAll
)
2410 PLIST_ENTRY ModuleListHead
;
2413 static ULONG CallingCount
= 0;
2415 DPRINT("LdrpDetachProcess() called for %wZ\n",
2416 &ExeModule
->BaseDllName
);
2420 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2421 Entry
= ModuleListHead
->Blink
;
2422 while (Entry
!= ModuleListHead
)
2424 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2425 if (((UnloadAll
&& Module
->LoadCount
<= 0) || Module
->LoadCount
== 0) &&
2426 Module
->Flags
& ENTRY_PROCESSED
&&
2427 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2429 Module
->Flags
|= UNLOAD_IN_PROGRESS
;
2430 if (Module
== LdrpLastModule
)
2432 LdrpLastModule
= NULL
;
2434 if (Module
->Flags
& PROCESS_ATTACH_CALLED
)
2436 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2437 &Module
->BaseDllName
, Module
->EntryPoint
);
2438 LdrpCallDllEntry(Module
, DLL_PROCESS_DETACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2442 TRACE_LDR("Unload %wZ\n", &Module
->BaseDllName
);
2444 Entry
= ModuleListHead
->Blink
;
2448 Entry
= Entry
->Blink
;
2452 if (CallingCount
== 1)
2454 Entry
= ModuleListHead
->Blink
;
2455 while (Entry
!= ModuleListHead
)
2457 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2458 Entry
= Entry
->Blink
;
2459 if (Module
->Flags
& UNLOAD_IN_PROGRESS
&&
2460 ((UnloadAll
&& Module
->LoadCount
>= 0) || Module
->LoadCount
== 0))
2462 /* remove the module entry from the list */
2463 RemoveEntryList (&Module
->InLoadOrderModuleList
);
2464 RemoveEntryList (&Module
->InInitializationOrderModuleList
);
2466 NtUnmapViewOfSection (NtCurrentProcess (), Module
->BaseAddress
);
2467 NtClose (Module
->SectionHandle
);
2469 TRACE_LDR("%wZ unloaded\n", &Module
->BaseDllName
);
2471 RtlFreeUnicodeString (&Module
->FullDllName
);
2472 RtlFreeUnicodeString (&Module
->BaseDllName
);
2474 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
2479 DPRINT("LdrpDetachProcess() done\n");
2482 /**********************************************************************
2487 * Initialize all dll's which are prepered for loading
2498 * The loader lock must be held on entry.
2502 LdrpAttachProcess(VOID
)
2504 PLIST_ENTRY ModuleListHead
;
2508 NTSTATUS Status
= STATUS_SUCCESS
;
2510 DPRINT("LdrpAttachProcess() called for %wZ\n",
2511 &ExeModule
->BaseDllName
);
2513 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2514 Entry
= ModuleListHead
->Flink
;
2515 while (Entry
!= ModuleListHead
)
2517 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2518 if (!(Module
->Flags
& (LOAD_IN_PROGRESS
|UNLOAD_IN_PROGRESS
|ENTRY_PROCESSED
)))
2520 Module
->Flags
|= LOAD_IN_PROGRESS
;
2521 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2522 &Module
->BaseDllName
, Module
->EntryPoint
);
2523 Result
= LdrpCallDllEntry(Module
, DLL_PROCESS_ATTACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2526 Status
= STATUS_DLL_INIT_FAILED
;
2529 if (Module
->Flags
& IMAGE_DLL
&& Module
->EntryPoint
!= 0)
2531 Module
->Flags
|= PROCESS_ATTACH_CALLED
|ENTRY_PROCESSED
;
2535 Module
->Flags
|= ENTRY_PROCESSED
;
2537 Module
->Flags
&= ~LOAD_IN_PROGRESS
;
2539 Entry
= Entry
->Flink
;
2542 DPRINT("LdrpAttachProcess() done\n");
2551 LdrShutdownProcess (VOID
)
2553 LdrpDetachProcess(TRUE
);
2554 return STATUS_SUCCESS
;
2562 LdrpAttachThread (VOID
)
2564 PLIST_ENTRY ModuleListHead
;
2569 DPRINT("LdrpAttachThread() called for %wZ\n",
2570 &ExeModule
->BaseDllName
);
2572 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2574 Status
= LdrpInitializeTlsForThread();
2576 if (NT_SUCCESS(Status
))
2578 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2579 Entry
= ModuleListHead
->Flink
;
2581 while (Entry
!= ModuleListHead
)
2583 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2584 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2585 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2586 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2588 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2589 &Module
->BaseDllName
, Module
->EntryPoint
);
2590 LdrpCallDllEntry(Module
, DLL_THREAD_ATTACH
, NULL
);
2592 Entry
= Entry
->Flink
;
2595 Entry
= NtCurrentPeb()->Ldr
->InLoadOrderModuleList
.Flink
;
2596 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2597 LdrpTlsCallback(Module
, DLL_THREAD_ATTACH
);
2600 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2602 DPRINT("LdrpAttachThread() done\n");
2612 LdrShutdownThread (VOID
)
2614 PLIST_ENTRY ModuleListHead
;
2618 DPRINT("LdrShutdownThread() called for %wZ\n",
2619 &ExeModule
->BaseDllName
);
2621 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2623 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2624 Entry
= ModuleListHead
->Blink
;
2625 while (Entry
!= ModuleListHead
)
2627 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2629 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2630 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2631 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2633 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2634 &Module
->BaseDllName
, Module
->EntryPoint
);
2635 LdrpCallDllEntry(Module
, DLL_THREAD_DETACH
, NULL
);
2637 Entry
= Entry
->Blink
;
2640 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2644 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer
);
2647 DPRINT("LdrShutdownThread() done\n");
2649 return STATUS_SUCCESS
;
2653 /***************************************************************************
2655 * LdrQueryProcessModuleInformation
2670 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
2671 IN ULONG Size OPTIONAL
,
2672 OUT PULONG ReturnedSize
)
2674 PLIST_ENTRY ModuleListHead
;
2677 PDEBUG_MODULE_INFORMATION ModulePtr
= NULL
;
2678 NTSTATUS Status
= STATUS_SUCCESS
;
2679 ULONG UsedSize
= sizeof(ULONG
);
2680 ANSI_STRING AnsiString
;
2683 DPRINT("LdrQueryProcessModuleInformation() called\n");
2685 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2687 if (ModuleInformation
== NULL
|| Size
== 0)
2689 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2693 ModuleInformation
->ModuleCount
= 0;
2694 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
2695 Status
= STATUS_SUCCESS
;
2698 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2699 Entry
= ModuleListHead
->Flink
;
2701 while (Entry
!= ModuleListHead
)
2703 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2705 DPRINT(" Module %wZ\n",
2706 &Module
->FullDllName
);
2708 if (UsedSize
> Size
)
2710 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2712 else if (ModuleInformation
!= NULL
)
2714 ModulePtr
->Reserved
[0] = ModulePtr
->Reserved
[1] = 0; // FIXME: ??
2715 ModulePtr
->Base
= Module
->BaseAddress
;
2716 ModulePtr
->Size
= Module
->ResidentSize
;
2717 ModulePtr
->Flags
= Module
->Flags
;
2718 ModulePtr
->Index
= 0; // FIXME: index ??
2719 ModulePtr
->Unknown
= 0; // FIXME: ??
2720 ModulePtr
->LoadCount
= Module
->LoadCount
;
2722 AnsiString
.Length
= 0;
2723 AnsiString
.MaximumLength
= 256;
2724 AnsiString
.Buffer
= ModulePtr
->ImageName
;
2725 RtlUnicodeStringToAnsiString(&AnsiString
,
2726 &Module
->FullDllName
,
2728 p
= strrchr(ModulePtr
->ImageName
, '\\');
2730 ModulePtr
->ModuleNameOffset
= p
- ModulePtr
->ImageName
+ 1;
2732 ModulePtr
->ModuleNameOffset
= 0;
2735 ModuleInformation
->ModuleCount
++;
2737 UsedSize
+= sizeof(DEBUG_MODULE_INFORMATION
);
2739 Entry
= Entry
->Flink
;
2742 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2744 if (ReturnedSize
!= 0)
2745 *ReturnedSize
= UsedSize
;
2747 DPRINT("LdrQueryProcessModuleInformation() done\n");
2754 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
2757 PIMAGE_NT_HEADERS Header
;
2764 Header
= RtlImageNtHeader (BaseAddress
);
2768 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
2773 Ptr
= (PUSHORT
) BaseAddress
;
2774 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
2777 if (HIWORD(Sum
) != 0)
2779 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2786 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
2787 if (HIWORD(Sum
) != 0)
2789 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2793 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
2795 /* Subtract image checksum from calculated checksum. */
2796 /* fix low word of checksum */
2797 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
2799 CalcSum
-= LOWORD(HeaderSum
);
2803 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
2806 /* fix high word of checksum */
2807 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
2809 CalcSum
-= HIWORD(HeaderSum
);
2813 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
2816 /* add file length */
2817 CalcSum
+= ImageSize
;
2819 return (BOOLEAN
)(CalcSum
== HeaderSum
);
2823 * Compute size of an image as it is actually present in virt memory
2824 * (i.e. excluding NEVER_LOAD sections)
2827 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders
)
2829 PIMAGE_SECTION_HEADER SectionHeader
;
2830 unsigned SectionIndex
;
2833 SectionHeader
= (PIMAGE_SECTION_HEADER
)((char *) &NTHeaders
->OptionalHeader
2834 + NTHeaders
->FileHeader
.SizeOfOptionalHeader
);
2836 for (SectionIndex
= 0; SectionIndex
< NTHeaders
->FileHeader
.NumberOfSections
; SectionIndex
++)
2838 if (0 == (SectionHeader
->Characteristics
& IMAGE_SCN_LNK_REMOVE
)
2839 && ResidentSize
< SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
)
2841 ResidentSize
= SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
;
2846 return ResidentSize
;
2850 /***************************************************************************
2852 * LdrVerifyImageMatchesChecksum
2867 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
2872 FILE_STANDARD_INFORMATION FileInfo
;
2873 IO_STATUS_BLOCK IoStatusBlock
;
2874 HANDLE SectionHandle
;
2880 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2882 Status
= NtCreateSection (&SectionHandle
,
2889 if (!NT_SUCCESS(Status
))
2891 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
2897 Status
= NtMapViewOfSection (SectionHandle
,
2898 NtCurrentProcess (),
2907 if (!NT_SUCCESS(Status
))
2909 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2910 NtClose (SectionHandle
);
2914 Status
= NtQueryInformationFile (FileHandle
,
2917 sizeof (FILE_STANDARD_INFORMATION
),
2918 FileStandardInformation
);
2919 if (!NT_SUCCESS(Status
))
2921 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2922 NtUnmapViewOfSection (NtCurrentProcess (),
2924 NtClose (SectionHandle
);
2928 Result
= LdrpCheckImageChecksum (BaseAddress
,
2929 FileInfo
.EndOfFile
.u
.LowPart
);
2930 if (Result
== FALSE
)
2932 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2935 NtUnmapViewOfSection (NtCurrentProcess (),
2938 NtClose (SectionHandle
);
2944 /***************************************************************************
2946 * LdrQueryImageFileExecutionOptions
2961 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
2962 IN PCWSTR ValueName
,
2965 IN ULONG BufferSize
,
2966 OUT PULONG ReturnedLength OPTIONAL
)
2968 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2969 OBJECT_ATTRIBUTES ObjectAttributes
;
2970 UNICODE_STRING ValueNameString
;
2971 UNICODE_STRING KeyName
;
2972 WCHAR NameBuffer
[256];
2980 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2981 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
2984 Ptr
= SubKey
->Buffer
;
2990 wcscat (NameBuffer
, Ptr
);
2991 RtlInitUnicodeString (&KeyName
,
2994 InitializeObjectAttributes (&ObjectAttributes
,
2996 OBJ_CASE_INSENSITIVE
,
3000 Status
= NtOpenKey (&KeyHandle
,
3003 if (!NT_SUCCESS(Status
))
3005 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
3009 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
3010 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3014 RtlInitUnicodeString (&ValueNameString
,
3016 Status
= NtQueryValueKey (KeyHandle
,
3018 KeyValuePartialInformation
,
3022 if (Status
== STATUS_BUFFER_OVERFLOW
)
3024 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
3025 RtlFreeHeap (RtlGetProcessHeap(),
3028 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3031 if (KeyInfo
== NULL
)
3033 NtClose (KeyHandle
);
3037 Status
= NtQueryValueKey (KeyHandle
,
3039 KeyValuePartialInformation
,
3044 NtClose (KeyHandle
);
3046 if (!NT_SUCCESS(Status
))
3048 if (KeyInfo
!= NULL
)
3050 RtlFreeHeap (RtlGetProcessHeap(),
3057 if (KeyInfo
->Type
!= Type
)
3059 RtlFreeHeap (RtlGetProcessHeap(),
3062 return STATUS_OBJECT_TYPE_MISMATCH
;
3065 ResultSize
= BufferSize
;
3066 if (ResultSize
< KeyInfo
->DataLength
)
3068 Status
= STATUS_BUFFER_OVERFLOW
;
3072 ResultSize
= KeyInfo
->DataLength
;
3074 RtlCopyMemory (Buffer
,
3078 RtlFreeHeap (RtlGetProcessHeap(),
3082 if (ReturnedLength
!= NULL
)
3084 *ReturnedLength
= ResultSize
;
3091 PIMAGE_BASE_RELOCATION STDCALL
3092 LdrProcessRelocationBlock(IN PVOID Address
,
3094 IN PUSHORT TypeOffset
,
3103 for (i
= 0; i
< Count
; i
++)
3105 Offset
= *TypeOffset
& 0xFFF;
3106 Type
= *TypeOffset
>> 12;
3110 case IMAGE_REL_BASED_ABSOLUTE
:
3113 case IMAGE_REL_BASED_HIGH
:
3114 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3115 *ShortPtr
+= HIWORD(Delta
);
3118 case IMAGE_REL_BASED_LOW
:
3119 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3120 *ShortPtr
+= LOWORD(Delta
);
3123 case IMAGE_REL_BASED_HIGHLOW
:
3124 LongPtr
= (PULONG
)(Address
+ Offset
);
3128 case IMAGE_REL_BASED_HIGHADJ
:
3129 case IMAGE_REL_BASED_MIPS_JMPADDR
:
3131 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type
);
3138 return (PIMAGE_BASE_RELOCATION
)TypeOffset
;