Merge trunk HEAD (r46369)
[reactos.git] / reactos / dll / ntdll / ldr / utils.c
1 /*
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)
8 * Michael Martin
9 */
10
11 /*
12 * TODO:
13 * - Handle loading flags correctly
14 * - Handle errors correctly (unload dll's)
15 * - Implement a faster way to find modules (hash table)
16 * - any more ??
17 */
18
19 /* INCLUDES *****************************************************************/
20
21 #include <ntdll.h>
22 #define NDEBUG
23 #include <debug.h>
24
25 #define LDRP_PROCESS_CREATION_TIME 0xffff
26 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
27
28 /* GLOBALS *******************************************************************/
29
30 #ifdef NDEBUG
31 #define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
32 #endif
33
34 typedef struct _TLS_DATA
35 {
36 PVOID StartAddressOfRawData;
37 DWORD TlsDataSize;
38 DWORD TlsZeroSize;
39 PIMAGE_TLS_CALLBACK *TlsAddressOfCallBacks;
40 PLDR_DATA_TABLE_ENTRY Module;
41 } TLS_DATA, *PTLS_DATA;
42
43 static BOOLEAN LdrpDllShutdownInProgress = FALSE;
44 static PTLS_DATA LdrpTlsArray = NULL;
45 static ULONG LdrpTlsCount = 0;
46 static ULONG LdrpTlsSize = 0;
47 static HANDLE LdrpKnownDllsDirHandle = NULL;
48 static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
49 static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
50 extern PLDR_DATA_TABLE_ENTRY ExeModule;
51
52 /* PROTOTYPES ****************************************************************/
53
54 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
55 static PVOID LdrFixupForward(PCHAR ForwardName);
56 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
57 static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
58 IN ULONG LoadFlags,
59 IN PUNICODE_STRING Name,
60 OUT PLDR_DATA_TABLE_ENTRY *Module,
61 OUT PVOID *BaseAddress OPTIONAL);
62 static NTSTATUS LdrpAttachProcess(VOID);
63 static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
64 static NTSTATUS LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Unload);
65
66 NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname );
67 NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module );
68
69 /* FUNCTIONS *****************************************************************/
70
71 BOOLEAN
72 LdrMappedAsDataFile(PVOID *BaseAddress)
73 {
74 if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1)))
75 {
76 *BaseAddress = (PVOID) ((DWORD_PTR) *BaseAddress & ~ ((DWORD_PTR) PAGE_SIZE - 1));
77 return TRUE;
78 }
79
80 return FALSE;
81 }
82
83 static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
84 {
85 LONG LoadCount;
86 if (!Locked)
87 {
88 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
89 }
90 LoadCount = Module->LoadCount;
91 if (Module->LoadCount > 0 && Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
92 {
93 Module->LoadCount--;
94 }
95 if (!Locked)
96 {
97 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
98 }
99 return LoadCount;
100 }
101
102 static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
103 {
104 LONG LoadCount;
105 if (!Locked)
106 {
107 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
108 }
109 LoadCount = Module->LoadCount;
110 if (Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
111 {
112 Module->LoadCount++;
113 }
114 if (!Locked)
115 {
116 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
117 }
118 return LoadCount;
119 }
120
121 static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size, BOOLEAN Locked)
122 {
123 if (!Locked)
124 {
125 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
126 }
127 Module->TlsIndex = (SHORT)LdrpTlsCount;
128 LdrpTlsCount++;
129 LdrpTlsSize += Size;
130 if (!Locked)
131 {
132 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
133 }
134 }
135
136 static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
137 {
138 PIMAGE_TLS_CALLBACK *TlsCallback;
139 if (Module->TlsIndex != 0xFFFF && Module->LoadCount == LDRP_PROCESS_CREATION_TIME)
140 {
141 TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
142 if (TlsCallback)
143 {
144 while (*TlsCallback)
145 {
146 TRACE_LDR("%wZ - Calling tls callback at %x\n",
147 &Module->BaseDllName, *TlsCallback);
148 (*TlsCallback)(Module->DllBase, dwReason, NULL);
149 TlsCallback++;
150 }
151 }
152 }
153 }
154
155 static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
156 {
157 if (!(Module->Flags & LDRP_IMAGE_DLL) ||
158 Module->EntryPoint == 0)
159 {
160 return TRUE;
161 }
162 LdrpTlsCallback(Module, dwReason);
163 return ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
164 }
165
166 static PWSTR
167 LdrpQueryAppPaths(IN PCWSTR ImageName)
168 {
169 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
170 OBJECT_ATTRIBUTES ObjectAttributes;
171 WCHAR SearchPathBuffer[5*MAX_PATH];
172 UNICODE_STRING ValueNameString;
173 UNICODE_STRING KeyName;
174 WCHAR NameBuffer[MAX_PATH];
175 ULONG KeyInfoSize;
176 ULONG ResultSize;
177 PWCHAR Backslash;
178 HANDLE KeyHandle;
179 NTSTATUS Status;
180 PWSTR Path = NULL;
181
182 _snwprintf(NameBuffer,
183 sizeof(NameBuffer) / sizeof(WCHAR),
184 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s",
185 ImageName);
186
187 RtlInitUnicodeString(&KeyName, NameBuffer);
188
189 InitializeObjectAttributes(&ObjectAttributes,
190 &KeyName,
191 OBJ_CASE_INSENSITIVE,
192 NULL,
193 NULL);
194
195 Status = NtOpenKey(&KeyHandle,
196 KEY_READ,
197 &ObjectAttributes);
198 if (!NT_SUCCESS(Status))
199 {
200 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
201 return NULL;
202 }
203
204 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR);
205
206 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize);
207 if (KeyInfo == NULL)
208 {
209 DPRINT("RtlAllocateHeap() failed\n");
210 NtClose(KeyHandle);
211 return NULL;
212 }
213
214 RtlInitUnicodeString(&ValueNameString,
215 L"Path");
216
217 Status = NtQueryValueKey(KeyHandle,
218 &ValueNameString,
219 KeyValuePartialInformation,
220 KeyInfo,
221 KeyInfoSize,
222 &ResultSize);
223
224 if (!NT_SUCCESS(Status))
225 {
226 NtClose(KeyHandle);
227 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
228 return NULL;
229 }
230
231 RtlCopyMemory(SearchPathBuffer,
232 &KeyInfo->Data,
233 KeyInfo->DataLength);
234
235 /* Free KeyInfo memory, we won't need it anymore */
236 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
237
238 /* Close the key handle */
239 NtClose(KeyHandle);
240
241 /* get application running path */
242 wcscat(SearchPathBuffer, L";");
243 wcscat(SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer); // FIXME: Don't rely on it being NULL-terminated!!!
244
245 /* Remove trailing backslash */
246 Backslash = wcsrchr(SearchPathBuffer, L'\\');
247 if (Backslash) Backslash = L'\0';
248
249 wcscat(SearchPathBuffer, L";");
250
251 wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
252 wcscat(SearchPathBuffer, L"\\system32;");
253 wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
254 wcscat(SearchPathBuffer, L";.");
255
256 /* Copy it to the heap allocd memory */
257 Path = RtlAllocateHeap(RtlGetProcessHeap(),
258 0,
259 wcslen(SearchPathBuffer) * sizeof(WCHAR));
260
261 if (!Path)
262 {
263 DPRINT1("RtlAllocateHeap() failed\n");
264 return NULL;
265 }
266
267 wcscpy(Path, SearchPathBuffer);
268
269 return Path;
270 }
271
272 static NTSTATUS
273 LdrpInitializeTlsForThread(VOID)
274 {
275 PVOID* TlsPointers;
276 PTLS_DATA TlsInfo;
277 PVOID TlsData;
278 ULONG i;
279 PTEB Teb = NtCurrentTeb();
280
281 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
282
283 Teb->StaticUnicodeString.Length = 0;
284 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
285 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
286
287 if (LdrpTlsCount > 0)
288 {
289 TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
290 0,
291 LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
292 if (TlsPointers == NULL)
293 {
294 DPRINT1("failed to allocate thread tls data\n");
295 return STATUS_NO_MEMORY;
296 }
297
298 TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));
299 Teb->ThreadLocalStoragePointer = TlsPointers;
300
301 TlsInfo = LdrpTlsArray;
302 for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
303 {
304 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
305 TlsPointers[i] = TlsData;
306 if (TlsInfo->TlsDataSize)
307 {
308 memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
309 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);
310 }
311 if (TlsInfo->TlsZeroSize)
312 {
313 memset(TlsData, 0, TlsInfo->TlsZeroSize);
314 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);
315 }
316 }
317 }
318
319 DPRINT("LdrpInitializeTlsForThread() done\n");
320 return STATUS_SUCCESS;
321 }
322
323 static NTSTATUS
324 LdrpInitializeTlsForProccess(VOID)
325 {
326 PLIST_ENTRY ModuleListHead;
327 PLIST_ENTRY Entry;
328 PLDR_DATA_TABLE_ENTRY Module;
329 PIMAGE_TLS_DIRECTORY TlsDirectory;
330 PTLS_DATA TlsData;
331 ULONG Size;
332
333 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
334
335 if (LdrpTlsCount > 0)
336 {
337 LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
338 0,
339 LdrpTlsCount * sizeof(TLS_DATA));
340 if (LdrpTlsArray == NULL)
341 {
342 DPRINT1("Failed to allocate global tls data\n");
343 return STATUS_NO_MEMORY;
344 }
345
346 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
347 Entry = ModuleListHead->Flink;
348 while (Entry != ModuleListHead)
349 {
350 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
351 if (Module->LoadCount == LDRP_PROCESS_CREATION_TIME &&
352 Module->TlsIndex != 0xFFFF)
353 {
354 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
355 RtlImageDirectoryEntryToData(Module->DllBase,
356 TRUE,
357 IMAGE_DIRECTORY_ENTRY_TLS,
358 &Size);
359 ASSERT(Module->TlsIndex < LdrpTlsCount);
360 TlsData = &LdrpTlsArray[Module->TlsIndex];
361 TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
362 TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
363 TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
364 if (TlsDirectory->AddressOfCallBacks)
365 TlsData->TlsAddressOfCallBacks = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
366 else
367 TlsData->TlsAddressOfCallBacks = NULL;
368 TlsData->Module = Module;
369 #if 0
370 DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
371 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
372 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory->EndAddressOfRawData);
373 DbgPrint("SizeOfRawData: %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
374 DbgPrint("AddressOfIndex: %x\n", TlsDirectory->AddressOfIndex);
375 DbgPrint("AddressOfCallBacks: %x\n", TlsDirectory->AddressOfCallBacks);
376 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory->SizeOfZeroFill);
377 DbgPrint("Characteristics: %x\n", TlsDirectory->Characteristics);
378 #endif
379 /*
380 * FIXME:
381 * Is this region allways writable ?
382 */
383 *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
384 }
385 Entry = Entry->Flink;
386 }
387 }
388
389 DPRINT("LdrpInitializeTlsForProccess() done\n");
390 return STATUS_SUCCESS;
391 }
392
393 VOID
394 LdrpInitLoader(VOID)
395 {
396 OBJECT_ATTRIBUTES ObjectAttributes;
397 UNICODE_STRING LinkTarget;
398 UNICODE_STRING Name;
399 HANDLE LinkHandle;
400 ULONG Length;
401 NTSTATUS Status;
402
403 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
404
405 /* Get handle to the 'KnownDlls' directory */
406 RtlInitUnicodeString(&Name,
407 L"\\KnownDlls");
408 InitializeObjectAttributes(&ObjectAttributes,
409 &Name,
410 OBJ_CASE_INSENSITIVE,
411 NULL,
412 NULL);
413 Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
414 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
415 &ObjectAttributes);
416 if (!NT_SUCCESS(Status))
417 {
418 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
419 LdrpKnownDllsDirHandle = NULL;
420 return;
421 }
422
423 /* Allocate target name string */
424 LinkTarget.Length = 0;
425 LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
426 LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
427 0,
428 MAX_PATH * sizeof(WCHAR));
429 if (LinkTarget.Buffer == NULL)
430 {
431 NtClose(LdrpKnownDllsDirHandle);
432 LdrpKnownDllsDirHandle = NULL;
433 return;
434 }
435
436 RtlInitUnicodeString(&Name,
437 L"KnownDllPath");
438 InitializeObjectAttributes(&ObjectAttributes,
439 &Name,
440 OBJ_CASE_INSENSITIVE,
441 LdrpKnownDllsDirHandle,
442 NULL);
443 Status = NtOpenSymbolicLinkObject(&LinkHandle,
444 SYMBOLIC_LINK_ALL_ACCESS,
445 &ObjectAttributes);
446 if (!NT_SUCCESS(Status))
447 {
448 RtlFreeUnicodeString(&LinkTarget);
449 NtClose(LdrpKnownDllsDirHandle);
450 LdrpKnownDllsDirHandle = NULL;
451 return;
452 }
453
454 Status = NtQuerySymbolicLinkObject(LinkHandle,
455 &LinkTarget,
456 &Length);
457 NtClose(LinkHandle);
458 if (!NT_SUCCESS(Status))
459 {
460 RtlFreeUnicodeString(&LinkTarget);
461 NtClose(LdrpKnownDllsDirHandle);
462 LdrpKnownDllsDirHandle = NULL;
463 }
464
465 RtlCreateUnicodeString(&LdrpKnownDllPath,
466 LinkTarget.Buffer);
467
468 RtlFreeUnicodeString(&LinkTarget);
469
470 DPRINT("LdrpInitLoader() done\n");
471 }
472
473
474 /***************************************************************************
475 * NAME LOCAL
476 * LdrAdjustDllName
477 *
478 * DESCRIPTION
479 * Adjusts the name of a dll to a fully qualified name.
480 *
481 * ARGUMENTS
482 * FullDllName: Pointer to caller supplied storage for the fully
483 * qualified dll name.
484 * DllName: Pointer to the dll name.
485 * BaseName: TRUE: Only the file name is passed to FullDllName
486 * FALSE: The full path is preserved in FullDllName
487 *
488 * RETURN VALUE
489 * None
490 *
491 * REVISIONS
492 *
493 * NOTE
494 * A given path is not affected by the adjustment, but the file
495 * name only:
496 * ntdll --> ntdll.dll
497 * ntdll. --> ntdll
498 * ntdll.xyz --> ntdll.xyz
499 */
500 static VOID
501 LdrAdjustDllName (PUNICODE_STRING FullDllName,
502 PUNICODE_STRING DllName,
503 BOOLEAN BaseName)
504 {
505 WCHAR Buffer[MAX_PATH];
506 ULONG Length;
507 PWCHAR Extension;
508 PWCHAR Pointer;
509
510 Length = DllName->Length / sizeof(WCHAR);
511
512 if (BaseName)
513 {
514 /* get the base dll name */
515 Pointer = DllName->Buffer + Length;
516 Extension = Pointer;
517
518 do
519 {
520 --Pointer;
521 }
522 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
523
524 Pointer++;
525 Length = Extension - Pointer;
526 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
527 Buffer[Length] = L'\0';
528 }
529 else
530 {
531 /* get the full dll name */
532 memmove (Buffer, DllName->Buffer, DllName->Length);
533 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
534 }
535
536 /* Build the DLL's absolute name */
537 Extension = wcsrchr (Buffer, L'.');
538 if ((Extension != NULL) && (*Extension == L'.'))
539 {
540 /* with extension - remove dot if it's the last character */
541 if (Buffer[Length - 1] == L'.')
542 Length--;
543 Buffer[Length] = 0;
544 }
545 else
546 {
547 /* name without extension - assume that it is .dll */
548 memmove (Buffer + Length, L".dll", 10);
549 }
550
551 RtlCreateUnicodeString(FullDllName, Buffer);
552 }
553
554 PLDR_DATA_TABLE_ENTRY
555 LdrAddModuleEntry(PVOID ImageBase,
556 PIMAGE_NT_HEADERS NTHeaders,
557 PWSTR FullDosName)
558 {
559 PLDR_DATA_TABLE_ENTRY Module;
560
561 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY));
562 ASSERT(Module);
563 memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
564 Module->DllBase = (PVOID)ImageBase;
565 Module->EntryPoint = (PVOID)(ULONG_PTR)NTHeaders->OptionalHeader.AddressOfEntryPoint;
566 if (Module->EntryPoint != 0)
567 Module->EntryPoint = (PVOID)((ULONG_PTR)Module->EntryPoint + (ULONG_PTR)Module->DllBase);
568 Module->SizeOfImage = LdrpGetResidentSize(NTHeaders);
569 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
570 {
571 /* loading while app is running */
572 Module->LoadCount = 1;
573 } else {
574 /*
575 * loading while app is initializing
576 * dll must not be unloaded
577 */
578 Module->LoadCount = LDRP_PROCESS_CREATION_TIME;
579 }
580
581 Module->Flags = 0;
582 Module->TlsIndex = -1;
583 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
584 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
585
586 RtlCreateUnicodeString (&Module->FullDllName,
587 FullDosName);
588 RtlCreateUnicodeString (&Module->BaseDllName,
589 wcsrchr(FullDosName, L'\\') + 1);
590 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
591
592 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
593 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
594 &Module->InLoadOrderLinks);
595 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
596
597 return(Module);
598 }
599
600
601 static NTSTATUS
602 LdrpMapKnownDll(IN PUNICODE_STRING DllName,
603 OUT PUNICODE_STRING FullDosName,
604 OUT PHANDLE SectionHandle)
605 {
606 OBJECT_ATTRIBUTES ObjectAttributes;
607 NTSTATUS Status;
608
609 DPRINT("LdrpMapKnownDll() called\n");
610
611 if (LdrpKnownDllsDirHandle == NULL)
612 {
613 DPRINT("Invalid 'KnownDlls' directory\n");
614 return STATUS_UNSUCCESSFUL;
615 }
616
617 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
618
619 InitializeObjectAttributes(&ObjectAttributes,
620 DllName,
621 OBJ_CASE_INSENSITIVE,
622 LdrpKnownDllsDirHandle,
623 NULL);
624 Status = NtOpenSection(SectionHandle,
625 SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
626 &ObjectAttributes);
627 if (!NT_SUCCESS(Status))
628 {
629 DPRINT("NtOpenSection() failed for '%wZ' (Status 0x%08lx)\n", DllName, Status);
630 return Status;
631 }
632
633 FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR);
634 FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR);
635 FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
636 0,
637 FullDosName->MaximumLength);
638 if (FullDosName->Buffer == NULL)
639 {
640 FullDosName->Length = 0;
641 FullDosName->MaximumLength = 0;
642 return STATUS_SUCCESS;
643 }
644
645 wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
646 wcscat(FullDosName->Buffer, L"\\");
647 wcscat(FullDosName->Buffer, DllName->Buffer);
648
649 DPRINT("FullDosName '%wZ'\n", FullDosName);
650
651 DPRINT("LdrpMapKnownDll() done\n");
652
653 return STATUS_SUCCESS;
654 }
655
656
657 static NTSTATUS
658 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
659 IN PUNICODE_STRING DllName,
660 OUT PUNICODE_STRING FullDosName,
661 IN BOOLEAN MapAsDataFile,
662 OUT PHANDLE SectionHandle)
663 {
664 WCHAR *SearchPathBuffer = NULL;
665 WCHAR *ImagePathNameBufferPtr = NULL;
666 WCHAR DosName[MAX_PATH];
667 UNICODE_STRING FullNtFileName;
668 UNICODE_STRING PathEnvironmentVar_U;
669 UNICODE_STRING PathName_U;
670 OBJECT_ATTRIBUTES FileObjectAttributes;
671 HANDLE FileHandle;
672 char BlockBuffer [1024];
673 PIMAGE_DOS_HEADER DosHeader;
674 PIMAGE_NT_HEADERS NTHeaders;
675 IO_STATUS_BLOCK IoStatusBlock;
676 NTSTATUS Status;
677 ULONG len;
678 ULONG ImagePathLen;
679
680 DPRINT("LdrpMapDllImageFile() called\n");
681
682 if (SearchPath == NULL)
683 {
684 /* get application running path */
685 ImagePathNameBufferPtr = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
686
687 /* Length of ImagePathName */
688 ImagePathLen = wcslen(ImagePathNameBufferPtr);
689
690 /* Subtract application name leaveing only the directory length */
691 while (ImagePathLen && ImagePathNameBufferPtr[ImagePathLen - 1] != L'\\')
692 ImagePathLen--;
693
694 /* Length of directory + semicolon */
695 len = ImagePathLen + 1;
696
697 /* Length of SystemRoot + "//system32" + semicolon*/
698 len += wcslen(SharedUserData->NtSystemRoot) + 10;
699 /* Length of SystemRoot + semicolon */
700 len += wcslen(SharedUserData->NtSystemRoot) + 1;
701
702 RtlInitUnicodeString (&PathName_U, L"PATH");
703 PathEnvironmentVar_U.Length = 0;
704 PathEnvironmentVar_U.MaximumLength = 0;
705 PathEnvironmentVar_U.Buffer = NULL;
706
707 /* Get the path environment variable */
708 Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
709
710 /* Check that valid information was returned */
711 if ((Status == STATUS_BUFFER_TOO_SMALL) && (PathEnvironmentVar_U.Length > 0))
712 {
713 /* Allocate memory for the path env var */
714 PathEnvironmentVar_U.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, PathEnvironmentVar_U.Length + sizeof(WCHAR));
715 if (!PathEnvironmentVar_U.Buffer)
716 {
717 DPRINT1("Fatal! Out of Memory!!\n");
718 return STATUS_NO_MEMORY;
719 }
720 PathEnvironmentVar_U.MaximumLength = PathEnvironmentVar_U.Length + sizeof(WCHAR);
721
722 /* Retry */
723 Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
724
725 if (!NT_SUCCESS(Status))
726 {
727 DPRINT1("Unable to get path environment string!\n");
728 ASSERT(FALSE);
729 }
730 /* Length of path evn var + semicolon */
731 len += (PathEnvironmentVar_U.Length / sizeof(WCHAR)) + 1;
732 }
733
734 /* Allocate the size needed to hold all the above paths + period */
735 SearchPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (len + 2) * sizeof(WCHAR));
736 if (!SearchPathBuffer)
737 {
738 DPRINT1("Fatal! Out of Memory!!\n");
739 return STATUS_NO_MEMORY;
740 }
741
742 wcsncpy(SearchPathBuffer, ImagePathNameBufferPtr, ImagePathLen);
743 wcscat (SearchPathBuffer, L";");
744 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
745 wcscat (SearchPathBuffer, L"\\system32;");
746 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
747 wcscat (SearchPathBuffer, L";");
748
749 if (PathEnvironmentVar_U.Buffer)
750 {
751 wcscat (SearchPathBuffer, PathEnvironmentVar_U.Buffer);
752 wcscat (SearchPathBuffer, L";");
753 RtlFreeHeap(RtlGetProcessHeap(), 0, PathEnvironmentVar_U.Buffer);
754 }
755 wcscat (SearchPathBuffer, L".");
756
757 SearchPath = SearchPathBuffer;
758 }
759
760 if (RtlDosSearchPath_U (SearchPath,
761 DllName->Buffer,
762 NULL,
763 MAX_PATH,
764 DosName,
765 NULL) == 0)
766 {
767 /* try to find active context dll */
768 Status = find_actctx_dll(DllName->Buffer, DosName);
769 if(Status == STATUS_SUCCESS)
770 DPRINT("found %S for %S\n", DosName,DllName->Buffer);
771 else
772 return STATUS_DLL_NOT_FOUND;
773 }
774
775 if (!RtlDosPathNameToNtPathName_U (DosName,
776 &FullNtFileName,
777 NULL,
778 NULL))
779 {
780 DPRINT("Dll %wZ not found!\n", DllName);
781 return STATUS_DLL_NOT_FOUND;
782 }
783
784 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
785
786 InitializeObjectAttributes(&FileObjectAttributes,
787 &FullNtFileName,
788 0,
789 NULL,
790 NULL);
791
792 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
793
794 Status = NtOpenFile(&FileHandle,
795 GENERIC_READ|SYNCHRONIZE,
796 &FileObjectAttributes,
797 &IoStatusBlock,
798 FILE_SHARE_READ,
799 FILE_SYNCHRONOUS_IO_NONALERT);
800 if (!NT_SUCCESS(Status))
801 {
802 DPRINT1("Dll open of %wZ failed: Status = 0x%08lx\n",
803 &FullNtFileName, Status);
804 RtlFreeHeap (RtlGetProcessHeap (),
805 0,
806 FullNtFileName.Buffer);
807 return Status;
808 }
809 RtlFreeHeap (RtlGetProcessHeap (),
810 0,
811 FullNtFileName.Buffer);
812
813 if (!MapAsDataFile)
814 {
815
816 Status = NtReadFile(FileHandle,
817 NULL,
818 NULL,
819 NULL,
820 &IoStatusBlock,
821 BlockBuffer,
822 sizeof(BlockBuffer),
823 NULL,
824 NULL);
825 if (!NT_SUCCESS(Status))
826 {
827 DPRINT("Dll header read failed: Status = 0x%08lx\n", Status);
828 NtClose(FileHandle);
829 return Status;
830 }
831
832 /*
833 * Overlay DOS and NT headers structures to the
834 * buffer with DLL's header raw data.
835 */
836 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
837 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
838 /*
839 * Check it is a PE image file.
840 */
841 if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
842 || (DosHeader->e_lfanew == 0L)
843 || (*(PULONG)(NTHeaders) != IMAGE_NT_SIGNATURE))
844 {
845 DPRINT("NTDLL format invalid\n");
846 NtClose(FileHandle);
847
848 return STATUS_UNSUCCESSFUL;
849 }
850 }
851
852 /*
853 * Create a section for dll.
854 */
855 Status = NtCreateSection(SectionHandle,
856 SECTION_ALL_ACCESS,
857 NULL,
858 NULL,
859 PAGE_READONLY,
860 MapAsDataFile ? SEC_COMMIT : SEC_IMAGE,
861 FileHandle);
862 NtClose(FileHandle);
863
864 if (!NT_SUCCESS(Status))
865 {
866 DPRINT("NTDLL create section failed: Status = 0x%08lx\n", Status);
867 return Status;
868 }
869
870 RtlCreateUnicodeString(FullDosName,
871 DosName);
872
873 return Status;
874 }
875
876
877
878 /***************************************************************************
879 * NAME EXPORTED
880 * LdrLoadDll
881 *
882 * DESCRIPTION
883 *
884 * ARGUMENTS
885 *
886 * RETURN VALUE
887 *
888 * REVISIONS
889 *
890 * NOTE
891 *
892 * @implemented
893 */
894 NTSTATUS NTAPI
895 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
896 IN PULONG LoadFlags OPTIONAL,
897 IN PUNICODE_STRING Name,
898 OUT PVOID *BaseAddress /* also known as HMODULE*, and PHANDLE 'DllHandle' */)
899 {
900 NTSTATUS Status;
901 PLDR_DATA_TABLE_ENTRY Module;
902 ULONG_PTR cookie;
903 PPEB Peb = NtCurrentPeb();
904
905 TRACE_LDR("LdrLoadDll loading %wZ%S%S with flags %d\n",
906 Name,
907 SearchPath ? L" from " : L"",
908 SearchPath ? SearchPath : L"",
909 LoadFlags ? *LoadFlags : 0);
910
911 Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress);
912
913 if (NT_SUCCESS(Status) &&
914 (!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE)))
915 {
916 if (!create_module_activation_context( Module ))
917 {
918 RtlActivateActivationContext(0, Module->EntryPointActivationContext, &cookie);
919 }
920
921 if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED))
922 {
923 RtlEnterCriticalSection(Peb->LoaderLock);
924 Status = LdrpAttachProcess();
925 RtlLeaveCriticalSection(Peb->LoaderLock);
926 }
927 if (Module->EntryPointActivationContext) RtlDeactivateActivationContext(0, cookie);
928 }
929
930 if ((!Module) && (NT_SUCCESS(Status)))
931 return Status;
932
933 *BaseAddress = NT_SUCCESS(Status) ? Module->DllBase : NULL;
934
935 return Status;
936 }
937
938
939 /***************************************************************************
940 * NAME EXPORTED
941 * LdrFindEntryForAddress
942 *
943 * DESCRIPTION
944 *
945 * ARGUMENTS
946 *
947 * RETURN VALUE
948 *
949 * REVISIONS
950 *
951 * NOTE
952 *
953 * @implemented
954 */
955 NTSTATUS NTAPI
956 LdrFindEntryForAddress(PVOID Address,
957 PLDR_DATA_TABLE_ENTRY *Module)
958 {
959 PLIST_ENTRY ModuleListHead;
960 PLIST_ENTRY Entry;
961 PLDR_DATA_TABLE_ENTRY ModulePtr;
962
963 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
964
965 if (NtCurrentPeb()->Ldr == NULL)
966 return(STATUS_NO_MORE_ENTRIES);
967
968 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
969 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
970 Entry = ModuleListHead->Flink;
971 if (Entry == ModuleListHead)
972 {
973 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
974 return(STATUS_NO_MORE_ENTRIES);
975 }
976
977 while (Entry != ModuleListHead)
978 {
979 ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
980
981 DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->DllBase);
982
983 if ((Address >= ModulePtr->DllBase) &&
984 ((ULONG_PTR)Address <= ((ULONG_PTR)ModulePtr->DllBase + ModulePtr->SizeOfImage)))
985 {
986 *Module = ModulePtr;
987 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
988 return(STATUS_SUCCESS);
989 }
990
991 Entry = Entry->Flink;
992 }
993
994 DPRINT("Failed to find module entry.\n");
995
996 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
997 return(STATUS_NO_MORE_ENTRIES);
998 }
999
1000
1001 /***************************************************************************
1002 * NAME LOCAL
1003 * LdrFindEntryForName
1004 *
1005 * DESCRIPTION
1006 *
1007 * ARGUMENTS
1008 *
1009 * RETURN VALUE
1010 *
1011 * REVISIONS
1012 *
1013 * NOTE
1014 *
1015 */
1016 static NTSTATUS
1017 LdrFindEntryForName(PUNICODE_STRING Name,
1018 PLDR_DATA_TABLE_ENTRY *Module,
1019 BOOLEAN Ref)
1020 {
1021 PLIST_ENTRY ModuleListHead;
1022 PLIST_ENTRY Entry;
1023 PLDR_DATA_TABLE_ENTRY ModulePtr;
1024 BOOLEAN ContainsPath;
1025 UNICODE_STRING AdjustedName;
1026
1027 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name);
1028
1029 if (NtCurrentPeb()->Ldr == NULL)
1030 return(STATUS_NO_MORE_ENTRIES);
1031
1032 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
1033 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1034 Entry = ModuleListHead->Flink;
1035 if (Entry == ModuleListHead)
1036 {
1037 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1038 return(STATUS_NO_MORE_ENTRIES);
1039 }
1040
1041 // NULL is the current process
1042 if (Name == NULL)
1043 {
1044 *Module = ExeModule;
1045 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1046 return(STATUS_SUCCESS);
1047 }
1048
1049 ContainsPath = (Name->Length >= 2 * sizeof(WCHAR) && L':' == Name->Buffer[1]);
1050 LdrAdjustDllName (&AdjustedName, Name, !ContainsPath);
1051
1052 if (LdrpLastModule)
1053 {
1054 if ((! ContainsPath &&
1055 0 == RtlCompareUnicodeString(&LdrpLastModule->BaseDllName, &AdjustedName, TRUE)) ||
1056 (ContainsPath &&
1057 0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
1058 {
1059 *Module = LdrpLastModule;
1060 if (Ref && (*Module)->LoadCount != LDRP_PROCESS_CREATION_TIME)
1061 {
1062 (*Module)->LoadCount++;
1063 }
1064 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1065 RtlFreeUnicodeString(&AdjustedName);
1066 return(STATUS_SUCCESS);
1067 }
1068 }
1069 while (Entry != ModuleListHead)
1070 {
1071 ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1072
1073 DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, &AdjustedName);
1074
1075 if ((! ContainsPath &&
1076 0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, &AdjustedName, TRUE)) ||
1077 (ContainsPath &&
1078 0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
1079 {
1080 *Module = LdrpLastModule = ModulePtr;
1081 if (Ref && ModulePtr->LoadCount != LDRP_PROCESS_CREATION_TIME)
1082 {
1083 ModulePtr->LoadCount++;
1084 }
1085 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1086 RtlFreeUnicodeString(&AdjustedName);
1087 return(STATUS_SUCCESS);
1088 }
1089
1090 Entry = Entry->Flink;
1091 }
1092
1093 DPRINT("Failed to find dll %wZ\n", Name);
1094 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1095 RtlFreeUnicodeString(&AdjustedName);
1096 return(STATUS_NO_MORE_ENTRIES);
1097 }
1098
1099 /**********************************************************************
1100 * NAME LOCAL
1101 * LdrFixupForward
1102 *
1103 * DESCRIPTION
1104 *
1105 * ARGUMENTS
1106 *
1107 * RETURN VALUE
1108 *
1109 * REVISIONS
1110 *
1111 * NOTE
1112 *
1113 */
1114 static PVOID
1115 LdrFixupForward(PCHAR ForwardName)
1116 {
1117 CHAR NameBuffer[128];
1118 UNICODE_STRING DllName;
1119 NTSTATUS Status;
1120 PCHAR p;
1121 PLDR_DATA_TABLE_ENTRY Module;
1122 PVOID BaseAddress;
1123
1124 strcpy(NameBuffer, ForwardName);
1125 p = strchr(NameBuffer, '.');
1126 if (p != NULL)
1127 {
1128 *p = 0;
1129
1130 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
1131 RtlCreateUnicodeStringFromAsciiz (&DllName,
1132 NameBuffer);
1133
1134 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
1135 /* FIXME:
1136 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
1137 */
1138 if (!NT_SUCCESS(Status))
1139 {
1140 Status = LdrLoadDll(NULL,
1141 NULL,
1142 &DllName,
1143 &BaseAddress);
1144 if (NT_SUCCESS(Status))
1145 {
1146 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
1147 }
1148 }
1149 RtlFreeUnicodeString (&DllName);
1150 if (!NT_SUCCESS(Status))
1151 {
1152 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer);
1153 return NULL;
1154 }
1155
1156 DPRINT("BaseAddress: %p\n", Module->DllBase);
1157
1158 return LdrGetExportByName(Module->DllBase, (PUCHAR)(p+1), -1);
1159 }
1160
1161 return NULL;
1162 }
1163
1164
1165 /**********************************************************************
1166 * NAME LOCAL
1167 * LdrGetExportByOrdinal
1168 *
1169 * DESCRIPTION
1170 *
1171 * ARGUMENTS
1172 *
1173 * RETURN VALUE
1174 *
1175 * REVISIONS
1176 *
1177 * NOTE
1178 *
1179 */
1180 static PVOID
1181 LdrGetExportByOrdinal (
1182 PVOID BaseAddress,
1183 ULONG Ordinal
1184 )
1185 {
1186 PIMAGE_EXPORT_DIRECTORY ExportDir;
1187 ULONG ExportDirSize;
1188 PDWORD * ExFunctions;
1189 PVOID Function;
1190
1191 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1192 RtlImageDirectoryEntryToData (BaseAddress,
1193 TRUE,
1194 IMAGE_DIRECTORY_ENTRY_EXPORT,
1195 &ExportDirSize);
1196
1197
1198 ExFunctions = (PDWORD *)
1199 RVA(
1200 BaseAddress,
1201 ExportDir->AddressOfFunctions
1202 );
1203 DPRINT(
1204 "LdrGetExportByOrdinal(Ordinal %lu) = %p\n",
1205 Ordinal,
1206 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1207 );
1208
1209 Function = (0 != ExFunctions[Ordinal - ExportDir->Base]
1210 ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1211 : NULL);
1212
1213 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1214 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1215 {
1216 DPRINT("Forward: %s\n", (PCHAR)Function);
1217 Function = LdrFixupForward((PCHAR)Function);
1218 }
1219
1220 return Function;
1221 }
1222
1223
1224 /**********************************************************************
1225 * NAME LOCAL
1226 * LdrGetExportByName
1227 *
1228 * DESCRIPTION
1229 *
1230 * ARGUMENTS
1231 *
1232 * RETURN VALUE
1233 *
1234 * REVISIONS
1235 *
1236 * NOTE
1237 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1238 * both with NumberOfNames entries.
1239 *
1240 */
1241 static PVOID
1242 LdrGetExportByName(PVOID BaseAddress,
1243 PUCHAR SymbolName,
1244 WORD Hint)
1245 {
1246 PIMAGE_EXPORT_DIRECTORY ExportDir;
1247 PDWORD * ExFunctions;
1248 PDWORD * ExNames;
1249 USHORT * ExOrdinals;
1250 PVOID ExName;
1251 ULONG Ordinal;
1252 PVOID Function;
1253 LONG minn, maxn;
1254 ULONG ExportDirSize;
1255
1256 DPRINT("LdrGetExportByName %p %s %hu\n", BaseAddress, SymbolName, Hint);
1257
1258 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1259 RtlImageDirectoryEntryToData(BaseAddress,
1260 TRUE,
1261 IMAGE_DIRECTORY_ENTRY_EXPORT,
1262 &ExportDirSize);
1263 if (ExportDir == NULL)
1264 {
1265 DPRINT1("LdrGetExportByName(): no export directory, "
1266 "can't lookup %s/%hu!\n", SymbolName, Hint);
1267 return NULL;
1268 }
1269
1270
1271 //The symbol names may be missing entirely
1272 if (ExportDir->AddressOfNames == 0)
1273 {
1274 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1275 return NULL;
1276 }
1277
1278 /*
1279 * Get header pointers
1280 */
1281 ExNames = (PDWORD *)RVA(BaseAddress,
1282 ExportDir->AddressOfNames);
1283 ExOrdinals = (USHORT *)RVA(BaseAddress,
1284 ExportDir->AddressOfNameOrdinals);
1285 ExFunctions = (PDWORD *)RVA(BaseAddress,
1286 ExportDir->AddressOfFunctions);
1287
1288 /*
1289 * Check the hint first
1290 */
1291 if (Hint < ExportDir->NumberOfNames)
1292 {
1293 ExName = RVA(BaseAddress, ExNames[Hint]);
1294 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
1295 {
1296 Ordinal = ExOrdinals[Hint];
1297 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1298 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1299 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1300 {
1301 DPRINT("Forward: %s\n", (PCHAR)Function);
1302 Function = LdrFixupForward((PCHAR)Function);
1303 if (Function == NULL)
1304 {
1305 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
1306 }
1307 return Function;
1308 }
1309 if (Function != NULL)
1310 return Function;
1311 }
1312 }
1313
1314 /*
1315 * Binary search
1316 */
1317 minn = 0;
1318 maxn = ExportDir->NumberOfNames - 1;
1319 while (minn <= maxn)
1320 {
1321 LONG mid;
1322 LONG res;
1323
1324 mid = (minn + maxn) / 2;
1325
1326 ExName = RVA(BaseAddress, ExNames[mid]);
1327 res = strcmp(ExName, (PCHAR)SymbolName);
1328 if (res == 0)
1329 {
1330 Ordinal = ExOrdinals[mid];
1331 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1332 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1333 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1334 {
1335 DPRINT("Forward: %s\n", (PCHAR)Function);
1336 Function = LdrFixupForward((PCHAR)Function);
1337 if (Function == NULL)
1338 {
1339 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
1340 }
1341 return Function;
1342 }
1343 if (Function != NULL)
1344 return Function;
1345 }
1346 else if (minn == maxn)
1347 {
1348 DPRINT("LdrGetExportByName(): binary search failed\n");
1349 break;
1350 }
1351 else if (res > 0)
1352 {
1353 maxn = mid - 1;
1354 }
1355 else
1356 {
1357 minn = mid + 1;
1358 }
1359 }
1360
1361 DPRINT("LdrGetExportByName(): failed to find %s\n",SymbolName);
1362 return (PVOID)NULL;
1363 }
1364
1365
1366 /**********************************************************************
1367 * NAME LOCAL
1368 * LdrPerformRelocations
1369 *
1370 * DESCRIPTION
1371 * Relocate a DLL's memory image.
1372 *
1373 * ARGUMENTS
1374 *
1375 * RETURN VALUE
1376 *
1377 * REVISIONS
1378 *
1379 * NOTE
1380 *
1381 */
1382 static NTSTATUS
1383 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
1384 PVOID ImageBase)
1385 {
1386 PIMAGE_DATA_DIRECTORY RelocationDDir;
1387 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
1388 ULONG Count, OldProtect, OldProtect2;
1389 SIZE_T ProtectSize;
1390 PVOID Page, ProtectPage, ProtectPage2;
1391 PUSHORT TypeOffset;
1392 ULONG_PTR Delta;
1393 NTSTATUS Status;
1394
1395 if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1396 {
1397 return STATUS_SUCCESS;
1398 }
1399
1400 RelocationDDir =
1401 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1402
1403 if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
1404 {
1405 return STATUS_SUCCESS;
1406 }
1407
1408 ProtectSize = PAGE_SIZE;
1409 Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
1410 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1411 RelocationDDir->VirtualAddress);
1412 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1413 RelocationDDir->VirtualAddress + RelocationDDir->Size);
1414
1415 while (RelocationDir < RelocationEnd &&
1416 RelocationDir->SizeOfBlock > 0)
1417 {
1418 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
1419 sizeof(USHORT);
1420 Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
1421 TypeOffset = (PUSHORT)(RelocationDir + 1);
1422
1423 /* Unprotect the page(s) we're about to relocate. */
1424 ProtectPage = Page;
1425 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1426 &ProtectPage,
1427 &ProtectSize,
1428 PAGE_READWRITE,
1429 &OldProtect);
1430 if (!NT_SUCCESS(Status))
1431 {
1432 DPRINT1("Failed to unprotect relocation target.\n");
1433 return Status;
1434 }
1435
1436 if (RelocationDir->VirtualAddress + PAGE_SIZE <
1437 NTHeaders->OptionalHeader.SizeOfImage)
1438 {
1439 ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
1440 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1441 &ProtectPage2,
1442 &ProtectSize,
1443 PAGE_READWRITE,
1444 &OldProtect2);
1445 if (!NT_SUCCESS(Status))
1446 {
1447 DPRINT1("Failed to unprotect relocation target (2).\n");
1448 NtProtectVirtualMemory(NtCurrentProcess(),
1449 &ProtectPage,
1450 &ProtectSize,
1451 OldProtect,
1452 &OldProtect);
1453 return Status;
1454 }
1455 }
1456 else
1457 {
1458 ProtectPage2 = NULL;
1459 }
1460
1461 RelocationDir = LdrProcessRelocationBlock((ULONG_PTR)Page,
1462 Count,
1463 TypeOffset,
1464 Delta);
1465 if (RelocationDir == NULL)
1466 return STATUS_UNSUCCESSFUL;
1467
1468 /* Restore old page protection. */
1469 NtProtectVirtualMemory(NtCurrentProcess(),
1470 &ProtectPage,
1471 &ProtectSize,
1472 OldProtect,
1473 &OldProtect);
1474
1475 if (ProtectPage2 != NULL)
1476 {
1477 NtProtectVirtualMemory(NtCurrentProcess(),
1478 &ProtectPage2,
1479 &ProtectSize,
1480 OldProtect2,
1481 &OldProtect2);
1482 }
1483 }
1484
1485 return STATUS_SUCCESS;
1486 }
1487
1488 static NTSTATUS
1489 LdrpGetOrLoadModule(PWCHAR SearchPath,
1490 PCHAR Name,
1491 PLDR_DATA_TABLE_ENTRY* Module,
1492 BOOLEAN Load)
1493 {
1494 ANSI_STRING AnsiDllName;
1495 UNICODE_STRING DllName;
1496 NTSTATUS Status;
1497
1498 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
1499
1500 RtlInitAnsiString(&AnsiDllName, Name);
1501 Status = RtlAnsiStringToUnicodeString(&DllName, &AnsiDllName, TRUE);
1502 if (!NT_SUCCESS(Status))
1503 {
1504 return Status;
1505 }
1506
1507 Status = LdrFindEntryForName (&DllName, Module, Load);
1508 if (Load && !NT_SUCCESS(Status))
1509 {
1510 Status = LdrpLoadModule(SearchPath,
1511 0,
1512 &DllName,
1513 Module,
1514 NULL);
1515 if (NT_SUCCESS(Status))
1516 {
1517 Status = LdrFindEntryForName (&DllName, Module, FALSE);
1518 }
1519 if (!NT_SUCCESS(Status))
1520 {
1521 ULONG ErrorResponse;
1522 ULONG_PTR ErrorParameter = (ULONG_PTR)&DllName;
1523
1524 DPRINT1("failed to load %wZ\n", &DllName);
1525
1526 NtRaiseHardError(STATUS_DLL_NOT_FOUND,
1527 1,
1528 1,
1529 &ErrorParameter,
1530 OptionOk,
1531 &ErrorResponse);
1532 }
1533 }
1534 RtlFreeUnicodeString (&DllName);
1535 return Status;
1536 }
1537
1538 void
1539 RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName)
1540 {
1541 ULONG ErrorResponse;
1542 ULONG_PTR ErrorParameters[2];
1543 ANSI_STRING ProcNameAnsi;
1544 UNICODE_STRING ProcName;
1545 CHAR Buffer[8];
1546
1547 if (!FuncName)
1548 {
1549 _snprintf(Buffer, 8, "# %ld", Ordinal);
1550 FuncName = Buffer;
1551 }
1552
1553 RtlInitAnsiString(&ProcNameAnsi, FuncName);
1554 RtlAnsiStringToUnicodeString(&ProcName, &ProcNameAnsi, TRUE);
1555 ErrorParameters[0] = (ULONG_PTR)&ProcName;
1556 ErrorParameters[1] = (ULONG_PTR)DllName;
1557 NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND,
1558 2,
1559 3,
1560 ErrorParameters,
1561 OptionOk,
1562 &ErrorResponse);
1563 RtlFreeUnicodeString(&ProcName);
1564 }
1565
1566 static NTSTATUS
1567 LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
1568 PLDR_DATA_TABLE_ENTRY ImportedModule,
1569 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
1570 {
1571 NTSTATUS Status;
1572 PVOID* ImportAddressList;
1573 PULONG FunctionNameList;
1574 PVOID IATBase;
1575 ULONG OldProtect;
1576 ULONG Ordinal;
1577 SIZE_T IATSize;
1578
1579 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
1580 {
1581 return STATUS_UNSUCCESSFUL;
1582 }
1583
1584 /* Get the import address list. */
1585 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1586
1587 /* Get the list of functions to import. */
1588 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1589 {
1590 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1591 }
1592 else
1593 {
1594 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1595 }
1596
1597 /* Get the size of IAT. */
1598 IATSize = 0;
1599 while (FunctionNameList[IATSize] != 0L)
1600 {
1601 IATSize++;
1602 }
1603
1604 /* Unprotect the region we are about to write into. */
1605 IATBase = (PVOID)ImportAddressList;
1606 IATSize *= sizeof(PVOID*);
1607 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1608 &IATBase,
1609 &IATSize,
1610 PAGE_READWRITE,
1611 &OldProtect);
1612 if (!NT_SUCCESS(Status))
1613 {
1614 DPRINT1("Failed to unprotect IAT.\n");
1615 return(Status);
1616 }
1617
1618 /* Walk through function list and fixup addresses. */
1619 while (*FunctionNameList != 0L)
1620 {
1621 if ((*FunctionNameList) & 0x80000000)
1622 {
1623 Ordinal = (*FunctionNameList) & 0x7fffffff;
1624 *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1625 if ((*ImportAddressList) == NULL)
1626 {
1627 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1628 RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName);
1629 return STATUS_ENTRYPOINT_NOT_FOUND;
1630 }
1631 }
1632 else
1633 {
1634 IMAGE_IMPORT_BY_NAME *pe_name;
1635 pe_name = RVA(Module->DllBase, *FunctionNameList);
1636 *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
1637 if ((*ImportAddressList) == NULL)
1638 {
1639 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1640 RtlpRaiseImportNotFound((CHAR*)pe_name->Name, 0, &ImportedModule->FullDllName);
1641 return STATUS_ENTRYPOINT_NOT_FOUND;
1642 }
1643 }
1644 ImportAddressList++;
1645 FunctionNameList++;
1646 }
1647
1648 /* Protect the region we are about to write into. */
1649 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1650 &IATBase,
1651 &IATSize,
1652 OldProtect,
1653 &OldProtect);
1654 if (!NT_SUCCESS(Status))
1655 {
1656 DPRINT1("Failed to protect IAT.\n");
1657 return(Status);
1658 }
1659
1660 return STATUS_SUCCESS;
1661 }
1662
1663 static NTSTATUS
1664 LdrpProcessImportDirectory(
1665 PLDR_DATA_TABLE_ENTRY Module,
1666 PLDR_DATA_TABLE_ENTRY ImportedModule,
1667 PCHAR ImportedName)
1668 {
1669 NTSTATUS Status;
1670 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1671 PCHAR Name;
1672 ULONG Size;
1673
1674 DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
1675 Module, &Module->BaseDllName, ImportedName);
1676
1677
1678 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1679 RtlImageDirectoryEntryToData(Module->DllBase,
1680 TRUE,
1681 IMAGE_DIRECTORY_ENTRY_IMPORT,
1682 &Size);
1683 if (ImportModuleDirectory == NULL)
1684 {
1685 return STATUS_UNSUCCESSFUL;
1686 }
1687
1688 while (ImportModuleDirectory->Name)
1689 {
1690 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1691 if (0 == _stricmp(Name, ImportedName))
1692 {
1693 Status = LdrpProcessImportDirectoryEntry(Module,
1694 ImportedModule,
1695 ImportModuleDirectory);
1696 if (!NT_SUCCESS(Status))
1697 {
1698 return Status;
1699 }
1700 }
1701 ImportModuleDirectory++;
1702 }
1703
1704
1705 return STATUS_SUCCESS;
1706 }
1707
1708
1709 static NTSTATUS
1710 LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
1711 PLDR_DATA_TABLE_ENTRY ImportedModule,
1712 PCHAR ImportedName)
1713 {
1714 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1715 NTSTATUS Status;
1716 PVOID* ImportAddressList;
1717 PVOID Start;
1718 PVOID End;
1719 PULONG FunctionNameList;
1720 PVOID IATBase;
1721 ULONG OldProtect;
1722 ULONG Offset;
1723 SIZE_T IATSize;
1724 PIMAGE_NT_HEADERS NTHeaders;
1725 PCHAR Name;
1726 ULONG Size;
1727
1728 DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
1729 Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
1730
1731 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1732 RtlImageDirectoryEntryToData(Module->DllBase,
1733 TRUE,
1734 IMAGE_DIRECTORY_ENTRY_IMPORT,
1735 &Size);
1736 if (ImportModuleDirectory == NULL)
1737 {
1738 return STATUS_UNSUCCESSFUL;
1739 }
1740
1741 while (ImportModuleDirectory->Name)
1742 {
1743 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1744 if (0 == _stricmp(Name, (PCHAR)ImportedName))
1745 {
1746
1747 /* Get the import address list. */
1748 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1749
1750 /* Get the list of functions to import. */
1751 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1752 {
1753 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1754 }
1755 else
1756 {
1757 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1758 }
1759
1760 /* Get the size of IAT. */
1761 IATSize = 0;
1762 while (FunctionNameList[IATSize] != 0L)
1763 {
1764 IATSize++;
1765 }
1766
1767 /* Unprotect the region we are about to write into. */
1768 IATBase = (PVOID)ImportAddressList;
1769 IATSize *= sizeof(PVOID*);
1770 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1771 &IATBase,
1772 &IATSize,
1773 PAGE_READWRITE,
1774 &OldProtect);
1775 if (!NT_SUCCESS(Status))
1776 {
1777 DPRINT1("Failed to unprotect IAT.\n");
1778 return(Status);
1779 }
1780
1781 NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
1782 Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
1783 End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
1784 Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
1785
1786 /* Walk through function list and fixup addresses. */
1787 while (*FunctionNameList != 0L)
1788 {
1789 if (*ImportAddressList >= Start && *ImportAddressList < End)
1790 {
1791 (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
1792 }
1793 ImportAddressList++;
1794 FunctionNameList++;
1795 }
1796
1797 /* Protect the region we are about to write into. */
1798 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1799 &IATBase,
1800 &IATSize,
1801 OldProtect,
1802 &OldProtect);
1803 if (!NT_SUCCESS(Status))
1804 {
1805 DPRINT1("Failed to protect IAT.\n");
1806 return(Status);
1807 }
1808 }
1809 ImportModuleDirectory++;
1810 }
1811 return STATUS_SUCCESS;
1812 }
1813
1814
1815 /**********************************************************************
1816 * NAME LOCAL
1817 * LdrFixupImports
1818 *
1819 * DESCRIPTION
1820 * Compute the entry point for every symbol the DLL imports
1821 * from other modules.
1822 *
1823 * ARGUMENTS
1824 *
1825 * RETURN VALUE
1826 *
1827 * REVISIONS
1828 *
1829 * NOTE
1830 *
1831 */
1832 static NTSTATUS
1833 LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
1834 IN PLDR_DATA_TABLE_ENTRY Module)
1835 {
1836 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1837 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent;
1838 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
1839 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
1840 PIMAGE_TLS_DIRECTORY TlsDirectory;
1841 ULONG TlsSize = 0;
1842 NTSTATUS Status = STATUS_SUCCESS;
1843 PLDR_DATA_TABLE_ENTRY ImportedModule;
1844 PCHAR ImportedName;
1845 PWSTR ModulePath;
1846 ULONG Size;
1847 ULONG_PTR cookie;
1848
1849 DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
1850
1851 /* Check for tls data */
1852 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
1853 RtlImageDirectoryEntryToData(Module->DllBase,
1854 TRUE,
1855 IMAGE_DIRECTORY_ENTRY_TLS,
1856 &Size);
1857 if (TlsDirectory)
1858 {
1859 TlsSize = TlsDirectory->EndAddressOfRawData
1860 - TlsDirectory->StartAddressOfRawData
1861 + TlsDirectory->SizeOfZeroFill;
1862
1863 if (TlsSize > 0 && NtCurrentPeb()->Ldr->Initialized)
1864 {
1865 TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n",
1866 &Module->BaseDllName);
1867 TlsDirectory = NULL;
1868 }
1869 }
1870
1871 if (!create_module_activation_context( Module ))
1872 {
1873 if (Module->EntryPointActivationContext == NULL)
1874 {
1875 DPRINT("EntryPointActivationContext has not be allocated\n");
1876 DPRINT("Module->DllBaseName %wZ\n", Module->BaseDllName);
1877 }
1878 RtlActivateActivationContext( 0, Module->EntryPointActivationContext, &cookie );
1879 }
1880
1881 /*
1882 * Process each import module.
1883 */
1884 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1885 RtlImageDirectoryEntryToData(Module->DllBase,
1886 TRUE,
1887 IMAGE_DIRECTORY_ENTRY_IMPORT,
1888 &Size);
1889
1890 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
1891 RtlImageDirectoryEntryToData(Module->DllBase,
1892 TRUE,
1893 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
1894 &Size);
1895
1896 if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL)
1897 {
1898 DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName);
1899 return STATUS_UNSUCCESSFUL;
1900 }
1901 if (BoundImportDescriptor)
1902 {
1903 DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor);
1904
1905 BoundImportDescriptorCurrent = BoundImportDescriptor;
1906 while (BoundImportDescriptorCurrent->OffsetModuleName)
1907 {
1908 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
1909 TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName);
1910 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
1911 if (!NT_SUCCESS(Status))
1912 {
1913 DPRINT1("failed to load %s\n", ImportedName);
1914 return Status;
1915 }
1916 if (Module == ImportedModule)
1917 {
1918 LdrpDecrementLoadCount(Module, FALSE);
1919 }
1920 if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp)
1921 {
1922 TRACE_LDR("%wZ has stale binding to %wZ\n",
1923 &Module->BaseDllName, &ImportedModule->BaseDllName);
1924 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1925 if (!NT_SUCCESS(Status))
1926 {
1927 DPRINT1("failed to import %s\n", ImportedName);
1928 return Status;
1929 }
1930 }
1931 else
1932 {
1933 BOOLEAN WrongForwarder;
1934 WrongForwarder = FALSE;
1935 if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1936 {
1937 TRACE_LDR("%wZ has stale binding to %s\n",
1938 &Module->BaseDllName, ImportedName);
1939 }
1940 else
1941 {
1942 TRACE_LDR("%wZ has correct binding to %wZ\n",
1943 &Module->BaseDllName, &ImportedModule->BaseDllName);
1944 }
1945 if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs)
1946 {
1947 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef;
1948 ULONG i;
1949 PLDR_DATA_TABLE_ENTRY ForwarderModule;
1950 PCHAR ForwarderName;
1951
1952 BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1);
1953 for (i = 0; i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; i++, BoundForwarderRef++)
1954 {
1955 ForwarderName = (PCHAR)BoundImportDescriptor + BoundForwarderRef->OffsetModuleName;
1956 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1957 &Module->BaseDllName, ForwarderName, ImportedName);
1958 Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE);
1959 if (!NT_SUCCESS(Status))
1960 {
1961 DPRINT1("failed to load %s\n", ForwarderName);
1962 return Status;
1963 }
1964 if (Module == ImportedModule)
1965 {
1966 LdrpDecrementLoadCount(Module, FALSE);
1967 }
1968 if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp ||
1969 ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1970 {
1971 TRACE_LDR("%wZ has stale binding to %s\n",
1972 &Module->BaseDllName, ForwarderName);
1973 WrongForwarder = TRUE;
1974 }
1975 else
1976 {
1977 TRACE_LDR("%wZ has correct binding to %s\n",
1978 &Module->BaseDllName, ForwarderName);
1979 }
1980 }
1981 }
1982 if (WrongForwarder ||
1983 ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1984 {
1985 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1986 if (!NT_SUCCESS(Status))
1987 {
1988 DPRINT1("failed to import %s\n", ImportedName);
1989 return Status;
1990 }
1991 }
1992 else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1993 {
1994 TRACE_LDR("Adjust imports for %s from %wZ\n",
1995 ImportedName, &Module->BaseDllName);
1996 Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
1997 if (!NT_SUCCESS(Status))
1998 {
1999 DPRINT1("failed to adjust import entries for %s\n", ImportedName);
2000 return Status;
2001 }
2002 }
2003 else if (WrongForwarder)
2004 {
2005 /*
2006 * FIXME:
2007 * Update only forwarders
2008 */
2009 TRACE_LDR("Stale BIND %s from %wZ\n",
2010 ImportedName, &Module->BaseDllName);
2011 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
2012 if (!NT_SUCCESS(Status))
2013 {
2014 DPRINT1("faild to import %s\n", ImportedName);
2015 return Status;
2016 }
2017 }
2018 else
2019 {
2020 /* nothing to do */
2021 }
2022 }
2023 BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
2024 }
2025 }
2026 else if (ImportModuleDirectory)
2027 {
2028 DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory);
2029
2030 ImportModuleDirectoryCurrent = ImportModuleDirectory;
2031 while (ImportModuleDirectoryCurrent->Name)
2032 {
2033 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2034 TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
2035
2036 if (SearchPath == NULL)
2037 {
2038 ModulePath = LdrpQueryAppPaths(Module->BaseDllName.Buffer);
2039
2040 Status = LdrpGetOrLoadModule(ModulePath, ImportedName, &ImportedModule, TRUE);
2041 if (ModulePath != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath);
2042 if (NT_SUCCESS(Status)) goto Success;
2043 }
2044
2045 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
2046 if (!NT_SUCCESS(Status))
2047 {
2048 DPRINT1("failed to load %s\n", ImportedName);
2049 break;
2050 }
2051 Success:
2052 if (Module == ImportedModule)
2053 {
2054 LdrpDecrementLoadCount(Module, FALSE);
2055 }
2056
2057 TRACE_LDR("Initializing imports for %wZ from %s\n",
2058 &Module->BaseDllName, ImportedName);
2059 Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent);
2060 if (!NT_SUCCESS(Status))
2061 {
2062 DPRINT1("failed to import %s\n", ImportedName);
2063 break;
2064 }
2065 ImportModuleDirectoryCurrent++;
2066 }
2067
2068 if (!NT_SUCCESS(Status))
2069 {
2070 NTSTATUS errorStatus = Status;
2071
2072 while (ImportModuleDirectoryCurrent >= ImportModuleDirectory)
2073 {
2074 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2075
2076 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2077 if (NT_SUCCESS(Status) && Module != ImportedModule)
2078 {
2079 Status = LdrpUnloadModule(ImportedModule, FALSE);
2080 if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName);
2081 }
2082 ImportModuleDirectoryCurrent--;
2083 }
2084 return errorStatus;
2085 }
2086 }
2087
2088 if (TlsDirectory && TlsSize > 0)
2089 {
2090 LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
2091 }
2092
2093 if (Module->EntryPointActivationContext) RtlDeactivateActivationContext( 0, cookie );
2094
2095 return STATUS_SUCCESS;
2096 }
2097
2098
2099 /**********************************************************************
2100 * NAME
2101 * LdrPEStartup
2102 *
2103 * DESCRIPTION
2104 * 1. Relocate, if needed the EXE.
2105 * 2. Fixup any imported symbol.
2106 * 3. Compute the EXE's entry point.
2107 *
2108 * ARGUMENTS
2109 * ImageBase
2110 * Address at which the EXE's image
2111 * is loaded.
2112 *
2113 * SectionHandle
2114 * Handle of the section that contains
2115 * the EXE's image.
2116 *
2117 * RETURN VALUE
2118 * NULL on error; otherwise the entry point
2119 * to call for initializing the DLL.
2120 *
2121 * REVISIONS
2122 *
2123 * NOTE
2124 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
2125 * Currently the function is only used for the exe.
2126 */
2127 PEPFUNC LdrPEStartup (PVOID ImageBase,
2128 HANDLE SectionHandle,
2129 PLDR_DATA_TABLE_ENTRY* Module,
2130 PWSTR FullDosName)
2131 {
2132 NTSTATUS Status;
2133 PEPFUNC EntryPoint = NULL;
2134 PIMAGE_DOS_HEADER DosHeader;
2135 PIMAGE_NT_HEADERS NTHeaders;
2136 PLDR_DATA_TABLE_ENTRY tmpModule;
2137 PVOID ActivationContextStack;
2138
2139 DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
2140 ImageBase, SectionHandle);
2141
2142 /*
2143 * Overlay DOS and WNT headers structures
2144 * to the DLL's image.
2145 */
2146 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
2147 NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)ImageBase + DosHeader->e_lfanew);
2148
2149 /*
2150 * If the base address is different from the
2151 * one the DLL is actually loaded, perform any
2152 * relocation.
2153 */
2154 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2155 {
2156 DPRINT("LDR: Performing relocations\n");
2157 Status = LdrPerformRelocations(NTHeaders, ImageBase);
2158 if (!NT_SUCCESS(Status))
2159 {
2160 DPRINT1("LdrPerformRelocations() failed\n");
2161 return NULL;
2162 }
2163 }
2164
2165 if (Module != NULL)
2166 {
2167 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
2168 (*Module)->SectionPointer = SectionHandle;
2169 }
2170 else
2171 {
2172 Module = &tmpModule;
2173 Status = LdrFindEntryForAddress(ImageBase, Module);
2174 if (!NT_SUCCESS(Status))
2175 {
2176 return NULL;
2177 }
2178 }
2179
2180 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2181 {
2182 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2183 }
2184
2185 /* Allocate memory for the ActivationContextStack */
2186 /* FIXME: Verify RtlAllocateActivationContextStack behavior */
2187 Status = RtlAllocateActivationContextStack(&ActivationContextStack);
2188 if (NT_SUCCESS(Status))
2189 {
2190 DPRINT("ActivationContextStack %x\n",ActivationContextStack);
2191 DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK)ActivationContextStack)->ActiveFrame);
2192 NtCurrentTeb()->ActivationContextStackPointer = ActivationContextStack;
2193 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL;
2194 }
2195 else
2196 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
2197
2198 /*
2199 * If the DLL's imports symbols from other
2200 * modules, fixup the imported calls entry points.
2201 */
2202 DPRINT("About to fixup imports\n");
2203 Status = LdrFixupImports(NULL, *Module);
2204 if (!NT_SUCCESS(Status))
2205 {
2206 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
2207 return NULL;
2208 }
2209 DPRINT("Fixup done\n");
2210 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2211 Status = LdrpInitializeTlsForProccess();
2212 if (NT_SUCCESS(Status))
2213 {
2214 Status = LdrpAttachProcess();
2215 }
2216 if (NT_SUCCESS(Status))
2217 {
2218 LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
2219 }
2220
2221
2222 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
2223 if (!NT_SUCCESS(Status))
2224 {
2225 return NULL;
2226 }
2227
2228 /*
2229 * Compute the DLL's entry point's address.
2230 */
2231 DPRINT("ImageBase = %p\n", ImageBase);
2232 DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
2233 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
2234 {
2235 EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
2236 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
2237 }
2238 DPRINT("LdrPEStartup() = %p\n",EntryPoint);
2239 return EntryPoint;
2240 }
2241
2242 static NTSTATUS
2243 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
2244 IN ULONG LoadFlags,
2245 IN PUNICODE_STRING Name,
2246 PLDR_DATA_TABLE_ENTRY *Module,
2247 PVOID *BaseAddress OPTIONAL)
2248 {
2249 UNICODE_STRING AdjustedName;
2250 UNICODE_STRING FullDosName;
2251 NTSTATUS Status;
2252 PLDR_DATA_TABLE_ENTRY tmpModule;
2253 HANDLE SectionHandle;
2254 SIZE_T ViewSize;
2255 PVOID ImageBase;
2256 PIMAGE_NT_HEADERS NtHeaders;
2257 BOOLEAN MappedAsDataFile;
2258 PVOID ArbitraryUserPointer;
2259
2260 if (Module == NULL)
2261 {
2262 Module = &tmpModule;
2263 }
2264 /* adjust the full dll name */
2265 LdrAdjustDllName(&AdjustedName, Name, FALSE);
2266
2267 DPRINT("%wZ\n", &AdjustedName);
2268
2269 MappedAsDataFile = FALSE;
2270 /* Test if dll is already loaded */
2271 Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
2272 if (NT_SUCCESS(Status))
2273 {
2274 RtlFreeUnicodeString(&AdjustedName);
2275 if (NULL != BaseAddress)
2276 {
2277 *BaseAddress = (*Module)->DllBase;
2278 }
2279 }
2280 else
2281 {
2282 /* Open or create dll image section */
2283 Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
2284 if (!NT_SUCCESS(Status))
2285 {
2286 MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE));
2287 Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName,
2288 MappedAsDataFile, &SectionHandle);
2289 }
2290 if (!NT_SUCCESS(Status))
2291 {
2292 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
2293 RtlFreeUnicodeString(&AdjustedName);
2294 return Status;
2295 }
2296 RtlFreeUnicodeString(&AdjustedName);
2297 /* Map the dll into the process */
2298 ViewSize = 0;
2299 ImageBase = 0;
2300 ArbitraryUserPointer = NtCurrentTeb()->NtTib.ArbitraryUserPointer;
2301 NtCurrentTeb()->NtTib.ArbitraryUserPointer = FullDosName.Buffer;
2302 Status = NtMapViewOfSection(SectionHandle,
2303 NtCurrentProcess(),
2304 &ImageBase,
2305 0,
2306 0,
2307 NULL,
2308 &ViewSize,
2309 ViewShare,
2310 0,
2311 PAGE_READONLY);
2312 NtCurrentTeb()->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
2313 if (!NT_SUCCESS(Status))
2314 {
2315 DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
2316 RtlFreeUnicodeString(&FullDosName);
2317 NtClose(SectionHandle);
2318 return(Status);
2319 }
2320 if (NULL != BaseAddress)
2321 {
2322 *BaseAddress = ImageBase;
2323 }
2324 if (!MappedAsDataFile)
2325 {
2326 /* Get and check the NT headers */
2327 NtHeaders = RtlImageNtHeader(ImageBase);
2328 if (NtHeaders == NULL)
2329 {
2330 DPRINT1("RtlImageNtHeaders() failed\n");
2331 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2332 NtClose (SectionHandle);
2333 RtlFreeUnicodeString(&FullDosName);
2334 return STATUS_UNSUCCESSFUL;
2335 }
2336 }
2337 DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase);
2338 if (MappedAsDataFile)
2339 {
2340 ASSERT(NULL != BaseAddress);
2341 if (NULL != BaseAddress)
2342 {
2343 *BaseAddress = (PVOID) ((char *) *BaseAddress + 1);
2344 }
2345 *Module = NULL;
2346 RtlFreeUnicodeString(&FullDosName);
2347 NtClose(SectionHandle);
2348 return STATUS_SUCCESS;
2349 }
2350 /* If the base address is different from the
2351 * one the DLL is actually loaded, perform any
2352 * relocation. */
2353 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2354 {
2355 DPRINT1("Relocating (%lx -> %p) %wZ\n",
2356 NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
2357 Status = LdrPerformRelocations(NtHeaders, ImageBase);
2358 if (!NT_SUCCESS(Status))
2359 {
2360 DPRINT1("LdrPerformRelocations() failed\n");
2361 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2362 NtClose (SectionHandle);
2363 RtlFreeUnicodeString(&FullDosName);
2364 return STATUS_UNSUCCESSFUL;
2365 }
2366 }
2367 *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
2368 (*Module)->SectionPointer = SectionHandle;
2369 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2370 {
2371 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2372 }
2373 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
2374 {
2375 (*Module)->Flags |= LDRP_IMAGE_DLL;
2376 }
2377 /* fixup the imported calls entry points */
2378 Status = LdrFixupImports(SearchPath, *Module);
2379 if (!NT_SUCCESS(Status))
2380 {
2381 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
2382 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2383 NtClose (SectionHandle);
2384 RtlFreeUnicodeString (&FullDosName);
2385 RtlFreeUnicodeString (&(*Module)->FullDllName);
2386 RtlFreeUnicodeString (&(*Module)->BaseDllName);
2387 RemoveEntryList (&(*Module)->InLoadOrderLinks);
2388 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2389 return Status;
2390 }
2391
2392 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2393 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
2394 &(*Module)->InInitializationOrderLinks);
2395 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2396 }
2397 return STATUS_SUCCESS;
2398 }
2399
2400 static NTSTATUS
2401 LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
2402 BOOLEAN Unload)
2403 {
2404 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
2405 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
2406 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
2407 PCHAR ImportedName;
2408 PLDR_DATA_TABLE_ENTRY ImportedModule;
2409 NTSTATUS Status = 0;
2410 LONG LoadCount;
2411 ULONG Size;
2412
2413 if (Unload)
2414 {
2415 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2416 }
2417
2418 LoadCount = LdrpDecrementLoadCount(Module, Unload);
2419
2420 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
2421
2422 if (LoadCount == 0)
2423 {
2424 /* ?????????????????? */
2425 }
2426 else if (!(Module->Flags & LDRP_STATIC_LINK) && LoadCount == 1)
2427 {
2428 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
2429 RtlImageDirectoryEntryToData(Module->DllBase,
2430 TRUE,
2431 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
2432 &Size);
2433 if (BoundImportDescriptor)
2434 {
2435 /* dereferencing all imported modules, use the bound import descriptor */
2436 BoundImportDescriptorCurrent = BoundImportDescriptor;
2437 while (BoundImportDescriptorCurrent->OffsetModuleName)
2438 {
2439 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
2440 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2441 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2442 if (!NT_SUCCESS(Status))
2443 {
2444 DPRINT1("unable to found imported modul %s\n", ImportedName);
2445 }
2446 else
2447 {
2448 if (Module != ImportedModule)
2449 {
2450 Status = LdrpUnloadModule(ImportedModule, FALSE);
2451 if (!NT_SUCCESS(Status))
2452 {
2453 DPRINT1("unable to unload %s\n", ImportedName);
2454 }
2455 }
2456 }
2457 BoundImportDescriptorCurrent++;
2458 }
2459 }
2460 else
2461 {
2462 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
2463 RtlImageDirectoryEntryToData(Module->DllBase,
2464 TRUE,
2465 IMAGE_DIRECTORY_ENTRY_IMPORT,
2466 &Size);
2467 if (ImportModuleDirectory)
2468 {
2469 /* dereferencing all imported modules, use the import descriptor */
2470 while (ImportModuleDirectory->Name)
2471 {
2472 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
2473 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2474 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2475 if (!NT_SUCCESS(Status))
2476 {
2477 DPRINT1("unable to found imported modul %s\n", ImportedName);
2478 }
2479 else
2480 {
2481 if (Module != ImportedModule)
2482 {
2483 Status = LdrpUnloadModule(ImportedModule, FALSE);
2484 if (!NT_SUCCESS(Status))
2485 {
2486 DPRINT1("unable to unload %s\n", ImportedName);
2487 }
2488 }
2489 }
2490 ImportModuleDirectory++;
2491 }
2492 }
2493 }
2494 }
2495
2496 if (Unload)
2497 {
2498 if (!(Module->Flags & LDRP_STATIC_LINK))
2499 {
2500 LdrpDetachProcess(FALSE);
2501 }
2502
2503 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2504 }
2505 return STATUS_SUCCESS;
2506
2507 }
2508
2509 /*
2510 * @implemented
2511 */
2512 NTSTATUS NTAPI
2513 LdrUnloadDll (IN PVOID BaseAddress)
2514 {
2515 PLDR_DATA_TABLE_ENTRY Module;
2516 NTSTATUS Status;
2517
2518 if (BaseAddress == NULL)
2519 return STATUS_SUCCESS;
2520
2521 if (LdrMappedAsDataFile(&BaseAddress))
2522 {
2523 Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
2524 }
2525 else
2526 {
2527 Status = LdrFindEntryForAddress(BaseAddress, &Module);
2528 if (NT_SUCCESS(Status))
2529 {
2530 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
2531 Status = LdrpUnloadModule(Module, TRUE);
2532 }
2533 }
2534
2535 return Status;
2536 }
2537
2538 /*
2539 * @implemented
2540 */
2541 NTSTATUS NTAPI
2542 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
2543 {
2544 PLIST_ENTRY ModuleListHead;
2545 PLIST_ENTRY Entry;
2546 PLDR_DATA_TABLE_ENTRY Module;
2547 NTSTATUS Status;
2548
2549 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
2550
2551 Status = STATUS_DLL_NOT_FOUND;
2552 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2553 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2554 Entry = ModuleListHead->Flink;
2555 while (Entry != ModuleListHead)
2556 {
2557 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2558
2559 DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
2560
2561 if (Module->DllBase == BaseAddress)
2562 {
2563 if (Module->TlsIndex == 0xFFFF)
2564 {
2565 Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
2566 Status = STATUS_SUCCESS;
2567 }
2568 break;
2569 }
2570 Entry = Entry->Flink;
2571 }
2572 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2573 return Status;
2574 }
2575
2576 /*
2577 * @implemented
2578 */
2579 NTSTATUS NTAPI
2580 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
2581 IN PULONG DllCharacteristics,
2582 IN PUNICODE_STRING DllName,
2583 OUT PVOID *DllHandle)
2584 {
2585 PLDR_DATA_TABLE_ENTRY Module;
2586 NTSTATUS Status;
2587
2588 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
2589 DllName, DllPath ? DllPath : L"");
2590
2591 /* NULL is the current executable */
2592 if (DllName == NULL)
2593 {
2594 *DllHandle = ExeModule->DllBase;
2595 DPRINT("BaseAddress 0x%lx\n", *DllHandle);
2596 return STATUS_SUCCESS;
2597 }
2598
2599 Status = LdrFindEntryForName(DllName, &Module, FALSE);
2600 if (NT_SUCCESS(Status))
2601 {
2602 *DllHandle = Module->DllBase;
2603 return STATUS_SUCCESS;
2604 }
2605
2606 DPRINT("Failed to find dll %wZ\n", DllName);
2607 *DllHandle = NULL;
2608 return STATUS_DLL_NOT_FOUND;
2609 }
2610
2611 /*
2612 * @implemented
2613 */
2614 NTSTATUS NTAPI
2615 LdrAddRefDll(IN ULONG Flags,
2616 IN PVOID BaseAddress)
2617 {
2618 PLIST_ENTRY ModuleListHead;
2619 PLIST_ENTRY Entry;
2620 PLDR_DATA_TABLE_ENTRY Module;
2621 NTSTATUS Status;
2622
2623 if (Flags & ~(LDR_PIN_MODULE))
2624 {
2625 return STATUS_INVALID_PARAMETER;
2626 }
2627
2628 Status = STATUS_DLL_NOT_FOUND;
2629 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2630 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2631 Entry = ModuleListHead->Flink;
2632 while (Entry != ModuleListHead)
2633 {
2634 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2635
2636 if (Module->DllBase == BaseAddress)
2637 {
2638 if (Flags & LDR_PIN_MODULE)
2639 {
2640 Module->Flags |= LDRP_STATIC_LINK;
2641 }
2642 else
2643 {
2644 LdrpIncrementLoadCount(Module,
2645 FALSE);
2646 }
2647 Status = STATUS_SUCCESS;
2648 break;
2649 }
2650 Entry = Entry->Flink;
2651 }
2652 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2653 return Status;
2654 }
2655
2656 /*
2657 * @implemented
2658 */
2659 PVOID NTAPI
2660 RtlPcToFileHeader(IN PVOID PcValue,
2661 PVOID* BaseOfImage)
2662 {
2663 PLIST_ENTRY ModuleListHead;
2664 PLIST_ENTRY Entry;
2665 PLDR_DATA_TABLE_ENTRY Module;
2666 PVOID ImageBase = NULL;
2667
2668 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2669 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2670 Entry = ModuleListHead->Flink;
2671 while (Entry != ModuleListHead)
2672 {
2673 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2674
2675 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
2676 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
2677 {
2678 ImageBase = Module->DllBase;
2679 break;
2680 }
2681 Entry = Entry->Flink;
2682 }
2683 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2684
2685 *BaseOfImage = ImageBase;
2686 return ImageBase;
2687 }
2688
2689 /*
2690 * @implemented
2691 */
2692 NTSTATUS NTAPI
2693 LdrGetProcedureAddress (IN PVOID BaseAddress,
2694 IN PANSI_STRING Name,
2695 IN ULONG Ordinal,
2696 OUT PVOID *ProcedureAddress)
2697 {
2698 NTSTATUS Status = STATUS_PROCEDURE_NOT_FOUND;
2699 if (Name && Name->Length)
2700 {
2701 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
2702 }
2703 else
2704 {
2705 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
2706 }
2707
2708 DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
2709 BaseAddress, Name, Ordinal, ProcedureAddress);
2710
2711 _SEH2_TRY
2712 {
2713 if (Name && Name->Length)
2714 {
2715 /* by name */
2716 *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
2717 if (*ProcedureAddress != NULL)
2718 {
2719 Status = STATUS_SUCCESS;
2720 }
2721 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
2722 }
2723 else
2724 {
2725 /* by ordinal */
2726 Ordinal &= 0x0000FFFF;
2727 *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
2728 if (*ProcedureAddress)
2729 {
2730 Status = STATUS_SUCCESS;
2731 }
2732 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
2733 }
2734 }
2735 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2736 {
2737 Status = STATUS_DLL_NOT_FOUND;
2738 }
2739 _SEH2_END;
2740
2741 return Status;
2742 }
2743
2744 /**********************************************************************
2745 * NAME LOCAL
2746 * LdrpDetachProcess
2747 *
2748 * DESCRIPTION
2749 * Unload dll's which are no longer referenced from others dll's
2750 *
2751 * ARGUMENTS
2752 * none
2753 *
2754 * RETURN VALUE
2755 * none
2756 *
2757 * REVISIONS
2758 *
2759 * NOTE
2760 * The loader lock must be held on enty.
2761 */
2762 static VOID
2763 LdrpDetachProcess(BOOLEAN UnloadAll)
2764 {
2765 PLIST_ENTRY ModuleListHead;
2766 PLIST_ENTRY Entry;
2767 PLDR_DATA_TABLE_ENTRY Module;
2768 static ULONG CallingCount = 0;
2769
2770 DPRINT("LdrpDetachProcess() called for %wZ\n",
2771 &ExeModule->BaseDllName);
2772
2773 if (UnloadAll)
2774 LdrpDllShutdownInProgress = TRUE;
2775
2776 CallingCount++;
2777
2778 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2779 Entry = ModuleListHead->Blink;
2780 while (Entry != ModuleListHead)
2781 {
2782 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2783 if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) &&
2784 Module->Flags & LDRP_ENTRY_PROCESSED &&
2785 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2786 {
2787 Module->Flags |= LDRP_UNLOAD_IN_PROGRESS;
2788 if (Module == LdrpLastModule)
2789 {
2790 LdrpLastModule = NULL;
2791 }
2792 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED)
2793 {
2794 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2795 &Module->BaseDllName, Module->EntryPoint);
2796 LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2797 }
2798 else
2799 {
2800 TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
2801 }
2802 Entry = ModuleListHead->Blink;
2803 }
2804 else
2805 {
2806 Entry = Entry->Blink;
2807 }
2808 }
2809
2810 if (CallingCount == 1)
2811 {
2812 Entry = ModuleListHead->Blink;
2813 while (Entry != ModuleListHead)
2814 {
2815 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2816 Entry = Entry->Blink;
2817 if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
2818 ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0))
2819 {
2820 /* remove the module entry from the list */
2821 RemoveEntryList (&Module->InLoadOrderLinks);
2822 RemoveEntryList (&Module->InInitializationOrderLinks);
2823
2824 NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
2825 NtClose (Module->SectionPointer);
2826
2827 TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
2828
2829 RtlFreeUnicodeString (&Module->FullDllName);
2830 RtlFreeUnicodeString (&Module->BaseDllName);
2831
2832 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2833 }
2834 }
2835 }
2836 CallingCount--;
2837 DPRINT("LdrpDetachProcess() done\n");
2838 }
2839
2840 /**********************************************************************
2841 * NAME LOCAL
2842 * LdrpAttachProcess
2843 *
2844 * DESCRIPTION
2845 * Initialize all dll's which are prepered for loading
2846 *
2847 * ARGUMENTS
2848 * none
2849 *
2850 * RETURN VALUE
2851 * status
2852 *
2853 * REVISIONS
2854 *
2855 * NOTE
2856 * The loader lock must be held on entry.
2857 *
2858 */
2859 static NTSTATUS
2860 LdrpAttachProcess(VOID)
2861 {
2862 PLIST_ENTRY ModuleListHead;
2863 PLIST_ENTRY Entry;
2864 PLDR_DATA_TABLE_ENTRY Module;
2865 BOOLEAN Result;
2866 NTSTATUS Status = STATUS_SUCCESS;
2867
2868 DPRINT("LdrpAttachProcess() called for %wZ\n",
2869 &ExeModule->BaseDllName);
2870
2871 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2872 Entry = ModuleListHead->Flink;
2873 while (Entry != ModuleListHead)
2874 {
2875 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2876 if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
2877 {
2878 Module->Flags |= LDRP_LOAD_IN_PROGRESS;
2879 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2880 &Module->BaseDllName, Module->EntryPoint);
2881 Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2882 if (!Result)
2883 {
2884 Status = STATUS_DLL_INIT_FAILED;
2885 break;
2886 }
2887 if (Module->Flags & LDRP_IMAGE_DLL && Module->EntryPoint != 0)
2888 {
2889 Module->Flags |= LDRP_PROCESS_ATTACH_CALLED|LDRP_ENTRY_PROCESSED;
2890 }
2891 else
2892 {
2893 Module->Flags |= LDRP_ENTRY_PROCESSED;
2894 }
2895 Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2896 }
2897 Entry = Entry->Flink;
2898 }
2899
2900 DPRINT("LdrpAttachProcess() done\n");
2901
2902 return Status;
2903 }
2904
2905 /*
2906 * @implemented
2907 */
2908 BOOLEAN NTAPI
2909 RtlDllShutdownInProgress (VOID)
2910 {
2911 return LdrpDllShutdownInProgress;
2912 }
2913
2914 /*
2915 * @implemented
2916 */
2917 NTSTATUS NTAPI
2918 LdrShutdownProcess (VOID)
2919 {
2920 LdrpDetachProcess(TRUE);
2921 return STATUS_SUCCESS;
2922 }
2923
2924 /*
2925 * @implemented
2926 */
2927
2928 NTSTATUS
2929 LdrpAttachThread (VOID)
2930 {
2931 PLIST_ENTRY ModuleListHead;
2932 PLIST_ENTRY Entry;
2933 PLDR_DATA_TABLE_ENTRY Module;
2934 NTSTATUS Status;
2935
2936 DPRINT("LdrpAttachThread() called for %wZ\n",
2937 &ExeModule->BaseDllName);
2938
2939 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2940
2941 Status = LdrpInitializeTlsForThread();
2942
2943 if (NT_SUCCESS(Status))
2944 {
2945 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2946 Entry = ModuleListHead->Flink;
2947
2948 while (Entry != ModuleListHead)
2949 {
2950 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2951 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2952 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2953 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2954 {
2955 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2956 &Module->BaseDllName, Module->EntryPoint);
2957 LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
2958 }
2959 Entry = Entry->Flink;
2960 }
2961
2962 Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
2963 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2964 LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
2965 }
2966
2967 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2968
2969 DPRINT("LdrpAttachThread() done\n");
2970
2971 return Status;
2972 }
2973
2974
2975 /*
2976 * @implemented
2977 */
2978 NTSTATUS NTAPI
2979 LdrShutdownThread (VOID)
2980 {
2981 PLIST_ENTRY ModuleListHead;
2982 PLIST_ENTRY Entry;
2983 PLDR_DATA_TABLE_ENTRY Module;
2984
2985 DPRINT("LdrShutdownThread() called for %wZ\n",
2986 &ExeModule->BaseDllName);
2987
2988 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2989
2990 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2991 Entry = ModuleListHead->Blink;
2992 while (Entry != ModuleListHead)
2993 {
2994 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2995
2996 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2997 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2998 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2999 {
3000 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
3001 &Module->BaseDllName, Module->EntryPoint);
3002 LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
3003 }
3004 Entry = Entry->Blink;
3005 }
3006
3007 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3008
3009 if (LdrpTlsArray)
3010 {
3011 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer);
3012 }
3013
3014 DPRINT("LdrShutdownThread() done\n");
3015
3016 return STATUS_SUCCESS;
3017 }
3018
3019
3020 /***************************************************************************
3021 * NAME EXPORTED
3022 * LdrQueryProcessModuleInformation
3023 *
3024 * DESCRIPTION
3025 *
3026 * ARGUMENTS
3027 *
3028 * RETURN VALUE
3029 *
3030 * REVISIONS
3031 *
3032 * NOTE
3033 *
3034 * @implemented
3035 */
3036 NTSTATUS NTAPI
3037 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
3038 IN ULONG Size OPTIONAL,
3039 OUT PULONG ReturnedSize)
3040 {
3041 PLIST_ENTRY ModuleListHead;
3042 PLIST_ENTRY Entry;
3043 PLDR_DATA_TABLE_ENTRY Module;
3044 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
3045 NTSTATUS Status = STATUS_SUCCESS;
3046 ULONG UsedSize = sizeof(ULONG);
3047 ANSI_STRING AnsiString;
3048 PCHAR p;
3049
3050 DPRINT("LdrQueryProcessModuleInformation() called\n");
3051 // FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
3052 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
3053
3054 if (ModuleInformation == NULL || Size == 0)
3055 {
3056 Status = STATUS_INFO_LENGTH_MISMATCH;
3057 }
3058 else
3059 {
3060 ModuleInformation->NumberOfModules = 0;
3061 ModulePtr = &ModuleInformation->Modules[0];
3062 Status = STATUS_SUCCESS;
3063 }
3064
3065 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
3066 Entry = ModuleListHead->Flink;
3067
3068 while (Entry != ModuleListHead)
3069 {
3070 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3071
3072 DPRINT(" Module %wZ\n",
3073 &Module->FullDllName);
3074
3075 if (UsedSize > Size)
3076 {
3077 Status = STATUS_INFO_LENGTH_MISMATCH;
3078 }
3079 else if (ModuleInformation != NULL)
3080 {
3081 ModulePtr->Section = 0;
3082 ModulePtr->MappedBase = NULL; // FIXME: ??
3083 ModulePtr->ImageBase = Module->DllBase;
3084 ModulePtr->ImageSize = Module->SizeOfImage;
3085 ModulePtr->Flags = Module->Flags;
3086 ModulePtr->LoadOrderIndex = 0; // FIXME: ??
3087 ModulePtr->InitOrderIndex = 0; // FIXME: ??
3088 ModulePtr->LoadCount = Module->LoadCount;
3089
3090 AnsiString.Length = 0;
3091 AnsiString.MaximumLength = 256;
3092 AnsiString.Buffer = ModulePtr->FullPathName;
3093 RtlUnicodeStringToAnsiString(&AnsiString,
3094 &Module->FullDllName,
3095 FALSE);
3096
3097 p = strrchr(ModulePtr->FullPathName, '\\');
3098 if (p != NULL)
3099 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
3100 else
3101 ModulePtr->OffsetToFileName = 0;
3102
3103 ModulePtr++;
3104 ModuleInformation->NumberOfModules++;
3105 }
3106 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
3107
3108 Entry = Entry->Flink;
3109 }
3110
3111 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3112
3113 if (ReturnedSize != 0)
3114 *ReturnedSize = UsedSize;
3115
3116 DPRINT("LdrQueryProcessModuleInformation() done\n");
3117
3118 return(Status);
3119 }
3120
3121
3122 static BOOLEAN
3123 LdrpCheckImageChecksum (IN PVOID BaseAddress,
3124 IN ULONG ImageSize)
3125 {
3126 PIMAGE_NT_HEADERS Header;
3127 PUSHORT Ptr;
3128 ULONG Sum;
3129 ULONG CalcSum;
3130 ULONG HeaderSum;
3131 ULONG i;
3132
3133 Header = RtlImageNtHeader (BaseAddress);
3134 if (Header == NULL)
3135 return FALSE;
3136
3137 HeaderSum = Header->OptionalHeader.CheckSum;
3138 if (HeaderSum == 0)
3139 return TRUE;
3140
3141 Sum = 0;
3142 Ptr = (PUSHORT) BaseAddress;
3143 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
3144 {
3145 Sum += (ULONG)*Ptr;
3146 if (HIWORD(Sum) != 0)
3147 {
3148 Sum = LOWORD(Sum) + HIWORD(Sum);
3149 }
3150 Ptr++;
3151 }
3152
3153 if (ImageSize & 1)
3154 {
3155 Sum += (ULONG)*((PUCHAR)Ptr);
3156 if (HIWORD(Sum) != 0)
3157 {
3158 Sum = LOWORD(Sum) + HIWORD(Sum);
3159 }
3160 }
3161
3162 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
3163
3164 /* Subtract image checksum from calculated checksum. */
3165 /* fix low word of checksum */
3166 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
3167 {
3168 CalcSum -= LOWORD(HeaderSum);
3169 }
3170 else
3171 {
3172 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
3173 }
3174
3175 /* fix high word of checksum */
3176 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
3177 {
3178 CalcSum -= HIWORD(HeaderSum);
3179 }
3180 else
3181 {
3182 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
3183 }
3184
3185 /* add file length */
3186 CalcSum += ImageSize;
3187
3188 return (BOOLEAN)(CalcSum == HeaderSum);
3189 }
3190
3191 /*
3192 * Compute size of an image as it is actually present in virt memory
3193 * (i.e. excluding NEVER_LOAD sections)
3194 */
3195 ULONG
3196 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
3197 {
3198 PIMAGE_SECTION_HEADER SectionHeader;
3199 unsigned SectionIndex;
3200 ULONG ResidentSize;
3201
3202 SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
3203 + NTHeaders->FileHeader.SizeOfOptionalHeader);
3204 ResidentSize = 0;
3205 for (SectionIndex = 0; SectionIndex < NTHeaders->FileHeader.NumberOfSections; SectionIndex++)
3206 {
3207 if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
3208 && ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
3209 {
3210 ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
3211 }
3212 SectionHeader++;
3213 }
3214
3215 return ResidentSize;
3216 }
3217
3218
3219 /***************************************************************************
3220 * NAME EXPORTED
3221 * LdrVerifyImageMatchesChecksum
3222 *
3223 * DESCRIPTION
3224 *
3225 * ARGUMENTS
3226 *
3227 * RETURN VALUE
3228 *
3229 * REVISIONS
3230 *
3231 * NOTE
3232 *
3233 * @implemented
3234 */
3235 NTSTATUS NTAPI
3236 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
3237 ULONG Unknown1,
3238 ULONG Unknown2,
3239 ULONG Unknown3)
3240 {
3241 FILE_STANDARD_INFORMATION FileInfo;
3242 IO_STATUS_BLOCK IoStatusBlock;
3243 HANDLE SectionHandle;
3244 SIZE_T ViewSize;
3245 PVOID BaseAddress;
3246 BOOLEAN Result;
3247 NTSTATUS Status;
3248
3249 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
3250
3251 Status = NtCreateSection (&SectionHandle,
3252 SECTION_MAP_READ,
3253 NULL,
3254 NULL,
3255 PAGE_READONLY,
3256 SEC_COMMIT,
3257 FileHandle);
3258 if (!NT_SUCCESS(Status))
3259 {
3260 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
3261 return Status;
3262 }
3263
3264 ViewSize = 0;
3265 BaseAddress = NULL;
3266 Status = NtMapViewOfSection (SectionHandle,
3267 NtCurrentProcess (),
3268 &BaseAddress,
3269 0,
3270 0,
3271 NULL,
3272 &ViewSize,
3273 ViewShare,
3274 0,
3275 PAGE_READONLY);
3276 if (!NT_SUCCESS(Status))
3277 {
3278 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3279 NtClose (SectionHandle);
3280 return Status;
3281 }
3282
3283 Status = NtQueryInformationFile (FileHandle,
3284 &IoStatusBlock,
3285 &FileInfo,
3286 sizeof (FILE_STANDARD_INFORMATION),
3287 FileStandardInformation);
3288 if (!NT_SUCCESS(Status))
3289 {
3290 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3291 NtUnmapViewOfSection (NtCurrentProcess (),
3292 BaseAddress);
3293 NtClose (SectionHandle);
3294 return Status;
3295 }
3296
3297 Result = LdrpCheckImageChecksum (BaseAddress,
3298 FileInfo.EndOfFile.u.LowPart);
3299 if (Result == FALSE)
3300 {
3301 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
3302 }
3303
3304 NtUnmapViewOfSection (NtCurrentProcess (),
3305 BaseAddress);
3306
3307 NtClose (SectionHandle);
3308
3309 return Status;
3310 }
3311
3312
3313 /***************************************************************************
3314 * NAME EXPORTED
3315 * LdrQueryImageFileExecutionOptions
3316 *
3317 * DESCRIPTION
3318 *
3319 * ARGUMENTS
3320 *
3321 * RETURN VALUE
3322 *
3323 * REVISIONS
3324 *
3325 * NOTE
3326 *
3327 * @implemented
3328 */
3329 NTSTATUS NTAPI
3330 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
3331 IN PCWSTR ValueName,
3332 IN ULONG Type,
3333 OUT PVOID Buffer,
3334 IN ULONG BufferSize,
3335 OUT PULONG ReturnedLength OPTIONAL)
3336 {
3337 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
3338 OBJECT_ATTRIBUTES ObjectAttributes;
3339 UNICODE_STRING ValueNameString;
3340 UNICODE_STRING KeyName;
3341 WCHAR NameBuffer[256];
3342 HANDLE KeyHandle;
3343 ULONG KeyInfoSize;
3344 ULONG ResultSize;
3345 PWCHAR Ptr;
3346 NTSTATUS Status;
3347
3348 wcscpy (NameBuffer,
3349 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
3350 Ptr = wcsrchr (SubKey->Buffer, L'\\');
3351 if (Ptr == NULL)
3352 {
3353 Ptr = SubKey->Buffer;
3354 }
3355 else
3356 {
3357 Ptr++;
3358 }
3359 wcscat (NameBuffer, Ptr);
3360 RtlInitUnicodeString (&KeyName,
3361 NameBuffer);
3362
3363 InitializeObjectAttributes (&ObjectAttributes,
3364 &KeyName,
3365 OBJ_CASE_INSENSITIVE,
3366 NULL,
3367 NULL);
3368
3369 Status = NtOpenKey (&KeyHandle,
3370 KEY_READ,
3371 &ObjectAttributes);
3372 if (!NT_SUCCESS(Status))
3373 {
3374 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
3375 return Status;
3376 }
3377
3378 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
3379 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3380 HEAP_ZERO_MEMORY,
3381 KeyInfoSize);
3382 if (KeyInfo == NULL)
3383 {
3384 NtClose (KeyHandle);
3385 return STATUS_INSUFFICIENT_RESOURCES;
3386 }
3387
3388 RtlInitUnicodeString (&ValueNameString,
3389 (PWSTR)ValueName);
3390 Status = NtQueryValueKey (KeyHandle,
3391 &ValueNameString,
3392 KeyValuePartialInformation,
3393 KeyInfo,
3394 KeyInfoSize,
3395 &ResultSize);
3396 if (Status == STATUS_BUFFER_OVERFLOW)
3397 {
3398 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
3399 RtlFreeHeap (RtlGetProcessHeap(),
3400 0,
3401 KeyInfo);
3402 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3403 HEAP_ZERO_MEMORY,
3404 KeyInfoSize);
3405 if (KeyInfo == NULL)
3406 {
3407 NtClose (KeyHandle);
3408 return STATUS_INSUFFICIENT_RESOURCES;
3409 }
3410
3411 Status = NtQueryValueKey (KeyHandle,
3412 &ValueNameString,
3413 KeyValuePartialInformation,
3414 KeyInfo,
3415 KeyInfoSize,
3416 &ResultSize);
3417 }
3418 NtClose (KeyHandle);
3419
3420 if (!NT_SUCCESS(Status))
3421 {
3422 if (KeyInfo != NULL)
3423 {
3424 RtlFreeHeap (RtlGetProcessHeap(),
3425 0,
3426 KeyInfo);
3427 }
3428 return Status;
3429 }
3430
3431 if (KeyInfo->Type != Type)
3432 {
3433 RtlFreeHeap (RtlGetProcessHeap(),
3434 0,
3435 KeyInfo);
3436 return STATUS_OBJECT_TYPE_MISMATCH;
3437 }
3438
3439 ResultSize = BufferSize;
3440 if (ResultSize < KeyInfo->DataLength)
3441 {
3442 Status = STATUS_BUFFER_OVERFLOW;
3443 }
3444 else
3445 {
3446 ResultSize = KeyInfo->DataLength;
3447 }
3448 RtlCopyMemory (Buffer,
3449 &KeyInfo->Data,
3450 ResultSize);
3451
3452 RtlFreeHeap (RtlGetProcessHeap(),
3453 0,
3454 KeyInfo);
3455
3456 if (ReturnedLength != NULL)
3457 {
3458 *ReturnedLength = ResultSize;
3459 }
3460
3461 return Status;
3462 }
3463
3464
3465 PIMAGE_BASE_RELOCATION NTAPI
3466 LdrProcessRelocationBlock(IN ULONG_PTR Address,
3467 IN ULONG Count,
3468 IN PUSHORT TypeOffset,
3469 IN LONG_PTR Delta)
3470 {
3471 SHORT Offset;
3472 USHORT Type;
3473 USHORT i;
3474 PUSHORT ShortPtr;
3475 PULONG LongPtr;
3476
3477 for (i = 0; i < Count; i++)
3478 {
3479 Offset = *TypeOffset & 0xFFF;
3480 Type = *TypeOffset >> 12;
3481
3482 switch (Type)
3483 {
3484 case IMAGE_REL_BASED_ABSOLUTE:
3485 break;
3486
3487 case IMAGE_REL_BASED_HIGH:
3488 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3489 *ShortPtr += HIWORD(Delta);
3490 break;
3491
3492 case IMAGE_REL_BASED_LOW:
3493 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3494 *ShortPtr += LOWORD(Delta);
3495 break;
3496
3497 case IMAGE_REL_BASED_HIGHLOW:
3498 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3499 *LongPtr += Delta;
3500 break;
3501 #ifdef _WIN64
3502 case IMAGE_REL_BASED_DIR64:
3503 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3504 *LongPtr += Delta;
3505 break;
3506 #endif
3507
3508 case IMAGE_REL_BASED_HIGHADJ:
3509 case IMAGE_REL_BASED_MIPS_JMPADDR:
3510 default:
3511 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
3512 return NULL;
3513 }
3514
3515 TypeOffset++;
3516 }
3517
3518 return (PIMAGE_BASE_RELOCATION)TypeOffset;
3519 }
3520
3521 NTSTATUS
3522 NTAPI
3523 LdrLockLoaderLock(IN ULONG Flags,
3524 OUT PULONG Disposition OPTIONAL,
3525 OUT PULONG Cookie OPTIONAL)
3526 {
3527 NTSTATUS Status;
3528 BOOLEAN Ret;
3529 BOOLEAN CookieSet = FALSE;
3530
3531 if ((Flags != 0x01) && (Flags != 0x02))
3532 return STATUS_INVALID_PARAMETER_1;
3533
3534 if (!Cookie) return STATUS_INVALID_PARAMETER_3;
3535
3536 /* Set some defaults for failure while verifying params */
3537 _SEH2_TRY
3538 {
3539 *Cookie = 0;
3540 CookieSet = TRUE;
3541 if (Disposition) *Disposition = 0;
3542 }
3543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3544 {
3545 if (CookieSet)
3546 Status = STATUS_INVALID_PARAMETER_3;
3547 else
3548 Status = STATUS_INVALID_PARAMETER_2;
3549 }
3550 _SEH2_END;
3551
3552 if (Flags == 0x01)
3553 {
3554 DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
3555 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3556 Status = STATUS_SUCCESS;
3557
3558 }
3559 else
3560 {
3561 if (!Disposition) return STATUS_INVALID_PARAMETER_2;
3562
3563 Ret = RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3564
3565 if (Ret)
3566 *Disposition = 0x01;
3567 else
3568 *Disposition = 0x02;
3569
3570 Status = STATUS_SUCCESS;
3571 }
3572
3573 /* FIXME: Cookie is based on part of the thread id */
3574 *Cookie = (ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread;
3575 return Status;
3576 }
3577
3578 NTSTATUS
3579 NTAPI
3580 LdrUnlockLoaderLock(IN ULONG Flags,
3581 IN ULONG Cookie OPTIONAL)
3582 {
3583 if (Flags != 0x01)
3584 return STATUS_INVALID_PARAMETER_1;
3585
3586 if (Cookie != (ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread)
3587 return STATUS_INVALID_PARAMETER_2;
3588
3589 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
3590
3591 return STATUS_SUCCESS;
3592 }
3593
3594 BOOLEAN
3595 NTAPI
3596 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
3597 {
3598 UNIMPLEMENTED;
3599 return FALSE;
3600 }