2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/ntdll/ldr/utils.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
12 * - Handle loading flags correctly
13 * - Handle errors correctly (unload dll's)
14 * - Implement a faster way to find modules (hash table)
18 /* INCLUDES *****************************************************************/
24 #define LDRP_PROCESS_CREATION_TIME 0xffff
25 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
27 /* GLOBALS *******************************************************************/
30 #define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
33 typedef struct _TLS_DATA
35 PVOID StartAddressOfRawData
;
38 PIMAGE_TLS_CALLBACK
*TlsAddressOfCallBacks
;
39 PLDR_DATA_TABLE_ENTRY Module
;
40 } TLS_DATA
, *PTLS_DATA
;
42 static BOOLEAN LdrpDllShutdownInProgress
= FALSE
;
43 static PTLS_DATA LdrpTlsArray
= NULL
;
44 static ULONG LdrpTlsCount
= 0;
45 static ULONG LdrpTlsSize
= 0;
46 static HANDLE LdrpKnownDllsDirHandle
= NULL
;
47 static UNICODE_STRING LdrpKnownDllPath
= {0, 0, NULL
};
48 static PLDR_DATA_TABLE_ENTRY LdrpLastModule
= NULL
;
49 extern PLDR_DATA_TABLE_ENTRY ExeModule
;
51 /* PROTOTYPES ****************************************************************/
53 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_DATA_TABLE_ENTRY
*Module
, BOOLEAN Ref
);
54 static PVOID
LdrFixupForward(PCHAR ForwardName
);
55 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
56 static NTSTATUS
LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
58 IN PUNICODE_STRING Name
,
59 OUT PLDR_DATA_TABLE_ENTRY
*Module
,
60 OUT PVOID
*BaseAddress OPTIONAL
);
61 static NTSTATUS
LdrpAttachProcess(VOID
);
62 static VOID
LdrpDetachProcess(BOOLEAN UnloadAll
);
64 NTSTATUS
find_actctx_dll( LPCWSTR libname
, WCHAR
*fulldosname
);
65 NTSTATUS
create_module_activation_context( LDR_DATA_TABLE_ENTRY
*module
);
67 /* FUNCTIONS *****************************************************************/
70 LdrMappedAsDataFile(PVOID
*BaseAddress
)
72 if (0 != ((DWORD_PTR
) *BaseAddress
& (PAGE_SIZE
- 1)))
74 *BaseAddress
= (PVOID
) ((DWORD_PTR
) *BaseAddress
& ~ ((DWORD_PTR
) PAGE_SIZE
- 1));
81 static __inline LONG
LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module
, BOOLEAN Locked
)
86 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
88 LoadCount
= Module
->LoadCount
;
89 if (Module
->LoadCount
> 0 && Module
->LoadCount
!= LDRP_PROCESS_CREATION_TIME
)
95 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
100 static __inline LONG
LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module
, BOOLEAN Locked
)
105 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
107 LoadCount
= Module
->LoadCount
;
108 if (Module
->LoadCount
!= LDRP_PROCESS_CREATION_TIME
)
114 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
119 static __inline VOID
LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module
, ULONG Size
, BOOLEAN Locked
)
123 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
125 Module
->TlsIndex
= (SHORT
)LdrpTlsCount
;
130 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
134 static __inline VOID
LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module
, ULONG dwReason
)
136 PIMAGE_TLS_CALLBACK
*TlsCallback
;
137 if (Module
->TlsIndex
!= 0xFFFF && Module
->LoadCount
== LDRP_PROCESS_CREATION_TIME
)
139 TlsCallback
= LdrpTlsArray
[Module
->TlsIndex
].TlsAddressOfCallBacks
;
144 TRACE_LDR("%wZ - Calling tls callback at %x\n",
145 &Module
->BaseDllName
, *TlsCallback
);
146 (*TlsCallback
)(Module
->DllBase
, dwReason
, NULL
);
153 static BOOLEAN
LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module
, DWORD dwReason
, PVOID lpReserved
)
155 if (!(Module
->Flags
& LDRP_IMAGE_DLL
) ||
156 Module
->EntryPoint
== 0)
160 LdrpTlsCallback(Module
, dwReason
);
161 return ((PDLLMAIN_FUNC
)Module
->EntryPoint
)(Module
->DllBase
, dwReason
, lpReserved
);
165 LdrpQueryAppPaths(IN PCWSTR ImageName
)
167 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
168 OBJECT_ATTRIBUTES ObjectAttributes
;
169 WCHAR SearchPathBuffer
[5*MAX_PATH
];
170 UNICODE_STRING ValueNameString
;
171 UNICODE_STRING KeyName
;
172 WCHAR NameBuffer
[MAX_PATH
];
180 _snwprintf(NameBuffer
,
181 sizeof(NameBuffer
) / sizeof(WCHAR
),
182 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s",
185 RtlInitUnicodeString(&KeyName
, NameBuffer
);
187 InitializeObjectAttributes(&ObjectAttributes
,
189 OBJ_CASE_INSENSITIVE
,
193 Status
= NtOpenKey(&KeyHandle
,
196 if (!NT_SUCCESS(Status
))
198 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
202 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 256 * sizeof(WCHAR
);
204 KeyInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize
);
207 DPRINT("RtlAllocateHeap() failed\n");
212 RtlInitUnicodeString(&ValueNameString
,
215 Status
= NtQueryValueKey(KeyHandle
,
217 KeyValuePartialInformation
,
222 if (!NT_SUCCESS(Status
))
225 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
229 RtlCopyMemory(SearchPathBuffer
,
231 KeyInfo
->DataLength
);
233 /* Free KeyInfo memory, we won't need it anymore */
234 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
236 /* Close the key handle */
239 /* get application running path */
240 wcscat(SearchPathBuffer
, L
";");
241 wcscat(SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
); // FIXME: Don't rely on it being NULL-terminated!!!
243 /* Remove trailing backslash */
244 Backslash
= wcsrchr(SearchPathBuffer
, L
'\\');
245 if (Backslash
) Backslash
= L
'\0';
247 wcscat(SearchPathBuffer
, L
";");
249 wcscat(SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
250 wcscat(SearchPathBuffer
, L
"\\system32;");
251 wcscat(SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
252 wcscat(SearchPathBuffer
, L
";.");
254 /* Copy it to the heap allocd memory */
255 Path
= RtlAllocateHeap(RtlGetProcessHeap(),
257 wcslen(SearchPathBuffer
) * sizeof(WCHAR
));
261 DPRINT1("RtlAllocateHeap() failed\n");
265 wcscpy(Path
, SearchPathBuffer
);
271 LdrpInitializeTlsForThread(VOID
)
277 PTEB Teb
= NtCurrentTeb();
279 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule
->BaseDllName
);
281 Teb
->StaticUnicodeString
.Length
= 0;
282 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
283 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
285 if (LdrpTlsCount
> 0)
287 TlsPointers
= RtlAllocateHeap(RtlGetProcessHeap(),
289 LdrpTlsCount
* sizeof(PVOID
) + LdrpTlsSize
);
290 if (TlsPointers
== NULL
)
292 DPRINT1("failed to allocate thread tls data\n");
293 return STATUS_NO_MEMORY
;
296 TlsData
= (PVOID
)((ULONG_PTR
)TlsPointers
+ LdrpTlsCount
* sizeof(PVOID
));
297 Teb
->ThreadLocalStoragePointer
= TlsPointers
;
299 TlsInfo
= LdrpTlsArray
;
300 for (i
= 0; i
< LdrpTlsCount
; i
++, TlsInfo
++)
302 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo
->Module
->BaseDllName
);
303 TlsPointers
[i
] = TlsData
;
304 if (TlsInfo
->TlsDataSize
)
306 memcpy(TlsData
, TlsInfo
->StartAddressOfRawData
, TlsInfo
->TlsDataSize
);
307 TlsData
= (PVOID
)((ULONG_PTR
)TlsData
+ TlsInfo
->TlsDataSize
);
309 if (TlsInfo
->TlsZeroSize
)
311 memset(TlsData
, 0, TlsInfo
->TlsZeroSize
);
312 TlsData
= (PVOID
)((ULONG_PTR
)TlsData
+ TlsInfo
->TlsZeroSize
);
317 DPRINT("LdrpInitializeTlsForThread() done\n");
318 return STATUS_SUCCESS
;
322 LdrpInitializeTlsForProccess(VOID
)
324 PLIST_ENTRY ModuleListHead
;
326 PLDR_DATA_TABLE_ENTRY Module
;
327 PIMAGE_TLS_DIRECTORY TlsDirectory
;
331 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule
->BaseDllName
);
333 if (LdrpTlsCount
> 0)
335 LdrpTlsArray
= RtlAllocateHeap(RtlGetProcessHeap(),
337 LdrpTlsCount
* sizeof(TLS_DATA
));
338 if (LdrpTlsArray
== NULL
)
340 DPRINT1("Failed to allocate global tls data\n");
341 return STATUS_NO_MEMORY
;
344 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
345 Entry
= ModuleListHead
->Flink
;
346 while (Entry
!= ModuleListHead
)
348 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
349 if (Module
->LoadCount
== LDRP_PROCESS_CREATION_TIME
&&
350 Module
->TlsIndex
!= 0xFFFF)
352 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
353 RtlImageDirectoryEntryToData(Module
->DllBase
,
355 IMAGE_DIRECTORY_ENTRY_TLS
,
357 ASSERT(Module
->TlsIndex
< LdrpTlsCount
);
358 TlsData
= &LdrpTlsArray
[Module
->TlsIndex
];
359 TlsData
->StartAddressOfRawData
= (PVOID
)TlsDirectory
->StartAddressOfRawData
;
360 TlsData
->TlsDataSize
= TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
;
361 TlsData
->TlsZeroSize
= TlsDirectory
->SizeOfZeroFill
;
362 if (TlsDirectory
->AddressOfCallBacks
)
363 TlsData
->TlsAddressOfCallBacks
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
;
365 TlsData
->TlsAddressOfCallBacks
= NULL
;
366 TlsData
->Module
= Module
;
368 DbgPrint("TLS directory for %wZ\n", &Module
->BaseDllName
);
369 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory
->StartAddressOfRawData
);
370 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory
->EndAddressOfRawData
);
371 DbgPrint("SizeOfRawData: %d\n", TlsDirectory
->EndAddressOfRawData
- TlsDirectory
->StartAddressOfRawData
);
372 DbgPrint("AddressOfIndex: %x\n", TlsDirectory
->AddressOfIndex
);
373 DbgPrint("AddressOfCallBacks: %x\n", TlsDirectory
->AddressOfCallBacks
);
374 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory
->SizeOfZeroFill
);
375 DbgPrint("Characteristics: %x\n", TlsDirectory
->Characteristics
);
379 * Is this region allways writable ?
381 *(PULONG
)TlsDirectory
->AddressOfIndex
= Module
->TlsIndex
;
383 Entry
= Entry
->Flink
;
387 DPRINT("LdrpInitializeTlsForProccess() done\n");
388 return STATUS_SUCCESS
;
394 OBJECT_ATTRIBUTES ObjectAttributes
;
395 UNICODE_STRING LinkTarget
;
401 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule
->BaseDllName
);
403 /* Get handle to the 'KnownDlls' directory */
404 RtlInitUnicodeString(&Name
,
406 InitializeObjectAttributes(&ObjectAttributes
,
408 OBJ_CASE_INSENSITIVE
,
411 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
412 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
414 if (!NT_SUCCESS(Status
))
416 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
417 LdrpKnownDllsDirHandle
= NULL
;
421 /* Allocate target name string */
422 LinkTarget
.Length
= 0;
423 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
424 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
426 MAX_PATH
* sizeof(WCHAR
));
427 if (LinkTarget
.Buffer
== NULL
)
429 NtClose(LdrpKnownDllsDirHandle
);
430 LdrpKnownDllsDirHandle
= NULL
;
434 RtlInitUnicodeString(&Name
,
436 InitializeObjectAttributes(&ObjectAttributes
,
438 OBJ_CASE_INSENSITIVE
,
439 LdrpKnownDllsDirHandle
,
441 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
442 SYMBOLIC_LINK_ALL_ACCESS
,
444 if (!NT_SUCCESS(Status
))
446 RtlFreeUnicodeString(&LinkTarget
);
447 NtClose(LdrpKnownDllsDirHandle
);
448 LdrpKnownDllsDirHandle
= NULL
;
452 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
456 if (!NT_SUCCESS(Status
))
458 RtlFreeUnicodeString(&LinkTarget
);
459 NtClose(LdrpKnownDllsDirHandle
);
460 LdrpKnownDllsDirHandle
= NULL
;
463 RtlCreateUnicodeString(&LdrpKnownDllPath
,
466 RtlFreeUnicodeString(&LinkTarget
);
468 DPRINT("LdrpInitLoader() done\n");
472 /***************************************************************************
477 * Adjusts the name of a dll to a fully qualified name.
480 * FullDllName: Pointer to caller supplied storage for the fully
481 * qualified dll name.
482 * DllName: Pointer to the dll name.
483 * BaseName: TRUE: Only the file name is passed to FullDllName
484 * FALSE: The full path is preserved in FullDllName
492 * A given path is not affected by the adjustment, but the file
494 * ntdll --> ntdll.dll
496 * ntdll.xyz --> ntdll.xyz
499 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
500 PUNICODE_STRING DllName
,
503 WCHAR Buffer
[MAX_PATH
];
508 Length
= DllName
->Length
/ sizeof(WCHAR
);
512 /* get the base dll name */
513 Pointer
= DllName
->Buffer
+ Length
;
520 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
523 Length
= Extension
- Pointer
;
524 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
525 Buffer
[Length
] = L
'\0';
529 /* get the full dll name */
530 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
531 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
534 /* Build the DLL's absolute name */
535 Extension
= wcsrchr (Buffer
, L
'.');
536 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
538 /* with extension - remove dot if it's the last character */
539 if (Buffer
[Length
- 1] == L
'.')
545 /* name without extension - assume that it is .dll */
546 memmove (Buffer
+ Length
, L
".dll", 10);
549 RtlCreateUnicodeString(FullDllName
, Buffer
);
552 PLDR_DATA_TABLE_ENTRY
553 LdrAddModuleEntry(PVOID ImageBase
,
554 PIMAGE_NT_HEADERS NTHeaders
,
557 PLDR_DATA_TABLE_ENTRY Module
;
559 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY
));
561 memset(Module
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
562 Module
->DllBase
= (PVOID
)ImageBase
;
563 Module
->EntryPoint
= (PVOID
)(ULONG_PTR
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
564 if (Module
->EntryPoint
!= 0)
565 Module
->EntryPoint
= (PVOID
)((ULONG_PTR
)Module
->EntryPoint
+ (ULONG_PTR
)Module
->DllBase
);
566 Module
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
567 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
569 /* loading while app is running */
570 Module
->LoadCount
= 1;
573 * loading while app is initializing
574 * dll must not be unloaded
576 Module
->LoadCount
= LDRP_PROCESS_CREATION_TIME
;
580 Module
->TlsIndex
= -1;
581 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
582 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
584 RtlCreateUnicodeString (&Module
->FullDllName
,
586 RtlCreateUnicodeString (&Module
->BaseDllName
,
587 wcsrchr(FullDosName
, L
'\\') + 1);
588 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
590 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
591 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
592 &Module
->InLoadOrderLinks
);
593 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
600 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
601 OUT PUNICODE_STRING FullDosName
,
602 OUT PHANDLE SectionHandle
)
604 OBJECT_ATTRIBUTES ObjectAttributes
;
607 DPRINT("LdrpMapKnownDll() called\n");
609 if (LdrpKnownDllsDirHandle
== NULL
)
611 DPRINT("Invalid 'KnownDlls' directory\n");
612 return STATUS_UNSUCCESSFUL
;
615 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
617 InitializeObjectAttributes(&ObjectAttributes
,
619 OBJ_CASE_INSENSITIVE
,
620 LdrpKnownDllsDirHandle
,
622 Status
= NtOpenSection(SectionHandle
,
623 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
625 if (!NT_SUCCESS(Status
))
627 DPRINT("NtOpenSection() failed for '%wZ' (Status 0x%08lx)\n", DllName
, Status
);
631 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
632 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
633 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
635 FullDosName
->MaximumLength
);
636 if (FullDosName
->Buffer
== NULL
)
638 FullDosName
->Length
= 0;
639 FullDosName
->MaximumLength
= 0;
640 return STATUS_SUCCESS
;
643 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
644 wcscat(FullDosName
->Buffer
, L
"\\");
645 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
647 DPRINT("FullDosName '%wZ'\n", FullDosName
);
649 DPRINT("LdrpMapKnownDll() done\n");
651 return STATUS_SUCCESS
;
656 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
657 IN PUNICODE_STRING DllName
,
658 OUT PUNICODE_STRING FullDosName
,
659 IN BOOLEAN MapAsDataFile
,
660 OUT PHANDLE SectionHandle
)
662 WCHAR SearchPathBuffer
[MAX_PATH
];
663 WCHAR DosName
[MAX_PATH
];
664 UNICODE_STRING FullNtFileName
;
665 OBJECT_ATTRIBUTES FileObjectAttributes
;
667 char BlockBuffer
[1024];
668 PIMAGE_DOS_HEADER DosHeader
;
669 PIMAGE_NT_HEADERS NTHeaders
;
670 IO_STATUS_BLOCK IoStatusBlock
;
674 DPRINT("LdrpMapDllImageFile() called\n");
676 if (SearchPath
== NULL
)
678 /* get application running path */
680 wcscpy (SearchPathBuffer
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
682 len
= wcslen (SearchPathBuffer
);
684 while (len
&& SearchPathBuffer
[len
- 1] != L
'\\')
687 if (len
) SearchPathBuffer
[len
-1] = L
'\0';
689 wcscat (SearchPathBuffer
, L
";");
691 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
692 wcscat (SearchPathBuffer
, L
"\\system32;");
693 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
694 wcscat (SearchPathBuffer
, L
";.");
696 SearchPath
= SearchPathBuffer
;
699 if (RtlDosSearchPath_U (SearchPath
,
706 /* try to find active context dll */
707 Status
= find_actctx_dll(DllName
->Buffer
, DosName
);
708 if(Status
== STATUS_SUCCESS
)
709 DPRINT("found %S for %S\n", DosName
,DllName
->Buffer
);
711 return STATUS_DLL_NOT_FOUND
;
714 if (!RtlDosPathNameToNtPathName_U (DosName
,
719 DPRINT("Dll %wZ not found!\n", DllName
);
720 return STATUS_DLL_NOT_FOUND
;
723 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
725 InitializeObjectAttributes(&FileObjectAttributes
,
731 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
733 Status
= NtOpenFile(&FileHandle
,
734 GENERIC_READ
|SYNCHRONIZE
,
735 &FileObjectAttributes
,
738 FILE_SYNCHRONOUS_IO_NONALERT
);
739 if (!NT_SUCCESS(Status
))
741 DPRINT1("Dll open of %wZ failed: Status = 0x%08lx\n",
742 &FullNtFileName
, Status
);
743 RtlFreeHeap (RtlGetProcessHeap (),
745 FullNtFileName
.Buffer
);
748 RtlFreeHeap (RtlGetProcessHeap (),
750 FullNtFileName
.Buffer
);
755 Status
= NtReadFile(FileHandle
,
764 if (!NT_SUCCESS(Status
))
766 DPRINT("Dll header read failed: Status = 0x%08lx\n", Status
);
772 * Overlay DOS and NT headers structures to the
773 * buffer with DLL's header raw data.
775 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
776 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
778 * Check it is a PE image file.
780 if ((DosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
781 || (DosHeader
->e_lfanew
== 0L)
782 || (*(PULONG
)(NTHeaders
) != IMAGE_NT_SIGNATURE
))
784 DPRINT("NTDLL format invalid\n");
787 return STATUS_UNSUCCESSFUL
;
792 * Create a section for dll.
794 Status
= NtCreateSection(SectionHandle
,
799 MapAsDataFile
? SEC_COMMIT
: SEC_IMAGE
,
803 if (!NT_SUCCESS(Status
))
805 DPRINT("NTDLL create section failed: Status = 0x%08lx\n", Status
);
809 RtlCreateUnicodeString(FullDosName
,
817 /***************************************************************************
834 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
835 IN PULONG LoadFlags OPTIONAL
,
836 IN PUNICODE_STRING Name
,
837 OUT PVOID
*BaseAddress
/* also known as HMODULE*, and PHANDLE 'DllHandle' */)
840 PLDR_DATA_TABLE_ENTRY Module
;
842 PPEB Peb
= NtCurrentPeb();
844 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
846 SearchPath
? L
" from " : L
"",
847 SearchPath
? SearchPath
: L
"");
849 Status
= LdrpLoadModule(SearchPath
, LoadFlags
? *LoadFlags
: 0, Name
, &Module
, BaseAddress
);
851 if (NT_SUCCESS(Status
) &&
852 (!LoadFlags
|| 0 == (*LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
)))
854 if (!(Module
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
856 RtlEnterCriticalSection(Peb
->LoaderLock
);
857 Status
= LdrpAttachProcess();
858 RtlLeaveCriticalSection(Peb
->LoaderLock
);
862 if ((!Module
) && (NT_SUCCESS(Status
)))
865 *BaseAddress
= NT_SUCCESS(Status
) ? Module
->DllBase
: NULL
;
871 /***************************************************************************
873 * LdrFindEntryForAddress
888 LdrFindEntryForAddress(PVOID Address
,
889 PLDR_DATA_TABLE_ENTRY
*Module
)
891 PLIST_ENTRY ModuleListHead
;
893 PLDR_DATA_TABLE_ENTRY ModulePtr
;
895 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
897 if (NtCurrentPeb()->Ldr
== NULL
)
898 return(STATUS_NO_MORE_ENTRIES
);
900 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
901 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
902 Entry
= ModuleListHead
->Flink
;
903 if (Entry
== ModuleListHead
)
905 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
906 return(STATUS_NO_MORE_ENTRIES
);
909 while (Entry
!= ModuleListHead
)
911 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
913 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->DllBase
);
915 if ((Address
>= ModulePtr
->DllBase
) &&
916 ((ULONG_PTR
)Address
<= ((ULONG_PTR
)ModulePtr
->DllBase
+ ModulePtr
->SizeOfImage
)))
919 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
920 return(STATUS_SUCCESS
);
923 Entry
= Entry
->Flink
;
926 DPRINT("Failed to find module entry.\n");
928 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
929 return(STATUS_NO_MORE_ENTRIES
);
933 /***************************************************************************
935 * LdrFindEntryForName
949 LdrFindEntryForName(PUNICODE_STRING Name
,
950 PLDR_DATA_TABLE_ENTRY
*Module
,
953 PLIST_ENTRY ModuleListHead
;
955 PLDR_DATA_TABLE_ENTRY ModulePtr
;
956 BOOLEAN ContainsPath
;
957 UNICODE_STRING AdjustedName
;
959 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name
);
961 if (NtCurrentPeb()->Ldr
== NULL
)
962 return(STATUS_NO_MORE_ENTRIES
);
964 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
965 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
966 Entry
= ModuleListHead
->Flink
;
967 if (Entry
== ModuleListHead
)
969 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
970 return(STATUS_NO_MORE_ENTRIES
);
973 // NULL is the current process
977 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
978 return(STATUS_SUCCESS
);
981 ContainsPath
= (Name
->Length
>= 2 * sizeof(WCHAR
) && L
':' == Name
->Buffer
[1]);
982 LdrAdjustDllName (&AdjustedName
, Name
, !ContainsPath
);
986 if ((! ContainsPath
&&
987 0 == RtlCompareUnicodeString(&LdrpLastModule
->BaseDllName
, &AdjustedName
, TRUE
)) ||
989 0 == RtlCompareUnicodeString(&LdrpLastModule
->FullDllName
, &AdjustedName
, TRUE
)))
991 *Module
= LdrpLastModule
;
992 if (Ref
&& (*Module
)->LoadCount
!= LDRP_PROCESS_CREATION_TIME
)
994 (*Module
)->LoadCount
++;
996 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
997 RtlFreeUnicodeString(&AdjustedName
);
998 return(STATUS_SUCCESS
);
1001 while (Entry
!= ModuleListHead
)
1003 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1005 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, &AdjustedName
);
1007 if ((! ContainsPath
&&
1008 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, &AdjustedName
, TRUE
)) ||
1010 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, &AdjustedName
, TRUE
)))
1012 *Module
= LdrpLastModule
= ModulePtr
;
1013 if (Ref
&& ModulePtr
->LoadCount
!= LDRP_PROCESS_CREATION_TIME
)
1015 ModulePtr
->LoadCount
++;
1017 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1018 RtlFreeUnicodeString(&AdjustedName
);
1019 return(STATUS_SUCCESS
);
1022 Entry
= Entry
->Flink
;
1025 DPRINT("Failed to find dll %wZ\n", Name
);
1026 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1027 RtlFreeUnicodeString(&AdjustedName
);
1028 return(STATUS_NO_MORE_ENTRIES
);
1031 /**********************************************************************
1047 LdrFixupForward(PCHAR ForwardName
)
1049 CHAR NameBuffer
[128];
1050 UNICODE_STRING DllName
;
1053 PLDR_DATA_TABLE_ENTRY Module
;
1056 strcpy(NameBuffer
, ForwardName
);
1057 p
= strchr(NameBuffer
, '.');
1062 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
1063 RtlCreateUnicodeStringFromAsciiz (&DllName
,
1066 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
1068 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
1070 if (!NT_SUCCESS(Status
))
1072 Status
= LdrLoadDll(NULL
,
1076 if (NT_SUCCESS(Status
))
1078 Status
= LdrFindEntryForName (&DllName
, &Module
, FALSE
);
1081 RtlFreeUnicodeString (&DllName
);
1082 if (!NT_SUCCESS(Status
))
1084 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer
);
1088 DPRINT("BaseAddress: %p\n", Module
->DllBase
);
1090 return LdrGetExportByName(Module
->DllBase
, (PUCHAR
)(p
+1), -1);
1097 /**********************************************************************
1099 * LdrGetExportByOrdinal
1113 LdrGetExportByOrdinal (
1118 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1119 ULONG ExportDirSize
;
1120 PDWORD
* ExFunctions
;
1123 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1124 RtlImageDirectoryEntryToData (BaseAddress
,
1126 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1130 ExFunctions
= (PDWORD
*)
1133 ExportDir
->AddressOfFunctions
1136 "LdrGetExportByOrdinal(Ordinal %lu) = %p\n",
1138 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1141 Function
= (0 != ExFunctions
[Ordinal
- ExportDir
->Base
]
1142 ? RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
1145 if (((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
) &&
1146 ((ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ (ULONG_PTR
)ExportDirSize
))
1148 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1149 Function
= LdrFixupForward((PCHAR
)Function
);
1156 /**********************************************************************
1158 * LdrGetExportByName
1169 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1170 * both with NumberOfNames entries.
1174 LdrGetExportByName(PVOID BaseAddress
,
1178 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1179 PDWORD
* ExFunctions
;
1181 USHORT
* ExOrdinals
;
1186 ULONG ExportDirSize
;
1188 DPRINT("LdrGetExportByName %p %s %hu\n", BaseAddress
, SymbolName
, Hint
);
1190 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1191 RtlImageDirectoryEntryToData(BaseAddress
,
1193 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1195 if (ExportDir
== NULL
)
1197 DPRINT1("LdrGetExportByName(): no export directory, "
1198 "can't lookup %s/%hu!\n", SymbolName
, Hint
);
1203 //The symbol names may be missing entirely
1204 if (ExportDir
->AddressOfNames
== 0)
1206 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1211 * Get header pointers
1213 ExNames
= (PDWORD
*)RVA(BaseAddress
,
1214 ExportDir
->AddressOfNames
);
1215 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
1216 ExportDir
->AddressOfNameOrdinals
);
1217 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
1218 ExportDir
->AddressOfFunctions
);
1221 * Check the hint first
1223 if (Hint
< ExportDir
->NumberOfNames
)
1225 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
1226 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
1228 Ordinal
= ExOrdinals
[Hint
];
1229 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1230 if (((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
) &&
1231 ((ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ (ULONG_PTR
)ExportDirSize
))
1233 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1234 Function
= LdrFixupForward((PCHAR
)Function
);
1235 if (Function
== NULL
)
1237 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1241 if (Function
!= NULL
)
1250 maxn
= ExportDir
->NumberOfNames
- 1;
1251 while (minn
<= maxn
)
1256 mid
= (minn
+ maxn
) / 2;
1258 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
1259 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
1262 Ordinal
= ExOrdinals
[mid
];
1263 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1264 if (((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
) &&
1265 ((ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ (ULONG_PTR
)ExportDirSize
))
1267 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1268 Function
= LdrFixupForward((PCHAR
)Function
);
1269 if (Function
== NULL
)
1271 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1275 if (Function
!= NULL
)
1278 else if (minn
== maxn
)
1280 DPRINT("LdrGetExportByName(): binary search failed\n");
1293 DPRINT("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1298 /**********************************************************************
1300 * LdrPerformRelocations
1303 * Relocate a DLL's memory image.
1315 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
,
1318 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1319 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
1320 ULONG Count
, OldProtect
, OldProtect2
;
1322 PVOID Page
, ProtectPage
, ProtectPage2
;
1327 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1329 return STATUS_SUCCESS
;
1333 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1335 if (RelocationDDir
->VirtualAddress
== 0 || RelocationDDir
->Size
== 0)
1337 return STATUS_SUCCESS
;
1340 ProtectSize
= PAGE_SIZE
;
1341 Delta
= (ULONG_PTR
)ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
;
1342 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1343 RelocationDDir
->VirtualAddress
);
1344 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)ImageBase
+
1345 RelocationDDir
->VirtualAddress
+ RelocationDDir
->Size
);
1347 while (RelocationDir
< RelocationEnd
&&
1348 RelocationDir
->SizeOfBlock
> 0)
1350 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) /
1352 Page
= (PVOID
)((ULONG_PTR
)ImageBase
+ (ULONG_PTR
)RelocationDir
->VirtualAddress
);
1353 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
1355 /* Unprotect the page(s) we're about to relocate. */
1357 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1362 if (!NT_SUCCESS(Status
))
1364 DPRINT1("Failed to unprotect relocation target.\n");
1368 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
<
1369 NTHeaders
->OptionalHeader
.SizeOfImage
)
1371 ProtectPage2
= (PVOID
)((ULONG_PTR
)ProtectPage
+ PAGE_SIZE
);
1372 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1377 if (!NT_SUCCESS(Status
))
1379 DPRINT1("Failed to unprotect relocation target (2).\n");
1380 NtProtectVirtualMemory(NtCurrentProcess(),
1390 ProtectPage2
= NULL
;
1393 RelocationDir
= LdrProcessRelocationBlock((ULONG_PTR
)Page
,
1397 if (RelocationDir
== NULL
)
1398 return STATUS_UNSUCCESSFUL
;
1400 /* Restore old page protection. */
1401 NtProtectVirtualMemory(NtCurrentProcess(),
1407 if (ProtectPage2
!= NULL
)
1409 NtProtectVirtualMemory(NtCurrentProcess(),
1417 return STATUS_SUCCESS
;
1421 LdrpGetOrLoadModule(PWCHAR SearchPath
,
1423 PLDR_DATA_TABLE_ENTRY
* Module
,
1426 ANSI_STRING AnsiDllName
;
1427 UNICODE_STRING DllName
;
1430 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name
);
1432 RtlInitAnsiString(&AnsiDllName
, Name
);
1433 Status
= RtlAnsiStringToUnicodeString(&DllName
, &AnsiDllName
, TRUE
);
1434 if (!NT_SUCCESS(Status
))
1439 Status
= LdrFindEntryForName (&DllName
, Module
, Load
);
1440 if (Load
&& !NT_SUCCESS(Status
))
1442 Status
= LdrpLoadModule(SearchPath
,
1447 if (NT_SUCCESS(Status
))
1449 Status
= LdrFindEntryForName (&DllName
, Module
, FALSE
);
1451 if (!NT_SUCCESS(Status
))
1453 ULONG ErrorResponse
;
1454 ULONG_PTR ErrorParameter
= (ULONG_PTR
)&DllName
;
1456 DPRINT1("failed to load %wZ\n", &DllName
);
1458 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
1466 RtlFreeUnicodeString (&DllName
);
1471 RtlpRaiseImportNotFound(CHAR
*FuncName
, ULONG Ordinal
, PUNICODE_STRING DllName
)
1473 ULONG ErrorResponse
;
1474 ULONG_PTR ErrorParameters
[2];
1475 ANSI_STRING ProcNameAnsi
;
1476 UNICODE_STRING ProcName
;
1481 _snprintf(Buffer
, 8, "# %ld", Ordinal
);
1485 RtlInitAnsiString(&ProcNameAnsi
, FuncName
);
1486 RtlAnsiStringToUnicodeString(&ProcName
, &ProcNameAnsi
, TRUE
);
1487 ErrorParameters
[0] = (ULONG_PTR
)&ProcName
;
1488 ErrorParameters
[1] = (ULONG_PTR
)DllName
;
1489 NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND
,
1495 RtlFreeUnicodeString(&ProcName
);
1499 LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module
,
1500 PLDR_DATA_TABLE_ENTRY ImportedModule
,
1501 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
)
1504 PVOID
* ImportAddressList
;
1505 PULONG FunctionNameList
;
1511 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->Name
== 0)
1513 return STATUS_UNSUCCESSFUL
;
1516 /* Get the import address list. */
1517 ImportAddressList
= (PVOID
*)((ULONG_PTR
)Module
->DllBase
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1519 /* Get the list of functions to import. */
1520 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
1522 FunctionNameList
= (PULONG
) ((ULONG_PTR
)Module
->DllBase
+ (ULONG_PTR
)ImportModuleDirectory
->OriginalFirstThunk
);
1526 FunctionNameList
= (PULONG
)((ULONG_PTR
)Module
->DllBase
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1529 /* Get the size of IAT. */
1531 while (FunctionNameList
[IATSize
] != 0L)
1536 /* Unprotect the region we are about to write into. */
1537 IATBase
= (PVOID
)ImportAddressList
;
1538 IATSize
*= sizeof(PVOID
*);
1539 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1544 if (!NT_SUCCESS(Status
))
1546 DPRINT1("Failed to unprotect IAT.\n");
1550 /* Walk through function list and fixup addresses. */
1551 while (*FunctionNameList
!= 0L)
1553 if ((*FunctionNameList
) & 0x80000000)
1555 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1556 *ImportAddressList
= LdrGetExportByOrdinal(ImportedModule
->DllBase
, Ordinal
);
1557 if ((*ImportAddressList
) == NULL
)
1559 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal
, &ImportedModule
->FullDllName
);
1560 RtlpRaiseImportNotFound(NULL
, Ordinal
, &ImportedModule
->FullDllName
);
1561 return STATUS_ENTRYPOINT_NOT_FOUND
;
1566 IMAGE_IMPORT_BY_NAME
*pe_name
;
1567 pe_name
= RVA(Module
->DllBase
, *FunctionNameList
);
1568 *ImportAddressList
= LdrGetExportByName(ImportedModule
->DllBase
, pe_name
->Name
, pe_name
->Hint
);
1569 if ((*ImportAddressList
) == NULL
)
1571 DPRINT1("Failed to import %s from %wZ\n", pe_name
->Name
, &ImportedModule
->FullDllName
);
1572 RtlpRaiseImportNotFound((CHAR
*)pe_name
->Name
, 0, &ImportedModule
->FullDllName
);
1573 return STATUS_ENTRYPOINT_NOT_FOUND
;
1576 ImportAddressList
++;
1580 /* Protect the region we are about to write into. */
1581 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1586 if (!NT_SUCCESS(Status
))
1588 DPRINT1("Failed to protect IAT.\n");
1592 return STATUS_SUCCESS
;
1596 LdrpProcessImportDirectory(
1597 PLDR_DATA_TABLE_ENTRY Module
,
1598 PLDR_DATA_TABLE_ENTRY ImportedModule
,
1602 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1606 DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
1607 Module
, &Module
->BaseDllName
, ImportedName
);
1610 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1611 RtlImageDirectoryEntryToData(Module
->DllBase
,
1613 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1615 if (ImportModuleDirectory
== NULL
)
1617 return STATUS_UNSUCCESSFUL
;
1620 while (ImportModuleDirectory
->Name
)
1622 Name
= (PCHAR
)Module
->DllBase
+ ImportModuleDirectory
->Name
;
1623 if (0 == _stricmp(Name
, ImportedName
))
1625 Status
= LdrpProcessImportDirectoryEntry(Module
,
1627 ImportModuleDirectory
);
1628 if (!NT_SUCCESS(Status
))
1633 ImportModuleDirectory
++;
1637 return STATUS_SUCCESS
;
1642 LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module
,
1643 PLDR_DATA_TABLE_ENTRY ImportedModule
,
1646 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1648 PVOID
* ImportAddressList
;
1651 PULONG FunctionNameList
;
1656 PIMAGE_NT_HEADERS NTHeaders
;
1660 DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
1661 Module
, &Module
->BaseDllName
, ImportedModule
, &ImportedModule
->BaseDllName
, ImportedName
);
1663 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1664 RtlImageDirectoryEntryToData(Module
->DllBase
,
1666 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1668 if (ImportModuleDirectory
== NULL
)
1670 return STATUS_UNSUCCESSFUL
;
1673 while (ImportModuleDirectory
->Name
)
1675 Name
= (PCHAR
)Module
->DllBase
+ ImportModuleDirectory
->Name
;
1676 if (0 == _stricmp(Name
, (PCHAR
)ImportedName
))
1679 /* Get the import address list. */
1680 ImportAddressList
= (PVOID
*)((ULONG_PTR
)Module
->DllBase
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1682 /* Get the list of functions to import. */
1683 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
1685 FunctionNameList
= (PULONG
) ((ULONG_PTR
)Module
->DllBase
+ (ULONG_PTR
)ImportModuleDirectory
->OriginalFirstThunk
);
1689 FunctionNameList
= (PULONG
)((ULONG_PTR
)Module
->DllBase
+ (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
1692 /* Get the size of IAT. */
1694 while (FunctionNameList
[IATSize
] != 0L)
1699 /* Unprotect the region we are about to write into. */
1700 IATBase
= (PVOID
)ImportAddressList
;
1701 IATSize
*= sizeof(PVOID
*);
1702 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1707 if (!NT_SUCCESS(Status
))
1709 DPRINT1("Failed to unprotect IAT.\n");
1713 NTHeaders
= RtlImageNtHeader (ImportedModule
->DllBase
);
1714 Start
= (PVOID
)NTHeaders
->OptionalHeader
.ImageBase
;
1715 End
= (PVOID
)((ULONG_PTR
)Start
+ ImportedModule
->SizeOfImage
);
1716 Offset
= (ULONG
)((ULONG_PTR
)ImportedModule
->DllBase
- (ULONG_PTR
)Start
);
1718 /* Walk through function list and fixup addresses. */
1719 while (*FunctionNameList
!= 0L)
1721 if (*ImportAddressList
>= Start
&& *ImportAddressList
< End
)
1723 (*ImportAddressList
) = (PVOID
)((ULONG_PTR
)(*ImportAddressList
) + Offset
);
1725 ImportAddressList
++;
1729 /* Protect the region we are about to write into. */
1730 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1735 if (!NT_SUCCESS(Status
))
1737 DPRINT1("Failed to protect IAT.\n");
1741 ImportModuleDirectory
++;
1743 return STATUS_SUCCESS
;
1747 /**********************************************************************
1752 * Compute the entry point for every symbol the DLL imports
1753 * from other modules.
1765 LdrFixupImports(IN PWSTR SearchPath OPTIONAL
,
1766 IN PLDR_DATA_TABLE_ENTRY Module
)
1768 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
1769 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent
;
1770 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
1771 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
1772 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1775 PLDR_DATA_TABLE_ENTRY ImportedModule
;
1781 DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath
, Module
);
1783 /* Check for tls data */
1784 TlsDirectory
= (PIMAGE_TLS_DIRECTORY
)
1785 RtlImageDirectoryEntryToData(Module
->DllBase
,
1787 IMAGE_DIRECTORY_ENTRY_TLS
,
1791 TlsSize
= TlsDirectory
->EndAddressOfRawData
1792 - TlsDirectory
->StartAddressOfRawData
1793 + TlsDirectory
->SizeOfZeroFill
;
1795 if (TlsSize
> 0 && NtCurrentPeb()->Ldr
->Initialized
)
1797 TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n",
1798 &Module
->BaseDllName
);
1799 TlsDirectory
= NULL
;
1803 if (!create_module_activation_context( Module
))
1805 if (Module
->EntryPointActivationContext
== NULL
)
1807 DPRINT("EntryPointActivationContext has not be allocated\n");
1808 DPRINT("Module->DllBaseName %wZ\n", Module
->BaseDllName
);
1810 RtlActivateActivationContext( 0, Module
->EntryPointActivationContext
, &cookie
);
1814 * Process each import module.
1816 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
1817 RtlImageDirectoryEntryToData(Module
->DllBase
,
1819 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1822 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
1823 RtlImageDirectoryEntryToData(Module
->DllBase
,
1825 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
1828 if (BoundImportDescriptor
!= NULL
&& ImportModuleDirectory
== NULL
)
1830 DPRINT1("%wZ has only a bound import directory\n", &Module
->BaseDllName
);
1831 return STATUS_UNSUCCESSFUL
;
1833 if (BoundImportDescriptor
)
1835 DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor
);
1837 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
1838 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
1840 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
1841 TRACE_LDR("%wZ bound to %s\n", &Module
->BaseDllName
, ImportedName
);
1842 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1843 if (!NT_SUCCESS(Status
))
1845 DPRINT1("failed to load %s\n", ImportedName
);
1848 if (Module
== ImportedModule
)
1850 LdrpDecrementLoadCount(Module
, FALSE
);
1852 if (ImportedModule
->TimeDateStamp
!= BoundImportDescriptorCurrent
->TimeDateStamp
)
1854 TRACE_LDR("%wZ has stale binding to %wZ\n",
1855 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1856 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1857 if (!NT_SUCCESS(Status
))
1859 DPRINT1("failed to import %s\n", ImportedName
);
1865 BOOLEAN WrongForwarder
;
1866 WrongForwarder
= FALSE
;
1867 if (ImportedModule
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)
1869 TRACE_LDR("%wZ has stale binding to %s\n",
1870 &Module
->BaseDllName
, ImportedName
);
1874 TRACE_LDR("%wZ has correct binding to %wZ\n",
1875 &Module
->BaseDllName
, &ImportedModule
->BaseDllName
);
1877 if (BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
)
1879 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef
;
1881 PLDR_DATA_TABLE_ENTRY ForwarderModule
;
1882 PCHAR ForwarderName
;
1884 BoundForwarderRef
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundImportDescriptorCurrent
+ 1);
1885 for (i
= 0; i
< BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
; i
++, BoundForwarderRef
++)
1887 ForwarderName
= (PCHAR
)BoundImportDescriptor
+ BoundForwarderRef
->OffsetModuleName
;
1888 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1889 &Module
->BaseDllName
, ForwarderName
, ImportedName
);
1890 Status
= LdrpGetOrLoadModule(SearchPath
, ForwarderName
, &ForwarderModule
, TRUE
);
1891 if (!NT_SUCCESS(Status
))
1893 DPRINT1("failed to load %s\n", ForwarderName
);
1896 if (Module
== ImportedModule
)
1898 LdrpDecrementLoadCount(Module
, FALSE
);
1900 if (ForwarderModule
->TimeDateStamp
!= BoundForwarderRef
->TimeDateStamp
||
1901 ForwarderModule
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)
1903 TRACE_LDR("%wZ has stale binding to %s\n",
1904 &Module
->BaseDllName
, ForwarderName
);
1905 WrongForwarder
= TRUE
;
1909 TRACE_LDR("%wZ has correct binding to %s\n",
1910 &Module
->BaseDllName
, ForwarderName
);
1914 if (WrongForwarder
||
1915 ImportedModule
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)
1917 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1918 if (!NT_SUCCESS(Status
))
1920 DPRINT1("failed to import %s\n", ImportedName
);
1924 else if (ImportedModule
->Flags
& LDRP_IMAGE_NOT_AT_BASE
)
1926 TRACE_LDR("Adjust imports for %s from %wZ\n",
1927 ImportedName
, &Module
->BaseDllName
);
1928 Status
= LdrpAdjustImportDirectory(Module
, ImportedModule
, ImportedName
);
1929 if (!NT_SUCCESS(Status
))
1931 DPRINT1("failed to adjust import entries for %s\n", ImportedName
);
1935 else if (WrongForwarder
)
1939 * Update only forwarders
1941 TRACE_LDR("Stale BIND %s from %wZ\n",
1942 ImportedName
, &Module
->BaseDllName
);
1943 Status
= LdrpProcessImportDirectory(Module
, ImportedModule
, ImportedName
);
1944 if (!NT_SUCCESS(Status
))
1946 DPRINT1("faild to import %s\n", ImportedName
);
1955 BoundImportDescriptorCurrent
+= BoundImportDescriptorCurrent
->NumberOfModuleForwarderRefs
+ 1;
1958 else if (ImportModuleDirectory
)
1960 DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory
);
1962 ImportModuleDirectoryCurrent
= ImportModuleDirectory
;
1963 while (ImportModuleDirectoryCurrent
->Name
)
1965 ImportedName
= (PCHAR
)Module
->DllBase
+ ImportModuleDirectoryCurrent
->Name
;
1966 TRACE_LDR("%wZ imports functions from %s\n", &Module
->BaseDllName
, ImportedName
);
1968 if (SearchPath
== NULL
)
1970 ModulePath
= LdrpQueryAppPaths(Module
->BaseDllName
.Buffer
);
1972 Status
= LdrpGetOrLoadModule(ModulePath
, ImportedName
, &ImportedModule
, TRUE
);
1973 if (ModulePath
!= NULL
) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath
);
1974 if (NT_SUCCESS(Status
)) goto Success
;
1977 Status
= LdrpGetOrLoadModule(SearchPath
, ImportedName
, &ImportedModule
, TRUE
);
1978 if (!NT_SUCCESS(Status
))
1980 DPRINT1("failed to load %s\n", ImportedName
);
1984 if (Module
== ImportedModule
)
1986 LdrpDecrementLoadCount(Module
, FALSE
);
1989 TRACE_LDR("Initializing imports for %wZ from %s\n",
1990 &Module
->BaseDllName
, ImportedName
);
1991 Status
= LdrpProcessImportDirectoryEntry(Module
, ImportedModule
, ImportModuleDirectoryCurrent
);
1992 if (!NT_SUCCESS(Status
))
1994 DPRINT1("failed to import %s\n", ImportedName
);
1997 ImportModuleDirectoryCurrent
++;
2001 if (TlsDirectory
&& TlsSize
> 0)
2003 LdrpAcquireTlsSlot(Module
, TlsSize
, FALSE
);
2006 if (Module
->EntryPointActivationContext
) RtlDeactivateActivationContext( 0, cookie
);
2008 return STATUS_SUCCESS
;
2012 /**********************************************************************
2017 * 1. Relocate, if needed the EXE.
2018 * 2. Fixup any imported symbol.
2019 * 3. Compute the EXE's entry point.
2023 * Address at which the EXE's image
2027 * Handle of the section that contains
2031 * NULL on error; otherwise the entry point
2032 * to call for initializing the DLL.
2037 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
2038 * Currently the function is only used for the exe.
2040 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
2041 HANDLE SectionHandle
,
2042 PLDR_DATA_TABLE_ENTRY
* Module
,
2046 PEPFUNC EntryPoint
= NULL
;
2047 PIMAGE_DOS_HEADER DosHeader
;
2048 PIMAGE_NT_HEADERS NTHeaders
;
2049 PLDR_DATA_TABLE_ENTRY tmpModule
;
2050 PVOID ActivationContextStack
;
2052 DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
2053 ImageBase
, SectionHandle
);
2056 * Overlay DOS and WNT headers structures
2057 * to the DLL's image.
2059 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
2060 NTHeaders
= (PIMAGE_NT_HEADERS
) ((ULONG_PTR
)ImageBase
+ DosHeader
->e_lfanew
);
2063 * If the base address is different from the
2064 * one the DLL is actually loaded, perform any
2067 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
2069 DPRINT("LDR: Performing relocations\n");
2070 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
2071 if (!NT_SUCCESS(Status
))
2073 DPRINT1("LdrPerformRelocations() failed\n");
2080 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
2081 (*Module
)->SectionPointer
= SectionHandle
;
2085 Module
= &tmpModule
;
2086 Status
= LdrFindEntryForAddress(ImageBase
, Module
);
2087 if (!NT_SUCCESS(Status
))
2093 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
2095 (*Module
)->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
2098 /* Allocate memory for the ActivationContextStack */
2099 /* FIXME: Verify RtlAllocateActivationContextStack behavior */
2100 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
2101 if (NT_SUCCESS(Status
))
2103 DPRINT("ActivationContextStack %x\n",ActivationContextStack
);
2104 DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK
)ActivationContextStack
)->ActiveFrame
);
2105 NtCurrentTeb()->ActivationContextStackPointer
= ActivationContextStack
;
2106 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= NULL
;
2109 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
2112 * If the DLL's imports symbols from other
2113 * modules, fixup the imported calls entry points.
2115 DPRINT("About to fixup imports\n");
2116 Status
= LdrFixupImports(NULL
, *Module
);
2117 if (!NT_SUCCESS(Status
))
2119 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module
)->BaseDllName
);
2122 DPRINT("Fixup done\n");
2123 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2124 Status
= LdrpInitializeTlsForProccess();
2125 if (NT_SUCCESS(Status
))
2127 Status
= LdrpAttachProcess();
2129 if (NT_SUCCESS(Status
))
2131 LdrpTlsCallback(*Module
, DLL_PROCESS_ATTACH
);
2135 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
2136 if (!NT_SUCCESS(Status
))
2142 * Compute the DLL's entry point's address.
2144 DPRINT("ImageBase = %p\n", ImageBase
);
2145 DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
2146 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
2148 EntryPoint
= (PEPFUNC
) ((ULONG_PTR
)ImageBase
2149 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
2151 DPRINT("LdrPEStartup() = %p\n",EntryPoint
);
2156 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL
,
2158 IN PUNICODE_STRING Name
,
2159 PLDR_DATA_TABLE_ENTRY
*Module
,
2160 PVOID
*BaseAddress OPTIONAL
)
2162 UNICODE_STRING AdjustedName
;
2163 UNICODE_STRING FullDosName
;
2165 PLDR_DATA_TABLE_ENTRY tmpModule
;
2166 HANDLE SectionHandle
;
2169 PIMAGE_NT_HEADERS NtHeaders
;
2170 BOOLEAN MappedAsDataFile
;
2171 PVOID ArbitraryUserPointer
;
2175 Module
= &tmpModule
;
2177 /* adjust the full dll name */
2178 LdrAdjustDllName(&AdjustedName
, Name
, FALSE
);
2180 DPRINT("%wZ\n", &AdjustedName
);
2182 MappedAsDataFile
= FALSE
;
2183 /* Test if dll is already loaded */
2184 Status
= LdrFindEntryForName(&AdjustedName
, Module
, TRUE
);
2185 if (NT_SUCCESS(Status
))
2187 RtlFreeUnicodeString(&AdjustedName
);
2188 if (NULL
!= BaseAddress
)
2190 *BaseAddress
= (*Module
)->DllBase
;
2195 /* Open or create dll image section */
2196 Status
= LdrpMapKnownDll(&AdjustedName
, &FullDosName
, &SectionHandle
);
2197 if (!NT_SUCCESS(Status
))
2199 MappedAsDataFile
= (0 != (LoadFlags
& LOAD_LIBRARY_AS_DATAFILE
));
2200 Status
= LdrpMapDllImageFile(SearchPath
, &AdjustedName
, &FullDosName
,
2201 MappedAsDataFile
, &SectionHandle
);
2203 if (!NT_SUCCESS(Status
))
2205 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName
, Status
);
2206 RtlFreeUnicodeString(&AdjustedName
);
2209 RtlFreeUnicodeString(&AdjustedName
);
2210 /* Map the dll into the process */
2213 ArbitraryUserPointer
= NtCurrentTeb()->Tib
.ArbitraryUserPointer
;
2214 NtCurrentTeb()->Tib
.ArbitraryUserPointer
= FullDosName
.Buffer
;
2215 Status
= NtMapViewOfSection(SectionHandle
,
2225 NtCurrentTeb()->Tib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
2226 if (!NT_SUCCESS(Status
))
2228 DPRINT1("map view of section failed (Status 0x%08lx)\n", Status
);
2229 RtlFreeUnicodeString(&FullDosName
);
2230 NtClose(SectionHandle
);
2233 if (NULL
!= BaseAddress
)
2235 *BaseAddress
= ImageBase
;
2237 if (!MappedAsDataFile
)
2239 /* Get and check the NT headers */
2240 NtHeaders
= RtlImageNtHeader(ImageBase
);
2241 if (NtHeaders
== NULL
)
2243 DPRINT1("RtlImageNtHeaders() failed\n");
2244 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2245 NtClose (SectionHandle
);
2246 RtlFreeUnicodeString(&FullDosName
);
2247 return STATUS_UNSUCCESSFUL
;
2250 DPRINT("Mapped %wZ at %x\n", &FullDosName
, ImageBase
);
2251 if (MappedAsDataFile
)
2253 ASSERT(NULL
!= BaseAddress
);
2254 if (NULL
!= BaseAddress
)
2256 *BaseAddress
= (PVOID
) ((char *) *BaseAddress
+ 1);
2259 RtlFreeUnicodeString(&FullDosName
);
2260 NtClose(SectionHandle
);
2261 return STATUS_SUCCESS
;
2263 /* If the base address is different from the
2264 * one the DLL is actually loaded, perform any
2266 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2268 DPRINT1("Relocating (%lx -> %p) %wZ\n",
2269 NtHeaders
->OptionalHeader
.ImageBase
, ImageBase
, &FullDosName
);
2270 Status
= LdrPerformRelocations(NtHeaders
, ImageBase
);
2271 if (!NT_SUCCESS(Status
))
2273 DPRINT1("LdrPerformRelocations() failed\n");
2274 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase
);
2275 NtClose (SectionHandle
);
2276 RtlFreeUnicodeString(&FullDosName
);
2277 return STATUS_UNSUCCESSFUL
;
2280 *Module
= LdrAddModuleEntry(ImageBase
, NtHeaders
, FullDosName
.Buffer
);
2281 (*Module
)->SectionPointer
= SectionHandle
;
2282 if (ImageBase
!= (PVOID
) NtHeaders
->OptionalHeader
.ImageBase
)
2284 (*Module
)->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
2286 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
2288 (*Module
)->Flags
|= LDRP_IMAGE_DLL
;
2290 /* fixup the imported calls entry points */
2291 Status
= LdrFixupImports(SearchPath
, *Module
);
2292 if (!NT_SUCCESS(Status
))
2294 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module
)->BaseDllName
, Status
);
2298 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2299 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
2300 &(*Module
)->InInitializationOrderLinks
);
2301 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2303 return STATUS_SUCCESS
;
2307 LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module
,
2310 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
2311 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor
;
2312 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent
;
2314 PLDR_DATA_TABLE_ENTRY ImportedModule
;
2321 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
2324 LoadCount
= LdrpDecrementLoadCount(Module
, Unload
);
2326 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module
->BaseDllName
, LoadCount
);
2330 /* ?????????????????? */
2332 else if (!(Module
->Flags
& LDRP_STATIC_LINK
) && LoadCount
== 1)
2334 BoundImportDescriptor
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)
2335 RtlImageDirectoryEntryToData(Module
->DllBase
,
2337 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
2339 if (BoundImportDescriptor
)
2341 /* dereferencing all imported modules, use the bound import descriptor */
2342 BoundImportDescriptorCurrent
= BoundImportDescriptor
;
2343 while (BoundImportDescriptorCurrent
->OffsetModuleName
)
2345 ImportedName
= (PCHAR
)BoundImportDescriptor
+ BoundImportDescriptorCurrent
->OffsetModuleName
;
2346 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2347 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2348 if (!NT_SUCCESS(Status
))
2350 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2354 if (Module
!= ImportedModule
)
2356 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2357 if (!NT_SUCCESS(Status
))
2359 DPRINT1("unable to unload %s\n", ImportedName
);
2363 BoundImportDescriptorCurrent
++;
2368 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
2369 RtlImageDirectoryEntryToData(Module
->DllBase
,
2371 IMAGE_DIRECTORY_ENTRY_IMPORT
,
2373 if (ImportModuleDirectory
)
2375 /* dereferencing all imported modules, use the import descriptor */
2376 while (ImportModuleDirectory
->Name
)
2378 ImportedName
= (PCHAR
)Module
->DllBase
+ ImportModuleDirectory
->Name
;
2379 TRACE_LDR("%wZ trys to unload %s\n", &Module
->BaseDllName
, ImportedName
);
2380 Status
= LdrpGetOrLoadModule(NULL
, ImportedName
, &ImportedModule
, FALSE
);
2381 if (!NT_SUCCESS(Status
))
2383 DPRINT1("unable to found imported modul %s\n", ImportedName
);
2387 if (Module
!= ImportedModule
)
2389 Status
= LdrpUnloadModule(ImportedModule
, FALSE
);
2390 if (!NT_SUCCESS(Status
))
2392 DPRINT1("unable to unload %s\n", ImportedName
);
2396 ImportModuleDirectory
++;
2404 if (!(Module
->Flags
& LDRP_STATIC_LINK
))
2406 LdrpDetachProcess(FALSE
);
2409 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2411 return STATUS_SUCCESS
;
2419 LdrUnloadDll (IN PVOID BaseAddress
)
2421 PLDR_DATA_TABLE_ENTRY Module
;
2424 if (BaseAddress
== NULL
)
2425 return STATUS_SUCCESS
;
2427 if (LdrMappedAsDataFile(&BaseAddress
))
2429 Status
= NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
2433 Status
= LdrFindEntryForAddress(BaseAddress
, &Module
);
2434 if (NT_SUCCESS(Status
))
2436 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module
->BaseDllName
);
2437 Status
= LdrpUnloadModule(Module
, TRUE
);
2448 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
2450 PLIST_ENTRY ModuleListHead
;
2452 PLDR_DATA_TABLE_ENTRY Module
;
2455 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
2457 Status
= STATUS_DLL_NOT_FOUND
;
2458 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2459 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2460 Entry
= ModuleListHead
->Flink
;
2461 while (Entry
!= ModuleListHead
)
2463 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2465 DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module
->BaseDllName
, Module
->DllBase
);
2467 if (Module
->DllBase
== BaseAddress
)
2469 if (Module
->TlsIndex
== 0xFFFF)
2471 Module
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
2472 Status
= STATUS_SUCCESS
;
2476 Entry
= Entry
->Flink
;
2478 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2486 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
2487 IN PULONG DllCharacteristics
,
2488 IN PUNICODE_STRING DllName
,
2489 OUT PVOID
*DllHandle
)
2491 PLDR_DATA_TABLE_ENTRY Module
;
2494 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
2495 DllName
, DllPath
? DllPath
: L
"");
2497 /* NULL is the current executable */
2498 if (DllName
== NULL
)
2500 *DllHandle
= ExeModule
->DllBase
;
2501 DPRINT("BaseAddress 0x%lx\n", *DllHandle
);
2502 return STATUS_SUCCESS
;
2505 Status
= LdrFindEntryForName(DllName
, &Module
, FALSE
);
2506 if (NT_SUCCESS(Status
))
2508 *DllHandle
= Module
->DllBase
;
2509 return STATUS_SUCCESS
;
2512 DPRINT("Failed to find dll %wZ\n", DllName
);
2514 return STATUS_DLL_NOT_FOUND
;
2521 LdrAddRefDll(IN ULONG Flags
,
2522 IN PVOID BaseAddress
)
2524 PLIST_ENTRY ModuleListHead
;
2526 PLDR_DATA_TABLE_ENTRY Module
;
2529 if (Flags
& ~(LDR_PIN_MODULE
))
2531 return STATUS_INVALID_PARAMETER
;
2534 Status
= STATUS_DLL_NOT_FOUND
;
2535 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2536 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2537 Entry
= ModuleListHead
->Flink
;
2538 while (Entry
!= ModuleListHead
)
2540 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2542 if (Module
->DllBase
== BaseAddress
)
2544 if (Flags
& LDR_PIN_MODULE
)
2546 Module
->Flags
|= LDRP_STATIC_LINK
;
2550 LdrpIncrementLoadCount(Module
,
2553 Status
= STATUS_SUCCESS
;
2556 Entry
= Entry
->Flink
;
2558 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2566 RtlPcToFileHeader(IN PVOID PcValue
,
2569 PLIST_ENTRY ModuleListHead
;
2571 PLDR_DATA_TABLE_ENTRY Module
;
2572 PVOID ImageBase
= NULL
;
2574 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2575 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2576 Entry
= ModuleListHead
->Flink
;
2577 while (Entry
!= ModuleListHead
)
2579 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2581 if ((ULONG_PTR
)PcValue
>= (ULONG_PTR
)Module
->DllBase
&&
2582 (ULONG_PTR
)PcValue
< (ULONG_PTR
)Module
->DllBase
+ Module
->SizeOfImage
)
2584 ImageBase
= Module
->DllBase
;
2587 Entry
= Entry
->Flink
;
2589 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2591 *BaseOfImage
= ImageBase
;
2599 LdrGetProcedureAddress (IN PVOID BaseAddress
,
2600 IN PANSI_STRING Name
,
2602 OUT PVOID
*ProcedureAddress
)
2604 NTSTATUS Status
= STATUS_PROCEDURE_NOT_FOUND
;
2605 if (Name
&& Name
->Length
)
2607 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name
);
2611 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal
);
2614 DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
2615 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
2619 if (Name
&& Name
->Length
)
2622 *ProcedureAddress
= LdrGetExportByName(BaseAddress
, (PUCHAR
)Name
->Buffer
, 0xffff);
2623 if (*ProcedureAddress
!= NULL
)
2625 Status
= STATUS_SUCCESS
;
2627 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
2632 Ordinal
&= 0x0000FFFF;
2633 *ProcedureAddress
= LdrGetExportByOrdinal(BaseAddress
, (WORD
)Ordinal
);
2634 if (*ProcedureAddress
)
2636 Status
= STATUS_SUCCESS
;
2638 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal
);
2641 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2643 Status
= STATUS_DLL_NOT_FOUND
;
2650 /**********************************************************************
2655 * Unload dll's which are no longer referenced from others dll's
2666 * The loader lock must be held on enty.
2669 LdrpDetachProcess(BOOLEAN UnloadAll
)
2671 PLIST_ENTRY ModuleListHead
;
2673 PLDR_DATA_TABLE_ENTRY Module
;
2674 static ULONG CallingCount
= 0;
2676 DPRINT("LdrpDetachProcess() called for %wZ\n",
2677 &ExeModule
->BaseDllName
);
2680 LdrpDllShutdownInProgress
= TRUE
;
2684 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2685 Entry
= ModuleListHead
->Blink
;
2686 while (Entry
!= ModuleListHead
)
2688 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
2689 if (((UnloadAll
&& Module
->LoadCount
== LDRP_PROCESS_CREATION_TIME
) || Module
->LoadCount
== 0) &&
2690 Module
->Flags
& LDRP_ENTRY_PROCESSED
&&
2691 !(Module
->Flags
& LDRP_UNLOAD_IN_PROGRESS
))
2693 Module
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
2694 if (Module
== LdrpLastModule
)
2696 LdrpLastModule
= NULL
;
2698 if (Module
->Flags
& LDRP_PROCESS_ATTACH_CALLED
)
2700 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2701 &Module
->BaseDllName
, Module
->EntryPoint
);
2702 LdrpCallDllEntry(Module
, DLL_PROCESS_DETACH
, (PVOID
)(INT_PTR
)(Module
->LoadCount
== LDRP_PROCESS_CREATION_TIME
? 1 : 0));
2706 TRACE_LDR("Unload %wZ\n", &Module
->BaseDllName
);
2708 Entry
= ModuleListHead
->Blink
;
2712 Entry
= Entry
->Blink
;
2716 if (CallingCount
== 1)
2718 Entry
= ModuleListHead
->Blink
;
2719 while (Entry
!= ModuleListHead
)
2721 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
2722 Entry
= Entry
->Blink
;
2723 if (Module
->Flags
& LDRP_UNLOAD_IN_PROGRESS
&&
2724 ((UnloadAll
&& Module
->LoadCount
!= LDRP_PROCESS_CREATION_TIME
) || Module
->LoadCount
== 0))
2726 /* remove the module entry from the list */
2727 RemoveEntryList (&Module
->InLoadOrderLinks
);
2728 RemoveEntryList (&Module
->InInitializationOrderLinks
);
2730 NtUnmapViewOfSection (NtCurrentProcess (), Module
->DllBase
);
2731 NtClose (Module
->SectionPointer
);
2733 TRACE_LDR("%wZ unloaded\n", &Module
->BaseDllName
);
2735 RtlFreeUnicodeString (&Module
->FullDllName
);
2736 RtlFreeUnicodeString (&Module
->BaseDllName
);
2738 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
2743 DPRINT("LdrpDetachProcess() done\n");
2746 /**********************************************************************
2751 * Initialize all dll's which are prepered for loading
2762 * The loader lock must be held on entry.
2766 LdrpAttachProcess(VOID
)
2768 PLIST_ENTRY ModuleListHead
;
2770 PLDR_DATA_TABLE_ENTRY Module
;
2772 NTSTATUS Status
= STATUS_SUCCESS
;
2774 DPRINT("LdrpAttachProcess() called for %wZ\n",
2775 &ExeModule
->BaseDllName
);
2777 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2778 Entry
= ModuleListHead
->Flink
;
2779 while (Entry
!= ModuleListHead
)
2781 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
2782 if (!(Module
->Flags
& (LDRP_LOAD_IN_PROGRESS
|LDRP_UNLOAD_IN_PROGRESS
|LDRP_ENTRY_PROCESSED
)))
2784 Module
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
2785 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2786 &Module
->BaseDllName
, Module
->EntryPoint
);
2787 Result
= LdrpCallDllEntry(Module
, DLL_PROCESS_ATTACH
, (PVOID
)(INT_PTR
)(Module
->LoadCount
== LDRP_PROCESS_CREATION_TIME
? 1 : 0));
2790 Status
= STATUS_DLL_INIT_FAILED
;
2793 if (Module
->Flags
& LDRP_IMAGE_DLL
&& Module
->EntryPoint
!= 0)
2795 Module
->Flags
|= LDRP_PROCESS_ATTACH_CALLED
|LDRP_ENTRY_PROCESSED
;
2799 Module
->Flags
|= LDRP_ENTRY_PROCESSED
;
2801 Module
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2803 Entry
= Entry
->Flink
;
2806 DPRINT("LdrpAttachProcess() done\n");
2815 RtlDllShutdownInProgress (VOID
)
2817 return LdrpDllShutdownInProgress
;
2824 LdrShutdownProcess (VOID
)
2826 LdrpDetachProcess(TRUE
);
2827 return STATUS_SUCCESS
;
2835 LdrpAttachThread (VOID
)
2837 PLIST_ENTRY ModuleListHead
;
2839 PLDR_DATA_TABLE_ENTRY Module
;
2842 DPRINT("LdrpAttachThread() called for %wZ\n",
2843 &ExeModule
->BaseDllName
);
2845 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2847 Status
= LdrpInitializeTlsForThread();
2849 if (NT_SUCCESS(Status
))
2851 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2852 Entry
= ModuleListHead
->Flink
;
2854 while (Entry
!= ModuleListHead
)
2856 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
2857 if (Module
->Flags
& LDRP_PROCESS_ATTACH_CALLED
&&
2858 !(Module
->Flags
& LDRP_DONT_CALL_FOR_THREADS
) &&
2859 !(Module
->Flags
& LDRP_UNLOAD_IN_PROGRESS
))
2861 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2862 &Module
->BaseDllName
, Module
->EntryPoint
);
2863 LdrpCallDllEntry(Module
, DLL_THREAD_ATTACH
, NULL
);
2865 Entry
= Entry
->Flink
;
2868 Entry
= NtCurrentPeb()->Ldr
->InLoadOrderModuleList
.Flink
;
2869 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2870 LdrpTlsCallback(Module
, DLL_THREAD_ATTACH
);
2873 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2875 DPRINT("LdrpAttachThread() done\n");
2885 LdrShutdownThread (VOID
)
2887 PLIST_ENTRY ModuleListHead
;
2889 PLDR_DATA_TABLE_ENTRY Module
;
2891 DPRINT("LdrShutdownThread() called for %wZ\n",
2892 &ExeModule
->BaseDllName
);
2894 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2896 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2897 Entry
= ModuleListHead
->Blink
;
2898 while (Entry
!= ModuleListHead
)
2900 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
2902 if (Module
->Flags
& LDRP_PROCESS_ATTACH_CALLED
&&
2903 !(Module
->Flags
& LDRP_DONT_CALL_FOR_THREADS
) &&
2904 !(Module
->Flags
& LDRP_UNLOAD_IN_PROGRESS
))
2906 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2907 &Module
->BaseDllName
, Module
->EntryPoint
);
2908 LdrpCallDllEntry(Module
, DLL_THREAD_DETACH
, NULL
);
2910 Entry
= Entry
->Blink
;
2913 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
2917 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer
);
2920 DPRINT("LdrShutdownThread() done\n");
2922 return STATUS_SUCCESS
;
2926 /***************************************************************************
2928 * LdrQueryProcessModuleInformation
2943 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL
,
2944 IN ULONG Size OPTIONAL
,
2945 OUT PULONG ReturnedSize
)
2947 PLIST_ENTRY ModuleListHead
;
2949 PLDR_DATA_TABLE_ENTRY Module
;
2950 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
2951 NTSTATUS Status
= STATUS_SUCCESS
;
2952 ULONG UsedSize
= sizeof(ULONG
);
2953 ANSI_STRING AnsiString
;
2956 DPRINT("LdrQueryProcessModuleInformation() called\n");
2957 // FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
2958 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
2960 if (ModuleInformation
== NULL
|| Size
== 0)
2962 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2966 ModuleInformation
->NumberOfModules
= 0;
2967 ModulePtr
= &ModuleInformation
->Modules
[0];
2968 Status
= STATUS_SUCCESS
;
2971 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
2972 Entry
= ModuleListHead
->Flink
;
2974 while (Entry
!= ModuleListHead
)
2976 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2978 DPRINT(" Module %wZ\n",
2979 &Module
->FullDllName
);
2981 if (UsedSize
> Size
)
2983 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2985 else if (ModuleInformation
!= NULL
)
2987 ModulePtr
->Section
= 0;
2988 ModulePtr
->MappedBase
= NULL
; // FIXME: ??
2989 ModulePtr
->ImageBase
= Module
->DllBase
;
2990 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
2991 ModulePtr
->Flags
= Module
->Flags
;
2992 ModulePtr
->LoadOrderIndex
= 0; // FIXME: ??
2993 ModulePtr
->InitOrderIndex
= 0; // FIXME: ??
2994 ModulePtr
->LoadCount
= Module
->LoadCount
;
2996 AnsiString
.Length
= 0;
2997 AnsiString
.MaximumLength
= 256;
2998 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
2999 RtlUnicodeStringToAnsiString(&AnsiString
,
3000 &Module
->FullDllName
,
3003 p
= strrchr(ModulePtr
->FullPathName
, '\\');
3005 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
3007 ModulePtr
->OffsetToFileName
= 0;
3010 ModuleInformation
->NumberOfModules
++;
3012 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
3014 Entry
= Entry
->Flink
;
3017 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
3019 if (ReturnedSize
!= 0)
3020 *ReturnedSize
= UsedSize
;
3022 DPRINT("LdrQueryProcessModuleInformation() done\n");
3029 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
3032 PIMAGE_NT_HEADERS Header
;
3039 Header
= RtlImageNtHeader (BaseAddress
);
3043 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
3048 Ptr
= (PUSHORT
) BaseAddress
;
3049 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
3052 if (HIWORD(Sum
) != 0)
3054 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
3061 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
3062 if (HIWORD(Sum
) != 0)
3064 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
3068 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
3070 /* Subtract image checksum from calculated checksum. */
3071 /* fix low word of checksum */
3072 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
3074 CalcSum
-= LOWORD(HeaderSum
);
3078 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
3081 /* fix high word of checksum */
3082 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
3084 CalcSum
-= HIWORD(HeaderSum
);
3088 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
3091 /* add file length */
3092 CalcSum
+= ImageSize
;
3094 return (BOOLEAN
)(CalcSum
== HeaderSum
);
3098 * Compute size of an image as it is actually present in virt memory
3099 * (i.e. excluding NEVER_LOAD sections)
3102 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders
)
3104 PIMAGE_SECTION_HEADER SectionHeader
;
3105 unsigned SectionIndex
;
3108 SectionHeader
= (PIMAGE_SECTION_HEADER
)((char *) &NTHeaders
->OptionalHeader
3109 + NTHeaders
->FileHeader
.SizeOfOptionalHeader
);
3111 for (SectionIndex
= 0; SectionIndex
< NTHeaders
->FileHeader
.NumberOfSections
; SectionIndex
++)
3113 if (0 == (SectionHeader
->Characteristics
& IMAGE_SCN_LNK_REMOVE
)
3114 && ResidentSize
< SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
)
3116 ResidentSize
= SectionHeader
->VirtualAddress
+ SectionHeader
->Misc
.VirtualSize
;
3121 return ResidentSize
;
3125 /***************************************************************************
3127 * LdrVerifyImageMatchesChecksum
3142 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
3147 FILE_STANDARD_INFORMATION FileInfo
;
3148 IO_STATUS_BLOCK IoStatusBlock
;
3149 HANDLE SectionHandle
;
3155 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
3157 Status
= NtCreateSection (&SectionHandle
,
3164 if (!NT_SUCCESS(Status
))
3166 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
3172 Status
= NtMapViewOfSection (SectionHandle
,
3173 NtCurrentProcess (),
3182 if (!NT_SUCCESS(Status
))
3184 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
3185 NtClose (SectionHandle
);
3189 Status
= NtQueryInformationFile (FileHandle
,
3192 sizeof (FILE_STANDARD_INFORMATION
),
3193 FileStandardInformation
);
3194 if (!NT_SUCCESS(Status
))
3196 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
3197 NtUnmapViewOfSection (NtCurrentProcess (),
3199 NtClose (SectionHandle
);
3203 Result
= LdrpCheckImageChecksum (BaseAddress
,
3204 FileInfo
.EndOfFile
.u
.LowPart
);
3205 if (Result
== FALSE
)
3207 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
3210 NtUnmapViewOfSection (NtCurrentProcess (),
3213 NtClose (SectionHandle
);
3219 /***************************************************************************
3221 * LdrQueryImageFileExecutionOptions
3236 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
3237 IN PCWSTR ValueName
,
3240 IN ULONG BufferSize
,
3241 OUT PULONG ReturnedLength OPTIONAL
)
3243 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
3244 OBJECT_ATTRIBUTES ObjectAttributes
;
3245 UNICODE_STRING ValueNameString
;
3246 UNICODE_STRING KeyName
;
3247 WCHAR NameBuffer
[256];
3255 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
3256 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
3259 Ptr
= SubKey
->Buffer
;
3265 wcscat (NameBuffer
, Ptr
);
3266 RtlInitUnicodeString (&KeyName
,
3269 InitializeObjectAttributes (&ObjectAttributes
,
3271 OBJ_CASE_INSENSITIVE
,
3275 Status
= NtOpenKey (&KeyHandle
,
3278 if (!NT_SUCCESS(Status
))
3280 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status
);
3284 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
3285 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3288 if (KeyInfo
== NULL
)
3290 NtClose (KeyHandle
);
3291 return STATUS_INSUFFICIENT_RESOURCES
;
3294 RtlInitUnicodeString (&ValueNameString
,
3296 Status
= NtQueryValueKey (KeyHandle
,
3298 KeyValuePartialInformation
,
3302 if (Status
== STATUS_BUFFER_OVERFLOW
)
3304 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
3305 RtlFreeHeap (RtlGetProcessHeap(),
3308 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
3311 if (KeyInfo
== NULL
)
3313 NtClose (KeyHandle
);
3314 return STATUS_INSUFFICIENT_RESOURCES
;
3317 Status
= NtQueryValueKey (KeyHandle
,
3319 KeyValuePartialInformation
,
3324 NtClose (KeyHandle
);
3326 if (!NT_SUCCESS(Status
))
3328 if (KeyInfo
!= NULL
)
3330 RtlFreeHeap (RtlGetProcessHeap(),
3337 if (KeyInfo
->Type
!= Type
)
3339 RtlFreeHeap (RtlGetProcessHeap(),
3342 return STATUS_OBJECT_TYPE_MISMATCH
;
3345 ResultSize
= BufferSize
;
3346 if (ResultSize
< KeyInfo
->DataLength
)
3348 Status
= STATUS_BUFFER_OVERFLOW
;
3352 ResultSize
= KeyInfo
->DataLength
;
3354 RtlCopyMemory (Buffer
,
3358 RtlFreeHeap (RtlGetProcessHeap(),
3362 if (ReturnedLength
!= NULL
)
3364 *ReturnedLength
= ResultSize
;
3371 PIMAGE_BASE_RELOCATION NTAPI
3372 LdrProcessRelocationBlock(IN ULONG_PTR Address
,
3374 IN PUSHORT TypeOffset
,
3383 for (i
= 0; i
< Count
; i
++)
3385 Offset
= *TypeOffset
& 0xFFF;
3386 Type
= *TypeOffset
>> 12;
3390 case IMAGE_REL_BASED_ABSOLUTE
:
3393 case IMAGE_REL_BASED_HIGH
:
3394 ShortPtr
= (PUSHORT
)((ULONG_PTR
)Address
+ Offset
);
3395 *ShortPtr
+= HIWORD(Delta
);
3398 case IMAGE_REL_BASED_LOW
:
3399 ShortPtr
= (PUSHORT
)((ULONG_PTR
)Address
+ Offset
);
3400 *ShortPtr
+= LOWORD(Delta
);
3403 case IMAGE_REL_BASED_HIGHLOW
:
3404 LongPtr
= (PULONG
)((ULONG_PTR
)Address
+ Offset
);
3408 case IMAGE_REL_BASED_DIR64
:
3409 LongPtr
= (PULONG
)((ULONG_PTR
)Address
+ Offset
);
3414 case IMAGE_REL_BASED_HIGHADJ
:
3415 case IMAGE_REL_BASED_MIPS_JMPADDR
:
3417 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type
);
3424 return (PIMAGE_BASE_RELOCATION
)TypeOffset
;
3429 LdrLockLoaderLock(IN ULONG Flags
,
3430 OUT PULONG Disposition OPTIONAL
,
3431 OUT PULONG Cookie OPTIONAL
)
3435 BOOLEAN CookieSet
= FALSE
;
3437 if ((Flags
!= 0x01) && (Flags
!= 0x02))
3438 return STATUS_INVALID_PARAMETER_1
;
3440 if (!Cookie
) return STATUS_INVALID_PARAMETER_3
;
3442 /* Set some defaults for failure while verifying params */
3447 if (Disposition
) *Disposition
= 0;
3449 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3452 Status
= STATUS_INVALID_PARAMETER_3
;
3454 Status
= STATUS_INVALID_PARAMETER_2
;
3460 DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
3461 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
3462 Status
= STATUS_SUCCESS
;
3467 if (!Disposition
) return STATUS_INVALID_PARAMETER_2
;
3469 Ret
= RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
3472 *Disposition
= 0x01;
3474 *Disposition
= 0x02;
3476 Status
= STATUS_SUCCESS
;
3479 /* FIXME: Cookie is based on part of the thread id */
3480 *Cookie
= (ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
;
3486 LdrUnlockLoaderLock(IN ULONG Flags
,
3487 IN ULONG Cookie OPTIONAL
)
3490 return STATUS_INVALID_PARAMETER_1
;
3492 if (Cookie
!= (ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
)
3493 return STATUS_INVALID_PARAMETER_2
;
3495 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
3497 return STATUS_SUCCESS
;
3502 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress
)