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 *****************************************************************/
26 #define LDRP_PROCESS_CREATION_TIME 0x8000000
28 /* GLOBALS *******************************************************************/
32 #define TRACE_LDR(args...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); }
36 #define TRACE_LDR(args...) do { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0)
39 typedef struct _TLS_DATA
41 PVOID StartAddressOfRawData
;
44 PIMAGE_TLS_CALLBACK TlsAddressOfCallBacks
;
46 } TLS_DATA
, *PTLS_DATA
;
48 static PTLS_DATA LdrpTlsArray
= NULL
;
49 static ULONG LdrpTlsCount
= 0;
50 static ULONG LdrpTlsSize
= 0;
51 static HANDLE LdrpKnownDllsDirHandle
= NULL
;
52 static UNICODE_STRING LdrpKnownDllPath
= {0, 0, NULL
};
53 static PLDR_MODULE LdrpLastModule
= NULL
;
54 extern PLDR_MODULE ExeModule
;
56 /* PROTOTYPES ****************************************************************/
58 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_MODULE
*Module
, BOOLEAN Ref
);
59 static PVOID
LdrFixupForward(PCHAR ForwardName
);
60 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
61 static NTSTATUS
LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
63 IN PUNICODE_STRING Name
,
64 OUT PLDR_MODULE
*Module
,
65 OUT PVOID
*BaseAddress OPTIONAL
);
66 static NTSTATUS
LdrpAttachProcess(VOID
);
67 static VOID
LdrpDetachProcess(BOOLEAN UnloadAll
);
69 /* FUNCTIONS *****************************************************************/
71 #if defined(DBG) || defined(KDBG)
74 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
85 #endif /* DBG || KDBG */
88 LdrMappedAsDataFile(PVOID
*BaseAddress
)
90 if (0 != ((DWORD_PTR
) *BaseAddress
& (PAGE_SIZE
- 1)))
92 *BaseAddress
= (PVOID
) ((DWORD_PTR
) *BaseAddress
& ~ ((DWORD_PTR
) PAGE_SIZE
- 1));
99 static inline LONG
LdrpDecrementLoadCount(PLDR_MODULE Module
, BOOLEAN Locked
)
104 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
106 LoadCount
= Module
->LoadCount
;
107 if (Module
->LoadCount
> 0)
113 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
118 static inline LONG
LdrpIncrementLoadCount(PLDR_MODULE Module
, BOOLEAN Locked
)
123 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
125 LoadCount
= Module
->LoadCount
;
126 if (Module
->LoadCount
>= 0)
132 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
137 static inline VOID
LdrpAcquireTlsSlot(PLDR_MODULE Module
, ULONG Size
, BOOLEAN Locked
)
141 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
143 Module
->TlsIndex
= (SHORT
)LdrpTlsCount
;
148 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
152 static inline VOID
LdrpTlsCallback(PLDR_MODULE Module
, ULONG dwReason
)
154 PIMAGE_TLS_CALLBACK TlsCallback
;
155 if (Module
->TlsIndex
>= 0 && Module
->LoadCount
== -1)
157 TlsCallback
= LdrpTlsArray
[Module
->TlsIndex
].TlsAddressOfCallBacks
;
162 TRACE_LDR("%wZ - Calling tls callback at %x\n",
163 &Module
->BaseDllName
, TlsCallback
);
164 TlsCallback(Module
->BaseAddress
, dwReason
, NULL
);
171 static BOOLEAN
LdrpCallDllEntry(PLDR_MODULE Module
, DWORD dwReason
, PVOID lpReserved
)
173 if (!(Module
->Flags
& IMAGE_DLL
) ||
174 Module
->EntryPoint
== 0)
178 LdrpTlsCallback(Module
, dwReason
);
179 return ((PDLLMAIN_FUNC
)Module
->EntryPoint
)(Module
->BaseAddress
, dwReason
, lpReserved
);
183 LdrpInitializeTlsForThread(VOID
)
189 PTEB Teb
= NtCurrentTeb();
191 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule
->BaseDllName
);
193 Teb
->StaticUnicodeString
.Length
= 0;
194 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
195 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
197 if (LdrpTlsCount
> 0)
199 TlsPointers
= RtlAllocateHeap(RtlGetProcessHeap(),
201 LdrpTlsCount
* sizeof(PVOID
) + LdrpTlsSize
);
202 if (TlsPointers
== NULL
)
204 DPRINT1("failed to allocate thread tls data\n");
205 return STATUS_NO_MEMORY
;
208 TlsData
= (PVOID
)TlsPointers
+ LdrpTlsCount
* sizeof(PVOID
);
209 Teb
->ThreadLocalStoragePointer
= TlsPointers
;
211 TlsInfo
= LdrpTlsArray
;
212 for (i
= 0; i
< LdrpTlsCount
; i
++, TlsInfo
++)
214 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo
->Module
->BaseDllName
);
215 TlsPointers
[i
] = TlsData
;
216 if (TlsInfo
->TlsDataSize
)
218 memcpy(TlsData
, TlsInfo
->StartAddressOfRawData
, TlsInfo
->TlsDataSize
);
219 TlsData
+= TlsInfo
->TlsDataSize
;
221 if (TlsInfo
->TlsZeroSize
)
223 memset(TlsData
, 0, TlsInfo
->TlsZeroSize
);
224 TlsData
+= TlsInfo
->TlsZeroSize
;
228 DPRINT("LdrpInitializeTlsForThread() done\n");
229 return STATUS_SUCCESS
;
233 LdrpInitializeTlsForProccess(VOID
)
235 PLIST_ENTRY ModuleListHead
;
238 PIMAGE_TLS_DIRECTORY TlsDirectory
;
241 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule
->BaseDllName
);
243 if (LdrpTlsCount
> 0)
245 LdrpTlsArray
= RtlAllocateHeap(RtlGetProcessHeap(),
247 LdrpTlsCount
* sizeof(TLS_DATA
));
248 if (LdrpTlsArray
== NULL
)
250 DPRINT1("Failed to allocate global tls data\n");
251 return STATUS_NO_MEMORY
;
254 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
255 Entry
= ModuleListHead
->Flink
;
256 while (Entry
!= ModuleListHead
)
258 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
259 if (Module
->LoadCount
== -1 &&
260 Module
->TlsIndex
>= 0)
262 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
263 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
265 IMAGE_DIRECTORY_ENTRY_TLS
,
267 ASSERT(Module
->TlsIndex
< LdrpTlsCount
);
268 TlsData
= &LdrpTlsArray
[Module
->TlsIndex
];
269 TlsData
->StartAddressOfRawData
= (PVOID
)TlsDirectory
->StartAddressOfRawData
;
270 TlsData
->TlsDataSize
= TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
;
271 TlsData
->TlsZeroSize
= TlsDirectory
->SizeOfZeroFill
;
272 if (TlsDirectory
->AddressOfCallBacks
)
273 TlsData
->TlsAddressOfCallBacks
= *TlsDirectory
->AddressOfCallBacks
;
275 TlsData
->TlsAddressOfCallBacks
= NULL
;
276 TlsData
->Module
= Module
;
278 DbgPrint("TLS directory for %wZ\n", &Module
->BaseDllName
);
279 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory
->StartAddressOfRawData
);
280 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory
->EndAddressOfRawData
);
281 DbgPrint("SizeOfRawData: %d\n", TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
);
282 DbgPrint("AddressOfIndex: %x\n", TlsDirectory
->AddressOfIndex
);
283 DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory
->AddressOfCallBacks
, *TlsDirectory
->AddressOfCallBacks
);
284 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory
->SizeOfZeroFill
);
285 DbgPrint("Characteristics: %x\n", TlsDirectory
->Characteristics
);
289 * Is this region allways writable ?
291 *(PULONG
)TlsDirectory
->AddressOfIndex
= Module
->TlsIndex
;
293 Entry
= Entry
->Flink
;
296 DPRINT("LdrpInitializeTlsForProccess() done\n");
297 return STATUS_SUCCESS
;
303 OBJECT_ATTRIBUTES ObjectAttributes
;
304 UNICODE_STRING LinkTarget
;
310 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule
->BaseDllName
);
312 /* Get handle to the 'KnownDlls' directory */
313 RtlInitUnicodeString(&Name
,
315 InitializeObjectAttributes(&ObjectAttributes
,
317 OBJ_CASE_INSENSITIVE
,
320 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
321 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
323 if (!NT_SUCCESS(Status
))
325 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
326 LdrpKnownDllsDirHandle
= NULL
;
330 /* Allocate target name string */
331 LinkTarget
.Length
= 0;
332 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
333 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
335 MAX_PATH
* sizeof(WCHAR
));
336 if (LinkTarget
.Buffer
== NULL
)
338 NtClose(LdrpKnownDllsDirHandle
);
339 LdrpKnownDllsDirHandle
= NULL
;
343 RtlInitUnicodeString(&Name
,
345 InitializeObjectAttributes(&ObjectAttributes
,
347 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
348 LdrpKnownDllsDirHandle
,
350 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
351 SYMBOLIC_LINK_ALL_ACCESS
,
353 if (!NT_SUCCESS(Status
))
355 RtlFreeUnicodeString(&LinkTarget
);
356 NtClose(LdrpKnownDllsDirHandle
);
357 LdrpKnownDllsDirHandle
= NULL
;
361 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
365 if (!NT_SUCCESS(Status
))
367 RtlFreeUnicodeString(&LinkTarget
);
368 NtClose(LdrpKnownDllsDirHandle
);
369 LdrpKnownDllsDirHandle
= NULL
;
372 RtlCreateUnicodeString(&LdrpKnownDllPath
,
375 RtlFreeUnicodeString(&LinkTarget
);
377 DPRINT("LdrpInitLoader() done\n");
381 /***************************************************************************
386 * Adjusts the name of a dll to a fully qualified name.
389 * FullDllName: Pointer to caller supplied storage for the fully
390 * qualified dll name.
391 * DllName: Pointer to the dll name.
392 * BaseName: TRUE: Only the file name is passed to FullDllName
393 * FALSE: The full path is preserved in FullDllName
401 * A given path is not affected by the adjustment, but the file
403 * ntdll --> ntdll.dll
405 * ntdll.xyz --> ntdll.xyz
408 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
409 PUNICODE_STRING DllName
,
412 WCHAR Buffer
[MAX_PATH
];
417 Length
= DllName
->Length
/ sizeof(WCHAR
);
421 /* get the base dll name */
422 Pointer
= DllName
->Buffer
+ Length
;
429 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
432 Length
= Extension
- Pointer
;
433 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
434 Buffer
[Length
] = L
'\0';
438 /* get the full dll name */
439 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
440 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
443 /* Build the DLL's absolute name */
444 Extension
= wcsrchr (Buffer
, L
'.');
445 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
447 /* with extension - remove dot if it's the last character */
448 if (Buffer
[Length
- 1] == L
'.')
454 /* name without extension - assume that it is .dll */
455 memmove (Buffer
+ Length
, L
".dll", 10);
458 RtlCreateUnicodeString(FullDllName
, Buffer
);
462 LdrAddModuleEntry(PVOID ImageBase
,
463 PIMAGE_NT_HEADERS NTHeaders
,
468 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
470 memset(Module
, 0, sizeof(LDR_MODULE
));
471 Module
->BaseAddress
= (PVOID
)ImageBase
;
472 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
473 if (Module
->EntryPoint
!= 0)
474 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
475 Module
->ResidentSize
= LdrpGetResidentSize(NTHeaders
);
476 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
478 /* loading while app is running */
479 Module
->LoadCount
= 1;
482 * loading while app is initializing
483 * dll must not be unloaded
485 Module
->LoadCount
= -1;
489 Module
->TlsIndex
= -1;
490 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
491 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
493 RtlCreateUnicodeString (&Module
->FullDllName
,
495 RtlCreateUnicodeString (&Module
->BaseDllName
,
496 wcsrchr(FullDosName
, L
'\\') + 1);
497 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
499 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
500 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
501 &Module
->InLoadOrderModuleList
);
502 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
509 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
510 OUT PUNICODE_STRING FullDosName
,
511 OUT PHANDLE SectionHandle
)
513 OBJECT_ATTRIBUTES ObjectAttributes
;
516 DPRINT("LdrpMapKnownDll() called\n");
518 if (LdrpKnownDllsDirHandle
== NULL
)
520 DPRINT("Invalid 'KnownDlls' directory\n");
521 return STATUS_UNSUCCESSFUL
;
524 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
526 InitializeObjectAttributes(&ObjectAttributes
,
528 OBJ_CASE_INSENSITIVE
,
529 LdrpKnownDllsDirHandle
,
531 Status
= NtOpenSection(SectionHandle
,
532 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
534 if (!NT_SUCCESS(Status
))
536 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
540 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
541 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
542 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
544 FullDosName
->MaximumLength
);
545 if (FullDosName
->Buffer
== NULL
)
547 FullDosName
->Length
= 0;
548 FullDosName
->MaximumLength
= 0;
549 return STATUS_SUCCESS
;
552 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
553 wcscat(FullDosName
->Buffer
, L
"\\");
554 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
556 DPRINT("FullDosName '%wZ'\n", FullDosName
);
558 DPRINT("LdrpMapKnownDll() done\n");
560 return STATUS_SUCCESS
;
565 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
566 IN PUNICODE_STRING DllName
,
567 OUT PUNICODE_STRING FullDosName
,
568 IN BOOLEAN MapAsDataFile
,
569 OUT PHANDLE SectionHandle
)
571 WCHAR SearchPathBuffer
[MAX_PATH
];
572 WCHAR DosName
[MAX_PATH
];
573 UNICODE_STRING FullNtFileName
;
574 OBJECT_ATTRIBUTES FileObjectAttributes
;
576 char BlockBuffer
[1024];
577 PIMAGE_DOS_HEADER DosHeader
;
578 PIMAGE_NT_HEADERS NTHeaders
;
579 IO_STATUS_BLOCK IoStatusBlock
;
583 DPRINT("LdrpMapDllImageFile() called\n");
585 if (SearchPath
== NULL
)
587 /* get application running path */
589 wcscpy (SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
591 len
= wcslen (SearchPathBuffer
);
593 while (len
&& SearchPathBuffer
[len
- 1] != L
'\\')
596 if (len
) SearchPathBuffer
[len
-1] = L
'\0';
598 wcscat (SearchPathBuffer
, L
";");
600 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
601 wcscat (SearchPathBuffer
, L
"\\system32;");
602 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
603 wcscat (SearchPathBuffer
, L
";.");
605 SearchPath
= SearchPathBuffer
;
608 if (RtlDosSearchPath_U (SearchPath
,
614 return STATUS_DLL_NOT_FOUND
;
617 if (!RtlDosPathNameToNtPathName_U (DosName
,
621 return STATUS_DLL_NOT_FOUND
;
623 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
625 InitializeObjectAttributes(&FileObjectAttributes
,
631 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
633 Status
= NtOpenFile(&FileHandle
,
634 GENERIC_READ
|SYNCHRONIZE
,
635 &FileObjectAttributes
,
638 FILE_SYNCHRONOUS_IO_NONALERT
);
639 if (!NT_SUCCESS(Status
))
641 DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
642 &FullNtFileName
, Status
);
643 RtlFreeUnicodeString (&FullNtFileName
);
646 RtlFreeUnicodeString (&FullNtFileName
);
648 Status
= NtReadFile(FileHandle
,
657 if (!NT_SUCCESS(Status
))
659 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
664 * Overlay DOS and NT headers structures to the
665 * buffer with DLL's header raw data.
667 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
668 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
670 * Check it is a PE image file.
672 if ((DosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
673 || (DosHeader
->e_lfanew
== 0L)
674 || (*(PULONG
)(NTHeaders
) != IMAGE_NT_SIGNATURE
))
676 DPRINT("NTDLL format invalid\n");
679 return STATUS_UNSUCCESSFUL
;
683 * Create a section for dll.
685 Status
= NtCreateSection(SectionHandle
,
690 SEC_COMMIT
| (MapAsDataFile
? 0 : SEC_IMAGE
),
694 if (!NT_SUCCESS(Status
))
696 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
700 RtlCreateUnicodeString(FullDosName
,
708 /***************************************************************************
725 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
727 IN PUNICODE_STRING Name
,
728 OUT PVOID
*BaseAddress OPTIONAL
)
733 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
735 SearchPath
? " from " : "",
736 SearchPath
? SearchPath
: L
"");
740 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
741 return STATUS_SUCCESS
;
746 Status
= LdrpLoadModule(SearchPath
, LoadFlags
, Name
, &Module
, BaseAddress
);
747 if (NT_SUCCESS(Status
) && 0 == (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
))
749 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
750 Status
= LdrpAttachProcess();
751 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
752 if (NT_SUCCESS(Status
))
754 *BaseAddress
= Module
->BaseAddress
;
761 /***************************************************************************
763 * LdrFindEntryForAddress
778 LdrFindEntryForAddress(PVOID Address
,
781 PLIST_ENTRY ModuleListHead
;
783 PLDR_MODULE ModulePtr
;
785 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
787 if (NtCurrentPeb()->Ldr
== NULL
)
788 return(STATUS_NO_MORE_ENTRIES
);
790 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
791 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
792 Entry
= ModuleListHead
->Flink
;
793 if (Entry
== ModuleListHead
)
795 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
796 return(STATUS_NO_MORE_ENTRIES
);
799 while (Entry
!= ModuleListHead
)
801 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
803 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
805 if ((Address
>= ModulePtr
->BaseAddress
) &&
806 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->ResidentSize
)))
809 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
810 return(STATUS_SUCCESS
);
813 Entry
= Entry
->Flink
;
816 DPRINT("Failed to find module entry.\n");
818 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
819 return(STATUS_NO_MORE_ENTRIES
);
823 /***************************************************************************
825 * LdrFindEntryForName
839 LdrFindEntryForName(PUNICODE_STRING Name
,
843 PLIST_ENTRY ModuleListHead
;
845 PLDR_MODULE ModulePtr
;
846 BOOLEAN ContainsPath
;
847 UNICODE_STRING AdjustedName
;
850 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name
);
852 if (NtCurrentPeb()->Ldr
== NULL
)
853 return(STATUS_NO_MORE_ENTRIES
);
855 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
856 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
857 Entry
= ModuleListHead
->Flink
;
858 if (Entry
== ModuleListHead
)
860 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
861 return(STATUS_NO_MORE_ENTRIES
);
864 // NULL is the current process
868 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
869 return(STATUS_SUCCESS
);
872 LdrAdjustDllName (&AdjustedName
, Name
, FALSE
);
874 ContainsPath
= (AdjustedName
.Length
>= 2 * sizeof(WCHAR
) && L
':' == AdjustedName
.Buffer
[1]);
875 for (i
= 0; ! ContainsPath
&& i
< AdjustedName
.Length
/ sizeof(WCHAR
); i
++)
877 ContainsPath
= L
'\\' == AdjustedName
.Buffer
[i
] ||
878 L
'/' == AdjustedName
.Buffer
[i
];
883 if ((! ContainsPath
&&
884 0 == RtlCompareUnicodeString(&LdrpLastModule
->BaseDllName
, &AdjustedName
, TRUE
)) ||
886 0 == RtlCompareUnicodeString(&LdrpLastModule
->FullDllName
, &AdjustedName
, TRUE
)))
888 *Module
= LdrpLastModule
;
889 if (Ref
&& (*Module
)->LoadCount
!= -1)
891 (*Module
)->LoadCount
++;
893 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
894 RtlFreeUnicodeString(&AdjustedName
);
895 return(STATUS_SUCCESS
);
898 while (Entry
!= ModuleListHead
)
900 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
902 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, &AdjustedName
);
904 if ((! ContainsPath
&&
905 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, &AdjustedName
, TRUE
)) ||
907 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, &AdjustedName
, TRUE
)))
909 *Module
= LdrpLastModule
= ModulePtr
;
910 if (Ref
&& ModulePtr
->LoadCount
!= -1)
912 ModulePtr
->LoadCount
++;
914 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
915 RtlFreeUnicodeString(&AdjustedName
);
916 return(STATUS_SUCCESS
);
919 Entry
= Entry
->Flink
;
922 DPRINT("Failed to find dll %wZ\n", Name
);
923 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
924 RtlFreeUnicodeString(&AdjustedName
);
925 return(STATUS_NO_MORE_ENTRIES
);
928 /**********************************************************************
944 LdrFixupForward(PCHAR ForwardName
)
946 CHAR NameBuffer
[128];
947 UNICODE_STRING DllName
;
953 strcpy(NameBuffer
, ForwardName
);
954 p
= strchr(NameBuffer
, '.');
959 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
960 RtlCreateUnicodeStringFromAsciiz (&DllName
,
963 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
965 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
967 if (!NT_SUCCESS(Status
))
969 Status
= LdrLoadDll(NULL
,
970 LDRP_PROCESS_CREATION_TIME
,
973 if (NT_SUCCESS(Status
))
975 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
978 RtlFreeUnicodeString (&DllName
);
979 if (!NT_SUCCESS(Status
))
981 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer
);
985 DPRINT("BaseAddress: %p\n", Module
->BaseAddress
);
987 return LdrGetExportByName(Module
->BaseAddress
, (PUCHAR
)(p
+1), -1);
994 /**********************************************************************
996 * LdrGetExportByOrdinal
1010 LdrGetExportByOrdinal (
1015 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1016 ULONG ExportDirSize
;
1017 PDWORD
* ExFunctions
;
1020 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1021 RtlImageDirectoryEntryToData (BaseAddress
,
1023 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1027 ExFunctions
= (PDWORD
*)
1030 ExportDir
->AddressOfFunctions
1033 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
1035 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1038 Function
= (0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1039 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1042 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1043 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1045 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1046 Function
= LdrFixupForward((PCHAR
)Function
);
1053 /**********************************************************************
1055 * LdrGetExportByName
1066 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1067 * both with NumberOfNames entries.
1071 LdrGetExportByName(PVOID BaseAddress
,
1075 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1076 PDWORD
* ExFunctions
;
1078 USHORT
* ExOrdinals
;
1084 ULONG ExportDirSize
;
1086 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1088 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1089 RtlImageDirectoryEntryToData(BaseAddress
,
1091 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1093 if (ExportDir
== NULL
)
1095 DPRINT1("LdrGetExportByName(): no export directory!\n");
1100 //The symbol names may be missing entirely
1101 if (ExportDir
->AddressOfNames
== 0)
1103 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1108 * Get header pointers
1110 ExNames
= (PDWORD
*)RVA(BaseAddress
,
1111 ExportDir
->AddressOfNames
);
1112 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
1113 ExportDir
->AddressOfNameOrdinals
);
1114 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
1115 ExportDir
->AddressOfFunctions
);
1118 * Check the hint first
1120 if (Hint
< ExportDir
->NumberOfNames
)
1122 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1123 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1125 Ordinal
= ExOrdinals
[Hint
];
1126 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1127 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1128 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1130 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1131 Function
= LdrFixupForward((PCHAR
)Function
);
1132 if (Function
== NULL
)
1134 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1138 if (Function
!= NULL
)
1144 * Try a binary search first
1147 maxn
= ExportDir
->NumberOfNames
- 1;
1148 while (minn
<= maxn
)
1153 mid
= (minn
+ maxn
) / 2;
1155 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1156 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
1159 Ordinal
= ExOrdinals
[mid
];
1160 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1161 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1162 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1164 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1165 Function
= LdrFixupForward((PCHAR
)Function
);
1166 if (Function
== NULL
)
1168 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1172 if (Function
!= NULL
)
1175 else if (minn
== maxn
)
1177 DPRINT("LdrGetExportByName(): binary search failed\n");
1191 * Fall back on a linear search
1193 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1194 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1196 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1197 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1199 Ordinal
= ExOrdinals
[i
];
1200 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1201 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1202 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1203 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1205 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1206 Function
= LdrFixupForward((PCHAR
)Function
);
1208 if (Function
== NULL
)
1215 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1220 /**********************************************************************
1222 * LdrPerformRelocations
1225 * Relocate a DLL's memory image.
1237 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
,
1240 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1241 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
1242 ULONG Count
, ProtectSize
, OldProtect
, OldProtect2
;
1243 PVOID Page
, ProtectPage
, ProtectPage2
;
1248 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1250 return STATUS_UNSUCCESSFUL
;
1254 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1256 if (RelocationDDir
->VirtualAddress
== 0 || RelocationDDir
->Size
== 0)
1258 return STATUS_SUCCESS
;
1261 ProtectSize
= PAGE_SIZE
;
1262 Delta
= (ULONG_PTR
)ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
;
1263 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1264 RelocationDDir
->VirtualAddress
);
1265 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1266 RelocationDDir
->VirtualAddress
+ RelocationDDir
->Size
);
1268 while (RelocationDir
< RelocationEnd
&&
1269 RelocationDir
->SizeOfBlock
> 0)
1271 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) /
1273 Page
= ImageBase
+ RelocationDir
->VirtualAddress
;
1274 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
1276 /* Unprotect the page(s) we're about to relocate. */
1278 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1283 if (!NT_SUCCESS(Status
))
1285 DPRINT1("Failed to unprotect relocation target.\n");
1289 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
<
1290 NTHeaders
->OptionalHeader
.SizeOfImage
)
1292 ProtectPage2
= ProtectPage
+ PAGE_SIZE
;
1293 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1298 if (!NT_SUCCESS(Status
))
1300 DPRINT1("Failed to unprotect relocation target (2).\n");
1301 NtProtectVirtualMemory(NtCurrentProcess(),
1311 ProtectPage2
= NULL
;
1314 RelocationDir
= LdrProcessRelocationBlock(Page
,
1318 if (RelocationDir
== NULL
)
1319 return STATUS_UNSUCCESSFUL
;
1321 /* Restore old page protection. */
1322 NtProtectVirtualMemory(NtCurrentProcess(),
1328 if (ProtectPage2
!= NULL
)
1330 NtProtectVirtualMemory(NtCurrentProcess(),
1338 return STATUS_SUCCESS
;
1342 LdrpGetOrLoadModule(PWCHAR SerachPath
,
1344 PLDR_MODULE
* Module
,
1347 UNICODE_STRING DllName
;
1350 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name
);
1352 RtlCreateUnicodeStringFromAsciiz (&DllName
, Name
);
1354 Status
= LdrFindEntryForName (&DllName
, Module
, Load
);
1355 if (Load
&& !NT_SUCCESS(Status
))
1357 Status
= LdrpLoadModule(SerachPath
,
1358 NtCurrentPeb()->Ldr
->Initialized
? 0 : LDRP_PROCESS_CREATION_TIME
,
1362 if (NT_SUCCESS(Status
))
1364 Status
= LdrFindEntryForName (&DllName
, Module
, FALSE
);
1366 if (!NT_SUCCESS(Status
))
1368 DPRINT1("failed to load %wZ\n", &DllName
);
1371 RtlFreeUnicodeString (&DllName
);
1376 LdrpProcessImportDirectoryEntry(PLDR_MODULE Module
,
1377 PLDR_MODULE ImportedModule
,
1378 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
)
1381 PVOID
* ImportAddressList
;
1382 PULONG FunctionNameList
;
1388 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->Name
== 0)
1390 return STATUS_UNSUCCESSFUL
;
1393 /* Get the import address list. */
1394 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1396 /* Get the list of functions to import. */
1397 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
1399 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ (ULONG_PTR
)ImportModuleDirectory
->OriginalFirstThunk
);
1403 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1406 /* Get the size of IAT. */
1408 while (FunctionNameList
[IATSize
] != 0L)
1413 /* Unprotect the region we are about to write into. */
1414 IATBase
= (PVOID
)ImportAddressList
;
1415 IATSize
*= sizeof(PVOID
*);
1416 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1421 if (!NT_SUCCESS(Status
))
1423 DPRINT1("Failed to unprotect IAT.\n");
1427 /* Walk through function list and fixup addresses. */
1428 while (*FunctionNameList
!= 0L)
1430 if ((*FunctionNameList
) & 0x80000000)
1432 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1433 *ImportAddressList
= LdrGetExportByOrdinal(ImportedModule
->BaseAddress
, Ordinal
);
1434 if ((*ImportAddressList
) == NULL
)
1436 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1437 return STATUS_UNSUCCESSFUL
;
1442 IMAGE_IMPORT_BY_NAME
*pe_name
;
1443 pe_name
= RVA(Module
->BaseAddress
, *FunctionNameList
);
1444 *ImportAddressList
= LdrGetExportByName(ImportedModule
->BaseAddress
, pe_name
->Name
, pe_name
->Hint
);
1445 if ((*ImportAddressList
) == NULL
)
1447 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1448 return STATUS_UNSUCCESSFUL
;
1451 ImportAddressList
++;
1455 /* Protect the region we are about to write into. */
1456 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1461 if (!NT_SUCCESS(Status
))
1463 DPRINT1("Failed to protect IAT.\n");
1467 return STATUS_SUCCESS
;
1471 LdrpProcessImportDirectory(
1473 PLDR_MODULE ImportedModule
,
1477 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1480 DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
1481 Module
, &Module
->BaseDllName
, ImportedName
);
1484 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1485 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1487 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1489 if (ImportModuleDirectory
== NULL
)
1491 return STATUS_UNSUCCESSFUL
;
1494 while (ImportModuleDirectory
->Name
)
1496 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->Name
;
1497 if (0 == _stricmp(Name
, ImportedName
))
1499 Status
= LdrpProcessImportDirectoryEntry(Module
,
1501 ImportModuleDirectory
);
1502 if (!NT_SUCCESS(Status
))
1507 ImportModuleDirectory
++;
1511 return STATUS_SUCCESS
;
1516 LdrpAdjustImportDirectory(PLDR_MODULE Module
,
1517 PLDR_MODULE ImportedModule
,
1520 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1522 PVOID
* ImportAddressList
;
1525 PULONG FunctionNameList
;
1530 PIMAGE_NT_HEADERS NTHeaders
;
1533 DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
1534 Module
, &Module
->BaseDllName
, ImportedModule
, &ImportedModule
->BaseDllName
, ImportedName
);
1536 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1537 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1539 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1541 if (ImportModuleDirectory
== NULL
)
1543 return STATUS_UNSUCCESSFUL
;
1546 while (ImportModuleDirectory
->Name
)
1548 Name
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->Name
;
1549 if (0 == _stricmp(Name
, (PCHAR
)ImportedName
))
1552 /* Get the import address list. */
1553 ImportAddressList
= (PVOID
*)(Module
->BaseAddress
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1555 /* Get the list of functions to import. */
1556 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
1558 FunctionNameList
= (PULONG
) (Module
->BaseAddress
+ (ULONG_PTR
)ImportModuleDirectory
->OriginalFirstThunk
);
1562 FunctionNameList
= (PULONG
)(Module
->BaseAddress
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1565 /* Get the size of IAT. */
1567 while (FunctionNameList
[IATSize
] != 0L)
1572 /* Unprotect the region we are about to write into. */
1573 IATBase
= (PVOID
)ImportAddressList
;
1574 IATSize
*= sizeof(PVOID
*);
1575 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1580 if (!NT_SUCCESS(Status
))
1582 DPRINT1("Failed to unprotect IAT.\n");
1586 NTHeaders
= RtlImageNtHeader (ImportedModule
->BaseAddress
);
1587 Start
= (PVOID
)NTHeaders
->OptionalHeader
.ImageBase
;
1588 End
= Start
+ ImportedModule
->ResidentSize
;
1589 Offset
= ImportedModule
->BaseAddress
- Start
;
1591 /* Walk through function list and fixup addresses. */
1592 while (*FunctionNameList
!= 0L)
1594 if (*ImportAddressList
>= Start
&& *ImportAddressList
< End
)
1596 (*ImportAddressList
) += Offset
;
1598 ImportAddressList
++;
1602 /* Protect the region we are about to write into. */
1603 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1608 if (!NT_SUCCESS(Status
))
1610 DPRINT1("Failed to protect IAT.\n");
1614 ImportModuleDirectory
++;
1616 return STATUS_SUCCESS
;
1620 /**********************************************************************
1625 * Compute the entry point for every symbol the DLL imports
1626 * from other modules.
1638 LdrFixupImports(IN PWSTR SearchPath OPTIONAL
,
1639 IN PLDR_MODULE Module
)
1641 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1642 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent
;
1643 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
1644 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
1645 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1648 PLDR_MODULE ImportedModule
;
1651 DPRINT("LdrFixupImports(SearchPath %x, Module %x)\n", SearchPath
, Module
);
1653 /* Check for tls data */
1654 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
1655 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1657 IMAGE_DIRECTORY_ENTRY_TLS
,
1661 TlsSize
= TlsDirectory
->EndAddressOfRawData
1662 - TlsDirectory
->StartAddressOfRawData
1663 + TlsDirectory
->SizeOfZeroFill
;
1665 NtCurrentPeb()->Ldr
->Initialized
)
1667 TRACE_LDR("Trying to load dynamicly %wZ which contains a tls directory\n",
1668 &Module
->BaseDllName
);
1669 return STATUS_UNSUCCESSFUL
;
1673 * Process each import module.
1675 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1676 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1678 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1681 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
1682 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
1684 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
1687 if (BoundImportDescriptor
!= NULL
&& ImportModuleDirectory
== NULL
)
1689 DPRINT1("%wZ has only a bound import directory\n", &Module
->BaseDllName
);
1690 return STATUS_UNSUCCESSFUL
;
1692 if (BoundImportDescriptor
)
1694 DPRINT("BoundImportDescriptor %x\n", BoundImportDescriptor
);
1696 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
1697 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
1699 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
1700 TRACE_LDR("%wZ bound to %s\n", &Module
->BaseDllName
, ImportedName
);
1701 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1702 if (!NT_SUCCESS(Status
))
1704 DPRINT1("failed to load %s\n", ImportedName
);
1707 if (Module
== ImportedModule
)
1709 LdrpDecrementLoadCount(Module
, FALSE
);
1711 if (ImportedModule
->TimeDateStamp
!= BoundImportDescriptorCurrent
->TimeDateStamp
)
1713 TRACE_LDR("%wZ has stale binding to %wZ\n",
1714 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1715 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1716 if (!NT_SUCCESS(Status
))
1718 DPRINT1("failed to import %s\n", ImportedName
);
1724 BOOLEAN WrongForwarder
;
1725 WrongForwarder
= FALSE
;
1726 if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1728 TRACE_LDR("%wZ has stale binding to %s\n",
1729 &Module
->BaseDllName
, ImportedName
);
1733 TRACE_LDR("%wZ has correct binding to %wZ\n",
1734 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1736 if (BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
)
1738 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef
;
1740 PLDR_MODULE ForwarderModule
;
1741 PCHAR ForwarderName
;
1743 BoundForwarderRef
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundImportDescriptorCurrent
+ 1);
1744 for (i
= 0; i
< BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
; i
++, BoundForwarderRef
++)
1746 ForwarderName
= (PCHAR
)BoundImportDescriptor
+ BoundForwarderRef
->OffsetModuleName
;
1747 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1748 &Module
->BaseDllName
, ForwarderName
, ImportedName
);
1749 Status
= LdrpGetOrLoadModule(SearchPath
, ForwarderName
, &ForwarderModule
, TRUE
);
1750 if (!NT_SUCCESS(Status
))
1752 DPRINT1("failed to load %s\n", ForwarderName
);
1755 if (Module
== ImportedModule
)
1757 LdrpDecrementLoadCount(Module
, FALSE
);
1759 if (ForwarderModule
->TimeDateStamp
!= BoundForwarderRef
->TimeDateStamp
||
1760 ForwarderModule
->Flags
& IMAGE_NOT_AT_BASE
)
1762 TRACE_LDR("%wZ has stale binding to %s\n",
1763 &Module
->BaseDllName
, ForwarderName
);
1764 WrongForwarder
= TRUE
;
1768 TRACE_LDR("%wZ has correct binding to %s\n",
1769 &Module
->BaseDllName
, ForwarderName
);
1773 if (WrongForwarder
||
1774 ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1776 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1777 if (!NT_SUCCESS(Status
))
1779 DPRINT1("failed to import %s\n", ImportedName
);
1783 else if (ImportedModule
->Flags
& IMAGE_NOT_AT_BASE
)
1785 TRACE_LDR("Adjust imports for %s from %wZ\n",
1786 ImportedName
, &Module
->BaseDllName
);
1787 Status
= LdrpAdjustImportDirectory(Module
, ImportedModule
, ImportedName
);
1788 if (!NT_SUCCESS(Status
))
1790 DPRINT1("failed to adjust import entries for %s\n", ImportedName
);
1794 else if (WrongForwarder
)
1798 * Update only forwarders
1800 TRACE_LDR("Stale BIND %s from %wZ\n",
1801 ImportedName
, &Module
->BaseDllName
);
1802 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("faild to import %s\n", ImportedName
);
1814 BoundImportDescriptorCurrent
+= BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
+ 1;
1817 else if (ImportModuleDirectory
)
1819 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1821 ImportModuleDirectoryCurrent
= ImportModuleDirectory
;
1822 while (ImportModuleDirectoryCurrent
->Name
)
1824 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectoryCurrent
->Name
;
1825 TRACE_LDR("%wZ imports functions from %s\n", &Module
->BaseDllName
, ImportedName
);
1827 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1828 if (!NT_SUCCESS(Status
))
1830 DPRINT1("failed to load %s\n", ImportedName
);
1833 if (Module
== ImportedModule
)
1835 LdrpDecrementLoadCount(Module
, FALSE
);
1838 TRACE_LDR("Initializing imports for %wZ from %s\n",
1839 &Module
->BaseDllName
, ImportedName
);
1840 Status
= LdrpProcessImportDirectoryEntry(Module
, ImportedModule
, ImportModuleDirectoryCurrent
);
1841 if (!NT_SUCCESS(Status
))
1843 DPRINT1("failed to import %s\n", ImportedName
);
1846 ImportModuleDirectoryCurrent
++;
1850 if (TlsDirectory
&& TlsSize
> 0)
1852 LdrpAcquireTlsSlot(Module
, TlsSize
, FALSE
);
1855 return STATUS_SUCCESS
;
1859 /**********************************************************************
1864 * 1. Relocate, if needed the EXE.
1865 * 2. Fixup any imported symbol.
1866 * 3. Compute the EXE's entry point.
1870 * Address at which the EXE's image
1874 * Handle of the section that contains
1878 * NULL on error; otherwise the entry point
1879 * to call for initializing the DLL.
1884 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
1885 * Currently the function is only used for the exe.
1887 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1888 HANDLE SectionHandle
,
1889 PLDR_MODULE
* Module
,
1893 PEPFUNC EntryPoint
= NULL
;
1894 PIMAGE_DOS_HEADER DosHeader
;
1895 PIMAGE_NT_HEADERS NTHeaders
;
1896 PLDR_MODULE tmpModule
;
1898 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1899 ImageBase
, (ULONG
)SectionHandle
);
1902 * Overlay DOS and WNT headers structures
1903 * to the DLL's image.
1905 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1906 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1909 * If the base address is different from the
1910 * one the DLL is actually loaded, perform any
1913 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1915 DPRINT("LDR: Performing relocations\n");
1916 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1917 if (!NT_SUCCESS(Status
))
1919 DPRINT1("LdrPerformRelocations() failed\n");
1926 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1927 (*Module
)->SectionHandle
= SectionHandle
;
1931 Module
= &tmpModule
;
1932 Status
= LdrFindEntryForAddress(ImageBase
, Module
);
1933 if (!NT_SUCCESS(Status
))
1939 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1941 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
1945 * If the DLL's imports symbols from other
1946 * modules, fixup the imported calls entry points.
1948 DPRINT("About to fixup imports\n");
1949 Status
= LdrFixupImports(NULL
, *Module
);
1950 if (!NT_SUCCESS(Status
))
1952 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module
)->BaseDllName
);
1955 DPRINT("Fixup done\n");
1956 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
1957 Status
= LdrpInitializeTlsForProccess();
1958 if (NT_SUCCESS(Status
))
1960 Status
= LdrpAttachProcess();
1962 if (NT_SUCCESS(Status
))
1964 LdrpTlsCallback(*Module
, DLL_PROCESS_ATTACH
);
1968 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1969 if (!NT_SUCCESS(Status
))
1975 * Compute the DLL's entry point's address.
1977 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1978 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1979 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1981 EntryPoint
= (PEPFUNC
) (ImageBase
1982 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1984 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1989 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
1991 IN PUNICODE_STRING Name
,
1992 PLDR_MODULE
*Module
,
1993 PVOID
*BaseAddress OPTIONAL
)
1995 UNICODE_STRING AdjustedName
;
1996 UNICODE_STRING FullDosName
;
1998 PLDR_MODULE tmpModule
;
1999 HANDLE SectionHandle
;
2002 PIMAGE_NT_HEADERS NtHeaders
;
2003 BOOLEAN MappedAsDataFile
;
2007 Module
= &tmpModule
;
2009 /* adjust the full dll name */
2010 LdrAdjustDllName(&AdjustedName
, Name
, FALSE
);
2012 DPRINT("%wZ\n", &AdjustedName
);
2014 MappedAsDataFile
= FALSE
;
2015 /* Test if dll is already loaded */
2016 Status
= LdrFindEntryForName(&AdjustedName
, Module
, TRUE
);
2017 if (NT_SUCCESS(Status
))
2019 RtlFreeUnicodeString(&AdjustedName
);
2020 if (NULL
!= BaseAddress
)
2022 *BaseAddress
= (*Module
)->BaseAddress
;
2027 /* Open or create dll image section */
2028 Status
= LdrpMapKnownDll(&AdjustedName
, &FullDosName
, &SectionHandle
);
2029 if (!NT_SUCCESS(Status
))
2031 MappedAsDataFile
= (0 != (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
));
2032 Status
= LdrpMapDllImageFile(SearchPath
, &AdjustedName
, &FullDosName
,
2033 MappedAsDataFile
, &SectionHandle
);
2035 if (!NT_SUCCESS(Status
))
2037 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName
, Status
);
2038 RtlFreeUnicodeString(&AdjustedName
);
2041 RtlFreeUnicodeString(&AdjustedName
);
2042 /* Map the dll into the process */
2045 Status
= NtMapViewOfSection(SectionHandle
,
2055 if (!NT_SUCCESS(Status
))
2057 DPRINT1("map view of section failed (Status %x)\n", Status
);
2058 RtlFreeUnicodeString(&FullDosName
);
2059 NtClose(SectionHandle
);
2062 if (NULL
!= BaseAddress
)
2064 *BaseAddress
= ImageBase
;
2066 /* Get and check the NT headers */
2067 NtHeaders
= RtlImageNtHeader(ImageBase
);
2068 if (NtHeaders
== NULL
)
2070 DPRINT1("RtlImageNtHeaders() failed\n");
2071 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2072 NtClose (SectionHandle
);
2073 RtlFreeUnicodeString(&FullDosName
);
2074 return STATUS_UNSUCCESSFUL
;
2076 DPRINT("Mapped %wZ at %x\n", &FullDosName
, ImageBase
);
2077 if (MappedAsDataFile
)
2079 ASSERT(NULL
!= BaseAddress
);
2080 if (NULL
!= BaseAddress
)
2082 *BaseAddress
= (PVOID
) ((char *) *BaseAddress
+ 1);
2085 RtlFreeUnicodeString(&FullDosName
);
2086 NtClose(SectionHandle
);
2087 return STATUS_SUCCESS
;
2089 /* If the base address is different from the
2090 * one the DLL is actually loaded, perform any
2092 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2094 DPRINT1("Relocating (%x -> %x) %wZ\n",
2095 NtHeaders
->OptionalHeader
.ImageBase
, ImageBase
, &FullDosName
);
2096 Status
= LdrPerformRelocations(NtHeaders
, ImageBase
);
2097 if (!NT_SUCCESS(Status
))
2099 DPRINT1("LdrPerformRelocations() failed\n");
2100 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2101 NtClose (SectionHandle
);
2102 RtlFreeUnicodeString(&FullDosName
);
2103 return STATUS_UNSUCCESSFUL
;
2106 *Module
= LdrAddModuleEntry(ImageBase
, NtHeaders
, FullDosName
.Buffer
);
2107 (*Module
)->SectionHandle
= SectionHandle
;
2108 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2110 (*Module
)->Flags
|= IMAGE_NOT_AT_BASE
;
2112 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
2114 (*Module
)->Flags
|= IMAGE_DLL
;
2116 /* fixup the imported calls entry points */
2117 Status
= LdrFixupImports(SearchPath
, *Module
);
2118 if (!NT_SUCCESS(Status
))
2120 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module
)->BaseDllName
, Status
);
2123 #if defined(DBG) || defined(KDBG)
2124 LdrpLoadUserModuleSymbols(*Module
);
2125 #endif /* DBG || KDBG */
2126 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2127 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
2128 &(*Module
)->InInitializationOrderModuleList
);
2129 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2131 return STATUS_SUCCESS
;
2135 LdrpUnloadModule(PLDR_MODULE Module
,
2138 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
2139 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
2140 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
2142 PLDR_MODULE ImportedModule
;
2149 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2152 LoadCount
= LdrpDecrementLoadCount(Module
, Unload
);
2154 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module
->BaseDllName
, LoadCount
);
2158 /* ?????????????????? */
2160 else if (LoadCount
== 1)
2162 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
2163 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2165 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
2167 if (BoundImportDescriptor
)
2169 /* dereferencing all imported modules, use the bound import descriptor */
2170 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
2171 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
2173 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
2174 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2175 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2176 if (!NT_SUCCESS(Status
))
2178 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2182 if (Module
!= ImportedModule
)
2184 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2185 if (!NT_SUCCESS(Status
))
2187 DPRINT1("unable to unload %s\n", ImportedName
);
2191 BoundImportDescriptorCurrent
++;
2196 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
2197 RtlImageDirectoryEntryToData(Module
->BaseAddress
,
2199 IMAGE_DIRECTORY_ENTRY_IMPORT
,
2201 if (ImportModuleDirectory
)
2203 /* dereferencing all imported modules, use the import descriptor */
2204 while (ImportModuleDirectory
->Name
)
2206 ImportedName
= (PCHAR
)Module
->BaseAddress
+ ImportModuleDirectory
->Name
;
2207 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2208 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2209 if (!NT_SUCCESS(Status
))
2211 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2215 if (Module
!= ImportedModule
)
2217 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2218 if (!NT_SUCCESS(Status
))
2220 DPRINT1("unable to unload %s\n", ImportedName
);
2224 ImportModuleDirectory
++;
2232 LdrpDetachProcess(FALSE
);
2233 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2235 return STATUS_SUCCESS
;
2243 LdrUnloadDll (IN PVOID BaseAddress
)
2248 if (BaseAddress
== NULL
)
2249 return STATUS_SUCCESS
;
2251 if (LdrMappedAsDataFile(&BaseAddress
))
2253 Status
= NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
2257 Status
= LdrFindEntryForAddress(BaseAddress
, &Module
);
2258 if (NT_SUCCESS(Status
))
2260 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module
->BaseDllName
);
2261 Status
= LdrpUnloadModule(Module
, TRUE
);
2272 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
2274 PLIST_ENTRY ModuleListHead
;
2279 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
2281 Status
= STATUS_DLL_NOT_FOUND
;
2282 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2283 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2284 Entry
= ModuleListHead
->Flink
;
2285 while (Entry
!= ModuleListHead
)
2287 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2289 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
2291 if (Module
->BaseAddress
== BaseAddress
)
2293 if (Module
->TlsIndex
== -1)
2295 Module
->Flags
|= DONT_CALL_FOR_THREAD
;
2296 Status
= STATUS_SUCCESS
;
2300 Entry
= Entry
->Flink
;
2302 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2310 LdrGetDllHandle(IN PWCHAR Path OPTIONAL
,
2312 IN PUNICODE_STRING DllName
,
2313 OUT PVOID
* BaseAddress
)
2318 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName
, Path
? Path
: L
"");
2320 /* NULL is the current executable */
2321 if (DllName
== NULL
)
2323 *BaseAddress
= ExeModule
->BaseAddress
;
2324 DPRINT("BaseAddress %x\n", *BaseAddress
);
2325 return STATUS_SUCCESS
;
2328 Status
= LdrFindEntryForName(DllName
, &Module
, FALSE
);
2329 if (NT_SUCCESS(Status
))
2331 *BaseAddress
= Module
->BaseAddress
;
2332 return STATUS_SUCCESS
;
2335 DPRINT("Failed to find dll %wZ\n", DllName
);
2336 *BaseAddress
= NULL
;
2337 return STATUS_DLL_NOT_FOUND
;
2345 LdrGetProcedureAddress (IN PVOID BaseAddress
,
2346 IN PANSI_STRING Name
,
2348 OUT PVOID
*ProcedureAddress
)
2350 if (Name
&& Name
->Length
)
2352 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name
);
2356 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal
);
2359 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
2360 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
2362 if (Name
&& Name
->Length
)
2365 *ProcedureAddress
= LdrGetExportByName(BaseAddress
, (PUCHAR
)Name
->Buffer
, 0xffff);
2366 if (*ProcedureAddress
!= NULL
)
2368 return STATUS_SUCCESS
;
2370 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
2375 Ordinal
&= 0x0000FFFF;
2376 *ProcedureAddress
= LdrGetExportByOrdinal(BaseAddress
, (WORD
)Ordinal
);
2377 if (*ProcedureAddress
)
2379 return STATUS_SUCCESS
;
2381 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
2383 return STATUS_PROCEDURE_NOT_FOUND
;
2386 /**********************************************************************
2391 * Unload dll's which are no longer referenced from others dll's
2402 * The loader lock must be held on enty.
2405 LdrpDetachProcess(BOOLEAN UnloadAll
)
2407 PLIST_ENTRY ModuleListHead
;
2410 static ULONG CallingCount
= 0;
2412 DPRINT("LdrpDetachProcess() called for %wZ\n",
2413 &ExeModule
->BaseDllName
);
2417 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2418 Entry
= ModuleListHead
->Blink
;
2419 while (Entry
!= ModuleListHead
)
2421 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2422 if (((UnloadAll
&& Module
->LoadCount
<= 0) || Module
->LoadCount
== 0) &&
2423 Module
->Flags
& ENTRY_PROCESSED
&&
2424 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2426 Module
->Flags
|= UNLOAD_IN_PROGRESS
;
2427 if (Module
== LdrpLastModule
)
2429 LdrpLastModule
= NULL
;
2431 if (Module
->Flags
& PROCESS_ATTACH_CALLED
)
2433 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2434 &Module
->BaseDllName
, Module
->EntryPoint
);
2435 LdrpCallDllEntry(Module
, DLL_PROCESS_DETACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2439 TRACE_LDR("Unload %wZ\n", &Module
->BaseDllName
);
2441 Entry
= ModuleListHead
->Blink
;
2445 Entry
= Entry
->Blink
;
2449 if (CallingCount
== 1)
2451 Entry
= ModuleListHead
->Blink
;
2452 while (Entry
!= ModuleListHead
)
2454 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2455 Entry
= Entry
->Blink
;
2456 if (Module
->Flags
& UNLOAD_IN_PROGRESS
&&
2457 ((UnloadAll
&& Module
->LoadCount
>= 0) || Module
->LoadCount
== 0))
2459 /* remove the module entry from the list */
2460 RemoveEntryList (&Module
->InLoadOrderModuleList
);
2461 RemoveEntryList (&Module
->InInitializationOrderModuleList
);
2463 NtUnmapViewOfSection (NtCurrentProcess (), Module
->BaseAddress
);
2464 NtClose (Module
->SectionHandle
);
2466 TRACE_LDR("%wZ unloaded\n", &Module
->BaseDllName
);
2468 RtlFreeUnicodeString (&Module
->FullDllName
);
2469 RtlFreeUnicodeString (&Module
->BaseDllName
);
2471 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
2476 DPRINT("LdrpDetachProcess() done\n");
2479 /**********************************************************************
2484 * Initialize all dll's which are prepered for loading
2495 * The loader lock must be held on entry.
2499 LdrpAttachProcess(VOID
)
2501 PLIST_ENTRY ModuleListHead
;
2505 NTSTATUS Status
= STATUS_SUCCESS
;
2507 DPRINT("LdrpAttachProcess() called for %wZ\n",
2508 &ExeModule
->BaseDllName
);
2510 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2511 Entry
= ModuleListHead
->Flink
;
2512 while (Entry
!= ModuleListHead
)
2514 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2515 if (!(Module
->Flags
& (LOAD_IN_PROGRESS
|UNLOAD_IN_PROGRESS
|ENTRY_PROCESSED
)))
2517 Module
->Flags
|= LOAD_IN_PROGRESS
;
2518 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2519 &Module
->BaseDllName
, Module
->EntryPoint
);
2520 Result
= LdrpCallDllEntry(Module
, DLL_PROCESS_ATTACH
, (PVOID
)(Module
->LoadCount
== -1 ? 1 : 0));
2523 Status
= STATUS_DLL_INIT_FAILED
;
2526 if (Module
->Flags
& IMAGE_DLL
&& Module
->EntryPoint
!= 0)
2528 Module
->Flags
|= PROCESS_ATTACH_CALLED
|ENTRY_PROCESSED
;
2532 Module
->Flags
|= ENTRY_PROCESSED
;
2534 Module
->Flags
&= ~LOAD_IN_PROGRESS
;
2536 Entry
= Entry
->Flink
;
2539 DPRINT("LdrpAttachProcess() done\n");
2548 LdrShutdownProcess (VOID
)
2550 LdrpDetachProcess(TRUE
);
2551 return STATUS_SUCCESS
;
2559 LdrpAttachThread (VOID
)
2561 PLIST_ENTRY ModuleListHead
;
2566 DPRINT("LdrpAttachThread() called for %wZ\n",
2567 &ExeModule
->BaseDllName
);
2569 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2571 Status
= LdrpInitializeTlsForThread();
2573 if (NT_SUCCESS(Status
))
2575 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2576 Entry
= ModuleListHead
->Flink
;
2578 while (Entry
!= ModuleListHead
)
2580 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2581 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2582 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2583 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2585 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2586 &Module
->BaseDllName
, Module
->EntryPoint
);
2587 LdrpCallDllEntry(Module
, DLL_THREAD_ATTACH
, NULL
);
2589 Entry
= Entry
->Flink
;
2592 Entry
= NtCurrentPeb()->Ldr
->InLoadOrderModuleList
.Flink
;
2593 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2594 LdrpTlsCallback(Module
, DLL_THREAD_ATTACH
);
2597 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2599 DPRINT("LdrpAttachThread() done\n");
2609 LdrShutdownThread (VOID
)
2611 PLIST_ENTRY ModuleListHead
;
2615 DPRINT("LdrShutdownThread() called for %wZ\n",
2616 &ExeModule
->BaseDllName
);
2618 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2620 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2621 Entry
= ModuleListHead
->Blink
;
2622 while (Entry
!= ModuleListHead
)
2624 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2626 if (Module
->Flags
& PROCESS_ATTACH_CALLED
&&
2627 !(Module
->Flags
& DONT_CALL_FOR_THREAD
) &&
2628 !(Module
->Flags
& UNLOAD_IN_PROGRESS
))
2630 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2631 &Module
->BaseDllName
, Module
->EntryPoint
);
2632 LdrpCallDllEntry(Module
, DLL_THREAD_DETACH
, NULL
);
2634 Entry
= Entry
->Blink
;
2637 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2641 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer
);
2644 DPRINT("LdrShutdownThread() done\n");
2646 return STATUS_SUCCESS
;
2650 /***************************************************************************
2652 * LdrQueryProcessModuleInformation
2667 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
2668 IN ULONG Size OPTIONAL
,
2669 OUT PULONG ReturnedSize
)
2671 PLIST_ENTRY ModuleListHead
;
2674 PDEBUG_MODULE_INFORMATION ModulePtr
= NULL
;
2675 NTSTATUS Status
= STATUS_SUCCESS
;
2676 ULONG UsedSize
= sizeof(ULONG
);
2677 ANSI_STRING AnsiString
;
2680 DPRINT("LdrQueryProcessModuleInformation() called\n");
2682 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2684 if (ModuleInformation
== NULL
|| Size
== 0)
2686 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2690 ModuleInformation
->ModuleCount
= 0;
2691 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
2692 Status
= STATUS_SUCCESS
;
2695 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2696 Entry
= ModuleListHead
->Flink
;
2698 while (Entry
!= ModuleListHead
)
2700 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
2702 DPRINT(" Module %wZ\n",
2703 &Module
->FullDllName
);
2705 if (UsedSize
> Size
)
2707 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2709 else if (ModuleInformation
!= NULL
)
2711 ModulePtr
->Reserved
[0] = ModulePtr
->Reserved
[1] = 0; // FIXME: ??
2712 ModulePtr
->Base
= Module
->BaseAddress
;
2713 ModulePtr
->Size
= Module
->ResidentSize
;
2714 ModulePtr
->Flags
= Module
->Flags
;
2715 ModulePtr
->Index
= 0; // FIXME: index ??
2716 ModulePtr
->Unknown
= 0; // FIXME: ??
2717 ModulePtr
->LoadCount
= Module
->LoadCount
;
2719 AnsiString
.Length
= 0;
2720 AnsiString
.MaximumLength
= 256;
2721 AnsiString
.Buffer
= ModulePtr
->ImageName
;
2722 RtlUnicodeStringToAnsiString(&AnsiString
,
2723 &Module
->FullDllName
,
2725 p
= strrchr(ModulePtr
->ImageName
, '\\');
2727 ModulePtr
->ModuleNameOffset
= p
- ModulePtr
->ImageName
+ 1;
2729 ModulePtr
->ModuleNameOffset
= 0;
2732 ModuleInformation
->ModuleCount
++;
2734 UsedSize
+= sizeof(DEBUG_MODULE_INFORMATION
);
2736 Entry
= Entry
->Flink
;
2739 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2741 if (ReturnedSize
!= 0)
2742 *ReturnedSize
= UsedSize
;
2744 DPRINT("LdrQueryProcessModuleInformation() done\n");
2751 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
2754 PIMAGE_NT_HEADERS Header
;
2761 Header
= RtlImageNtHeader (BaseAddress
);
2765 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
2770 Ptr
= (PUSHORT
) BaseAddress
;
2771 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
2774 if (HIWORD(Sum
) != 0)
2776 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2783 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
2784 if (HIWORD(Sum
) != 0)
2786 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
2790 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
2792 /* Subtract image checksum from calculated checksum. */
2793 /* fix low word of checksum */
2794 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
2796 CalcSum
-= LOWORD(HeaderSum
);
2800 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
2803 /* fix high word of checksum */
2804 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
2806 CalcSum
-= HIWORD(HeaderSum
);
2810 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
2813 /* add file length */
2814 CalcSum
+= ImageSize
;
2816 return (BOOLEAN
)(CalcSum
== HeaderSum
);
2820 * Compute size of an image as it is actually present in virt memory
2821 * (i.e. excluding NEVER_LOAD sections)
2824 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders
)
2826 PIMAGE_SECTION_HEADER SectionHeader
;
2827 unsigned SectionIndex
;
2830 SectionHeader
= (PIMAGE_SECTION_HEADER
)((char *) &NTHeaders
->OptionalHeader
2831 + NTHeaders
->FileHeader
.SizeOfOptionalHeader
);
2833 for (SectionIndex
= 0; SectionIndex
< NTHeaders
->FileHeader
.NumberOfSections
; SectionIndex
++)
2835 if (0 == (SectionHeader
->Characteristics
& IMAGE_SCN_LNK_REMOVE
)
2836 && ResidentSize
< SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
)
2838 ResidentSize
= SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
;
2843 return ResidentSize
;
2847 /***************************************************************************
2849 * LdrVerifyImageMatchesChecksum
2864 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
2869 FILE_STANDARD_INFORMATION FileInfo
;
2870 IO_STATUS_BLOCK IoStatusBlock
;
2871 HANDLE SectionHandle
;
2877 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2879 Status
= NtCreateSection (&SectionHandle
,
2886 if (!NT_SUCCESS(Status
))
2888 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
2894 Status
= NtMapViewOfSection (SectionHandle
,
2895 NtCurrentProcess (),
2904 if (!NT_SUCCESS(Status
))
2906 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2907 NtClose (SectionHandle
);
2911 Status
= NtQueryInformationFile (FileHandle
,
2914 sizeof (FILE_STANDARD_INFORMATION
),
2915 FileStandardInformation
);
2916 if (!NT_SUCCESS(Status
))
2918 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2919 NtUnmapViewOfSection (NtCurrentProcess (),
2921 NtClose (SectionHandle
);
2925 Result
= LdrpCheckImageChecksum (BaseAddress
,
2926 FileInfo
.EndOfFile
.u
.LowPart
);
2927 if (Result
== FALSE
)
2929 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2932 NtUnmapViewOfSection (NtCurrentProcess (),
2935 NtClose (SectionHandle
);
2941 /***************************************************************************
2943 * LdrQueryImageFileExecutionOptions
2958 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
2959 IN PCWSTR ValueName
,
2962 IN ULONG BufferSize
,
2963 OUT PULONG ReturnedLength OPTIONAL
)
2965 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2966 OBJECT_ATTRIBUTES ObjectAttributes
;
2967 UNICODE_STRING ValueNameString
;
2968 UNICODE_STRING KeyName
;
2969 WCHAR NameBuffer
[256];
2977 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2978 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
2981 Ptr
= SubKey
->Buffer
;
2987 wcscat (NameBuffer
, Ptr
);
2988 RtlInitUnicodeString (&KeyName
,
2991 InitializeObjectAttributes (&ObjectAttributes
,
2993 OBJ_CASE_INSENSITIVE
,
2997 Status
= NtOpenKey (&KeyHandle
,
3000 if (!NT_SUCCESS(Status
))
3002 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
3006 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
3007 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3011 RtlInitUnicodeString (&ValueNameString
,
3013 Status
= NtQueryValueKey (KeyHandle
,
3015 KeyValuePartialInformation
,
3019 if (Status
== STATUS_BUFFER_OVERFLOW
)
3021 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
3022 RtlFreeHeap (RtlGetProcessHeap(),
3025 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3028 if (KeyInfo
== NULL
)
3030 NtClose (KeyHandle
);
3034 Status
= NtQueryValueKey (KeyHandle
,
3036 KeyValuePartialInformation
,
3041 NtClose (KeyHandle
);
3043 if (!NT_SUCCESS(Status
))
3045 if (KeyInfo
!= NULL
)
3047 RtlFreeHeap (RtlGetProcessHeap(),
3054 if (KeyInfo
->Type
!= Type
)
3056 RtlFreeHeap (RtlGetProcessHeap(),
3059 return STATUS_OBJECT_TYPE_MISMATCH
;
3062 ResultSize
= BufferSize
;
3063 if (ResultSize
< KeyInfo
->DataLength
)
3065 Status
= STATUS_BUFFER_OVERFLOW
;
3069 ResultSize
= KeyInfo
->DataLength
;
3071 RtlCopyMemory (Buffer
,
3075 RtlFreeHeap (RtlGetProcessHeap(),
3079 if (ReturnedLength
!= NULL
)
3081 *ReturnedLength
= ResultSize
;
3088 PIMAGE_BASE_RELOCATION STDCALL
3089 LdrProcessRelocationBlock(IN PVOID Address
,
3091 IN PUSHORT TypeOffset
,
3100 for (i
= 0; i
< Count
; i
++)
3102 Offset
= *TypeOffset
& 0xFFF;
3103 Type
= *TypeOffset
>> 12;
3107 case IMAGE_REL_BASED_ABSOLUTE
:
3110 case IMAGE_REL_BASED_HIGH
:
3111 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3112 *ShortPtr
+= HIWORD(Delta
);
3115 case IMAGE_REL_BASED_LOW
:
3116 ShortPtr
= (PUSHORT
)(Address
+ Offset
);
3117 *ShortPtr
+= LOWORD(Delta
);
3120 case IMAGE_REL_BASED_HIGHLOW
:
3121 LongPtr
= (PULONG
)(Address
+ Offset
);
3125 case IMAGE_REL_BASED_HIGHADJ
:
3126 case IMAGE_REL_BASED_MIPS_JMPADDR
:
3128 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type
);
3135 return (PIMAGE_BASE_RELOCATION
)TypeOffset
;