1 /* $Id: utils.c,v 1.103 2004/12/20 02:31:48 navaraf Exp $
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 ULONG NtGlobalFlag
;
55 extern PLDR_MODULE ExeModule
;
57 /* PROTOTYPES ****************************************************************/
59 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_MODULE
*Module
, BOOL Ref
);
60 static PVOID
LdrFixupForward(PCHAR ForwardName
);
61 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
62 static NTSTATUS
LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
64 IN PUNICODE_STRING Name
,
65 OUT PLDR_MODULE
*Module
);
66 static NTSTATUS
LdrpAttachProcess(VOID
);
67 static VOID
LdrpDetachProcess(BOOL UnloadAll
);
69 /* FUNCTIONS *****************************************************************/
71 #if defined(DBG) || defined(KDBG)
74 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
85 #endif /* DBG || KDBG */
87 static inline LONG
LdrpDecrementLoadCount(PLDR_MODULE Module
, BOOL Locked
)
92 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
94 LoadCount
= Module
->LoadCount
;
95 if (Module
->LoadCount
> 0)
101 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
106 static inline LONG
LdrpIncrementLoadCount(PLDR_MODULE Module
, BOOL Locked
)
111 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
113 LoadCount
= Module
->LoadCount
;
114 if (Module
->LoadCount
>= 0)
120 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
125 static inline VOID
LdrpAcquireTlsSlot(PLDR_MODULE Module
, ULONG Size
, BOOL Locked
)
129 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
131 Module
->TlsIndex
= (SHORT
)LdrpTlsCount
;
136 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
140 static inline VOID
LdrpTlsCallback(PLDR_MODULE Module
, ULONG dwReason
)
142 PIMAGE_TLS_CALLBACK TlsCallback
;
143 if (Module
->TlsIndex
>= 0 && Module
->LoadCount
== -1)
145 TlsCallback
= LdrpTlsArray
[Module
->TlsIndex
].TlsAddressOfCallBacks
;
150 TRACE_LDR("%wZ - Calling tls callback at %x\n",
151 &Module
->BaseDllName
, TlsCallback
);
152 TlsCallback(Module
->BaseAddress
, dwReason
, NULL
);
159 static BOOL
LdrpCallDllEntry(PLDR_MODULE Module
, DWORD dwReason
, PVOID lpReserved
)
161 if (!(Module
->Flags
& IMAGE_DLL
) ||
162 Module
->EntryPoint
== 0)
166 LdrpTlsCallback(Module
, dwReason
);
167 return ((PDLLMAIN_FUNC
)Module
->EntryPoint
)(Module
->BaseAddress
, dwReason
, lpReserved
);
171 LdrpInitializeTlsForThread(VOID
)
178 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule
->BaseDllName
);
180 if (LdrpTlsCount
> 0)
182 TlsPointers
= RtlAllocateHeap(RtlGetProcessHeap(),
184 LdrpTlsCount
* sizeof(PVOID
) + LdrpTlsSize
);
185 if (TlsPointers
== NULL
)
187 DPRINT1("failed to allocate thread tls data\n");
188 return STATUS_NO_MEMORY
;
191 TlsData
= (PVOID
)TlsPointers
+ LdrpTlsCount
* sizeof(PVOID
);
192 NtCurrentTeb()->ThreadLocalStoragePointer
= TlsPointers
;
194 TlsInfo
= LdrpTlsArray
;
195 for (i
= 0; i
< LdrpTlsCount
; i
++, TlsInfo
++)
197 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo
->Module
->BaseDllName
);
198 TlsPointers
[i
] = TlsData
;
199 if (TlsInfo
->TlsDataSize
)
201 memcpy(TlsData
, TlsInfo
->StartAddressOfRawData
, TlsInfo
->TlsDataSize
);
202 TlsData
+= TlsInfo
->TlsDataSize
;
204 if (TlsInfo
->TlsZeroSize
)
206 memset(TlsData
, 0, TlsInfo
->TlsZeroSize
);
207 TlsData
+= TlsInfo
->TlsZeroSize
;
211 DPRINT("LdrpInitializeTlsForThread() done\n");
212 return STATUS_SUCCESS
;
216 LdrpInitializeTlsForProccess(VOID
)
218 PLIST_ENTRY ModuleListHead
;
221 PIMAGE_TLS_DIRECTORY TlsDirectory
;
224 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule
->BaseDllName
);
226 if (LdrpTlsCount
> 0)
228 LdrpTlsArray
= RtlAllocateHeap(RtlGetProcessHeap(),
230 LdrpTlsCount
* sizeof(TLS_DATA
));
231 if (LdrpTlsArray
== NULL
)
233 DPRINT1("Failed to allocate global tls data\n");
234 return STATUS_NO_MEMORY
;
237 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
238 Entry
= ModuleListHead
->Flink
;
239 while (Entry
!= ModuleListHead
)
241 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
242 if (Module
->LoadCount
== -1 &&
243 Module
->TlsIndex
>= 0)
245 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
246 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
248 IMAGE_DIRECTORY_ENTRY_TLS
,
250 assert(Module
->TlsIndex
< LdrpTlsCount
);
251 TlsData
= &LdrpTlsArray
[Module
->TlsIndex
];
252 TlsData
->StartAddressOfRawData
= (PVOID
)TlsDirectory
->StartAddressOfRawData
;
253 TlsData
->TlsDataSize
= TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
;
254 TlsData
->TlsZeroSize
= TlsDirectory
->SizeOfZeroFill
;
255 if (TlsDirectory
->AddressOfCallBacks
)
256 TlsData
->TlsAddressOfCallBacks
= *TlsDirectory
->AddressOfCallBacks
;
258 TlsData
->TlsAddressOfCallBacks
= NULL
;
259 TlsData
->Module
= Module
;
261 DbgPrint("TLS directory for %wZ\n", &Module
->BaseDllName
);
262 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory
->StartAddressOfRawData
);
263 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory
->EndAddressOfRawData
);
264 DbgPrint("SizeOfRawData: %d\n", TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
);
265 DbgPrint("AddressOfIndex: %x\n", TlsDirectory
->AddressOfIndex
);
266 DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory
->AddressOfCallBacks
, *TlsDirectory
->AddressOfCallBacks
);
267 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory
->SizeOfZeroFill
);
268 DbgPrint("Characteristics: %x\n", TlsDirectory
->Characteristics
);
272 * Is this region allways writable ?
274 *(PULONG
)TlsDirectory
->AddressOfIndex
= Module
->TlsIndex
;
277 Entry
= Entry
->Flink
;
280 DPRINT("LdrpInitializeTlsForProccess() done\n");
281 return STATUS_SUCCESS
;
287 OBJECT_ATTRIBUTES ObjectAttributes
;
288 UNICODE_STRING LinkTarget
;
294 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule
->BaseDllName
);
296 /* Get handle to the 'KnownDlls' directory */
297 RtlInitUnicodeString(&Name
,
299 InitializeObjectAttributes(&ObjectAttributes
,
301 OBJ_CASE_INSENSITIVE
,
304 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
305 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
307 if (!NT_SUCCESS(Status
))
309 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
310 LdrpKnownDllsDirHandle
= NULL
;
314 /* Allocate target name string */
315 LinkTarget
.Length
= 0;
316 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
317 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
319 MAX_PATH
* sizeof(WCHAR
));
320 if (LinkTarget
.Buffer
== NULL
)
322 NtClose(LdrpKnownDllsDirHandle
);
323 LdrpKnownDllsDirHandle
= NULL
;
327 RtlInitUnicodeString(&Name
,
329 InitializeObjectAttributes(&ObjectAttributes
,
331 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
332 LdrpKnownDllsDirHandle
,
334 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
335 SYMBOLIC_LINK_ALL_ACCESS
,
337 if (!NT_SUCCESS(Status
))
339 RtlFreeUnicodeString(&LinkTarget
);
340 NtClose(LdrpKnownDllsDirHandle
);
341 LdrpKnownDllsDirHandle
= NULL
;
345 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
349 if (!NT_SUCCESS(Status
))
351 RtlFreeUnicodeString(&LinkTarget
);
352 NtClose(LdrpKnownDllsDirHandle
);
353 LdrpKnownDllsDirHandle
= NULL
;
356 RtlCreateUnicodeString(&LdrpKnownDllPath
,
359 RtlFreeUnicodeString(&LinkTarget
);
361 DPRINT("LdrpInitLoader() done\n");
365 /***************************************************************************
370 * Adjusts the name of a dll to a fully qualified name.
373 * FullDllName: Pointer to caller supplied storage for the fully
374 * qualified dll name.
375 * DllName: Pointer to the dll name.
376 * BaseName: TRUE: Only the file name is passed to FullDllName
377 * FALSE: The full path is preserved in FullDllName
385 * A given path is not affected by the adjustment, but the file
387 * ntdll --> ntdll.dll
389 * ntdll.xyz --> ntdll.xyz
392 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
393 PUNICODE_STRING DllName
,
396 WCHAR Buffer
[MAX_PATH
];
401 Length
= DllName
->Length
/ sizeof(WCHAR
);
405 /* get the base dll name */
406 Pointer
= DllName
->Buffer
+ Length
;
413 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
416 Length
= Extension
- Pointer
;
417 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
418 Buffer
[Length
] = L
'\0';
422 /* get the full dll name */
423 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
424 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
427 /* Build the DLL's absolute name */
428 Extension
= wcsrchr (Buffer
, L
'.');
429 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
431 /* with extension - remove dot if it's the last character */
432 if (Buffer
[Length
- 1] == L
'.')
438 /* name without extension - assume that it is .dll */
439 memmove (Buffer
+ Length
, L
".dll", 10);
442 RtlCreateUnicodeString(FullDllName
, Buffer
);
446 LdrAddModuleEntry(PVOID ImageBase
,
447 PIMAGE_NT_HEADERS NTHeaders
,
452 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
454 memset(Module
, 0, sizeof(LDR_MODULE
));
455 Module
->BaseAddress
= (PVOID
)ImageBase
;
456 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
457 if (Module
->EntryPoint
!= 0)
458 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
459 Module
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
460 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
462 /* loading while app is running */
463 Module
->LoadCount
= 1;
466 * loading while app is initializing
467 * dll must not be unloaded
469 Module
->LoadCount
= -1;
473 Module
->TlsIndex
= -1;
474 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
475 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
477 RtlCreateUnicodeString (&Module
->FullDllName
,
479 RtlCreateUnicodeString (&Module
->BaseDllName
,
480 wcsrchr(FullDosName
, L
'\\') + 1);
481 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
483 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
484 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
485 &Module
->InLoadOrderModuleList
);
486 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
493 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
494 OUT PUNICODE_STRING FullDosName
,
495 OUT PHANDLE SectionHandle
)
497 OBJECT_ATTRIBUTES ObjectAttributes
;
500 DPRINT("LdrpMapKnownDll() called\n");
502 if (LdrpKnownDllsDirHandle
== NULL
)
504 DPRINT("Invalid 'KnownDlls' directory\n");
505 return STATUS_UNSUCCESSFUL
;
508 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
510 InitializeObjectAttributes(&ObjectAttributes
,
512 OBJ_CASE_INSENSITIVE
,
513 LdrpKnownDllsDirHandle
,
515 Status
= NtOpenSection(SectionHandle
,
516 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
518 if (!NT_SUCCESS(Status
))
520 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
524 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
525 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
526 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
528 FullDosName
->MaximumLength
);
529 if (FullDosName
->Buffer
== NULL
)
531 FullDosName
->Length
= 0;
532 FullDosName
->MaximumLength
= 0;
533 return STATUS_SUCCESS
;
536 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
537 wcscat(FullDosName
->Buffer
, L
"\\");
538 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
540 DPRINT("FullDosName '%wZ'\n", FullDosName
);
542 DPRINT("LdrpMapKnownDll() done\n");
544 return STATUS_SUCCESS
;
549 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
550 IN PUNICODE_STRING DllName
,
551 OUT PUNICODE_STRING FullDosName
,
552 OUT PHANDLE SectionHandle
)
554 WCHAR SearchPathBuffer
[MAX_PATH
];
555 WCHAR DosName
[MAX_PATH
];
556 UNICODE_STRING FullNtFileName
;
557 OBJECT_ATTRIBUTES FileObjectAttributes
;
559 char BlockBuffer
[1024];
560 PIMAGE_DOS_HEADER DosHeader
;
561 PIMAGE_NT_HEADERS NTHeaders
;
564 IO_STATUS_BLOCK IoStatusBlock
;
568 DPRINT("LdrpMapDllImageFile() called\n");
570 if (SearchPath
== NULL
)
572 /* get application running path */
574 wcscpy (SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
576 len
= wcslen (SearchPathBuffer
);
578 while (len
&& SearchPathBuffer
[len
- 1] != L
'\\')
581 if (len
) SearchPathBuffer
[len
-1] = L
'\0';
583 wcscat (SearchPathBuffer
, L
";");
585 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
586 wcscat (SearchPathBuffer
, L
"\\system32;");
587 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
588 wcscat (SearchPathBuffer
, L
";.");
590 SearchPath
= SearchPathBuffer
;
593 if (RtlDosSearchPath_U (SearchPath
,
599 return STATUS_DLL_NOT_FOUND
;
602 if (!RtlDosPathNameToNtPathName_U (DosName
,
606 return STATUS_DLL_NOT_FOUND
;
608 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
610 InitializeObjectAttributes(&FileObjectAttributes
,
616 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
618 Status
= NtOpenFile(&FileHandle
,
619 GENERIC_READ
|SYNCHRONIZE
,
620 &FileObjectAttributes
,
623 FILE_SYNCHRONOUS_IO_NONALERT
);
624 if (!NT_SUCCESS(Status
))
626 DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
627 &FullNtFileName
, Status
);
628 RtlFreeUnicodeString (&FullNtFileName
);
631 RtlFreeUnicodeString (&FullNtFileName
);
633 Status
= NtReadFile(FileHandle
,
642 if (!NT_SUCCESS(Status
))
644 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
649 * Overlay DOS and NT headers structures to the
650 * buffer with DLL's header raw data.
652 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
653 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
655 * Check it is a PE image file.
657 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
658 || (DosHeader
->e_lfanew
== 0L)
659 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
661 DPRINT("NTDLL format invalid\n");
664 return STATUS_UNSUCCESSFUL
;
667 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
668 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
670 DPRINT("ImageBase 0x%08x\n", ImageBase
);
673 * Create a section for dll.
675 Status
= NtCreateSection(SectionHandle
,
680 SEC_COMMIT
| SEC_IMAGE
,
684 if (!NT_SUCCESS(Status
))
686 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
690 RtlCreateUnicodeString(FullDosName
,
698 /***************************************************************************
715 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
717 IN PUNICODE_STRING Name
,
718 OUT PVOID
*BaseAddress OPTIONAL
)
723 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
725 SearchPath
? " from " : "",
726 SearchPath
? SearchPath
: L
"");
730 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
731 return STATUS_SUCCESS
;
736 Status
= LdrpLoadModule(SearchPath
, LoadFlags
, Name
, &Module
);
737 if (NT_SUCCESS(Status
))
739 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
740 Status
= LdrpAttachProcess();
741 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
742 if (NT_SUCCESS(Status
))
744 *BaseAddress
= Module
->BaseAddress
;
751 /***************************************************************************
753 * LdrFindEntryForAddress
768 LdrFindEntryForAddress(PVOID Address
,
771 PLIST_ENTRY ModuleListHead
;
773 PLDR_MODULE ModulePtr
;
775 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
777 if (NtCurrentPeb()->Ldr
== NULL
)
778 return(STATUS_NO_MORE_ENTRIES
);
780 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
781 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
782 Entry
= ModuleListHead
->Flink
;
783 if (Entry
== ModuleListHead
)
785 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
786 return(STATUS_NO_MORE_ENTRIES
);
789 while (Entry
!= ModuleListHead
)
791 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
793 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
795 if ((Address
>= ModulePtr
->BaseAddress
) &&
796 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->SizeOfImage
)))
799 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
800 return(STATUS_SUCCESS
);
803 Entry
= Entry
->Flink
;
806 DPRINT("Failed to find module entry.\n");
808 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
809 return(STATUS_NO_MORE_ENTRIES
);
813 /***************************************************************************
815 * LdrFindEntryForName
829 LdrFindEntryForName(PUNICODE_STRING Name
,
833 PLIST_ENTRY ModuleListHead
;
835 PLDR_MODULE ModulePtr
;
836 BOOLEAN ContainsPath
;
837 UNICODE_STRING AdjustedName
;
840 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name
);
842 if (NtCurrentPeb()->Ldr
== NULL
)
843 return(STATUS_NO_MORE_ENTRIES
);
845 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
846 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
847 Entry
= ModuleListHead
->Flink
;
848 if (Entry
== ModuleListHead
)
850 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
851 return(STATUS_NO_MORE_ENTRIES
);
854 // NULL is the current process
858 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
859 return(STATUS_SUCCESS
);
862 LdrAdjustDllName (&AdjustedName
, Name
, FALSE
);
864 ContainsPath
= (AdjustedName
.Length
>= 2 * sizeof(WCHAR
) && L
':' == AdjustedName
.Buffer
[1]);
865 for (i
= 0; ! ContainsPath
&& i
< AdjustedName
.Length
/ sizeof(WCHAR
); i
++)
867 ContainsPath
= L
'\\' == AdjustedName
.Buffer
[i
] ||
868 L
'/' == AdjustedName
.Buffer
[i
];
873 if ((! ContainsPath
&&
874 0 == RtlCompareUnicodeString(&LdrpLastModule
->BaseDllName
, &AdjustedName
, TRUE
)) ||
876 0 == RtlCompareUnicodeString(&LdrpLastModule
->FullDllName
, &AdjustedName
, TRUE
)))
878 *Module
= LdrpLastModule
;
879 if (Ref
&& (*Module
)->LoadCount
!= -1)
881 (*Module
)->LoadCount
++;
883 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
884 RtlFreeUnicodeString(&AdjustedName
);
885 return(STATUS_SUCCESS
);
888 while (Entry
!= ModuleListHead
)
890 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
892 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, &AdjustedName
);
894 if ((! ContainsPath
&&
895 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, &AdjustedName
, TRUE
)) ||
897 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, &AdjustedName
, TRUE
)))
899 *Module
= LdrpLastModule
= ModulePtr
;
900 if (Ref
&& ModulePtr
->LoadCount
!= -1)
902 ModulePtr
->LoadCount
++;
904 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
905 RtlFreeUnicodeString(&AdjustedName
);
906 return(STATUS_SUCCESS
);
909 Entry
= Entry
->Flink
;
912 DPRINT("Failed to find dll %wZ\n", Name
);
913 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
914 RtlFreeUnicodeString(&AdjustedName
);
915 return(STATUS_NO_MORE_ENTRIES
);
918 /**********************************************************************
934 LdrFixupForward(PCHAR ForwardName
)
936 CHAR NameBuffer
[128];
937 UNICODE_STRING DllName
;
943 strcpy(NameBuffer
, ForwardName
);
944 p
= strchr(NameBuffer
, '.');
949 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
950 RtlCreateUnicodeStringFromAsciiz (&DllName
,
953 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
955 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
957 if (!NT_SUCCESS(Status
))
959 Status
= LdrLoadDll(NULL
,
960 LDRP_PROCESS_CREATION_TIME
,
963 if (NT_SUCCESS(Status
))
965 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
968 RtlFreeUnicodeString (&DllName
);
969 if (!NT_SUCCESS(Status
))
971 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer
);
975 DPRINT("BaseAddress: %p\n", Module
->BaseAddress
);
977 return LdrGetExportByName(Module
->BaseAddress
, p
+1, -1);
984 /**********************************************************************
986 * LdrGetExportByOrdinal
1000 LdrGetExportByOrdinal (
1005 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1006 ULONG ExportDirSize
;
1007 PDWORD
* ExFunctions
;
1010 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1011 RtlImageDirectoryEntryToData (BaseAddress
,
1013 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1017 ExFunctions
= (PDWORD
*)
1020 ExportDir
->AddressOfFunctions
1023 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
1025 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1028 Function
= (0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1029 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1032 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1033 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1035 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1036 Function
= LdrFixupForward((PCHAR
)Function
);
1043 /**********************************************************************
1045 * LdrGetExportByName
1056 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1057 * both with NumberOfNames entries.
1061 LdrGetExportByName(PVOID BaseAddress
,
1065 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1066 PDWORD
* ExFunctions
;
1068 USHORT
* ExOrdinals
;
1074 ULONG ExportDirSize
;
1076 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1078 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1079 RtlImageDirectoryEntryToData(BaseAddress
,
1081 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1083 if (ExportDir
== NULL
)
1085 DPRINT1("LdrGetExportByName(): no export directory!\n");
1090 //The symbol names may be missing entirely
1091 if (ExportDir
->AddressOfNames
== 0)
1093 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1098 * Get header pointers
1100 ExNames
= (PDWORD
*)RVA(BaseAddress
,
1101 ExportDir
->AddressOfNames
);
1102 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
1103 ExportDir
->AddressOfNameOrdinals
);
1104 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
1105 ExportDir
->AddressOfFunctions
);
1108 * Check the hint first
1110 if (Hint
< ExportDir
->NumberOfNames
)
1112 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1113 if (strcmp(ExName
, SymbolName
) == 0)
1115 Ordinal
= ExOrdinals
[Hint
];
1116 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1117 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1118 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1120 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1121 Function
= LdrFixupForward((PCHAR
)Function
);
1122 if (Function
== NULL
)
1124 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1128 if (Function
!= NULL
)
1134 * Try a binary search first
1137 maxn
= ExportDir
->NumberOfNames
- 1;
1138 while (minn
<= maxn
)
1143 mid
= (minn
+ maxn
) / 2;
1145 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1146 res
= strcmp(ExName
, SymbolName
);
1149 Ordinal
= ExOrdinals
[mid
];
1150 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1151 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1152 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1154 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1155 Function
= LdrFixupForward((PCHAR
)Function
);
1156 if (Function
== NULL
)
1158 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1162 if (Function
!= NULL
)
1165 else if (minn
== maxn
)
1167 DPRINT("LdrGetExportByName(): binary search failed\n");
1181 * Fall back on a linear search
1183 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1184 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1186 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1187 if (strcmp(ExName
,SymbolName
) == 0)
1189 Ordinal
= ExOrdinals
[i
];
1190 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1191 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1192 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1193 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1195 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1196 Function
= LdrFixupForward((PCHAR
)Function
);
1198 if (Function
== NULL
)
1205 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1210 /**********************************************************************
1212 * LdrPerformRelocations
1215 * Relocate a DLL's memory image.
1227 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
,
1230 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1231 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
1232 ULONG Count
, ProtectSize
, OldProtect
, OldProtect2
;
1233 PVOID Page
, ProtectPage
, ProtectPage2
;
1238 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1240 return STATUS_UNSUCCESSFUL
;
1244 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1246 if (RelocationDDir
->VirtualAddress
== 0 || RelocationDDir
->Size
== 0)
1248 return STATUS_SUCCESS
;
1251 ProtectSize
= PAGE_SIZE
;
1252 Delta
= (ULONG_PTR
)ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
;
1253 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1254 RelocationDDir
->VirtualAddress
);
1255 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1256 RelocationDDir
->VirtualAddress
+ RelocationDDir
->Size
);
1258 while (RelocationDir
< RelocationEnd
&&
1259 RelocationDir
->SizeOfBlock
> 0)
1261 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) /
1263 Page
= ImageBase
+ RelocationDir
->VirtualAddress
;
1264 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
1266 /* Unprotect the page(s) we're about to relocate. */
1268 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1273 if (!NT_SUCCESS(Status
))
1275 DPRINT1("Failed to unprotect relocation target.\n");
1279 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
<
1280 NTHeaders
->OptionalHeader
.SizeOfImage
)
1282 ProtectPage2
= ProtectPage
+ PAGE_SIZE
;
1283 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1288 if (!NT_SUCCESS(Status
))
1290 DPRINT1("Failed to unprotect relocation target (2).\n");
1291 NtProtectVirtualMemory(NtCurrentProcess(),
1301 ProtectPage2
= NULL
;
1304 RelocationDir
= LdrProcessRelocationBlock(Page
,
1308 if (RelocationDir
== NULL
)
1309 return STATUS_UNSUCCESSFUL
;
1311 /* Restore old page protection. */
1312 NtProtectVirtualMemory(NtCurrentProcess(),
1318 if (ProtectPage2
!= NULL
)
1320 NtProtectVirtualMemory(NtCurrentProcess(),
1328 return STATUS_SUCCESS
;
1332 LdrpGetOrLoadModule(PWCHAR SerachPath
,
1334 PLDR_MODULE
* Module
,
1337 UNICODE_STRING DllName
;
1340 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name
);
1342 RtlCreateUnicodeStringFromAsciiz (&DllName
, Name
);
1344 Status
= LdrFindEntryForName (&DllName
, Module
, Load
);
1345 if (Load
&& !NT_SUCCESS(Status
))
1347 Status
= LdrpLoadModule(SerachPath
,
1348 NtCurrentPeb()->Ldr
->Initialized
? 0 : LDRP_PROCESS_CREATION_TIME
,
1351 if (NT_SUCCESS(Status
))
1353 Status
= LdrFindEntryForName (&DllName
, Module
, FALSE
);
1355 if (!NT_SUCCESS(Status
))
1357 DPRINT1("failed to load %wZ\n", &DllName
);
1360 RtlFreeUnicodeString (&DllName
);
1365 LdrpProcessImportDirectoryEntry(PLDR_MODULE Module
,
1366 PLDR_MODULE ImportedModule
,
1367 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
)
1370 PVOID
* ImportAddressList
;
1371 PULONG FunctionNameList
;
1377 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->dwRVAModuleName
== 0)
1379 return STATUS_UNSUCCESSFUL
;
1382 /* Get the import address list. */
1383 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1385 /* Get the list of functions to import. */
1386 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1388 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1392 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1395 /* Get the size of IAT. */
1397 while (FunctionNameList
[IATSize
] != 0L)
1402 /* Unprotect the region we are about to write into. */
1403 IATBase
= (PVOID
)ImportAddressList
;
1404 IATSize
*= sizeof(PVOID
*);
1405 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1410 if (!NT_SUCCESS(Status
))
1412 DPRINT1("Failed to unprotect IAT.\n");
1416 /* Walk through function list and fixup addresses. */
1417 while (*FunctionNameList
!= 0L)
1419 if ((*FunctionNameList
) & 0x80000000)
1421 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1422 *ImportAddressList
= LdrGetExportByOrdinal(ImportedModule
->BaseAddress
, Ordinal
);
1423 if ((*ImportAddressList
) == NULL
)
1425 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1426 return STATUS_UNSUCCESSFUL
;
1431 IMAGE_IMPORT_BY_NAME
*pe_name
;
1432 pe_name
= RVA(Module
->BaseAddress
, *FunctionNameList
);
1433 *ImportAddressList
= LdrGetExportByName(ImportedModule
->BaseAddress
, pe_name
->Name
, pe_name
->Hint
);
1434 if ((*ImportAddressList
) == NULL
)
1436 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1437 return STATUS_UNSUCCESSFUL
;
1440 ImportAddressList
++;
1444 /* Protect the region we are about to write into. */
1445 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1450 if (!NT_SUCCESS(Status
))
1452 DPRINT1("Failed to protect IAT.\n");
1456 return STATUS_SUCCESS
;
1460 LdrpProcessImportDirectory(
1462 PLDR_MODULE ImportedModule
,
1466 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1469 DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
1470 Module
, &Module
->BaseDllName
, ImportedName
);
1473 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1474 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1476 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1478 if (ImportModuleDirectory
== NULL
)
1480 return STATUS_UNSUCCESSFUL
;
1483 while (ImportModuleDirectory
->dwRVAModuleName
)
1485 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1486 if (0 == _stricmp(Name
, ImportedName
))
1488 Status
= LdrpProcessImportDirectoryEntry(Module
,
1490 ImportModuleDirectory
);
1491 if (!NT_SUCCESS(Status
))
1496 ImportModuleDirectory
++;
1500 return STATUS_SUCCESS
;
1505 LdrpAdjustImportDirectory(PLDR_MODULE Module
,
1506 PLDR_MODULE ImportedModule
,
1507 PUCHAR ImportedName
)
1509 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1511 PVOID
* ImportAddressList
;
1514 PULONG FunctionNameList
;
1519 PIMAGE_NT_HEADERS NTHeaders
;
1522 DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
1523 Module
, &Module
->BaseDllName
, ImportedModule
, &ImportedModule
->BaseDllName
, ImportedName
);
1525 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1526 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1528 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1530 if (ImportModuleDirectory
== NULL
)
1532 return STATUS_UNSUCCESSFUL
;
1535 while (ImportModuleDirectory
->dwRVAModuleName
)
1537 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1538 if (0 == _stricmp(Name
, ImportedName
))
1541 /* Get the import address list. */
1542 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1544 /* Get the list of functions to import. */
1545 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1547 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1551 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1554 /* Get the size of IAT. */
1556 while (FunctionNameList
[IATSize
] != 0L)
1561 /* Unprotect the region we are about to write into. */
1562 IATBase
= (PVOID
)ImportAddressList
;
1563 IATSize
*= sizeof(PVOID
*);
1564 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1569 if (!NT_SUCCESS(Status
))
1571 DPRINT1("Failed to unprotect IAT.\n");
1575 NTHeaders
= RtlImageNtHeader (ImportedModule
->BaseAddress
);
1576 Start
= (PVOID
)NTHeaders
->OptionalHeader
.ImageBase
;
1577 End
= Start
+ ImportedModule
->SizeOfImage
;
1578 Offset
= ImportedModule
->BaseAddress
- Start
;
1580 /* Walk through function list and fixup addresses. */
1581 while (*FunctionNameList
!= 0L)
1583 if (*ImportAddressList
>= Start
&& *ImportAddressList
< End
)
1585 (*ImportAddressList
) += Offset
;
1587 ImportAddressList
++;
1591 /* Protect the region we are about to write into. */
1592 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1597 if (!NT_SUCCESS(Status
))
1599 DPRINT1("Failed to protect IAT.\n");
1603 ImportModuleDirectory
++;
1605 return STATUS_SUCCESS
;
1609 /**********************************************************************
1614 * Compute the entry point for every symbol the DLL imports
1615 * from other modules.
1627 LdrFixupImports(IN PWSTR SearchPath OPTIONAL
,
1628 IN PLDR_MODULE Module
)
1630 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1631 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectoryCurrent
;
1632 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
1633 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
1634 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1637 PLDR_MODULE ImportedModule
;
1640 DPRINT("LdrFixupImports(SearchPath %x, Module %x)\n", SearchPath
, Module
);
1642 /* Check for tls data */
1643 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
1644 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1646 IMAGE_DIRECTORY_ENTRY_TLS
,
1650 TlsSize
= TlsDirectory
->EndAddressOfRawData
1651 - TlsDirectory
->StartAddressOfRawData
1652 + TlsDirectory
->SizeOfZeroFill
;
1654 NtCurrentPeb()->Ldr
->Initialized
)
1656 TRACE_LDR("Trying to load dynamicly %wZ which contains a tls directory\n",
1657 &Module
->BaseDllName
);
1658 return STATUS_UNSUCCESSFUL
;
1662 * Process each import module.
1664 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1665 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1667 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1670 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
1671 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1673 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
1676 if (BoundImportDescriptor
!= NULL
&& ImportModuleDirectory
== NULL
)
1678 DPRINT1("%wZ has only a bound import directory\n", &Module
->BaseDllName
);
1679 return STATUS_UNSUCCESSFUL
;
1681 if (BoundImportDescriptor
)
1683 DPRINT("BoundImportDescriptor %x\n", BoundImportDescriptor
);
1685 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
1686 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
1688 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
1689 TRACE_LDR("%wZ bound to %s\n", &Module
->BaseDllName
, ImportedName
);
1690 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1691 if (!NT_SUCCESS(Status
))
1693 DPRINT1("failed to load %s\n", ImportedName
);
1696 if (Module
== ImportedModule
)
1698 LdrpDecrementLoadCount(Module
, FALSE
);
1700 if (ImportedModule
->TimeDateStamp
!= BoundImportDescriptorCurrent
->TimeDateStamp
)
1702 TRACE_LDR("%wZ has stale binding to %wZ\n",
1703 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1704 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1705 if (!NT_SUCCESS(Status
))
1707 DPRINT1("failed to import %s\n", ImportedName
);
1713 BOOL WrongForwarder
;
1714 WrongForwarder
= FALSE
;
1715 if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1717 TRACE_LDR("%wZ has stale binding to %s\n",
1718 &Module
->BaseDllName
, ImportedName
);
1722 TRACE_LDR("%wZ has correct binding to %wZ\n",
1723 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1725 if (BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
)
1727 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef
;
1729 PLDR_MODULE ForwarderModule
;
1730 PUCHAR ForwarderName
;
1732 BoundForwarderRef
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundImportDescriptorCurrent
+ 1);
1733 for (i
= 0; i
< BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
; i
++, BoundForwarderRef
++)
1735 ForwarderName
= (PCHAR
)BoundImportDescriptor
+ BoundForwarderRef
->OffsetModuleName
;
1736 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1737 &Module
->BaseDllName
, ForwarderName
, ImportedName
);
1738 Status
= LdrpGetOrLoadModule(SearchPath
, ForwarderName
, &ForwarderModule
, TRUE
);
1739 if (!NT_SUCCESS(Status
))
1741 DPRINT1("failed to load %s\n", ForwarderName
);
1744 if (Module
== ImportedModule
)
1746 LdrpDecrementLoadCount(Module
, FALSE
);
1748 if (ForwarderModule
->TimeDateStamp
!= BoundForwarderRef
->TimeDateStamp
||
1749 ForwarderModule
->Flags
& IMAGE_NOT_AT_BASE
)
1751 TRACE_LDR("%wZ has stale binding to %s\n",
1752 &Module
->BaseDllName
, ForwarderName
);
1753 WrongForwarder
= TRUE
;
1757 TRACE_LDR("%wZ has correct binding to %s\n",
1758 &Module
->BaseDllName
, ForwarderName
);
1762 if (WrongForwarder
||
1763 ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1765 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1766 if (!NT_SUCCESS(Status
))
1768 DPRINT1("failed to import %s\n", ImportedName
);
1772 else if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1774 TRACE_LDR("Adjust imports for %s from %wZ\n",
1775 ImportedName
, &Module
->BaseDllName
);
1776 Status
= LdrpAdjustImportDirectory(Module
, ImportedModule
, ImportedName
);
1777 if (!NT_SUCCESS(Status
))
1779 DPRINT1("failed to adjust import entries for %s\n", ImportedName
);
1783 else if (WrongForwarder
)
1787 * Update only forwarders
1789 TRACE_LDR("Stale BIND %s from %wZ\n",
1790 ImportedName
, &Module
->BaseDllName
);
1791 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1792 if (!NT_SUCCESS(Status
))
1794 DPRINT1("faild to import %s\n", ImportedName
);
1803 BoundImportDescriptorCurrent
+= BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
+ 1;
1806 else if (ImportModuleDirectory
)
1808 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1810 ImportModuleDirectoryCurrent
= ImportModuleDirectory
;
1811 while (ImportModuleDirectoryCurrent
->dwRVAModuleName
)
1813 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectoryCurrent
->dwRVAModuleName
;
1814 TRACE_LDR("%wZ imports functions from %s\n", &Module
->BaseDllName
, ImportedName
);
1816 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1817 if (!NT_SUCCESS(Status
))
1819 DPRINT1("failed to load %s\n", ImportedName
);
1822 if (Module
== ImportedModule
)
1824 LdrpDecrementLoadCount(Module
, FALSE
);
1827 TRACE_LDR("Initializing imports for %wZ from %s\n",
1828 &Module
->BaseDllName
, ImportedName
);
1829 Status
= LdrpProcessImportDirectoryEntry(Module
, ImportedModule
, ImportModuleDirectoryCurrent
);
1830 if (!NT_SUCCESS(Status
))
1832 DPRINT1("failed to import %s\n", ImportedName
);
1835 ImportModuleDirectoryCurrent
++;
1839 if (TlsDirectory
&& TlsSize
> 0)
1841 LdrpAcquireTlsSlot(Module
, TlsSize
, FALSE
);
1844 return STATUS_SUCCESS
;
1848 /**********************************************************************
1853 * 1. Relocate, if needed the EXE.
1854 * 2. Fixup any imported symbol.
1855 * 3. Compute the EXE's entry point.
1859 * Address at which the EXE's image
1863 * Handle of the section that contains
1867 * NULL on error; otherwise the entry point
1868 * to call for initializing the DLL.
1873 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
1874 * Currently the function is only used for the exe.
1876 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1877 HANDLE SectionHandle
,
1878 PLDR_MODULE
* Module
,
1882 PEPFUNC EntryPoint
= NULL
;
1883 PIMAGE_DOS_HEADER DosHeader
;
1884 PIMAGE_NT_HEADERS NTHeaders
;
1885 PLDR_MODULE tmpModule
;
1887 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1888 ImageBase
, (ULONG
)SectionHandle
);
1891 * Overlay DOS and WNT headers structures
1892 * to the DLL's image.
1894 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1895 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1898 * If the base address is different from the
1899 * one the DLL is actually loaded, perform any
1902 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1904 DPRINT("LDR: Performing relocations\n");
1905 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1906 if (!NT_SUCCESS(Status
))
1908 DPRINT1("LdrPerformRelocations() failed\n");
1915 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1916 (*Module
)->SectionHandle
= SectionHandle
;
1920 Module
= &tmpModule
;
1921 Status
= LdrFindEntryForAddress(ImageBase
, Module
);
1922 if (!NT_SUCCESS(Status
))
1928 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1930 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
1934 * If the DLL's imports symbols from other
1935 * modules, fixup the imported calls entry points.
1937 DPRINT("About to fixup imports\n");
1938 Status
= LdrFixupImports(NULL
, *Module
);
1939 if (!NT_SUCCESS(Status
))
1941 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module
)->BaseDllName
);
1944 DPRINT("Fixup done\n");
1945 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
1946 Status
= LdrpInitializeTlsForProccess();
1947 if (NT_SUCCESS(Status
))
1949 Status
= LdrpAttachProcess();
1951 if (NT_SUCCESS(Status
))
1953 LdrpTlsCallback(*Module
, DLL_PROCESS_ATTACH
);
1957 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1958 if (!NT_SUCCESS(Status
))
1965 * Compute the DLL's entry point's address.
1967 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1968 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1969 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1971 EntryPoint
= (PEPFUNC
) (ImageBase
1972 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1974 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1979 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
1981 IN PUNICODE_STRING Name
,
1982 PLDR_MODULE
*Module
)
1984 UNICODE_STRING AdjustedName
;
1985 UNICODE_STRING FullDosName
;
1987 PLDR_MODULE tmpModule
;
1988 HANDLE SectionHandle
;
1991 PIMAGE_NT_HEADERS NtHeaders
;
1995 Module
= &tmpModule
;
1997 /* adjust the full dll name */
1998 LdrAdjustDllName(&AdjustedName
, Name
, FALSE
);
2000 DPRINT("%wZ\n", &AdjustedName
);
2002 /* Test if dll is already loaded */
2003 Status
= LdrFindEntryForName(&AdjustedName
, Module
, TRUE
);
2004 if (NT_SUCCESS(Status
))
2006 RtlFreeUnicodeString(&AdjustedName
);
2010 /* Open or create dll image section */
2011 Status
= LdrpMapKnownDll(&AdjustedName
, &FullDosName
, &SectionHandle
);
2012 if (!NT_SUCCESS(Status
))
2014 Status
= LdrpMapDllImageFile(SearchPath
, &AdjustedName
, &FullDosName
, &SectionHandle
);
2016 if (!NT_SUCCESS(Status
))
2018 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName
, Status
);
2019 RtlFreeUnicodeString(&AdjustedName
);
2022 RtlFreeUnicodeString(&AdjustedName
);
2023 /* Map the dll into the process */
2026 Status
= NtMapViewOfSection(SectionHandle
,
2036 if (!NT_SUCCESS(Status
))
2038 DPRINT1("map view of section failed (Status %x)\n", Status
);
2039 RtlFreeUnicodeString(&FullDosName
);
2040 NtClose(SectionHandle
);
2043 /* Get and check the NT headers */
2044 NtHeaders
= RtlImageNtHeader(ImageBase
);
2045 if (NtHeaders
== NULL
)
2047 DPRINT1("RtlImageNtHeaders() failed\n");
2048 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2049 NtClose (SectionHandle
);
2050 RtlFreeUnicodeString(&FullDosName
);
2051 return STATUS_UNSUCCESSFUL
;
2053 /* If the base address is different from the
2054 * one the DLL is actually loaded, perform any
2056 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2058 DPRINT1("Relocating (%x -> %x) %wZ\n",
2059 NtHeaders
->OptionalHeader
.ImageBase
, ImageBase
, &FullDosName
);
2060 Status
= LdrPerformRelocations(NtHeaders
, ImageBase
);
2061 if (!NT_SUCCESS(Status
))
2063 DPRINT1("LdrPerformRelocations() failed\n");
2064 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2065 NtClose (SectionHandle
);
2066 RtlFreeUnicodeString(&FullDosName
);
2067 return STATUS_UNSUCCESSFUL
;
2070 *Module
= LdrAddModuleEntry(ImageBase
, NtHeaders
, FullDosName
.Buffer
);
2071 (*Module
)->SectionHandle
= SectionHandle
;
2072 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2074 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
2076 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
2078 (*Module
)->Flags
|= IMAGE_DLL
;
2080 /* fixup the imported calls entry points */
2081 Status
= LdrFixupImports(SearchPath
, *Module
);
2082 if (!NT_SUCCESS(Status
))
2084 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module
)->BaseDllName
, Status
);
2087 #if defined(DBG) || defined(KDBG)
2088 LdrpLoadUserModuleSymbols(*Module
);
2089 #endif /* DBG || KDBG */
2090 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2091 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
2092 &(*Module
)->InInitializationOrderModuleList
);
2093 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2095 return STATUS_SUCCESS
;
2099 LdrpUnloadModule(PLDR_MODULE Module
,
2102 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
2103 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
2104 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
2106 PLDR_MODULE ImportedModule
;
2113 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2116 LoadCount
= LdrpDecrementLoadCount(Module
, Unload
);
2118 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module
->BaseDllName
, LoadCount
);
2122 /* ?????????????????? */
2125 else if (LoadCount
== 1)
2127 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
2128 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2130 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
2132 if (BoundImportDescriptor
)
2134 /* dereferencing all imported modules, use the bound import descriptor */
2135 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
2136 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
2138 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
2139 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2140 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2141 if (!NT_SUCCESS(Status
))
2143 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2147 if (Module
!= ImportedModule
)
2149 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2150 if (!NT_SUCCESS(Status
))
2152 DPRINT1("unable to unload %s\n", ImportedName
);
2156 BoundImportDescriptorCurrent
++;
2161 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
2162 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2164 IMAGE_DIRECTORY_ENTRY_IMPORT
,
2166 if (ImportModuleDirectory
)
2168 /* dereferencing all imported modules, use the import descriptor */
2169 while (ImportModuleDirectory
->dwRVAModuleName
)
2171 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
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 ImportModuleDirectory
++;
2197 LdrpDetachProcess(FALSE
);
2198 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2200 return STATUS_SUCCESS
;
2208 LdrUnloadDll (IN PVOID BaseAddress
)
2213 if (BaseAddress
== NULL
)
2214 return STATUS_SUCCESS
;
2216 Status
= LdrFindEntryForAddress(BaseAddress
, &Module
);
2217 if (NT_SUCCESS(Status
))
2219 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module
->BaseDllName
);
2220 Status
= LdrpUnloadModule(Module
, TRUE
);
2229 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
2231 PLIST_ENTRY ModuleListHead
;
2236 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
2238 Status
= STATUS_DLL_NOT_FOUND
;
2239 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2240 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2241 Entry
= ModuleListHead
->Flink
;
2242 while (Entry
!= ModuleListHead
)
2244 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2246 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
2248 if (Module
->BaseAddress
== BaseAddress
)
2250 if (Module
->TlsIndex
== -1)
2252 Module
->Flags
|= DONT_CALL_FOR_THREAD
;
2253 Status
= STATUS_SUCCESS
;
2257 Entry
= Entry
->Flink
;
2259 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2267 LdrGetDllHandle(IN PWCHAR Path OPTIONAL
,
2269 IN PUNICODE_STRING DllName
,
2270 OUT PVOID
* BaseAddress
)
2275 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName
, Path
? Path
: L
"");
2277 /* NULL is the current executable */
2278 if (DllName
== NULL
)
2280 *BaseAddress
= ExeModule
->BaseAddress
;
2281 DPRINT("BaseAddress %x\n", *BaseAddress
);
2282 return STATUS_SUCCESS
;
2285 Status
= LdrFindEntryForName(DllName
, &Module
, FALSE
);
2286 if (NT_SUCCESS(Status
))
2288 *BaseAddress
= Module
->BaseAddress
;
2289 return STATUS_SUCCESS
;
2292 DPRINT("Failed to find dll %wZ\n", DllName
);
2293 *BaseAddress
= NULL
;
2294 return STATUS_DLL_NOT_FOUND
;
2302 LdrGetProcedureAddress (IN PVOID BaseAddress
,
2303 IN PANSI_STRING Name
,
2305 OUT PVOID
*ProcedureAddress
)
2307 if (Name
&& Name
->Length
)
2309 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name
);
2313 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal
);
2316 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
2317 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
2319 if (Name
&& Name
->Length
)
2322 *ProcedureAddress
= LdrGetExportByName(BaseAddress
, Name
->Buffer
, 0xffff);
2323 if (*ProcedureAddress
!= NULL
)
2325 return STATUS_SUCCESS
;
2327 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
2332 Ordinal
&= 0x0000FFFF;
2333 *ProcedureAddress
= LdrGetExportByOrdinal(BaseAddress
, (WORD
)Ordinal
);
2334 if (*ProcedureAddress
)
2336 return STATUS_SUCCESS
;
2338 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
2340 return STATUS_PROCEDURE_NOT_FOUND
;
2343 /**********************************************************************
2348 * Unload dll's which are no longer referenced from others dll's
2359 * The loader lock must be held on enty.
2362 LdrpDetachProcess(BOOL UnloadAll
)
2364 PLIST_ENTRY ModuleListHead
;
2367 static ULONG CallingCount
= 0;
2369 DPRINT("LdrpDetachProcess() called for %wZ\n",
2370 &ExeModule
->BaseDllName
);
2374 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2375 Entry
= ModuleListHead
->Blink
;
2376 while (Entry
!= ModuleListHead
)
2378 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2379 if (((UnloadAll
&& Module
->LoadCount
<= 0) || Module
->LoadCount
== 0) &&
2380 Module
->Flags
& ENTRY_PROCESSED
&&
2381 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2383 Module
->Flags
|= UNLOAD_IN_PROGRESS
;
2384 if (Module
== LdrpLastModule
)
2386 LdrpLastModule
= NULL
;
2388 if (Module
->Flags
& PROCESS_ATTACH_CALLED
)
2390 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2391 &Module
->BaseDllName
, Module
->EntryPoint
);
2392 LdrpCallDllEntry(Module
, DLL_PROCESS_DETACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2396 TRACE_LDR("Unload %wZ\n", &Module
->BaseDllName
);
2398 Entry
= ModuleListHead
->Blink
;
2402 Entry
= Entry
->Blink
;
2406 if (CallingCount
== 1)
2408 Entry
= ModuleListHead
->Blink
;
2409 while (Entry
!= ModuleListHead
)
2411 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2412 Entry
= Entry
->Blink
;
2413 if (Module
->Flags
& UNLOAD_IN_PROGRESS
&&
2414 ((UnloadAll
&& Module
->LoadCount
>= 0) || Module
->LoadCount
== 0))
2416 /* remove the module entry from the list */
2417 RemoveEntryList (&Module
->InLoadOrderModuleList
);
2418 RemoveEntryList (&Module
->InInitializationOrderModuleList
);
2420 NtUnmapViewOfSection (NtCurrentProcess (), Module
->BaseAddress
);
2421 NtClose (Module
->SectionHandle
);
2423 TRACE_LDR("%wZ unloaded\n", &Module
->BaseDllName
);
2425 RtlFreeUnicodeString (&Module
->FullDllName
);
2426 RtlFreeUnicodeString (&Module
->BaseDllName
);
2428 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
2433 DPRINT("LdrpDetachProcess() done\n");
2436 /**********************************************************************
2441 * Initialize all dll's which are prepered for loading
2452 * The loader lock must be held on entry.
2456 LdrpAttachProcess(VOID
)
2458 PLIST_ENTRY ModuleListHead
;
2462 NTSTATUS Status
= STATUS_SUCCESS
;
2464 DPRINT("LdrpAttachProcess() called for %wZ\n",
2465 &ExeModule
->BaseDllName
);
2467 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2468 Entry
= ModuleListHead
->Flink
;
2469 while (Entry
!= ModuleListHead
)
2471 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2472 if (!(Module
->Flags
& (LOAD_IN_PROGRESS
|UNLOAD_IN_PROGRESS
|ENTRY_PROCESSED
)))
2474 Module
->Flags
|= LOAD_IN_PROGRESS
;
2475 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2476 &Module
->BaseDllName
, Module
->EntryPoint
);
2477 Result
= LdrpCallDllEntry(Module
, DLL_PROCESS_ATTACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2480 Status
= STATUS_DLL_INIT_FAILED
;
2483 if (Module
->Flags
& IMAGE_DLL
&& Module
->EntryPoint
!= 0)
2485 Module
->Flags
|= PROCESS_ATTACH_CALLED
|ENTRY_PROCESSED
;
2489 Module
->Flags
|= ENTRY_PROCESSED
;
2491 Module
->Flags
&= ~LOAD_IN_PROGRESS
;
2493 Entry
= Entry
->Flink
;
2496 DPRINT("LdrpAttachProcess() done\n");
2505 LdrShutdownProcess (VOID
)
2507 LdrpDetachProcess(TRUE
);
2508 return STATUS_SUCCESS
;
2516 LdrpAttachThread (VOID
)
2518 PLIST_ENTRY ModuleListHead
;
2523 DPRINT("LdrpAttachThread() called for %wZ\n",
2524 &ExeModule
->BaseDllName
);
2526 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2528 Status
= LdrpInitializeTlsForThread();
2530 if (NT_SUCCESS(Status
))
2532 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2533 Entry
= ModuleListHead
->Flink
;
2535 while (Entry
!= ModuleListHead
)
2537 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2538 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2539 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2540 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2542 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2543 &Module
->BaseDllName
, Module
->EntryPoint
);
2544 LdrpCallDllEntry(Module
, DLL_THREAD_ATTACH
, NULL
);
2546 Entry
= Entry
->Flink
;
2549 Entry
= NtCurrentPeb()->Ldr
->InLoadOrderModuleList
.Flink
;
2550 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2551 LdrpTlsCallback(Module
, DLL_THREAD_ATTACH
);
2554 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2556 DPRINT("LdrpAttachThread() done\n");
2566 LdrShutdownThread (VOID
)
2568 PLIST_ENTRY ModuleListHead
;
2572 DPRINT("LdrShutdownThread() called for %wZ\n",
2573 &ExeModule
->BaseDllName
);
2575 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2577 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2578 Entry
= ModuleListHead
->Blink
;
2579 while (Entry
!= ModuleListHead
)
2581 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2583 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2584 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2585 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2587 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2588 &Module
->BaseDllName
, Module
->EntryPoint
);
2589 LdrpCallDllEntry(Module
, DLL_THREAD_DETACH
, NULL
);
2591 Entry
= Entry
->Blink
;
2594 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2598 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer
);
2601 DPRINT("LdrShutdownThread() done\n");
2603 return STATUS_SUCCESS
;
2607 /***************************************************************************
2609 * LdrQueryProcessModuleInformation
2624 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
2625 IN ULONG Size OPTIONAL
,
2626 OUT PULONG ReturnedSize
)
2628 PLIST_ENTRY ModuleListHead
;
2631 PDEBUG_MODULE_INFORMATION ModulePtr
= NULL
;
2632 NTSTATUS Status
= STATUS_SUCCESS
;
2633 ULONG UsedSize
= sizeof(ULONG
);
2634 ANSI_STRING AnsiString
;
2637 DPRINT("LdrQueryProcessModuleInformation() called\n");
2639 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2641 if (ModuleInformation
== NULL
|| Size
== 0)
2643 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2647 ModuleInformation
->ModuleCount
= 0;
2648 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
2649 Status
= STATUS_SUCCESS
;
2652 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2653 Entry
= ModuleListHead
->Flink
;
2655 while (Entry
!= ModuleListHead
)
2657 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2659 DPRINT(" Module %wZ\n",
2660 &Module
->FullDllName
);
2662 if (UsedSize
> Size
)
2664 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2666 else if (ModuleInformation
!= NULL
)
2668 ModulePtr
->Reserved
[0] = ModulePtr
->Reserved
[1] = 0; // FIXME: ??
2669 ModulePtr
->Base
= Module
->BaseAddress
;
2670 ModulePtr
->Size
= Module
->SizeOfImage
;
2671 ModulePtr
->Flags
= Module
->Flags
;
2672 ModulePtr
->Index
= 0; // FIXME: index ??
2673 ModulePtr
->Unknown
= 0; // FIXME: ??
2674 ModulePtr
->LoadCount
= Module
->LoadCount
;
2676 AnsiString
.Length
= 0;
2677 AnsiString
.MaximumLength
= 256;
2678 AnsiString
.Buffer
= ModulePtr
->ImageName
;
2679 RtlUnicodeStringToAnsiString(&AnsiString
,
2680 &Module
->FullDllName
,
2682 p
= strrchr(ModulePtr
->ImageName
, '\\');
2684 ModulePtr
->ModuleNameOffset
= p
- ModulePtr
->ImageName
+ 1;
2686 ModulePtr
->ModuleNameOffset
= 0;
2689 ModuleInformation
->ModuleCount
++;
2691 UsedSize
+= sizeof(DEBUG_MODULE_INFORMATION
);
2693 Entry
= Entry
->Flink
;
2696 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2698 if (ReturnedSize
!= 0)
2699 *ReturnedSize
= UsedSize
;
2701 DPRINT("LdrQueryProcessModuleInformation() done\n");
2708 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
2711 PIMAGE_NT_HEADERS Header
;
2718 Header
= RtlImageNtHeader (BaseAddress
);
2722 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
2727 Ptr
= (PUSHORT
) BaseAddress
;
2728 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
2731 if (HIWORD(Sum
) != 0)
2733 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2740 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
2741 if (HIWORD(Sum
) != 0)
2743 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2747 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
2749 /* Subtract image checksum from calculated checksum. */
2750 /* fix low word of checksum */
2751 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
2753 CalcSum
-= LOWORD(HeaderSum
);
2757 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
2760 /* fix high word of checksum */
2761 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
2763 CalcSum
-= HIWORD(HeaderSum
);
2767 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
2770 /* add file length */
2771 CalcSum
+= ImageSize
;
2773 return (BOOLEAN
)(CalcSum
== HeaderSum
);
2777 /***************************************************************************
2779 * LdrVerifyImageMatchesChecksum
2794 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
2799 FILE_STANDARD_INFORMATION FileInfo
;
2800 IO_STATUS_BLOCK IoStatusBlock
;
2801 HANDLE SectionHandle
;
2807 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2809 Status
= NtCreateSection (&SectionHandle
,
2810 SECTION_MAP_EXECUTE
,
2816 if (!NT_SUCCESS(Status
))
2818 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
2824 Status
= NtMapViewOfSection (SectionHandle
,
2825 NtCurrentProcess (),
2834 if (!NT_SUCCESS(Status
))
2836 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2837 NtClose (SectionHandle
);
2841 Status
= NtQueryInformationFile (FileHandle
,
2844 sizeof (FILE_STANDARD_INFORMATION
),
2845 FileStandardInformation
);
2846 if (!NT_SUCCESS(Status
))
2848 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2849 NtUnmapViewOfSection (NtCurrentProcess (),
2851 NtClose (SectionHandle
);
2855 Result
= LdrpCheckImageChecksum (BaseAddress
,
2856 FileInfo
.EndOfFile
.u
.LowPart
);
2857 if (Result
== FALSE
)
2859 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2862 NtUnmapViewOfSection (NtCurrentProcess (),
2865 NtClose (SectionHandle
);
2871 /***************************************************************************
2873 * LdrQueryImageFileExecutionOptions
2888 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
2889 IN PCWSTR ValueName
,
2892 IN ULONG BufferSize
,
2893 OUT PULONG ReturnedLength OPTIONAL
)
2895 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2896 OBJECT_ATTRIBUTES ObjectAttributes
;
2897 UNICODE_STRING ValueNameString
;
2898 UNICODE_STRING KeyName
;
2899 WCHAR NameBuffer
[256];
2907 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2908 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
2911 Ptr
= SubKey
->Buffer
;
2917 wcscat (NameBuffer
, Ptr
);
2918 RtlInitUnicodeString (&KeyName
,
2921 InitializeObjectAttributes (&ObjectAttributes
,
2923 OBJ_CASE_INSENSITIVE
,
2927 Status
= NtOpenKey (&KeyHandle
,
2930 if (!NT_SUCCESS(Status
))
2932 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
2936 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
2937 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
2941 RtlInitUnicodeString (&ValueNameString
,
2943 Status
= NtQueryValueKey (KeyHandle
,
2945 KeyValuePartialInformation
,
2949 if (Status
== STATUS_BUFFER_OVERFLOW
)
2951 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
2952 RtlFreeHeap (RtlGetProcessHeap(),
2955 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
2958 if (KeyInfo
== NULL
)
2960 NtClose (KeyHandle
);
2964 Status
= NtQueryValueKey (KeyHandle
,
2966 KeyValuePartialInformation
,
2971 NtClose (KeyHandle
);
2973 if (!NT_SUCCESS(Status
))
2975 if (KeyInfo
!= NULL
)
2977 RtlFreeHeap (RtlGetProcessHeap(),
2984 if (KeyInfo
->Type
!= Type
)
2986 RtlFreeHeap (RtlGetProcessHeap(),
2989 return STATUS_OBJECT_TYPE_MISMATCH
;
2992 ResultSize
= BufferSize
;
2993 if (ResultSize
< KeyInfo
->DataLength
)
2995 Status
= STATUS_BUFFER_OVERFLOW
;
2999 ResultSize
= KeyInfo
->DataLength
;
3001 RtlCopyMemory (Buffer
,
3005 RtlFreeHeap (RtlGetProcessHeap(),
3009 if (ReturnedLength
!= NULL
)
3011 *ReturnedLength
= ResultSize
;
3018 PIMAGE_BASE_RELOCATION STDCALL
3019 LdrProcessRelocationBlock(IN PVOID Address
,
3021 IN PUSHORT TypeOffset
,
3030 for (i
= 0; i
< Count
; i
++)
3032 Offset
= *TypeOffset
& 0xFFF;
3033 Type
= *TypeOffset
>> 12;
3037 case IMAGE_REL_BASED_ABSOLUTE
:
3040 case IMAGE_REL_BASED_HIGH
:
3041 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3042 *ShortPtr
+= HIWORD(Delta
);
3045 case IMAGE_REL_BASED_LOW
:
3046 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3047 *ShortPtr
+= LOWORD(Delta
);
3050 case IMAGE_REL_BASED_HIGHLOW
:
3051 LongPtr
= (PULONG
)(Address
+ Offset
);
3055 case IMAGE_REL_BASED_HIGHADJ
:
3056 case IMAGE_REL_BASED_MIPS_JMPADDR
:
3058 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type
);
3065 return (PIMAGE_BASE_RELOCATION
)TypeOffset
;