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