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
)
190 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule
->BaseDllName
);
192 if (LdrpTlsCount
> 0)
194 TlsPointers
= RtlAllocateHeap(RtlGetProcessHeap(),
196 LdrpTlsCount
* sizeof(PVOID
) + LdrpTlsSize
);
197 if (TlsPointers
== NULL
)
199 DPRINT1("failed to allocate thread tls data\n");
200 return STATUS_NO_MEMORY
;
203 TlsData
= (PVOID
)TlsPointers
+ LdrpTlsCount
* sizeof(PVOID
);
204 NtCurrentTeb()->ThreadLocalStoragePointer
= TlsPointers
;
206 TlsInfo
= LdrpTlsArray
;
207 for (i
= 0; i
< LdrpTlsCount
; i
++, TlsInfo
++)
209 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo
->Module
->BaseDllName
);
210 TlsPointers
[i
] = TlsData
;
211 if (TlsInfo
->TlsDataSize
)
213 memcpy(TlsData
, TlsInfo
->StartAddressOfRawData
, TlsInfo
->TlsDataSize
);
214 TlsData
+= TlsInfo
->TlsDataSize
;
216 if (TlsInfo
->TlsZeroSize
)
218 memset(TlsData
, 0, TlsInfo
->TlsZeroSize
);
219 TlsData
+= TlsInfo
->TlsZeroSize
;
223 DPRINT("LdrpInitializeTlsForThread() done\n");
224 return STATUS_SUCCESS
;
228 LdrpInitializeTlsForProccess(VOID
)
230 PLIST_ENTRY ModuleListHead
;
233 PIMAGE_TLS_DIRECTORY TlsDirectory
;
236 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule
->BaseDllName
);
238 if (LdrpTlsCount
> 0)
240 LdrpTlsArray
= RtlAllocateHeap(RtlGetProcessHeap(),
242 LdrpTlsCount
* sizeof(TLS_DATA
));
243 if (LdrpTlsArray
== NULL
)
245 DPRINT1("Failed to allocate global tls data\n");
246 return STATUS_NO_MEMORY
;
249 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
250 Entry
= ModuleListHead
->Flink
;
251 while (Entry
!= ModuleListHead
)
253 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
254 if (Module
->LoadCount
== -1 &&
255 Module
->TlsIndex
>= 0)
257 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
258 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
260 IMAGE_DIRECTORY_ENTRY_TLS
,
262 assert(Module
->TlsIndex
< LdrpTlsCount
);
263 TlsData
= &LdrpTlsArray
[Module
->TlsIndex
];
264 TlsData
->StartAddressOfRawData
= (PVOID
)TlsDirectory
->StartAddressOfRawData
;
265 TlsData
->TlsDataSize
= TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
;
266 TlsData
->TlsZeroSize
= TlsDirectory
->SizeOfZeroFill
;
267 if (TlsDirectory
->AddressOfCallBacks
)
268 TlsData
->TlsAddressOfCallBacks
= *TlsDirectory
->AddressOfCallBacks
;
270 TlsData
->TlsAddressOfCallBacks
= NULL
;
271 TlsData
->Module
= Module
;
273 DbgPrint("TLS directory for %wZ\n", &Module
->BaseDllName
);
274 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory
->StartAddressOfRawData
);
275 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory
->EndAddressOfRawData
);
276 DbgPrint("SizeOfRawData: %d\n", TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
);
277 DbgPrint("AddressOfIndex: %x\n", TlsDirectory
->AddressOfIndex
);
278 DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory
->AddressOfCallBacks
, *TlsDirectory
->AddressOfCallBacks
);
279 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory
->SizeOfZeroFill
);
280 DbgPrint("Characteristics: %x\n", TlsDirectory
->Characteristics
);
284 * Is this region allways writable ?
286 *(PULONG
)TlsDirectory
->AddressOfIndex
= Module
->TlsIndex
;
289 Entry
= Entry
->Flink
;
292 DPRINT("LdrpInitializeTlsForProccess() done\n");
293 return STATUS_SUCCESS
;
299 OBJECT_ATTRIBUTES ObjectAttributes
;
300 UNICODE_STRING LinkTarget
;
306 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule
->BaseDllName
);
308 /* Get handle to the 'KnownDlls' directory */
309 RtlInitUnicodeString(&Name
,
311 InitializeObjectAttributes(&ObjectAttributes
,
313 OBJ_CASE_INSENSITIVE
,
316 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
317 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
319 if (!NT_SUCCESS(Status
))
321 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
322 LdrpKnownDllsDirHandle
= NULL
;
326 /* Allocate target name string */
327 LinkTarget
.Length
= 0;
328 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
329 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
331 MAX_PATH
* sizeof(WCHAR
));
332 if (LinkTarget
.Buffer
== NULL
)
334 NtClose(LdrpKnownDllsDirHandle
);
335 LdrpKnownDllsDirHandle
= NULL
;
339 RtlInitUnicodeString(&Name
,
341 InitializeObjectAttributes(&ObjectAttributes
,
343 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
344 LdrpKnownDllsDirHandle
,
346 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
347 SYMBOLIC_LINK_ALL_ACCESS
,
349 if (!NT_SUCCESS(Status
))
351 RtlFreeUnicodeString(&LinkTarget
);
352 NtClose(LdrpKnownDllsDirHandle
);
353 LdrpKnownDllsDirHandle
= NULL
;
357 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
361 if (!NT_SUCCESS(Status
))
363 RtlFreeUnicodeString(&LinkTarget
);
364 NtClose(LdrpKnownDllsDirHandle
);
365 LdrpKnownDllsDirHandle
= NULL
;
368 RtlCreateUnicodeString(&LdrpKnownDllPath
,
371 RtlFreeUnicodeString(&LinkTarget
);
373 DPRINT("LdrpInitLoader() done\n");
377 /***************************************************************************
382 * Adjusts the name of a dll to a fully qualified name.
385 * FullDllName: Pointer to caller supplied storage for the fully
386 * qualified dll name.
387 * DllName: Pointer to the dll name.
388 * BaseName: TRUE: Only the file name is passed to FullDllName
389 * FALSE: The full path is preserved in FullDllName
397 * A given path is not affected by the adjustment, but the file
399 * ntdll --> ntdll.dll
401 * ntdll.xyz --> ntdll.xyz
404 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
405 PUNICODE_STRING DllName
,
408 WCHAR Buffer
[MAX_PATH
];
413 Length
= DllName
->Length
/ sizeof(WCHAR
);
417 /* get the base dll name */
418 Pointer
= DllName
->Buffer
+ Length
;
425 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
428 Length
= Extension
- Pointer
;
429 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
430 Buffer
[Length
] = L
'\0';
434 /* get the full dll name */
435 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
436 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
439 /* Build the DLL's absolute name */
440 Extension
= wcsrchr (Buffer
, L
'.');
441 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
443 /* with extension - remove dot if it's the last character */
444 if (Buffer
[Length
- 1] == L
'.')
450 /* name without extension - assume that it is .dll */
451 memmove (Buffer
+ Length
, L
".dll", 10);
454 RtlCreateUnicodeString(FullDllName
, Buffer
);
458 LdrAddModuleEntry(PVOID ImageBase
,
459 PIMAGE_NT_HEADERS NTHeaders
,
464 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
466 memset(Module
, 0, sizeof(LDR_MODULE
));
467 Module
->BaseAddress
= (PVOID
)ImageBase
;
468 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
469 if (Module
->EntryPoint
!= 0)
470 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
471 Module
->ResidentSize
= LdrpGetResidentSize(NTHeaders
);
472 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
474 /* loading while app is running */
475 Module
->LoadCount
= 1;
478 * loading while app is initializing
479 * dll must not be unloaded
481 Module
->LoadCount
= -1;
485 Module
->TlsIndex
= -1;
486 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
487 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
489 RtlCreateUnicodeString (&Module
->FullDllName
,
491 RtlCreateUnicodeString (&Module
->BaseDllName
,
492 wcsrchr(FullDosName
, L
'\\') + 1);
493 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
495 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
496 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
497 &Module
->InLoadOrderModuleList
);
498 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
505 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
506 OUT PUNICODE_STRING FullDosName
,
507 OUT PHANDLE SectionHandle
)
509 OBJECT_ATTRIBUTES ObjectAttributes
;
512 DPRINT("LdrpMapKnownDll() called\n");
514 if (LdrpKnownDllsDirHandle
== NULL
)
516 DPRINT("Invalid 'KnownDlls' directory\n");
517 return STATUS_UNSUCCESSFUL
;
520 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
522 InitializeObjectAttributes(&ObjectAttributes
,
524 OBJ_CASE_INSENSITIVE
,
525 LdrpKnownDllsDirHandle
,
527 Status
= NtOpenSection(SectionHandle
,
528 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
530 if (!NT_SUCCESS(Status
))
532 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
536 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
537 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
538 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
540 FullDosName
->MaximumLength
);
541 if (FullDosName
->Buffer
== NULL
)
543 FullDosName
->Length
= 0;
544 FullDosName
->MaximumLength
= 0;
545 return STATUS_SUCCESS
;
548 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
549 wcscat(FullDosName
->Buffer
, L
"\\");
550 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
552 DPRINT("FullDosName '%wZ'\n", FullDosName
);
554 DPRINT("LdrpMapKnownDll() done\n");
556 return STATUS_SUCCESS
;
561 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
562 IN PUNICODE_STRING DllName
,
563 OUT PUNICODE_STRING FullDosName
,
564 IN BOOLEAN MapAsDataFile
,
565 OUT PHANDLE SectionHandle
)
567 WCHAR SearchPathBuffer
[MAX_PATH
];
568 WCHAR DosName
[MAX_PATH
];
569 UNICODE_STRING FullNtFileName
;
570 OBJECT_ATTRIBUTES FileObjectAttributes
;
572 char BlockBuffer
[1024];
573 PIMAGE_DOS_HEADER DosHeader
;
574 PIMAGE_NT_HEADERS NTHeaders
;
575 IO_STATUS_BLOCK IoStatusBlock
;
579 DPRINT("LdrpMapDllImageFile() called\n");
581 if (SearchPath
== NULL
)
583 /* get application running path */
585 wcscpy (SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
587 len
= wcslen (SearchPathBuffer
);
589 while (len
&& SearchPathBuffer
[len
- 1] != L
'\\')
592 if (len
) SearchPathBuffer
[len
-1] = L
'\0';
594 wcscat (SearchPathBuffer
, L
";");
596 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
597 wcscat (SearchPathBuffer
, L
"\\system32;");
598 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
599 wcscat (SearchPathBuffer
, L
";.");
601 SearchPath
= SearchPathBuffer
;
604 if (RtlDosSearchPath_U (SearchPath
,
610 return STATUS_DLL_NOT_FOUND
;
613 if (!RtlDosPathNameToNtPathName_U (DosName
,
617 return STATUS_DLL_NOT_FOUND
;
619 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
621 InitializeObjectAttributes(&FileObjectAttributes
,
627 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
629 Status
= NtOpenFile(&FileHandle
,
630 GENERIC_READ
|SYNCHRONIZE
,
631 &FileObjectAttributes
,
634 FILE_SYNCHRONOUS_IO_NONALERT
);
635 if (!NT_SUCCESS(Status
))
637 DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
638 &FullNtFileName
, Status
);
639 RtlFreeUnicodeString (&FullNtFileName
);
642 RtlFreeUnicodeString (&FullNtFileName
);
644 Status
= NtReadFile(FileHandle
,
653 if (!NT_SUCCESS(Status
))
655 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
660 * Overlay DOS and NT headers structures to the
661 * buffer with DLL's header raw data.
663 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
664 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
666 * Check it is a PE image file.
668 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
669 || (DosHeader
->e_lfanew
== 0L)
670 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
672 DPRINT("NTDLL format invalid\n");
675 return STATUS_UNSUCCESSFUL
;
679 * Create a section for dll.
681 Status
= NtCreateSection(SectionHandle
,
686 SEC_COMMIT
| (MapAsDataFile
? 0 : SEC_IMAGE
),
690 if (!NT_SUCCESS(Status
))
692 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
696 RtlCreateUnicodeString(FullDosName
,
704 /***************************************************************************
721 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
723 IN PUNICODE_STRING Name
,
724 OUT PVOID
*BaseAddress OPTIONAL
)
729 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
731 SearchPath
? " from " : "",
732 SearchPath
? SearchPath
: L
"");
736 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
737 return STATUS_SUCCESS
;
742 Status
= LdrpLoadModule(SearchPath
, LoadFlags
, Name
, &Module
, BaseAddress
);
743 if (NT_SUCCESS(Status
) && 0 == (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
))
745 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
746 Status
= LdrpAttachProcess();
747 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
748 if (NT_SUCCESS(Status
))
750 *BaseAddress
= Module
->BaseAddress
;
757 /***************************************************************************
759 * LdrFindEntryForAddress
774 LdrFindEntryForAddress(PVOID Address
,
777 PLIST_ENTRY ModuleListHead
;
779 PLDR_MODULE ModulePtr
;
781 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
783 if (NtCurrentPeb()->Ldr
== NULL
)
784 return(STATUS_NO_MORE_ENTRIES
);
786 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
787 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
788 Entry
= ModuleListHead
->Flink
;
789 if (Entry
== ModuleListHead
)
791 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
792 return(STATUS_NO_MORE_ENTRIES
);
795 while (Entry
!= ModuleListHead
)
797 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
799 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
801 if ((Address
>= ModulePtr
->BaseAddress
) &&
802 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->ResidentSize
)))
805 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
806 return(STATUS_SUCCESS
);
809 Entry
= Entry
->Flink
;
812 DPRINT("Failed to find module entry.\n");
814 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
815 return(STATUS_NO_MORE_ENTRIES
);
819 /***************************************************************************
821 * LdrFindEntryForName
835 LdrFindEntryForName(PUNICODE_STRING Name
,
839 PLIST_ENTRY ModuleListHead
;
841 PLDR_MODULE ModulePtr
;
842 BOOLEAN ContainsPath
;
843 UNICODE_STRING AdjustedName
;
846 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name
);
848 if (NtCurrentPeb()->Ldr
== NULL
)
849 return(STATUS_NO_MORE_ENTRIES
);
851 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
852 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
853 Entry
= ModuleListHead
->Flink
;
854 if (Entry
== ModuleListHead
)
856 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
857 return(STATUS_NO_MORE_ENTRIES
);
860 // NULL is the current process
864 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
865 return(STATUS_SUCCESS
);
868 LdrAdjustDllName (&AdjustedName
, Name
, FALSE
);
870 ContainsPath
= (AdjustedName
.Length
>= 2 * sizeof(WCHAR
) && L
':' == AdjustedName
.Buffer
[1]);
871 for (i
= 0; ! ContainsPath
&& i
< AdjustedName
.Length
/ sizeof(WCHAR
); i
++)
873 ContainsPath
= L
'\\' == AdjustedName
.Buffer
[i
] ||
874 L
'/' == AdjustedName
.Buffer
[i
];
879 if ((! ContainsPath
&&
880 0 == RtlCompareUnicodeString(&LdrpLastModule
->BaseDllName
, &AdjustedName
, TRUE
)) ||
882 0 == RtlCompareUnicodeString(&LdrpLastModule
->FullDllName
, &AdjustedName
, TRUE
)))
884 *Module
= LdrpLastModule
;
885 if (Ref
&& (*Module
)->LoadCount
!= -1)
887 (*Module
)->LoadCount
++;
889 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
890 RtlFreeUnicodeString(&AdjustedName
);
891 return(STATUS_SUCCESS
);
894 while (Entry
!= ModuleListHead
)
896 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
898 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, &AdjustedName
);
900 if ((! ContainsPath
&&
901 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, &AdjustedName
, TRUE
)) ||
903 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, &AdjustedName
, TRUE
)))
905 *Module
= LdrpLastModule
= ModulePtr
;
906 if (Ref
&& ModulePtr
->LoadCount
!= -1)
908 ModulePtr
->LoadCount
++;
910 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
911 RtlFreeUnicodeString(&AdjustedName
);
912 return(STATUS_SUCCESS
);
915 Entry
= Entry
->Flink
;
918 DPRINT("Failed to find dll %wZ\n", Name
);
919 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
920 RtlFreeUnicodeString(&AdjustedName
);
921 return(STATUS_NO_MORE_ENTRIES
);
924 /**********************************************************************
940 LdrFixupForward(PCHAR ForwardName
)
942 CHAR NameBuffer
[128];
943 UNICODE_STRING DllName
;
949 strcpy(NameBuffer
, ForwardName
);
950 p
= strchr(NameBuffer
, '.');
955 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
956 RtlCreateUnicodeStringFromAsciiz (&DllName
,
959 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
961 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
963 if (!NT_SUCCESS(Status
))
965 Status
= LdrLoadDll(NULL
,
966 LDRP_PROCESS_CREATION_TIME
,
969 if (NT_SUCCESS(Status
))
971 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
974 RtlFreeUnicodeString (&DllName
);
975 if (!NT_SUCCESS(Status
))
977 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer
);
981 DPRINT("BaseAddress: %p\n", Module
->BaseAddress
);
983 return LdrGetExportByName(Module
->BaseAddress
, (PUCHAR
)(p
+1), -1);
990 /**********************************************************************
992 * LdrGetExportByOrdinal
1006 LdrGetExportByOrdinal (
1011 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1012 ULONG ExportDirSize
;
1013 PDWORD
* ExFunctions
;
1016 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1017 RtlImageDirectoryEntryToData (BaseAddress
,
1019 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1023 ExFunctions
= (PDWORD
*)
1026 ExportDir
->AddressOfFunctions
1029 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
1031 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1034 Function
= (0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1035 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1038 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1039 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1041 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1042 Function
= LdrFixupForward((PCHAR
)Function
);
1049 /**********************************************************************
1051 * LdrGetExportByName
1062 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1063 * both with NumberOfNames entries.
1067 LdrGetExportByName(PVOID BaseAddress
,
1071 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1072 PDWORD
* ExFunctions
;
1074 USHORT
* ExOrdinals
;
1080 ULONG ExportDirSize
;
1082 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1084 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1085 RtlImageDirectoryEntryToData(BaseAddress
,
1087 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1089 if (ExportDir
== NULL
)
1091 DPRINT1("LdrGetExportByName(): no export directory!\n");
1096 //The symbol names may be missing entirely
1097 if (ExportDir
->AddressOfNames
== 0)
1099 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1104 * Get header pointers
1106 ExNames
= (PDWORD
*)RVA(BaseAddress
,
1107 ExportDir
->AddressOfNames
);
1108 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
1109 ExportDir
->AddressOfNameOrdinals
);
1110 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
1111 ExportDir
->AddressOfFunctions
);
1114 * Check the hint first
1116 if (Hint
< ExportDir
->NumberOfNames
)
1118 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1119 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1121 Ordinal
= ExOrdinals
[Hint
];
1122 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1123 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1124 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1126 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1127 Function
= LdrFixupForward((PCHAR
)Function
);
1128 if (Function
== NULL
)
1130 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1134 if (Function
!= NULL
)
1140 * Try a binary search first
1143 maxn
= ExportDir
->NumberOfNames
- 1;
1144 while (minn
<= maxn
)
1149 mid
= (minn
+ maxn
) / 2;
1151 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1152 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
1155 Ordinal
= ExOrdinals
[mid
];
1156 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1157 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1158 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1160 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1161 Function
= LdrFixupForward((PCHAR
)Function
);
1162 if (Function
== NULL
)
1164 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1168 if (Function
!= NULL
)
1171 else if (minn
== maxn
)
1173 DPRINT("LdrGetExportByName(): binary search failed\n");
1187 * Fall back on a linear search
1189 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1190 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1192 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1193 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1195 Ordinal
= ExOrdinals
[i
];
1196 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1197 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1198 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1199 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1201 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1202 Function
= LdrFixupForward((PCHAR
)Function
);
1204 if (Function
== NULL
)
1211 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1216 /**********************************************************************
1218 * LdrPerformRelocations
1221 * Relocate a DLL's memory image.
1233 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
,
1236 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1237 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
1238 ULONG Count
, ProtectSize
, OldProtect
, OldProtect2
;
1239 PVOID Page
, ProtectPage
, ProtectPage2
;
1244 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1246 return STATUS_UNSUCCESSFUL
;
1250 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1252 if (RelocationDDir
->VirtualAddress
== 0 || RelocationDDir
->Size
== 0)
1254 return STATUS_SUCCESS
;
1257 ProtectSize
= PAGE_SIZE
;
1258 Delta
= (ULONG_PTR
)ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
;
1259 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1260 RelocationDDir
->VirtualAddress
);
1261 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1262 RelocationDDir
->VirtualAddress
+ RelocationDDir
->Size
);
1264 while (RelocationDir
< RelocationEnd
&&
1265 RelocationDir
->SizeOfBlock
> 0)
1267 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) /
1269 Page
= ImageBase
+ RelocationDir
->VirtualAddress
;
1270 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
1272 /* Unprotect the page(s) we're about to relocate. */
1274 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1279 if (!NT_SUCCESS(Status
))
1281 DPRINT1("Failed to unprotect relocation target.\n");
1285 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
<
1286 NTHeaders
->OptionalHeader
.SizeOfImage
)
1288 ProtectPage2
= ProtectPage
+ PAGE_SIZE
;
1289 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1294 if (!NT_SUCCESS(Status
))
1296 DPRINT1("Failed to unprotect relocation target (2).\n");
1297 NtProtectVirtualMemory(NtCurrentProcess(),
1307 ProtectPage2
= NULL
;
1310 RelocationDir
= LdrProcessRelocationBlock(Page
,
1314 if (RelocationDir
== NULL
)
1315 return STATUS_UNSUCCESSFUL
;
1317 /* Restore old page protection. */
1318 NtProtectVirtualMemory(NtCurrentProcess(),
1324 if (ProtectPage2
!= NULL
)
1326 NtProtectVirtualMemory(NtCurrentProcess(),
1334 return STATUS_SUCCESS
;
1338 LdrpGetOrLoadModule(PWCHAR SerachPath
,
1340 PLDR_MODULE
* Module
,
1343 UNICODE_STRING DllName
;
1346 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name
);
1348 RtlCreateUnicodeStringFromAsciiz (&DllName
, Name
);
1350 Status
= LdrFindEntryForName (&DllName
, Module
, Load
);
1351 if (Load
&& !NT_SUCCESS(Status
))
1353 Status
= LdrpLoadModule(SerachPath
,
1354 NtCurrentPeb()->Ldr
->Initialized
? 0 : LDRP_PROCESS_CREATION_TIME
,
1358 if (NT_SUCCESS(Status
))
1360 Status
= LdrFindEntryForName (&DllName
, Module
, FALSE
);
1362 if (!NT_SUCCESS(Status
))
1364 DPRINT1("failed to load %wZ\n", &DllName
);
1367 RtlFreeUnicodeString (&DllName
);
1372 LdrpProcessImportDirectoryEntry(PLDR_MODULE Module
,
1373 PLDR_MODULE ImportedModule
,
1374 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
)
1377 PVOID
* ImportAddressList
;
1378 PULONG FunctionNameList
;
1384 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->dwRVAModuleName
== 0)
1386 return STATUS_UNSUCCESSFUL
;
1389 /* Get the import address list. */
1390 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1392 /* Get the list of functions to import. */
1393 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1395 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1399 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1402 /* Get the size of IAT. */
1404 while (FunctionNameList
[IATSize
] != 0L)
1409 /* Unprotect the region we are about to write into. */
1410 IATBase
= (PVOID
)ImportAddressList
;
1411 IATSize
*= sizeof(PVOID
*);
1412 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1417 if (!NT_SUCCESS(Status
))
1419 DPRINT1("Failed to unprotect IAT.\n");
1423 /* Walk through function list and fixup addresses. */
1424 while (*FunctionNameList
!= 0L)
1426 if ((*FunctionNameList
) & 0x80000000)
1428 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1429 *ImportAddressList
= LdrGetExportByOrdinal(ImportedModule
->BaseAddress
, Ordinal
);
1430 if ((*ImportAddressList
) == NULL
)
1432 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1433 return STATUS_UNSUCCESSFUL
;
1438 IMAGE_IMPORT_BY_NAME
*pe_name
;
1439 pe_name
= RVA(Module
->BaseAddress
, *FunctionNameList
);
1440 *ImportAddressList
= LdrGetExportByName(ImportedModule
->BaseAddress
, pe_name
->Name
, pe_name
->Hint
);
1441 if ((*ImportAddressList
) == NULL
)
1443 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1444 return STATUS_UNSUCCESSFUL
;
1447 ImportAddressList
++;
1451 /* Protect the region we are about to write into. */
1452 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1457 if (!NT_SUCCESS(Status
))
1459 DPRINT1("Failed to protect IAT.\n");
1463 return STATUS_SUCCESS
;
1467 LdrpProcessImportDirectory(
1469 PLDR_MODULE ImportedModule
,
1473 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1476 DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
1477 Module
, &Module
->BaseDllName
, ImportedName
);
1480 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1481 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1483 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1485 if (ImportModuleDirectory
== NULL
)
1487 return STATUS_UNSUCCESSFUL
;
1490 while (ImportModuleDirectory
->dwRVAModuleName
)
1492 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1493 if (0 == _stricmp(Name
, ImportedName
))
1495 Status
= LdrpProcessImportDirectoryEntry(Module
,
1497 ImportModuleDirectory
);
1498 if (!NT_SUCCESS(Status
))
1503 ImportModuleDirectory
++;
1507 return STATUS_SUCCESS
;
1512 LdrpAdjustImportDirectory(PLDR_MODULE Module
,
1513 PLDR_MODULE ImportedModule
,
1516 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1518 PVOID
* ImportAddressList
;
1521 PULONG FunctionNameList
;
1526 PIMAGE_NT_HEADERS NTHeaders
;
1529 DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
1530 Module
, &Module
->BaseDllName
, ImportedModule
, &ImportedModule
->BaseDllName
, ImportedName
);
1532 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1533 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1535 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1537 if (ImportModuleDirectory
== NULL
)
1539 return STATUS_UNSUCCESSFUL
;
1542 while (ImportModuleDirectory
->dwRVAModuleName
)
1544 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1545 if (0 == _stricmp(Name
, (PCHAR
)ImportedName
))
1548 /* Get the import address list. */
1549 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1551 /* Get the list of functions to import. */
1552 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1554 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1558 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1561 /* Get the size of IAT. */
1563 while (FunctionNameList
[IATSize
] != 0L)
1568 /* Unprotect the region we are about to write into. */
1569 IATBase
= (PVOID
)ImportAddressList
;
1570 IATSize
*= sizeof(PVOID
*);
1571 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1576 if (!NT_SUCCESS(Status
))
1578 DPRINT1("Failed to unprotect IAT.\n");
1582 NTHeaders
= RtlImageNtHeader (ImportedModule
->BaseAddress
);
1583 Start
= (PVOID
)NTHeaders
->OptionalHeader
.ImageBase
;
1584 End
= Start
+ ImportedModule
->ResidentSize
;
1585 Offset
= ImportedModule
->BaseAddress
- Start
;
1587 /* Walk through function list and fixup addresses. */
1588 while (*FunctionNameList
!= 0L)
1590 if (*ImportAddressList
>= Start
&& *ImportAddressList
< End
)
1592 (*ImportAddressList
) += Offset
;
1594 ImportAddressList
++;
1598 /* Protect the region we are about to write into. */
1599 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1604 if (!NT_SUCCESS(Status
))
1606 DPRINT1("Failed to protect IAT.\n");
1610 ImportModuleDirectory
++;
1612 return STATUS_SUCCESS
;
1616 /**********************************************************************
1621 * Compute the entry point for every symbol the DLL imports
1622 * from other modules.
1634 LdrFixupImports(IN PWSTR SearchPath OPTIONAL
,
1635 IN PLDR_MODULE Module
)
1637 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1638 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectoryCurrent
;
1639 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
1640 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
1641 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1644 PLDR_MODULE ImportedModule
;
1647 DPRINT("LdrFixupImports(SearchPath %x, Module %x)\n", SearchPath
, Module
);
1649 /* Check for tls data */
1650 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
1651 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1653 IMAGE_DIRECTORY_ENTRY_TLS
,
1657 TlsSize
= TlsDirectory
->EndAddressOfRawData
1658 - TlsDirectory
->StartAddressOfRawData
1659 + TlsDirectory
->SizeOfZeroFill
;
1661 NtCurrentPeb()->Ldr
->Initialized
)
1663 TRACE_LDR("Trying to load dynamicly %wZ which contains a tls directory\n",
1664 &Module
->BaseDllName
);
1665 return STATUS_UNSUCCESSFUL
;
1669 * Process each import module.
1671 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1672 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1674 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1677 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
1678 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1680 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
1683 if (BoundImportDescriptor
!= NULL
&& ImportModuleDirectory
== NULL
)
1685 DPRINT1("%wZ has only a bound import directory\n", &Module
->BaseDllName
);
1686 return STATUS_UNSUCCESSFUL
;
1688 if (BoundImportDescriptor
)
1690 DPRINT("BoundImportDescriptor %x\n", BoundImportDescriptor
);
1692 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
1693 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
1695 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
1696 TRACE_LDR("%wZ bound to %s\n", &Module
->BaseDllName
, ImportedName
);
1697 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1698 if (!NT_SUCCESS(Status
))
1700 DPRINT1("failed to load %s\n", ImportedName
);
1703 if (Module
== ImportedModule
)
1705 LdrpDecrementLoadCount(Module
, FALSE
);
1707 if (ImportedModule
->TimeDateStamp
!= BoundImportDescriptorCurrent
->TimeDateStamp
)
1709 TRACE_LDR("%wZ has stale binding to %wZ\n",
1710 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1711 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1712 if (!NT_SUCCESS(Status
))
1714 DPRINT1("failed to import %s\n", ImportedName
);
1720 BOOLEAN WrongForwarder
;
1721 WrongForwarder
= FALSE
;
1722 if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1724 TRACE_LDR("%wZ has stale binding to %s\n",
1725 &Module
->BaseDllName
, ImportedName
);
1729 TRACE_LDR("%wZ has correct binding to %wZ\n",
1730 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1732 if (BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
)
1734 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef
;
1736 PLDR_MODULE ForwarderModule
;
1737 PCHAR ForwarderName
;
1739 BoundForwarderRef
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundImportDescriptorCurrent
+ 1);
1740 for (i
= 0; i
< BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
; i
++, BoundForwarderRef
++)
1742 ForwarderName
= (PCHAR
)BoundImportDescriptor
+ BoundForwarderRef
->OffsetModuleName
;
1743 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1744 &Module
->BaseDllName
, ForwarderName
, ImportedName
);
1745 Status
= LdrpGetOrLoadModule(SearchPath
, ForwarderName
, &ForwarderModule
, TRUE
);
1746 if (!NT_SUCCESS(Status
))
1748 DPRINT1("failed to load %s\n", ForwarderName
);
1751 if (Module
== ImportedModule
)
1753 LdrpDecrementLoadCount(Module
, FALSE
);
1755 if (ForwarderModule
->TimeDateStamp
!= BoundForwarderRef
->TimeDateStamp
||
1756 ForwarderModule
->Flags
& IMAGE_NOT_AT_BASE
)
1758 TRACE_LDR("%wZ has stale binding to %s\n",
1759 &Module
->BaseDllName
, ForwarderName
);
1760 WrongForwarder
= TRUE
;
1764 TRACE_LDR("%wZ has correct binding to %s\n",
1765 &Module
->BaseDllName
, ForwarderName
);
1769 if (WrongForwarder
||
1770 ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1772 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1773 if (!NT_SUCCESS(Status
))
1775 DPRINT1("failed to import %s\n", ImportedName
);
1779 else if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1781 TRACE_LDR("Adjust imports for %s from %wZ\n",
1782 ImportedName
, &Module
->BaseDllName
);
1783 Status
= LdrpAdjustImportDirectory(Module
, ImportedModule
, ImportedName
);
1784 if (!NT_SUCCESS(Status
))
1786 DPRINT1("failed to adjust import entries for %s\n", ImportedName
);
1790 else if (WrongForwarder
)
1794 * Update only forwarders
1796 TRACE_LDR("Stale BIND %s from %wZ\n",
1797 ImportedName
, &Module
->BaseDllName
);
1798 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1799 if (!NT_SUCCESS(Status
))
1801 DPRINT1("faild to import %s\n", ImportedName
);
1810 BoundImportDescriptorCurrent
+= BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
+ 1;
1813 else if (ImportModuleDirectory
)
1815 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1817 ImportModuleDirectoryCurrent
= ImportModuleDirectory
;
1818 while (ImportModuleDirectoryCurrent
->dwRVAModuleName
)
1820 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectoryCurrent
->dwRVAModuleName
;
1821 TRACE_LDR("%wZ imports functions from %s\n", &Module
->BaseDllName
, ImportedName
);
1823 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1824 if (!NT_SUCCESS(Status
))
1826 DPRINT1("failed to load %s\n", ImportedName
);
1829 if (Module
== ImportedModule
)
1831 LdrpDecrementLoadCount(Module
, FALSE
);
1834 TRACE_LDR("Initializing imports for %wZ from %s\n",
1835 &Module
->BaseDllName
, ImportedName
);
1836 Status
= LdrpProcessImportDirectoryEntry(Module
, ImportedModule
, ImportModuleDirectoryCurrent
);
1837 if (!NT_SUCCESS(Status
))
1839 DPRINT1("failed to import %s\n", ImportedName
);
1842 ImportModuleDirectoryCurrent
++;
1846 if (TlsDirectory
&& TlsSize
> 0)
1848 LdrpAcquireTlsSlot(Module
, TlsSize
, FALSE
);
1851 return STATUS_SUCCESS
;
1855 /**********************************************************************
1860 * 1. Relocate, if needed the EXE.
1861 * 2. Fixup any imported symbol.
1862 * 3. Compute the EXE's entry point.
1866 * Address at which the EXE's image
1870 * Handle of the section that contains
1874 * NULL on error; otherwise the entry point
1875 * to call for initializing the DLL.
1880 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
1881 * Currently the function is only used for the exe.
1883 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1884 HANDLE SectionHandle
,
1885 PLDR_MODULE
* Module
,
1889 PEPFUNC EntryPoint
= NULL
;
1890 PIMAGE_DOS_HEADER DosHeader
;
1891 PIMAGE_NT_HEADERS NTHeaders
;
1892 PLDR_MODULE tmpModule
;
1894 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1895 ImageBase
, (ULONG
)SectionHandle
);
1898 * Overlay DOS and WNT headers structures
1899 * to the DLL's image.
1901 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1902 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1905 * If the base address is different from the
1906 * one the DLL is actually loaded, perform any
1909 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1911 DPRINT("LDR: Performing relocations\n");
1912 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1913 if (!NT_SUCCESS(Status
))
1915 DPRINT1("LdrPerformRelocations() failed\n");
1922 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1923 (*Module
)->SectionHandle
= SectionHandle
;
1927 Module
= &tmpModule
;
1928 Status
= LdrFindEntryForAddress(ImageBase
, Module
);
1929 if (!NT_SUCCESS(Status
))
1935 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1937 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
1941 * If the DLL's imports symbols from other
1942 * modules, fixup the imported calls entry points.
1944 DPRINT("About to fixup imports\n");
1945 Status
= LdrFixupImports(NULL
, *Module
);
1946 if (!NT_SUCCESS(Status
))
1948 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module
)->BaseDllName
);
1951 DPRINT("Fixup done\n");
1952 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
1953 Status
= LdrpInitializeTlsForProccess();
1954 if (NT_SUCCESS(Status
))
1956 Status
= LdrpAttachProcess();
1958 if (NT_SUCCESS(Status
))
1960 LdrpTlsCallback(*Module
, DLL_PROCESS_ATTACH
);
1964 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1965 if (!NT_SUCCESS(Status
))
1972 * Compute the DLL's entry point's address.
1974 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1975 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1976 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1978 EntryPoint
= (PEPFUNC
) (ImageBase
1979 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1981 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1986 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
1988 IN PUNICODE_STRING Name
,
1989 PLDR_MODULE
*Module
,
1990 PVOID
*BaseAddress OPTIONAL
)
1992 UNICODE_STRING AdjustedName
;
1993 UNICODE_STRING FullDosName
;
1995 PLDR_MODULE tmpModule
;
1996 HANDLE SectionHandle
;
1999 PIMAGE_NT_HEADERS NtHeaders
;
2000 BOOLEAN MappedAsDataFile
;
2004 Module
= &tmpModule
;
2006 /* adjust the full dll name */
2007 LdrAdjustDllName(&AdjustedName
, Name
, FALSE
);
2009 DPRINT("%wZ\n", &AdjustedName
);
2011 MappedAsDataFile
= FALSE
;
2012 /* Test if dll is already loaded */
2013 Status
= LdrFindEntryForName(&AdjustedName
, Module
, TRUE
);
2014 if (NT_SUCCESS(Status
))
2016 RtlFreeUnicodeString(&AdjustedName
);
2017 if (NULL
!= BaseAddress
)
2019 *BaseAddress
= (*Module
)->BaseAddress
;
2024 /* Open or create dll image section */
2025 Status
= LdrpMapKnownDll(&AdjustedName
, &FullDosName
, &SectionHandle
);
2026 if (!NT_SUCCESS(Status
))
2028 MappedAsDataFile
= (0 != (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
));
2029 Status
= LdrpMapDllImageFile(SearchPath
, &AdjustedName
, &FullDosName
,
2030 MappedAsDataFile
, &SectionHandle
);
2032 if (!NT_SUCCESS(Status
))
2034 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName
, Status
);
2035 RtlFreeUnicodeString(&AdjustedName
);
2038 RtlFreeUnicodeString(&AdjustedName
);
2039 /* Map the dll into the process */
2042 Status
= NtMapViewOfSection(SectionHandle
,
2052 if (!NT_SUCCESS(Status
))
2054 DPRINT1("map view of section failed (Status %x)\n", Status
);
2055 RtlFreeUnicodeString(&FullDosName
);
2056 NtClose(SectionHandle
);
2059 if (NULL
!= BaseAddress
)
2061 *BaseAddress
= ImageBase
;
2063 /* Get and check the NT headers */
2064 NtHeaders
= RtlImageNtHeader(ImageBase
);
2065 if (NtHeaders
== NULL
)
2067 DPRINT1("RtlImageNtHeaders() failed\n");
2068 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2069 NtClose (SectionHandle
);
2070 RtlFreeUnicodeString(&FullDosName
);
2071 return STATUS_UNSUCCESSFUL
;
2073 DPRINT("Mapped %wZ at %x\n", &FullDosName
, ImageBase
);
2074 if (MappedAsDataFile
)
2076 assert(NULL
!= BaseAddress
);
2077 if (NULL
!= BaseAddress
)
2079 *BaseAddress
= (PVOID
) ((char *) *BaseAddress
+ 1);
2082 RtlFreeUnicodeString(&FullDosName
);
2083 NtClose(SectionHandle
);
2084 return STATUS_SUCCESS
;
2086 /* If the base address is different from the
2087 * one the DLL is actually loaded, perform any
2089 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2091 DPRINT1("Relocating (%x -> %x) %wZ\n",
2092 NtHeaders
->OptionalHeader
.ImageBase
, ImageBase
, &FullDosName
);
2093 Status
= LdrPerformRelocations(NtHeaders
, ImageBase
);
2094 if (!NT_SUCCESS(Status
))
2096 DPRINT1("LdrPerformRelocations() failed\n");
2097 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2098 NtClose (SectionHandle
);
2099 RtlFreeUnicodeString(&FullDosName
);
2100 return STATUS_UNSUCCESSFUL
;
2103 *Module
= LdrAddModuleEntry(ImageBase
, NtHeaders
, FullDosName
.Buffer
);
2104 (*Module
)->SectionHandle
= SectionHandle
;
2105 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2107 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
2109 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
2111 (*Module
)->Flags
|= IMAGE_DLL
;
2113 /* fixup the imported calls entry points */
2114 Status
= LdrFixupImports(SearchPath
, *Module
);
2115 if (!NT_SUCCESS(Status
))
2117 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module
)->BaseDllName
, Status
);
2120 #if defined(DBG) || defined(KDBG)
2121 LdrpLoadUserModuleSymbols(*Module
);
2122 #endif /* DBG || KDBG */
2123 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2124 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
2125 &(*Module
)->InInitializationOrderModuleList
);
2126 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2128 return STATUS_SUCCESS
;
2132 LdrpUnloadModule(PLDR_MODULE Module
,
2135 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
2136 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
2137 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
2139 PLDR_MODULE ImportedModule
;
2146 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2149 LoadCount
= LdrpDecrementLoadCount(Module
, Unload
);
2151 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module
->BaseDllName
, LoadCount
);
2155 /* ?????????????????? */
2158 else if (LoadCount
== 1)
2160 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
2161 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2163 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
2165 if (BoundImportDescriptor
)
2167 /* dereferencing all imported modules, use the bound import descriptor */
2168 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
2169 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
2171 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
2172 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2173 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2174 if (!NT_SUCCESS(Status
))
2176 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2180 if (Module
!= ImportedModule
)
2182 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2183 if (!NT_SUCCESS(Status
))
2185 DPRINT1("unable to unload %s\n", ImportedName
);
2189 BoundImportDescriptorCurrent
++;
2194 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
2195 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2197 IMAGE_DIRECTORY_ENTRY_IMPORT
,
2199 if (ImportModuleDirectory
)
2201 /* dereferencing all imported modules, use the import descriptor */
2202 while (ImportModuleDirectory
->dwRVAModuleName
)
2204 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
2205 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2206 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2207 if (!NT_SUCCESS(Status
))
2209 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2213 if (Module
!= ImportedModule
)
2215 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2216 if (!NT_SUCCESS(Status
))
2218 DPRINT1("unable to unload %s\n", ImportedName
);
2222 ImportModuleDirectory
++;
2230 LdrpDetachProcess(FALSE
);
2231 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2233 return STATUS_SUCCESS
;
2241 LdrUnloadDll (IN PVOID BaseAddress
)
2246 if (BaseAddress
== NULL
)
2247 return STATUS_SUCCESS
;
2249 if (LdrMappedAsDataFile(&BaseAddress
))
2251 Status
= NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
2255 Status
= LdrFindEntryForAddress(BaseAddress
, &Module
);
2256 if (NT_SUCCESS(Status
))
2258 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module
->BaseDllName
);
2259 Status
= LdrpUnloadModule(Module
, TRUE
);
2270 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
2272 PLIST_ENTRY ModuleListHead
;
2277 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
2279 Status
= STATUS_DLL_NOT_FOUND
;
2280 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2281 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2282 Entry
= ModuleListHead
->Flink
;
2283 while (Entry
!= ModuleListHead
)
2285 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2287 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
2289 if (Module
->BaseAddress
== BaseAddress
)
2291 if (Module
->TlsIndex
== -1)
2293 Module
->Flags
|= DONT_CALL_FOR_THREAD
;
2294 Status
= STATUS_SUCCESS
;
2298 Entry
= Entry
->Flink
;
2300 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2308 LdrGetDllHandle(IN PWCHAR Path OPTIONAL
,
2310 IN PUNICODE_STRING DllName
,
2311 OUT PVOID
* BaseAddress
)
2316 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName
, Path
? Path
: L
"");
2318 /* NULL is the current executable */
2319 if (DllName
== NULL
)
2321 *BaseAddress
= ExeModule
->BaseAddress
;
2322 DPRINT("BaseAddress %x\n", *BaseAddress
);
2323 return STATUS_SUCCESS
;
2326 Status
= LdrFindEntryForName(DllName
, &Module
, FALSE
);
2327 if (NT_SUCCESS(Status
))
2329 *BaseAddress
= Module
->BaseAddress
;
2330 return STATUS_SUCCESS
;
2333 DPRINT("Failed to find dll %wZ\n", DllName
);
2334 *BaseAddress
= NULL
;
2335 return STATUS_DLL_NOT_FOUND
;
2343 LdrGetProcedureAddress (IN PVOID BaseAddress
,
2344 IN PANSI_STRING Name
,
2346 OUT PVOID
*ProcedureAddress
)
2348 if (Name
&& Name
->Length
)
2350 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name
);
2354 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal
);
2357 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
2358 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
2360 if (Name
&& Name
->Length
)
2363 *ProcedureAddress
= LdrGetExportByName(BaseAddress
, (PUCHAR
)Name
->Buffer
, 0xffff);
2364 if (*ProcedureAddress
!= NULL
)
2366 return STATUS_SUCCESS
;
2368 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
2373 Ordinal
&= 0x0000FFFF;
2374 *ProcedureAddress
= LdrGetExportByOrdinal(BaseAddress
, (WORD
)Ordinal
);
2375 if (*ProcedureAddress
)
2377 return STATUS_SUCCESS
;
2379 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
2381 return STATUS_PROCEDURE_NOT_FOUND
;
2384 /**********************************************************************
2389 * Unload dll's which are no longer referenced from others dll's
2400 * The loader lock must be held on enty.
2403 LdrpDetachProcess(BOOLEAN UnloadAll
)
2405 PLIST_ENTRY ModuleListHead
;
2408 static ULONG CallingCount
= 0;
2410 DPRINT("LdrpDetachProcess() called for %wZ\n",
2411 &ExeModule
->BaseDllName
);
2415 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2416 Entry
= ModuleListHead
->Blink
;
2417 while (Entry
!= ModuleListHead
)
2419 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2420 if (((UnloadAll
&& Module
->LoadCount
<= 0) || Module
->LoadCount
== 0) &&
2421 Module
->Flags
& ENTRY_PROCESSED
&&
2422 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2424 Module
->Flags
|= UNLOAD_IN_PROGRESS
;
2425 if (Module
== LdrpLastModule
)
2427 LdrpLastModule
= NULL
;
2429 if (Module
->Flags
& PROCESS_ATTACH_CALLED
)
2431 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2432 &Module
->BaseDllName
, Module
->EntryPoint
);
2433 LdrpCallDllEntry(Module
, DLL_PROCESS_DETACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2437 TRACE_LDR("Unload %wZ\n", &Module
->BaseDllName
);
2439 Entry
= ModuleListHead
->Blink
;
2443 Entry
= Entry
->Blink
;
2447 if (CallingCount
== 1)
2449 Entry
= ModuleListHead
->Blink
;
2450 while (Entry
!= ModuleListHead
)
2452 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2453 Entry
= Entry
->Blink
;
2454 if (Module
->Flags
& UNLOAD_IN_PROGRESS
&&
2455 ((UnloadAll
&& Module
->LoadCount
>= 0) || Module
->LoadCount
== 0))
2457 /* remove the module entry from the list */
2458 RemoveEntryList (&Module
->InLoadOrderModuleList
);
2459 RemoveEntryList (&Module
->InInitializationOrderModuleList
);
2461 NtUnmapViewOfSection (NtCurrentProcess (), Module
->BaseAddress
);
2462 NtClose (Module
->SectionHandle
);
2464 TRACE_LDR("%wZ unloaded\n", &Module
->BaseDllName
);
2466 RtlFreeUnicodeString (&Module
->FullDllName
);
2467 RtlFreeUnicodeString (&Module
->BaseDllName
);
2469 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
2474 DPRINT("LdrpDetachProcess() done\n");
2477 /**********************************************************************
2482 * Initialize all dll's which are prepered for loading
2493 * The loader lock must be held on entry.
2497 LdrpAttachProcess(VOID
)
2499 PLIST_ENTRY ModuleListHead
;
2503 NTSTATUS Status
= STATUS_SUCCESS
;
2505 DPRINT("LdrpAttachProcess() called for %wZ\n",
2506 &ExeModule
->BaseDllName
);
2508 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2509 Entry
= ModuleListHead
->Flink
;
2510 while (Entry
!= ModuleListHead
)
2512 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2513 if (!(Module
->Flags
& (LOAD_IN_PROGRESS
|UNLOAD_IN_PROGRESS
|ENTRY_PROCESSED
)))
2515 Module
->Flags
|= LOAD_IN_PROGRESS
;
2516 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2517 &Module
->BaseDllName
, Module
->EntryPoint
);
2518 Result
= LdrpCallDllEntry(Module
, DLL_PROCESS_ATTACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2521 Status
= STATUS_DLL_INIT_FAILED
;
2524 if (Module
->Flags
& IMAGE_DLL
&& Module
->EntryPoint
!= 0)
2526 Module
->Flags
|= PROCESS_ATTACH_CALLED
|ENTRY_PROCESSED
;
2530 Module
->Flags
|= ENTRY_PROCESSED
;
2532 Module
->Flags
&= ~LOAD_IN_PROGRESS
;
2534 Entry
= Entry
->Flink
;
2537 DPRINT("LdrpAttachProcess() done\n");
2546 LdrShutdownProcess (VOID
)
2548 LdrpDetachProcess(TRUE
);
2549 return STATUS_SUCCESS
;
2557 LdrpAttachThread (VOID
)
2559 PLIST_ENTRY ModuleListHead
;
2564 DPRINT("LdrpAttachThread() called for %wZ\n",
2565 &ExeModule
->BaseDllName
);
2567 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2569 Status
= LdrpInitializeTlsForThread();
2571 if (NT_SUCCESS(Status
))
2573 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2574 Entry
= ModuleListHead
->Flink
;
2576 while (Entry
!= ModuleListHead
)
2578 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2579 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2580 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2581 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2583 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2584 &Module
->BaseDllName
, Module
->EntryPoint
);
2585 LdrpCallDllEntry(Module
, DLL_THREAD_ATTACH
, NULL
);
2587 Entry
= Entry
->Flink
;
2590 Entry
= NtCurrentPeb()->Ldr
->InLoadOrderModuleList
.Flink
;
2591 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2592 LdrpTlsCallback(Module
, DLL_THREAD_ATTACH
);
2595 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2597 DPRINT("LdrpAttachThread() done\n");
2607 LdrShutdownThread (VOID
)
2609 PLIST_ENTRY ModuleListHead
;
2613 DPRINT("LdrShutdownThread() called for %wZ\n",
2614 &ExeModule
->BaseDllName
);
2616 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2618 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2619 Entry
= ModuleListHead
->Blink
;
2620 while (Entry
!= ModuleListHead
)
2622 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2624 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2625 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2626 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2628 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2629 &Module
->BaseDllName
, Module
->EntryPoint
);
2630 LdrpCallDllEntry(Module
, DLL_THREAD_DETACH
, NULL
);
2632 Entry
= Entry
->Blink
;
2635 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2639 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer
);
2642 DPRINT("LdrShutdownThread() done\n");
2644 return STATUS_SUCCESS
;
2648 /***************************************************************************
2650 * LdrQueryProcessModuleInformation
2665 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
2666 IN ULONG Size OPTIONAL
,
2667 OUT PULONG ReturnedSize
)
2669 PLIST_ENTRY ModuleListHead
;
2672 PDEBUG_MODULE_INFORMATION ModulePtr
= NULL
;
2673 NTSTATUS Status
= STATUS_SUCCESS
;
2674 ULONG UsedSize
= sizeof(ULONG
);
2675 ANSI_STRING AnsiString
;
2678 DPRINT("LdrQueryProcessModuleInformation() called\n");
2680 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2682 if (ModuleInformation
== NULL
|| Size
== 0)
2684 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2688 ModuleInformation
->ModuleCount
= 0;
2689 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
2690 Status
= STATUS_SUCCESS
;
2693 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2694 Entry
= ModuleListHead
->Flink
;
2696 while (Entry
!= ModuleListHead
)
2698 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2700 DPRINT(" Module %wZ\n",
2701 &Module
->FullDllName
);
2703 if (UsedSize
> Size
)
2705 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2707 else if (ModuleInformation
!= NULL
)
2709 ModulePtr
->Reserved
[0] = ModulePtr
->Reserved
[1] = 0; // FIXME: ??
2710 ModulePtr
->Base
= Module
->BaseAddress
;
2711 ModulePtr
->Size
= Module
->ResidentSize
;
2712 ModulePtr
->Flags
= Module
->Flags
;
2713 ModulePtr
->Index
= 0; // FIXME: index ??
2714 ModulePtr
->Unknown
= 0; // FIXME: ??
2715 ModulePtr
->LoadCount
= Module
->LoadCount
;
2717 AnsiString
.Length
= 0;
2718 AnsiString
.MaximumLength
= 256;
2719 AnsiString
.Buffer
= ModulePtr
->ImageName
;
2720 RtlUnicodeStringToAnsiString(&AnsiString
,
2721 &Module
->FullDllName
,
2723 p
= strrchr(ModulePtr
->ImageName
, '\\');
2725 ModulePtr
->ModuleNameOffset
= p
- ModulePtr
->ImageName
+ 1;
2727 ModulePtr
->ModuleNameOffset
= 0;
2730 ModuleInformation
->ModuleCount
++;
2732 UsedSize
+= sizeof(DEBUG_MODULE_INFORMATION
);
2734 Entry
= Entry
->Flink
;
2737 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2739 if (ReturnedSize
!= 0)
2740 *ReturnedSize
= UsedSize
;
2742 DPRINT("LdrQueryProcessModuleInformation() done\n");
2749 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
2752 PIMAGE_NT_HEADERS Header
;
2759 Header
= RtlImageNtHeader (BaseAddress
);
2763 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
2768 Ptr
= (PUSHORT
) BaseAddress
;
2769 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
2772 if (HIWORD(Sum
) != 0)
2774 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2781 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
2782 if (HIWORD(Sum
) != 0)
2784 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2788 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
2790 /* Subtract image checksum from calculated checksum. */
2791 /* fix low word of checksum */
2792 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
2794 CalcSum
-= LOWORD(HeaderSum
);
2798 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
2801 /* fix high word of checksum */
2802 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
2804 CalcSum
-= HIWORD(HeaderSum
);
2808 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
2811 /* add file length */
2812 CalcSum
+= ImageSize
;
2814 return (BOOLEAN
)(CalcSum
== HeaderSum
);
2818 * Compute size of an image as it is actually present in virt memory
2819 * (i.e. excluding NEVER_LOAD sections)
2822 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders
)
2824 PIMAGE_SECTION_HEADER SectionHeader
;
2825 unsigned SectionIndex
;
2828 SectionHeader
= (PIMAGE_SECTION_HEADER
)((char *) &NTHeaders
->OptionalHeader
2829 + NTHeaders
->FileHeader
.SizeOfOptionalHeader
);
2831 for (SectionIndex
= 0; SectionIndex
< NTHeaders
->FileHeader
.NumberOfSections
; SectionIndex
++)
2833 if (0 == (SectionHeader
->Characteristics
& IMAGE_SCN_LNK_REMOVE
)
2834 && ResidentSize
< SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
)
2836 ResidentSize
= SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
;
2841 return ResidentSize
;
2845 /***************************************************************************
2847 * LdrVerifyImageMatchesChecksum
2862 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
2867 FILE_STANDARD_INFORMATION FileInfo
;
2868 IO_STATUS_BLOCK IoStatusBlock
;
2869 HANDLE SectionHandle
;
2875 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2877 Status
= NtCreateSection (&SectionHandle
,
2878 SECTION_MAP_EXECUTE
,
2884 if (!NT_SUCCESS(Status
))
2886 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
2892 Status
= NtMapViewOfSection (SectionHandle
,
2893 NtCurrentProcess (),
2902 if (!NT_SUCCESS(Status
))
2904 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2905 NtClose (SectionHandle
);
2909 Status
= NtQueryInformationFile (FileHandle
,
2912 sizeof (FILE_STANDARD_INFORMATION
),
2913 FileStandardInformation
);
2914 if (!NT_SUCCESS(Status
))
2916 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2917 NtUnmapViewOfSection (NtCurrentProcess (),
2919 NtClose (SectionHandle
);
2923 Result
= LdrpCheckImageChecksum (BaseAddress
,
2924 FileInfo
.EndOfFile
.u
.LowPart
);
2925 if (Result
== FALSE
)
2927 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2930 NtUnmapViewOfSection (NtCurrentProcess (),
2933 NtClose (SectionHandle
);
2939 /***************************************************************************
2941 * LdrQueryImageFileExecutionOptions
2956 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
2957 IN PCWSTR ValueName
,
2960 IN ULONG BufferSize
,
2961 OUT PULONG ReturnedLength OPTIONAL
)
2963 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2964 OBJECT_ATTRIBUTES ObjectAttributes
;
2965 UNICODE_STRING ValueNameString
;
2966 UNICODE_STRING KeyName
;
2967 WCHAR NameBuffer
[256];
2975 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2976 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
2979 Ptr
= SubKey
->Buffer
;
2985 wcscat (NameBuffer
, Ptr
);
2986 RtlInitUnicodeString (&KeyName
,
2989 InitializeObjectAttributes (&ObjectAttributes
,
2991 OBJ_CASE_INSENSITIVE
,
2995 Status
= NtOpenKey (&KeyHandle
,
2998 if (!NT_SUCCESS(Status
))
3000 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
3004 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
3005 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3009 RtlInitUnicodeString (&ValueNameString
,
3011 Status
= NtQueryValueKey (KeyHandle
,
3013 KeyValuePartialInformation
,
3017 if (Status
== STATUS_BUFFER_OVERFLOW
)
3019 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
3020 RtlFreeHeap (RtlGetProcessHeap(),
3023 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3026 if (KeyInfo
== NULL
)
3028 NtClose (KeyHandle
);
3032 Status
= NtQueryValueKey (KeyHandle
,
3034 KeyValuePartialInformation
,
3039 NtClose (KeyHandle
);
3041 if (!NT_SUCCESS(Status
))
3043 if (KeyInfo
!= NULL
)
3045 RtlFreeHeap (RtlGetProcessHeap(),
3052 if (KeyInfo
->Type
!= Type
)
3054 RtlFreeHeap (RtlGetProcessHeap(),
3057 return STATUS_OBJECT_TYPE_MISMATCH
;
3060 ResultSize
= BufferSize
;
3061 if (ResultSize
< KeyInfo
->DataLength
)
3063 Status
= STATUS_BUFFER_OVERFLOW
;
3067 ResultSize
= KeyInfo
->DataLength
;
3069 RtlCopyMemory (Buffer
,
3073 RtlFreeHeap (RtlGetProcessHeap(),
3077 if (ReturnedLength
!= NULL
)
3079 *ReturnedLength
= ResultSize
;
3086 PIMAGE_BASE_RELOCATION STDCALL
3087 LdrProcessRelocationBlock(IN PVOID Address
,
3089 IN PUSHORT TypeOffset
,
3098 for (i
= 0; i
< Count
; i
++)
3100 Offset
= *TypeOffset
& 0xFFF;
3101 Type
= *TypeOffset
>> 12;
3105 case IMAGE_REL_BASED_ABSOLUTE
:
3108 case IMAGE_REL_BASED_HIGH
:
3109 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3110 *ShortPtr
+= HIWORD(Delta
);
3113 case IMAGE_REL_BASED_LOW
:
3114 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3115 *ShortPtr
+= LOWORD(Delta
);
3118 case IMAGE_REL_BASED_HIGHLOW
:
3119 LongPtr
= (PULONG
)(Address
+ Offset
);
3123 case IMAGE_REL_BASED_HIGHADJ
:
3124 case IMAGE_REL_BASED_MIPS_JMPADDR
:
3126 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type
);
3133 return (PIMAGE_BASE_RELOCATION
)TypeOffset
;