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