1 /* $Id: utils.c,v 1.91 2004/06/25 18:50:48 ekohl 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 *****************************************************************/
74 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
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 TlsData
->TlsAddressOfCallBacks
= *TlsDirectory
->AddressOfCallBacks
;
256 TlsData
->Module
= Module
;
258 DbgPrint("TLS directory for %wZ\n", &Module
->BaseDllName
);
259 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory
->StartAddressOfRawData
);
260 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory
->EndAddressOfRawData
);
261 DbgPrint("SizeOfRawData: %d\n", TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
);
262 DbgPrint("AddressOfIndex: %x\n", TlsDirectory
->AddressOfIndex
);
263 DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory
->AddressOfCallBacks
, *TlsDirectory
->AddressOfCallBacks
);
264 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory
->SizeOfZeroFill
);
265 DbgPrint("Characteristics: %x\n", TlsDirectory
->Characteristics
);
269 * Is this region allways writable ?
271 *(PULONG
)TlsDirectory
->AddressOfIndex
= Module
->TlsIndex
;
274 Entry
= Entry
->Flink
;
277 DPRINT("LdrpInitializeTlsForProccess() done\n");
278 return STATUS_SUCCESS
;
284 OBJECT_ATTRIBUTES ObjectAttributes
;
285 UNICODE_STRING LinkTarget
;
291 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule
->BaseDllName
);
293 /* Get handle to the 'KnownDlls' directory */
294 RtlInitUnicodeString(&Name
,
296 InitializeObjectAttributes(&ObjectAttributes
,
298 OBJ_CASE_INSENSITIVE
,
301 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
302 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
304 if (!NT_SUCCESS(Status
))
306 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
307 LdrpKnownDllsDirHandle
= NULL
;
311 /* Allocate target name string */
312 LinkTarget
.Length
= 0;
313 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
314 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
316 MAX_PATH
* sizeof(WCHAR
));
317 if (LinkTarget
.Buffer
== NULL
)
319 NtClose(LdrpKnownDllsDirHandle
);
320 LdrpKnownDllsDirHandle
= NULL
;
324 RtlInitUnicodeString(&Name
,
326 InitializeObjectAttributes(&ObjectAttributes
,
328 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
329 LdrpKnownDllsDirHandle
,
331 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
332 SYMBOLIC_LINK_ALL_ACCESS
,
334 if (!NT_SUCCESS(Status
))
336 RtlFreeUnicodeString(&LinkTarget
);
337 NtClose(LdrpKnownDllsDirHandle
);
338 LdrpKnownDllsDirHandle
= NULL
;
342 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
346 if (!NT_SUCCESS(Status
))
348 RtlFreeUnicodeString(&LinkTarget
);
349 NtClose(LdrpKnownDllsDirHandle
);
350 LdrpKnownDllsDirHandle
= NULL
;
353 RtlCreateUnicodeString(&LdrpKnownDllPath
,
356 RtlFreeUnicodeString(&LinkTarget
);
358 DPRINT("LdrpInitLoader() done\n");
362 /***************************************************************************
367 * Adjusts the name of a dll to a fully qualified name.
370 * FullDllName: Pointer to caller supplied storage for the fully
371 * qualified dll name.
372 * DllName: Pointer to the dll name.
373 * BaseName: TRUE: Only the file name is passed to FullDllName
374 * FALSE: The full path is preserved in FullDllName
382 * A given path is not affected by the adjustment, but the file
384 * ntdll --> ntdll.dll
386 * ntdll.xyz --> ntdll.xyz
389 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
390 PUNICODE_STRING DllName
,
393 WCHAR Buffer
[MAX_PATH
];
398 Length
= DllName
->Length
/ sizeof(WCHAR
);
402 /* get the base dll name */
403 Pointer
= DllName
->Buffer
+ Length
;
410 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
413 Length
= Extension
- Pointer
;
414 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
415 Buffer
[Length
] = L
'\0';
419 /* get the full dll name */
420 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
421 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
424 /* Build the DLL's absolute name */
425 Extension
= wcsrchr (Buffer
, L
'.');
426 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
428 /* with extension - remove dot if it's the last character */
429 if (Buffer
[Length
- 1] == L
'.')
435 /* name without extension - assume that it is .dll */
436 memmove (Buffer
+ Length
, L
".dll", 10);
439 RtlCreateUnicodeString(FullDllName
, Buffer
);
443 LdrAddModuleEntry(PVOID ImageBase
,
444 PIMAGE_NT_HEADERS NTHeaders
,
449 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
451 memset(Module
, 0, sizeof(LDR_MODULE
));
452 Module
->BaseAddress
= (PVOID
)ImageBase
;
453 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
454 if (Module
->EntryPoint
!= 0)
455 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
456 Module
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
457 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
459 /* loading while app is running */
460 Module
->LoadCount
= 1;
463 * loading while app is initializing
464 * dll must not be unloaded
466 Module
->LoadCount
= -1;
470 Module
->TlsIndex
= -1;
471 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
472 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
474 RtlCreateUnicodeString (&Module
->FullDllName
,
476 RtlCreateUnicodeString (&Module
->BaseDllName
,
477 wcsrchr(FullDosName
, L
'\\') + 1);
478 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
480 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
481 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
482 &Module
->InLoadOrderModuleList
);
483 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
490 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
491 OUT PUNICODE_STRING FullDosName
,
492 OUT PHANDLE SectionHandle
)
494 OBJECT_ATTRIBUTES ObjectAttributes
;
497 DPRINT("LdrpMapKnownDll() called\n");
499 if (LdrpKnownDllsDirHandle
== NULL
)
501 DPRINT("Invalid 'KnownDlls' directory\n");
502 return STATUS_UNSUCCESSFUL
;
505 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
507 InitializeObjectAttributes(&ObjectAttributes
,
509 OBJ_CASE_INSENSITIVE
,
510 LdrpKnownDllsDirHandle
,
512 Status
= NtOpenSection(SectionHandle
,
513 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
515 if (!NT_SUCCESS(Status
))
517 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
521 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
522 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
523 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
525 FullDosName
->MaximumLength
);
526 if (FullDosName
->Buffer
== NULL
)
528 FullDosName
->Length
= 0;
529 FullDosName
->MaximumLength
= 0;
530 return STATUS_SUCCESS
;
533 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
534 wcscat(FullDosName
->Buffer
, L
"\\");
535 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
537 DPRINT("FullDosName '%wZ'\n", FullDosName
);
539 DPRINT("LdrpMapKnownDll() done\n");
541 return STATUS_SUCCESS
;
546 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
547 IN PUNICODE_STRING DllName
,
548 OUT PUNICODE_STRING FullDosName
,
549 OUT PHANDLE SectionHandle
)
551 WCHAR SearchPathBuffer
[MAX_PATH
];
552 WCHAR DosName
[MAX_PATH
];
553 UNICODE_STRING FullNtFileName
;
554 OBJECT_ATTRIBUTES FileObjectAttributes
;
556 char BlockBuffer
[1024];
557 PIMAGE_DOS_HEADER DosHeader
;
558 PIMAGE_NT_HEADERS NTHeaders
;
561 IO_STATUS_BLOCK IoStatusBlock
;
565 DPRINT("LdrpMapDllImageFile() called\n");
567 if (SearchPath
== NULL
)
569 /* get application running path */
571 wcscpy (SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
573 len
= wcslen (SearchPathBuffer
);
575 while (len
&& SearchPathBuffer
[len
- 1] != L
'\\')
578 if (len
) SearchPathBuffer
[len
-1] = L
'\0';
580 wcscat (SearchPathBuffer
, L
";");
582 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
583 wcscat (SearchPathBuffer
, L
"\\system32;");
584 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
585 wcscat (SearchPathBuffer
, L
";.");
587 SearchPath
= SearchPathBuffer
;
590 if (RtlDosSearchPath_U (SearchPath
,
596 return STATUS_DLL_NOT_FOUND
;
599 if (!RtlDosPathNameToNtPathName_U (DosName
,
603 return STATUS_DLL_NOT_FOUND
;
605 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
607 InitializeObjectAttributes(&FileObjectAttributes
,
613 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
615 Status
= NtOpenFile(&FileHandle
,
616 GENERIC_READ
|SYNCHRONIZE
,
617 &FileObjectAttributes
,
620 FILE_SYNCHRONOUS_IO_NONALERT
);
621 if (!NT_SUCCESS(Status
))
623 DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
624 &FullNtFileName
, Status
);
625 RtlFreeUnicodeString (&FullNtFileName
);
628 RtlFreeUnicodeString (&FullNtFileName
);
630 Status
= NtReadFile(FileHandle
,
639 if (!NT_SUCCESS(Status
))
641 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
646 * Overlay DOS and NT headers structures to the
647 * buffer with DLL's header raw data.
649 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
650 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
652 * Check it is a PE image file.
654 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
655 || (DosHeader
->e_lfanew
== 0L)
656 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
658 DPRINT("NTDLL format invalid\n");
661 return STATUS_UNSUCCESSFUL
;
664 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
665 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
667 DPRINT("ImageBase 0x%08x\n", ImageBase
);
670 * Create a section for dll.
672 Status
= NtCreateSection(SectionHandle
,
677 SEC_COMMIT
| SEC_IMAGE
,
681 if (!NT_SUCCESS(Status
))
683 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
687 RtlCreateUnicodeString(FullDosName
,
695 /***************************************************************************
712 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
714 IN PUNICODE_STRING Name
,
715 OUT PVOID
*BaseAddress OPTIONAL
)
720 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
722 SearchPath
? " from " : "",
723 SearchPath
? SearchPath
: L
"");
727 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
728 return STATUS_SUCCESS
;
733 Status
= LdrpLoadModule(SearchPath
, LoadFlags
, Name
, &Module
);
734 if (NT_SUCCESS(Status
))
736 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
737 Status
= LdrpAttachProcess();
738 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
739 if (NT_SUCCESS(Status
))
741 *BaseAddress
= Module
->BaseAddress
;
748 /***************************************************************************
750 * LdrFindEntryForAddress
765 LdrFindEntryForAddress(PVOID Address
,
768 PLIST_ENTRY ModuleListHead
;
770 PLDR_MODULE ModulePtr
;
772 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
774 if (NtCurrentPeb()->Ldr
== NULL
)
775 return(STATUS_NO_MORE_ENTRIES
);
777 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
778 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
779 Entry
= ModuleListHead
->Flink
;
780 if (Entry
== ModuleListHead
)
782 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
783 return(STATUS_NO_MORE_ENTRIES
);
786 while (Entry
!= ModuleListHead
)
788 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
790 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
792 if ((Address
>= ModulePtr
->BaseAddress
) &&
793 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->SizeOfImage
)))
796 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
797 return(STATUS_SUCCESS
);
800 Entry
= Entry
->Flink
;
803 DPRINT("Failed to find module entry.\n");
805 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
806 return(STATUS_NO_MORE_ENTRIES
);
810 /***************************************************************************
812 * LdrFindEntryForName
826 LdrFindEntryForName(PUNICODE_STRING Name
,
830 PLIST_ENTRY ModuleListHead
;
832 PLDR_MODULE ModulePtr
;
833 BOOLEAN ContainsPath
;
834 UNICODE_STRING AdjustedName
;
837 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name
);
839 if (NtCurrentPeb()->Ldr
== NULL
)
840 return(STATUS_NO_MORE_ENTRIES
);
842 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
843 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
844 Entry
= ModuleListHead
->Flink
;
845 if (Entry
== ModuleListHead
)
847 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
848 return(STATUS_NO_MORE_ENTRIES
);
851 // NULL is the current process
855 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
856 return(STATUS_SUCCESS
);
859 LdrAdjustDllName (&AdjustedName
, Name
, FALSE
);
861 ContainsPath
= (AdjustedName
.Length
>= 2 * sizeof(WCHAR
) && L
':' == AdjustedName
.Buffer
[1]);
862 for (i
= 0; ! ContainsPath
&& i
< AdjustedName
.Length
/ sizeof(WCHAR
); i
++)
864 ContainsPath
= L
'\\' == AdjustedName
.Buffer
[i
] ||
865 L
'/' == AdjustedName
.Buffer
[i
];
870 if ((! ContainsPath
&&
871 0 == RtlCompareUnicodeString(&LdrpLastModule
->BaseDllName
, &AdjustedName
, TRUE
)) ||
873 0 == RtlCompareUnicodeString(&LdrpLastModule
->FullDllName
, &AdjustedName
, TRUE
)))
875 *Module
= LdrpLastModule
;
876 if (Ref
&& (*Module
)->LoadCount
!= -1)
878 (*Module
)->LoadCount
++;
880 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
881 RtlFreeUnicodeString(&AdjustedName
);
882 return(STATUS_SUCCESS
);
885 while (Entry
!= ModuleListHead
)
887 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
889 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, &AdjustedName
);
891 if ((! ContainsPath
&&
892 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, &AdjustedName
, TRUE
)) ||
894 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, &AdjustedName
, TRUE
)))
896 *Module
= LdrpLastModule
= ModulePtr
;
897 if (Ref
&& ModulePtr
->LoadCount
!= -1)
899 ModulePtr
->LoadCount
++;
901 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
902 RtlFreeUnicodeString(&AdjustedName
);
903 return(STATUS_SUCCESS
);
906 Entry
= Entry
->Flink
;
909 DPRINT("Failed to find dll %wZ\n", Name
);
910 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
911 RtlFreeUnicodeString(&AdjustedName
);
912 return(STATUS_NO_MORE_ENTRIES
);
915 /**********************************************************************
931 LdrFixupForward(PCHAR ForwardName
)
933 CHAR NameBuffer
[128];
934 UNICODE_STRING DllName
;
940 strcpy(NameBuffer
, ForwardName
);
941 p
= strchr(NameBuffer
, '.');
946 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
947 RtlCreateUnicodeStringFromAsciiz (&DllName
,
950 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
952 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
954 if (!NT_SUCCESS(Status
))
956 Status
= LdrLoadDll(NULL
,
957 LDRP_PROCESS_CREATION_TIME
,
960 if (NT_SUCCESS(Status
))
962 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
965 RtlFreeUnicodeString (&DllName
);
966 if (!NT_SUCCESS(Status
))
968 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer
);
972 DPRINT("BaseAddress: %p\n", Module
->BaseAddress
);
974 return LdrGetExportByName(Module
->BaseAddress
, p
+1, -1);
981 /**********************************************************************
983 * LdrGetExportByOrdinal
997 LdrGetExportByOrdinal (
1002 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1003 ULONG ExportDirSize
;
1004 PDWORD
* ExFunctions
;
1007 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1008 RtlImageDirectoryEntryToData (BaseAddress
,
1010 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1014 ExFunctions
= (PDWORD
*)
1017 ExportDir
->AddressOfFunctions
1020 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
1022 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1025 Function
= (0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1026 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1029 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1030 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1032 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1033 Function
= LdrFixupForward((PCHAR
)Function
);
1040 /**********************************************************************
1042 * LdrGetExportByName
1053 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1054 * both with NumberOfNames entries.
1058 LdrGetExportByName(PVOID BaseAddress
,
1062 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1063 PDWORD
* ExFunctions
;
1065 USHORT
* ExOrdinals
;
1071 ULONG ExportDirSize
;
1073 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1075 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1076 RtlImageDirectoryEntryToData(BaseAddress
,
1078 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1080 if (ExportDir
== NULL
)
1082 DPRINT1("LdrGetExportByName(): no export directory!\n");
1087 //The symbol names may be missing entirely
1088 if (ExportDir
->AddressOfNames
== 0)
1090 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1095 * Get header pointers
1097 ExNames
= (PDWORD
*)RVA(BaseAddress
,
1098 ExportDir
->AddressOfNames
);
1099 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
1100 ExportDir
->AddressOfNameOrdinals
);
1101 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
1102 ExportDir
->AddressOfFunctions
);
1105 * Check the hint first
1107 if (Hint
< ExportDir
->NumberOfNames
)
1109 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1110 if (strcmp(ExName
, SymbolName
) == 0)
1112 Ordinal
= ExOrdinals
[Hint
];
1113 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1114 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1115 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1117 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1118 Function
= LdrFixupForward((PCHAR
)Function
);
1119 if (Function
== NULL
)
1121 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1125 if (Function
!= NULL
)
1131 * Try a binary search first
1134 maxn
= ExportDir
->NumberOfNames
- 1;
1135 while (minn
<= maxn
)
1140 mid
= (minn
+ maxn
) / 2;
1142 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1143 res
= strcmp(ExName
, SymbolName
);
1146 Ordinal
= ExOrdinals
[mid
];
1147 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1148 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1149 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1151 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1152 Function
= LdrFixupForward((PCHAR
)Function
);
1153 if (Function
== NULL
)
1155 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1159 if (Function
!= NULL
)
1162 else if (minn
== maxn
)
1164 DPRINT("LdrGetExportByName(): binary search failed\n");
1178 * Fall back on a linear search
1180 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1181 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1183 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1184 if (strcmp(ExName
,SymbolName
) == 0)
1186 Ordinal
= ExOrdinals
[i
];
1187 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1188 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1189 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1190 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1192 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1193 Function
= LdrFixupForward((PCHAR
)Function
);
1195 if (Function
== NULL
)
1202 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1207 /**********************************************************************
1209 * LdrPerformRelocations
1212 * Relocate a DLL's memory image.
1224 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
,
1227 USHORT NumberOfEntries
;
1229 ULONG RelocationRVA
;
1233 PRELOCATION_DIRECTORY RelocationDir
;
1234 PRELOCATION_ENTRY RelocationBlock
;
1236 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1244 PIMAGE_SECTION_HEADER Sections
;
1246 ULONG RelocationBlockOffset
;
1247 ULONG RelocationSectionSize
;
1249 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1251 return STATUS_UNSUCCESSFUL
;
1255 (PIMAGE_SECTION_HEADER
)((PVOID
)NTHeaders
+ sizeof(IMAGE_NT_HEADERS
));
1257 RelocationSectionSize
= 0;
1258 for (i
= 0; i
< NTHeaders
->FileHeader
.NumberOfSections
; i
++)
1260 if (!(Sections
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
1264 (ULONG
)(Sections
[i
].VirtualAddress
+ Sections
[i
].Misc
.VirtualSize
);
1265 MaxExtend
= max(MaxExtend
, Extend
);
1268 if (!memcmp(Sections
[i
].Name
,".reloc", 6))
1270 RelocationSectionSize
= Sections
[i
].Misc
.VirtualSize
;
1271 DPRINT("Relocation section size: %lx\n", RelocationSectionSize
);
1276 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1277 RelocationRVA
= RelocationDDir
->VirtualAddress
;
1282 (PRELOCATION_DIRECTORY
)((PCHAR
)ImageBase
+ RelocationRVA
);
1284 RelocationBlockOffset
= 0;
1285 while (RelocationBlockOffset
< RelocationSectionSize
)
1287 if (RelocationDir
->VirtualAddress
> MaxExtend
)
1289 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1291 (PRELOCATION_DIRECTORY
) (ImageBase
+ RelocationRVA
);
1295 Delta32
= (ULONG
)(ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
);
1297 (PRELOCATION_ENTRY
) (RelocationRVA
+ ImageBase
+
1298 sizeof (RELOCATION_DIRECTORY
));
1300 RelocationDir
->SizeOfBlock
- sizeof (RELOCATION_DIRECTORY
);
1301 NumberOfEntries
= NumberOfEntries
/ sizeof (RELOCATION_ENTRY
);
1303 ProtectBase
= ImageBase
+ RelocationDir
->VirtualAddress
;
1304 ProtectSize
= PAGE_SIZE
;
1305 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1310 if (!NT_SUCCESS(Status
))
1312 DPRINT1("Failed to unprotect relocation target.\n");
1316 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
< MaxExtend
)
1318 ProtectBase2
= ImageBase
+ RelocationDir
->VirtualAddress
+ PAGE_SIZE
;
1319 ProtectSize2
= PAGE_SIZE
;
1320 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1325 if (!NT_SUCCESS(Status
))
1327 DPRINT1("Failed to unprotect relocation target (2).\n");
1328 NtProtectVirtualMemory(NtCurrentProcess(),
1336 for (i
= 0; i
< NumberOfEntries
; i
++)
1338 Offset
= (RelocationBlock
[i
].TypeOffset
& 0xfff);
1339 Offset
+= (ULONG
)(RelocationDir
->VirtualAddress
+ ImageBase
);
1342 * What kind of relocations should we perform
1343 * for the current entry?
1345 switch (RelocationBlock
[i
].TypeOffset
>> 12)
1347 case TYPE_RELOC_ABSOLUTE
:
1350 case TYPE_RELOC_HIGH
:
1351 pValue16
= (PUSHORT
)Offset
;
1352 *pValue16
+= Delta32
>> 16;
1355 case TYPE_RELOC_LOW
:
1356 pValue16
= (PUSHORT
)Offset
;
1357 *pValue16
+= Delta32
& 0xffff;
1360 case TYPE_RELOC_HIGHLOW
:
1361 pValue32
= (PULONG
)Offset
;
1362 *pValue32
+= Delta32
;
1365 case TYPE_RELOC_HIGHADJ
:
1366 /* FIXME: do the highadjust fixup */
1367 DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1368 return STATUS_UNSUCCESSFUL
;
1371 DPRINT("unexpected fixup type\n");
1372 return STATUS_UNSUCCESSFUL
;
1376 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1381 if (!NT_SUCCESS(Status
))
1383 DPRINT1("Failed to protect relocation target.\n");
1387 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
< MaxExtend
)
1389 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1394 if (!NT_SUCCESS(Status
))
1396 DPRINT1("Failed to protect relocation target2.\n");
1401 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1403 (PRELOCATION_DIRECTORY
) (ImageBase
+ RelocationRVA
);
1404 RelocationBlockOffset
+= RelocationDir
->SizeOfBlock
;
1408 return STATUS_SUCCESS
;
1412 LdrpGetOrLoadModule(PWCHAR SerachPath
,
1414 PLDR_MODULE
* Module
,
1417 UNICODE_STRING DllName
;
1420 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name
);
1422 RtlCreateUnicodeStringFromAsciiz (&DllName
, Name
);
1424 Status
= LdrFindEntryForName (&DllName
, Module
, Load
);
1425 if (Load
&& !NT_SUCCESS(Status
))
1427 Status
= LdrpLoadModule(SerachPath
,
1428 NtCurrentPeb()->Ldr
->Initialized
? 0 : LDRP_PROCESS_CREATION_TIME
,
1431 if (NT_SUCCESS(Status
))
1433 Status
= LdrFindEntryForName (&DllName
, Module
, FALSE
);
1435 if (!NT_SUCCESS(Status
))
1437 DPRINT1("failed to load %wZ\n", &DllName
);
1440 RtlFreeUnicodeString (&DllName
);
1445 LdrpProcessImportDirectoryEntry(PLDR_MODULE Module
,
1446 PLDR_MODULE ImportedModule
,
1447 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
)
1450 PVOID
* ImportAddressList
;
1451 PULONG FunctionNameList
;
1457 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->dwRVAModuleName
== 0)
1459 return STATUS_UNSUCCESSFUL
;
1462 /* Get the import address list. */
1463 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1465 /* Get the list of functions to import. */
1466 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1468 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1472 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1475 /* Get the size of IAT. */
1477 while (FunctionNameList
[IATSize
] != 0L)
1482 /* Unprotect the region we are about to write into. */
1483 IATBase
= (PVOID
)ImportAddressList
;
1484 IATSize
*= sizeof(PVOID
*);
1485 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1490 if (!NT_SUCCESS(Status
))
1492 DPRINT1("Failed to unprotect IAT.\n");
1496 /* Walk through function list and fixup addresses. */
1497 while (*FunctionNameList
!= 0L)
1499 if ((*FunctionNameList
) & 0x80000000)
1501 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1502 *ImportAddressList
= LdrGetExportByOrdinal(ImportedModule
->BaseAddress
, Ordinal
);
1503 if ((*ImportAddressList
) == NULL
)
1505 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1506 return STATUS_UNSUCCESSFUL
;
1511 IMAGE_IMPORT_BY_NAME
*pe_name
;
1512 pe_name
= RVA(Module
->BaseAddress
, *FunctionNameList
);
1513 *ImportAddressList
= LdrGetExportByName(ImportedModule
->BaseAddress
, pe_name
->Name
, pe_name
->Hint
);
1514 if ((*ImportAddressList
) == NULL
)
1516 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1517 return STATUS_UNSUCCESSFUL
;
1520 ImportAddressList
++;
1524 /* Protect the region we are about to write into. */
1525 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1530 if (!NT_SUCCESS(Status
))
1532 DPRINT1("Failed to protect IAT.\n");
1536 return STATUS_SUCCESS
;
1540 LdrpProcessImportDirectory(
1542 PLDR_MODULE ImportedModule
,
1546 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1549 DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
1550 Module
, &Module
->BaseDllName
, ImportedName
);
1553 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1554 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1556 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1558 if (ImportModuleDirectory
== NULL
)
1560 return STATUS_UNSUCCESSFUL
;
1563 while (ImportModuleDirectory
->dwRVAModuleName
)
1565 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1566 if (0 == _stricmp(Name
, ImportedName
))
1568 Status
= LdrpProcessImportDirectoryEntry(Module
,
1570 ImportModuleDirectory
);
1571 if (!NT_SUCCESS(Status
))
1576 ImportModuleDirectory
++;
1580 return STATUS_SUCCESS
;
1585 LdrpAdjustImportDirectory(PLDR_MODULE Module
,
1586 PLDR_MODULE ImportedModule
,
1587 PUCHAR ImportedName
)
1589 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1591 PVOID
* ImportAddressList
;
1594 PULONG FunctionNameList
;
1599 PIMAGE_NT_HEADERS NTHeaders
;
1602 DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
1603 Module
, &Module
->BaseDllName
, ImportedModule
, &ImportedModule
->BaseDllName
, ImportedName
);
1605 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1606 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1608 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1610 if (ImportModuleDirectory
== NULL
)
1612 return STATUS_UNSUCCESSFUL
;
1615 while (ImportModuleDirectory
->dwRVAModuleName
)
1617 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
1618 if (0 == _stricmp(Name
, ImportedName
))
1621 /* Get the import address list. */
1622 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1624 /* Get the list of functions to import. */
1625 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1627 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionNameList
);
1631 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAFunctionAddressList
);
1634 /* Get the size of IAT. */
1636 while (FunctionNameList
[IATSize
] != 0L)
1641 /* Unprotect the region we are about to write into. */
1642 IATBase
= (PVOID
)ImportAddressList
;
1643 IATSize
*= sizeof(PVOID
*);
1644 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1649 if (!NT_SUCCESS(Status
))
1651 DPRINT1("Failed to unprotect IAT.\n");
1655 NTHeaders
= RtlImageNtHeader (ImportedModule
->BaseAddress
);
1656 Start
= (PVOID
)NTHeaders
->OptionalHeader
.ImageBase
;
1657 End
= Start
+ ImportedModule
->SizeOfImage
;
1658 Offset
= ImportedModule
->BaseAddress
- Start
;
1660 /* Walk through function list and fixup addresses. */
1661 while (*FunctionNameList
!= 0L)
1663 if (*ImportAddressList
>= Start
&& *ImportAddressList
< End
)
1665 (*ImportAddressList
) += Offset
;
1667 ImportAddressList
++;
1671 /* Protect the region we are about to write into. */
1672 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1677 if (!NT_SUCCESS(Status
))
1679 DPRINT1("Failed to protect IAT.\n");
1683 ImportModuleDirectory
++;
1685 return STATUS_SUCCESS
;
1689 /**********************************************************************
1694 * Compute the entry point for every symbol the DLL imports
1695 * from other modules.
1707 LdrFixupImports(IN PWSTR SearchPath OPTIONAL
,
1708 IN PLDR_MODULE Module
)
1710 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1711 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectoryCurrent
;
1712 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
1713 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
1714 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1717 PLDR_MODULE ImportedModule
;
1720 DPRINT("LdrFixupImports(SearchPath %x, Module %x)\n", SearchPath
, Module
);
1722 /* Check for tls data */
1723 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
1724 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1726 IMAGE_DIRECTORY_ENTRY_TLS
,
1730 TlsSize
= TlsDirectory
->EndAddressOfRawData
1731 - TlsDirectory
->StartAddressOfRawData
1732 + TlsDirectory
->SizeOfZeroFill
;
1734 NtCurrentPeb()->Ldr
->Initialized
)
1736 TRACE_LDR("Trying to load dynamicly %wZ which contains a tls directory\n",
1737 &Module
->BaseDllName
);
1738 return STATUS_UNSUCCESSFUL
;
1742 * Process each import module.
1744 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1745 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1747 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1750 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
1751 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1753 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
1756 if (BoundImportDescriptor
!= NULL
&& ImportModuleDirectory
== NULL
)
1758 DPRINT1("%wZ has only a bound import directory\n", &Module
->BaseDllName
);
1759 return STATUS_UNSUCCESSFUL
;
1761 if (BoundImportDescriptor
)
1763 DPRINT("BoundImportDescriptor %x\n", BoundImportDescriptor
);
1765 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
1766 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
1768 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
1769 TRACE_LDR("%wZ bound to %s\n", &Module
->BaseDllName
, ImportedName
);
1770 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1771 if (!NT_SUCCESS(Status
))
1773 DPRINT1("failed to load %s\n", ImportedName
);
1776 if (Module
== ImportedModule
)
1778 LdrpDecrementLoadCount(Module
, FALSE
);
1780 if (ImportedModule
->TimeDateStamp
!= BoundImportDescriptorCurrent
->TimeDateStamp
)
1782 TRACE_LDR("%wZ has stale binding to %wZ\n",
1783 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1784 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1785 if (!NT_SUCCESS(Status
))
1787 DPRINT1("failed to import %s\n", ImportedName
);
1793 BOOL WrongForwarder
;
1794 WrongForwarder
= FALSE
;
1795 if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1797 TRACE_LDR("%wZ has stale binding to %s\n",
1798 &Module
->BaseDllName
, ImportedName
);
1802 TRACE_LDR("%wZ has correct binding to %wZ\n",
1803 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1805 if (BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
)
1807 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef
;
1809 PLDR_MODULE ForwarderModule
;
1810 PUCHAR ForwarderName
;
1812 BoundForwarderRef
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundImportDescriptorCurrent
+ 1);
1813 for (i
= 0; i
< BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
; i
++, BoundForwarderRef
++)
1815 ForwarderName
= (PCHAR
)BoundImportDescriptor
+ BoundForwarderRef
->OffsetModuleName
;
1816 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1817 &Module
->BaseDllName
, ForwarderName
, ImportedName
);
1818 Status
= LdrpGetOrLoadModule(SearchPath
, ForwarderName
, &ForwarderModule
, TRUE
);
1819 if (!NT_SUCCESS(Status
))
1821 DPRINT1("failed to load %s\n", ForwarderName
);
1824 if (Module
== ImportedModule
)
1826 LdrpDecrementLoadCount(Module
, FALSE
);
1828 if (ForwarderModule
->TimeDateStamp
!= BoundForwarderRef
->TimeDateStamp
||
1829 ForwarderModule
->Flags
& IMAGE_NOT_AT_BASE
)
1831 TRACE_LDR("%wZ has stale binding to %s\n",
1832 &Module
->BaseDllName
, ForwarderName
);
1833 WrongForwarder
= TRUE
;
1837 TRACE_LDR("%wZ has correct binding to %s\n",
1838 &Module
->BaseDllName
, ForwarderName
);
1842 if (WrongForwarder
||
1843 ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1845 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1846 if (!NT_SUCCESS(Status
))
1848 DPRINT1("failed to import %s\n", ImportedName
);
1852 else if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1854 TRACE_LDR("Adjust imports for %s from %wZ\n",
1855 ImportedName
, &Module
->BaseDllName
);
1856 Status
= LdrpAdjustImportDirectory(Module
, ImportedModule
, ImportedName
);
1857 if (!NT_SUCCESS(Status
))
1859 DPRINT1("failed to adjust import entries for %s\n", ImportedName
);
1863 else if (WrongForwarder
)
1867 * Update only forwarders
1869 TRACE_LDR("Stale BIND %s from %wZ\n",
1870 ImportedName
, &Module
->BaseDllName
);
1871 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1872 if (!NT_SUCCESS(Status
))
1874 DPRINT1("faild to import %s\n", ImportedName
);
1883 BoundImportDescriptorCurrent
+= BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
+ 1;
1886 else if (ImportModuleDirectory
)
1888 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1890 ImportModuleDirectoryCurrent
= ImportModuleDirectory
;
1891 while (ImportModuleDirectoryCurrent
->dwRVAModuleName
)
1893 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectoryCurrent
->dwRVAModuleName
;
1894 TRACE_LDR("%wZ imports functions from %s\n", &Module
->BaseDllName
, ImportedName
);
1896 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1897 if (!NT_SUCCESS(Status
))
1899 DPRINT1("failed to load %s\n", ImportedName
);
1902 if (Module
== ImportedModule
)
1904 LdrpDecrementLoadCount(Module
, FALSE
);
1907 TRACE_LDR("Initializing imports for %wZ from %s\n",
1908 &Module
->BaseDllName
, ImportedName
);
1909 Status
= LdrpProcessImportDirectoryEntry(Module
, ImportedModule
, ImportModuleDirectoryCurrent
);
1910 if (!NT_SUCCESS(Status
))
1912 DPRINT1("failed to import %s\n", ImportedName
);
1915 ImportModuleDirectoryCurrent
++;
1919 if (TlsDirectory
&& TlsSize
> 0)
1921 LdrpAcquireTlsSlot(Module
, TlsSize
, FALSE
);
1924 return STATUS_SUCCESS
;
1928 /**********************************************************************
1933 * 1. Relocate, if needed the EXE.
1934 * 2. Fixup any imported symbol.
1935 * 3. Compute the EXE's entry point.
1939 * Address at which the EXE's image
1943 * Handle of the section that contains
1947 * NULL on error; otherwise the entry point
1948 * to call for initializing the DLL.
1953 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
1954 * Currently the function is only used for the exe.
1956 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1957 HANDLE SectionHandle
,
1958 PLDR_MODULE
* Module
,
1962 PEPFUNC EntryPoint
= NULL
;
1963 PIMAGE_DOS_HEADER DosHeader
;
1964 PIMAGE_NT_HEADERS NTHeaders
;
1965 PLDR_MODULE tmpModule
;
1967 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1968 ImageBase
, (ULONG
)SectionHandle
);
1971 * Overlay DOS and WNT headers structures
1972 * to the DLL's image.
1974 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1975 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1978 * If the base address is different from the
1979 * one the DLL is actually loaded, perform any
1982 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1984 DPRINT("LDR: Performing relocations\n");
1985 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1986 if (!NT_SUCCESS(Status
))
1988 DPRINT1("LdrPerformRelocations() failed\n");
1995 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1996 (*Module
)->SectionHandle
= SectionHandle
;
2000 Module
= &tmpModule
;
2001 Status
= LdrFindEntryForAddress(ImageBase
, Module
);
2002 if (!NT_SUCCESS(Status
))
2008 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
2010 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
2014 * If the DLL's imports symbols from other
2015 * modules, fixup the imported calls entry points.
2017 DPRINT("About to fixup imports\n");
2018 Status
= LdrFixupImports(NULL
, *Module
);
2019 if (!NT_SUCCESS(Status
))
2021 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module
)->BaseDllName
);
2024 DPRINT("Fixup done\n");
2025 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2026 Status
= LdrpInitializeTlsForProccess();
2027 if (NT_SUCCESS(Status
))
2029 Status
= LdrpAttachProcess();
2031 if (NT_SUCCESS(Status
))
2033 LdrpTlsCallback(*Module
, DLL_PROCESS_ATTACH
);
2037 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
2038 if (!NT_SUCCESS(Status
))
2045 * Compute the DLL's entry point's address.
2047 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
2048 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
2049 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
2051 EntryPoint
= (PEPFUNC
) (ImageBase
2052 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
2054 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
2059 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
2061 IN PUNICODE_STRING Name
,
2062 PLDR_MODULE
*Module
)
2064 UNICODE_STRING AdjustedName
;
2065 UNICODE_STRING FullDosName
;
2067 PLDR_MODULE tmpModule
;
2068 HANDLE SectionHandle
;
2071 PIMAGE_NT_HEADERS NtHeaders
;
2075 Module
= &tmpModule
;
2077 /* adjust the full dll name */
2078 LdrAdjustDllName(&AdjustedName
, Name
, FALSE
);
2080 DPRINT("%wZ\n", &AdjustedName
);
2082 /* Test if dll is already loaded */
2083 Status
= LdrFindEntryForName(&AdjustedName
, Module
, TRUE
);
2084 if (NT_SUCCESS(Status
))
2086 RtlFreeUnicodeString(&AdjustedName
);
2090 /* Open or create dll image section */
2091 Status
= LdrpMapKnownDll(&AdjustedName
, &FullDosName
, &SectionHandle
);
2092 if (!NT_SUCCESS(Status
))
2094 Status
= LdrpMapDllImageFile(SearchPath
, &AdjustedName
, &FullDosName
, &SectionHandle
);
2096 if (!NT_SUCCESS(Status
))
2098 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName
, Status
);
2099 RtlFreeUnicodeString(&AdjustedName
);
2100 RtlFreeUnicodeString(&FullDosName
);
2103 RtlFreeUnicodeString(&AdjustedName
);
2104 /* Map the dll into the process */
2107 Status
= NtMapViewOfSection(SectionHandle
,
2117 if (!NT_SUCCESS(Status
))
2119 DPRINT1("map view of section failed (Status %x)\n", Status
);
2120 RtlFreeUnicodeString(&FullDosName
);
2121 NtClose(SectionHandle
);
2124 /* Get and check the NT headers */
2125 NtHeaders
= RtlImageNtHeader(ImageBase
);
2126 if (NtHeaders
== NULL
)
2128 DPRINT1("RtlImageNtHeaders() failed\n");
2129 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2130 NtClose (SectionHandle
);
2131 RtlFreeUnicodeString(&FullDosName
);
2132 return STATUS_UNSUCCESSFUL
;
2134 /* If the base address is different from the
2135 * one the DLL is actually loaded, perform any
2137 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2139 DPRINT1("Relocating (%x -> %x) %wZ\n",
2140 NtHeaders
->OptionalHeader
.ImageBase
, ImageBase
, &FullDosName
);
2141 Status
= LdrPerformRelocations(NtHeaders
, ImageBase
);
2142 if (!NT_SUCCESS(Status
))
2144 DPRINT1("LdrPerformRelocations() failed\n");
2145 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2146 NtClose (SectionHandle
);
2147 RtlFreeUnicodeString(&FullDosName
);
2148 return STATUS_UNSUCCESSFUL
;
2151 *Module
= LdrAddModuleEntry(ImageBase
, NtHeaders
, FullDosName
.Buffer
);
2152 (*Module
)->SectionHandle
= SectionHandle
;
2153 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2155 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
2157 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
2159 (*Module
)->Flags
|= IMAGE_DLL
;
2161 /* fixup the imported calls entry points */
2162 Status
= LdrFixupImports(SearchPath
, *Module
);
2163 if (!NT_SUCCESS(Status
))
2165 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module
)->BaseDllName
, Status
);
2169 LdrpLoadUserModuleSymbols(*Module
);
2171 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2172 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
2173 &(*Module
)->InInitializationOrderModuleList
);
2174 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2176 return STATUS_SUCCESS
;
2180 LdrpUnloadModule(PLDR_MODULE Module
,
2183 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
2184 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
2185 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
2187 PLDR_MODULE ImportedModule
;
2194 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2197 LoadCount
= LdrpDecrementLoadCount(Module
, Unload
);
2199 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module
->BaseDllName
, LoadCount
);
2203 /* ?????????????????? */
2206 else if (LoadCount
== 1)
2208 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
2209 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2211 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
2213 if (BoundImportDescriptor
)
2215 /* dereferencing all imported modules, use the bound import descriptor */
2216 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
2217 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
2219 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
2220 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2221 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2222 if (!NT_SUCCESS(Status
))
2224 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2228 if (Module
!= ImportedModule
)
2230 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2231 if (!NT_SUCCESS(Status
))
2233 DPRINT1("unable to unload %s\n", ImportedName
);
2237 BoundImportDescriptorCurrent
++;
2242 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
2243 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2245 IMAGE_DIRECTORY_ENTRY_IMPORT
,
2247 if (ImportModuleDirectory
)
2249 /* dereferencing all imported modules, use the import descriptor */
2250 while (ImportModuleDirectory
->dwRVAModuleName
)
2252 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->dwRVAModuleName
;
2253 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2254 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2255 if (!NT_SUCCESS(Status
))
2257 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2261 if (Module
!= ImportedModule
)
2263 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2264 if (!NT_SUCCESS(Status
))
2266 DPRINT1("unable to unload %s\n", ImportedName
);
2270 ImportModuleDirectory
++;
2278 LdrpDetachProcess(FALSE
);
2279 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2281 return STATUS_SUCCESS
;
2289 LdrUnloadDll (IN PVOID BaseAddress
)
2294 if (BaseAddress
== NULL
)
2295 return STATUS_SUCCESS
;
2297 Status
= LdrFindEntryForAddress(BaseAddress
, &Module
);
2298 if (NT_SUCCESS(Status
))
2300 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module
->BaseDllName
);
2301 Status
= LdrpUnloadModule(Module
, TRUE
);
2310 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
2312 PLIST_ENTRY ModuleListHead
;
2317 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
2319 Status
= STATUS_DLL_NOT_FOUND
;
2320 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2321 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2322 Entry
= ModuleListHead
->Flink
;
2323 while (Entry
!= ModuleListHead
)
2325 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2327 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
2329 if (Module
->BaseAddress
== BaseAddress
)
2331 if (Module
->TlsIndex
== -1)
2333 Module
->Flags
|= DONT_CALL_FOR_THREAD
;
2334 Status
= STATUS_SUCCESS
;
2338 Entry
= Entry
->Flink
;
2340 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2348 LdrGetDllHandle(IN PWCHAR Path OPTIONAL
,
2350 IN PUNICODE_STRING DllName
,
2351 OUT PVOID
* BaseAddress
)
2356 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName
, Path
? Path
: L
"");
2358 /* NULL is the current executable */
2359 if (DllName
== NULL
)
2361 *BaseAddress
= ExeModule
->BaseAddress
;
2362 DPRINT("BaseAddress %x\n", *BaseAddress
);
2363 return STATUS_SUCCESS
;
2366 Status
= LdrFindEntryForName(DllName
, &Module
, FALSE
);
2367 if (NT_SUCCESS(Status
))
2369 *BaseAddress
= Module
->BaseAddress
;
2370 return STATUS_SUCCESS
;
2373 DPRINT("Failed to find dll %wZ\n", DllName
);
2374 *BaseAddress
= NULL
;
2375 return STATUS_DLL_NOT_FOUND
;
2383 LdrGetProcedureAddress (IN PVOID BaseAddress
,
2384 IN PANSI_STRING Name
,
2386 OUT PVOID
*ProcedureAddress
)
2388 if (Name
&& Name
->Length
)
2390 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name
);
2394 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal
);
2397 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
2398 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
2400 if (Name
&& Name
->Length
)
2403 *ProcedureAddress
= LdrGetExportByName(BaseAddress
, Name
->Buffer
, 0xffff);
2404 if (*ProcedureAddress
!= NULL
)
2406 return STATUS_SUCCESS
;
2408 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
2413 Ordinal
&= 0x0000FFFF;
2414 *ProcedureAddress
= LdrGetExportByOrdinal(BaseAddress
, (WORD
)Ordinal
);
2415 if (*ProcedureAddress
)
2417 return STATUS_SUCCESS
;
2419 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
2421 return STATUS_PROCEDURE_NOT_FOUND
;
2424 /**********************************************************************
2429 * Unload dll's which are no longer referenced from others dll's
2440 * The loader lock must be held on enty.
2443 LdrpDetachProcess(BOOL UnloadAll
)
2445 PLIST_ENTRY ModuleListHead
;
2448 static ULONG CallingCount
= 0;
2450 DPRINT("LdrpDetachProcess() called for %wZ\n",
2451 &ExeModule
->BaseDllName
);
2455 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2456 Entry
= ModuleListHead
->Blink
;
2457 while (Entry
!= ModuleListHead
)
2459 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2460 if (((UnloadAll
&& Module
->LoadCount
<= 0) || Module
->LoadCount
== 0) &&
2461 Module
->Flags
& ENTRY_PROCESSED
&&
2462 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2464 Module
->Flags
|= UNLOAD_IN_PROGRESS
;
2465 if (Module
== LdrpLastModule
)
2467 LdrpLastModule
= NULL
;
2469 if (Module
->Flags
& PROCESS_ATTACH_CALLED
)
2471 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2472 &Module
->BaseDllName
, Module
->EntryPoint
);
2473 LdrpCallDllEntry(Module
, DLL_PROCESS_DETACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2477 TRACE_LDR("Unload %wZ\n", &Module
->BaseDllName
);
2479 Entry
= ModuleListHead
->Blink
;
2483 Entry
= Entry
->Blink
;
2487 if (CallingCount
== 1)
2489 Entry
= ModuleListHead
->Blink
;
2490 while (Entry
!= ModuleListHead
)
2492 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2493 Entry
= Entry
->Blink
;
2494 if (Module
->Flags
& UNLOAD_IN_PROGRESS
&&
2495 ((UnloadAll
&& Module
->LoadCount
>= 0) || Module
->LoadCount
== 0))
2497 /* remove the module entry from the list */
2498 RemoveEntryList (&Module
->InLoadOrderModuleList
)
2499 RemoveEntryList (&Module
->InInitializationOrderModuleList
);
2501 NtUnmapViewOfSection (NtCurrentProcess (), Module
->BaseAddress
);
2502 NtClose (Module
->SectionHandle
);
2504 TRACE_LDR("%wZ unloaded\n", &Module
->BaseDllName
);
2506 RtlFreeUnicodeString (&Module
->FullDllName
);
2507 RtlFreeUnicodeString (&Module
->BaseDllName
);
2509 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
2514 DPRINT("LdrpDetachProcess() done\n");
2517 /**********************************************************************
2522 * Initialize all dll's which are prepered for loading
2533 * The loader lock must be held on entry.
2537 LdrpAttachProcess(VOID
)
2539 PLIST_ENTRY ModuleListHead
;
2543 NTSTATUS Status
= STATUS_SUCCESS
;
2545 DPRINT("LdrpAttachProcess() called for %wZ\n",
2546 &ExeModule
->BaseDllName
);
2548 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2549 Entry
= ModuleListHead
->Flink
;
2550 while (Entry
!= ModuleListHead
)
2552 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2553 if (!(Module
->Flags
& (LOAD_IN_PROGRESS
|UNLOAD_IN_PROGRESS
|ENTRY_PROCESSED
)))
2555 Module
->Flags
|= LOAD_IN_PROGRESS
;
2556 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2557 &Module
->BaseDllName
, Module
->EntryPoint
);
2558 Result
= LdrpCallDllEntry(Module
, DLL_PROCESS_ATTACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2561 Status
= STATUS_DLL_INIT_FAILED
;
2564 if (Module
->Flags
& IMAGE_DLL
&& Module
->EntryPoint
!= 0)
2566 Module
->Flags
|= PROCESS_ATTACH_CALLED
|ENTRY_PROCESSED
;
2570 Module
->Flags
|= ENTRY_PROCESSED
;
2572 Module
->Flags
&= ~LOAD_IN_PROGRESS
;
2574 Entry
= Entry
->Flink
;
2577 DPRINT("LdrpAttachProcess() done\n");
2586 LdrShutdownProcess (VOID
)
2588 LdrpDetachProcess(TRUE
);
2589 return STATUS_SUCCESS
;
2597 LdrpAttachThread (VOID
)
2599 PLIST_ENTRY ModuleListHead
;
2604 DPRINT("LdrpAttachThread() called for %wZ\n",
2605 &ExeModule
->BaseDllName
);
2607 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2609 Status
= LdrpInitializeTlsForThread();
2611 if (NT_SUCCESS(Status
))
2613 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2614 Entry
= ModuleListHead
->Flink
;
2616 while (Entry
!= ModuleListHead
)
2618 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2619 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2620 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2621 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2623 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2624 &Module
->BaseDllName
, Module
->EntryPoint
);
2625 LdrpCallDllEntry(Module
, DLL_THREAD_ATTACH
, NULL
);
2627 Entry
= Entry
->Flink
;
2630 Entry
= NtCurrentPeb()->Ldr
->InLoadOrderModuleList
.Flink
;
2631 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2632 LdrpTlsCallback(Module
, DLL_THREAD_ATTACH
);
2635 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2637 DPRINT("LdrpAttachThread() done\n");
2647 LdrShutdownThread (VOID
)
2649 PLIST_ENTRY ModuleListHead
;
2653 DPRINT("LdrShutdownThread() called for %wZ\n",
2654 &ExeModule
->BaseDllName
);
2656 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2658 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2659 Entry
= ModuleListHead
->Blink
;
2660 while (Entry
!= ModuleListHead
)
2662 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2664 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2665 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2666 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2668 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2669 &Module
->BaseDllName
, Module
->EntryPoint
);
2670 LdrpCallDllEntry(Module
, DLL_THREAD_DETACH
, NULL
);
2672 Entry
= Entry
->Blink
;
2675 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2679 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer
);
2682 DPRINT("LdrShutdownThread() done\n");
2684 return STATUS_SUCCESS
;
2688 /***************************************************************************
2690 * LdrQueryProcessModuleInformation
2705 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
2706 IN ULONG Size OPTIONAL
,
2707 OUT PULONG ReturnedSize
)
2709 PLIST_ENTRY ModuleListHead
;
2712 PMODULE_ENTRY ModulePtr
= NULL
;
2713 NTSTATUS Status
= STATUS_SUCCESS
;
2714 ULONG UsedSize
= sizeof(ULONG
);
2715 ANSI_STRING AnsiString
;
2718 DPRINT("LdrQueryProcessModuleInformation() called\n");
2720 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2722 if (ModuleInformation
== NULL
|| Size
== 0)
2724 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2728 ModuleInformation
->ModuleCount
= 0;
2729 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
2730 Status
= STATUS_SUCCESS
;
2733 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2734 Entry
= ModuleListHead
->Flink
;
2736 while (Entry
!= ModuleListHead
)
2738 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2740 DPRINT(" Module %wZ\n",
2741 &Module
->FullDllName
);
2743 if (UsedSize
> Size
)
2745 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2747 else if (ModuleInformation
!= NULL
)
2749 ModulePtr
->Unknown0
= 0; // FIXME: ??
2750 ModulePtr
->Unknown1
= 0; // FIXME: ??
2751 ModulePtr
->BaseAddress
= Module
->BaseAddress
;
2752 ModulePtr
->SizeOfImage
= Module
->SizeOfImage
;
2753 ModulePtr
->Flags
= Module
->Flags
;
2754 ModulePtr
->Unknown2
= 0; // FIXME: load order index ??
2755 ModulePtr
->Unknown3
= 0; // FIXME: ??
2756 ModulePtr
->LoadCount
= Module
->LoadCount
;
2758 AnsiString
.Length
= 0;
2759 AnsiString
.MaximumLength
= 256;
2760 AnsiString
.Buffer
= ModulePtr
->ModuleName
;
2761 RtlUnicodeStringToAnsiString(&AnsiString
,
2762 &Module
->FullDllName
,
2764 p
= strrchr(ModulePtr
->ModuleName
, '\\');
2766 ModulePtr
->PathLength
= p
- ModulePtr
->ModuleName
+ 1;
2768 ModulePtr
->PathLength
= 0;
2771 ModuleInformation
->ModuleCount
++;
2773 UsedSize
+= sizeof(MODULE_ENTRY
);
2775 Entry
= Entry
->Flink
;
2778 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2780 if (ReturnedSize
!= 0)
2781 *ReturnedSize
= UsedSize
;
2783 DPRINT("LdrQueryProcessModuleInformation() done\n");
2790 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
2793 PIMAGE_NT_HEADERS Header
;
2800 Header
= RtlImageNtHeader (BaseAddress
);
2804 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
2809 Ptr
= (PUSHORT
) BaseAddress
;
2810 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
2813 if (HIWORD(Sum
) != 0)
2815 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2822 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
2823 if (HIWORD(Sum
) != 0)
2825 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2829 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
2831 /* Subtract image checksum from calculated checksum. */
2832 /* fix low word of checksum */
2833 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
2835 CalcSum
-= LOWORD(HeaderSum
);
2839 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
2842 /* fix high word of checksum */
2843 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
2845 CalcSum
-= HIWORD(HeaderSum
);
2849 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
2852 /* add file length */
2853 CalcSum
+= ImageSize
;
2855 return (BOOLEAN
)(CalcSum
== HeaderSum
);
2859 /***************************************************************************
2861 * LdrVerifyImageMatchesChecksum
2876 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
2881 FILE_STANDARD_INFORMATION FileInfo
;
2882 IO_STATUS_BLOCK IoStatusBlock
;
2883 HANDLE SectionHandle
;
2889 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2891 Status
= NtCreateSection (&SectionHandle
,
2892 SECTION_MAP_EXECUTE
,
2898 if (!NT_SUCCESS(Status
))
2900 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
2906 Status
= NtMapViewOfSection (SectionHandle
,
2907 NtCurrentProcess (),
2916 if (!NT_SUCCESS(Status
))
2918 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2919 NtClose (SectionHandle
);
2923 Status
= NtQueryInformationFile (FileHandle
,
2926 sizeof (FILE_STANDARD_INFORMATION
),
2927 FileStandardInformation
);
2928 if (!NT_SUCCESS(Status
))
2930 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2931 NtUnmapViewOfSection (NtCurrentProcess (),
2933 NtClose (SectionHandle
);
2937 Result
= LdrpCheckImageChecksum (BaseAddress
,
2938 FileInfo
.EndOfFile
.u
.LowPart
);
2939 if (Result
== FALSE
)
2941 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2944 NtUnmapViewOfSection (NtCurrentProcess (),
2947 NtClose (SectionHandle
);
2953 /***************************************************************************
2955 * LdrQueryImageFileExecutionOptions
2970 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
2971 IN PCWSTR ValueName
,
2974 IN ULONG BufferSize
,
2975 OUT PULONG ReturnedLength OPTIONAL
)
2977 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2978 OBJECT_ATTRIBUTES ObjectAttributes
;
2979 UNICODE_STRING ValueNameString
;
2980 UNICODE_STRING KeyName
;
2981 WCHAR NameBuffer
[256];
2989 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2990 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
2993 Ptr
= SubKey
->Buffer
;
2999 wcscat (NameBuffer
, Ptr
);
3000 RtlInitUnicodeString (&KeyName
,
3003 InitializeObjectAttributes (&ObjectAttributes
,
3005 OBJ_CASE_INSENSITIVE
,
3009 Status
= NtOpenKey (&KeyHandle
,
3012 if (!NT_SUCCESS(Status
))
3014 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
3018 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
3019 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3023 RtlInitUnicodeString (&ValueNameString
,
3025 Status
= NtQueryValueKey (KeyHandle
,
3027 KeyValuePartialInformation
,
3031 if (Status
== STATUS_BUFFER_OVERFLOW
)
3033 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
3034 RtlFreeHeap (RtlGetProcessHeap(),
3037 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3040 if (KeyInfo
== NULL
)
3042 NtClose (KeyHandle
);
3046 Status
= NtQueryValueKey (KeyHandle
,
3048 KeyValuePartialInformation
,
3053 NtClose (KeyHandle
);
3055 if (!NT_SUCCESS(Status
))
3057 if (KeyInfo
!= NULL
)
3059 RtlFreeHeap (RtlGetProcessHeap(),
3066 if (KeyInfo
->Type
!= Type
)
3068 RtlFreeHeap (RtlGetProcessHeap(),
3071 return STATUS_OBJECT_TYPE_MISMATCH
;
3074 ResultSize
= BufferSize
;
3075 if (ResultSize
< KeyInfo
->DataLength
)
3077 Status
= STATUS_BUFFER_OVERFLOW
;
3081 ResultSize
= KeyInfo
->DataLength
;
3083 RtlCopyMemory (Buffer
,
3087 RtlFreeHeap (RtlGetProcessHeap(),
3091 if (ReturnedLength
!= NULL
)
3093 *ReturnedLength
= ResultSize
;