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